Merge branch 'master' of git://scm.dev.nokia.troll.no/qt/qtbase-earth-staging
* 'master' of git://scm.dev.nokia.troll.no/qt/qtbase-earth-staging: (26 commits) QSslConfiguration documentation fix HTTP auto tests: do not load resources from cache that must be revalidtd HTTP cache backend: do not load resources that must be revalidated HTTP reply: do not load resources from cache that must be revalidated QNetworkCookie: allow spaces in unquoted values QNAM HTTP: Removes some comments QNAM HTTP: More comments QNAM HTTP: Implement abort() and close() QNAM HTTP: Comments QNAM: Function re-ordering Revert "HTTP caching internals: fix logic for PreferNetwork and PreferCache" HTTP caching documentation: add some comments Revert "HTTP caching internals: fix logic for PreferNetwork and PreferCache" QNAM: Fix initialization order warnings QNAM: TODO comments for Qt 5 QNAM HTTP: Fix upload progress signal HTTP caching internals: fix logic for PreferNetwork and PreferCache HTTP Network Reply Impl: return earlier when resource loaded from cache HTTP Reply implementation: make cache validation method return bool cache: rename validateCache() to loadFromCacheIfAllowed() ...
This commit is contained in:
commit
33558a886d
@ -14,7 +14,6 @@ HEADERS += \
|
||||
access/qnetworkaccesscache_p.h \
|
||||
access/qnetworkaccessbackend_p.h \
|
||||
access/qnetworkaccessdebugpipebackend_p.h \
|
||||
access/qnetworkaccesshttpbackend_p.h \
|
||||
access/qnetworkaccessfilebackend_p.h \
|
||||
access/qnetworkaccesscachebackend_p.h \
|
||||
access/qnetworkaccessftpbackend_p.h \
|
||||
@ -29,6 +28,7 @@ HEADERS += \
|
||||
access/qnetworkreply_p.h \
|
||||
access/qnetworkreplyimpl_p.h \
|
||||
access/qnetworkreplydataimpl_p.h \
|
||||
access/qnetworkreplyhttpimpl_p.h \
|
||||
access/qnetworkreplyfileimpl_p.h \
|
||||
access/qabstractnetworkcache_p.h \
|
||||
access/qabstractnetworkcache.h \
|
||||
@ -54,13 +54,13 @@ SOURCES += \
|
||||
access/qnetworkaccessfilebackend.cpp \
|
||||
access/qnetworkaccesscachebackend.cpp \
|
||||
access/qnetworkaccessftpbackend.cpp \
|
||||
access/qnetworkaccesshttpbackend.cpp \
|
||||
access/qnetworkcookie.cpp \
|
||||
access/qnetworkcookiejar.cpp \
|
||||
access/qnetworkrequest.cpp \
|
||||
access/qnetworkreply.cpp \
|
||||
access/qnetworkreplyimpl.cpp \
|
||||
access/qnetworkreplydataimpl.cpp \
|
||||
access/qnetworkreplyhttpimpl.cpp \
|
||||
access/qnetworkreplyfileimpl.cpp \
|
||||
access/qabstractnetworkcache.cpp \
|
||||
access/qnetworkdiskcache.cpp \
|
||||
|
@ -315,13 +315,13 @@ void QNetworkAccessBackend::error(QNetworkReply::NetworkError code, const QStrin
|
||||
void QNetworkAccessBackend::proxyAuthenticationRequired(const QNetworkProxy &proxy,
|
||||
QAuthenticator *authenticator)
|
||||
{
|
||||
manager->proxyAuthenticationRequired(this, proxy, authenticator);
|
||||
manager->proxyAuthenticationRequired(proxy, synchronous, authenticator, &reply->lastProxyAuthentication);
|
||||
}
|
||||
#endif
|
||||
|
||||
void QNetworkAccessBackend::authenticationRequired(QAuthenticator *authenticator)
|
||||
{
|
||||
manager->authenticationRequired(this, authenticator);
|
||||
manager->authenticationRequired(authenticator, reply->q_func(), synchronous, reply->url, &reply->urlForLastAuthentication);
|
||||
}
|
||||
|
||||
void QNetworkAccessBackend::metaDataChanged()
|
||||
|
@ -66,6 +66,7 @@ void QNetworkAccessCacheBackend::open()
|
||||
QString msg = QCoreApplication::translate("QNetworkAccessCacheBackend", "Error opening %1")
|
||||
.arg(this->url().toString());
|
||||
error(QNetworkReply::ContentNotFoundError, msg);
|
||||
} else {
|
||||
setAttribute(QNetworkRequest::SourceIsFromCacheAttribute, true);
|
||||
}
|
||||
finished();
|
||||
@ -85,14 +86,18 @@ bool QNetworkAccessCacheBackend::sendCacheContents()
|
||||
QNetworkCacheMetaData::AttributesMap attributes = item.attributes();
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, attributes.value(QNetworkRequest::HttpStatusCodeAttribute));
|
||||
setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, attributes.value(QNetworkRequest::HttpReasonPhraseAttribute));
|
||||
setAttribute(QNetworkRequest::SourceIsFromCacheAttribute, true);
|
||||
|
||||
// set the raw headers
|
||||
QNetworkCacheMetaData::RawHeaderList rawHeaders = item.rawHeaders();
|
||||
QNetworkCacheMetaData::RawHeaderList::ConstIterator it = rawHeaders.constBegin(),
|
||||
end = rawHeaders.constEnd();
|
||||
for ( ; it != end; ++it)
|
||||
for ( ; it != end; ++it) {
|
||||
if (it->first.toLower() == "cache-control" &&
|
||||
it->second.toLower().contains("must-revalidate")) {
|
||||
return false;
|
||||
}
|
||||
setRawHeader(it->first, it->second);
|
||||
}
|
||||
|
||||
// handle a possible redirect
|
||||
QVariant redirectionTarget = attributes.value(QNetworkRequest::RedirectionTargetAttribute);
|
||||
|
@ -67,13 +67,12 @@
|
||||
#include "QtNetwork/qhttpmultipart.h"
|
||||
#include "qhttpmultipart_p.h"
|
||||
|
||||
#include "qnetworkreplyhttpimpl_p.h"
|
||||
|
||||
#include "qthread.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_HTTP
|
||||
Q_GLOBAL_STATIC(QNetworkAccessHttpBackendFactory, httpBackend)
|
||||
#endif // QT_NO_HTTP
|
||||
Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
|
||||
#ifndef QT_NO_FTP
|
||||
Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
|
||||
@ -85,10 +84,6 @@ Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
|
||||
|
||||
static void ensureInitialized()
|
||||
{
|
||||
#ifndef QT_NO_HTTP
|
||||
(void) httpBackend();
|
||||
#endif // QT_NO_HTTP
|
||||
|
||||
#ifndef QT_NO_FTP
|
||||
(void) ftpBackend();
|
||||
#endif
|
||||
@ -356,6 +351,17 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
|
||||
ensureInitialized();
|
||||
|
||||
qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
qRegisterMetaType<QNetworkProxy>("QNetworkProxy");
|
||||
#endif
|
||||
#ifndef QT_NO_OPENSSL
|
||||
qRegisterMetaType<QList<QSslError> >("QList<QSslError>");
|
||||
qRegisterMetaType<QSslConfiguration>("QSslConfiguration");
|
||||
#endif
|
||||
qRegisterMetaType<QList<QPair<QByteArray,QByteArray> > >("QList<QPair<QByteArray,QByteArray> >");
|
||||
qRegisterMetaType<QHttpNetworkRequest>("QHttpNetworkRequest");
|
||||
qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
|
||||
qRegisterMetaType<QSharedPointer<char> >("QSharedPointer<char>");
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -967,6 +973,18 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef QT_NO_HTTP
|
||||
// Since Qt 5 we use the new QNetworkReplyHttpImpl
|
||||
if (scheme == QLatin1String("http") || scheme == QLatin1String("https") ) {
|
||||
QNetworkReplyHttpImpl *reply = new QNetworkReplyHttpImpl(this, request, op, outgoingData);
|
||||
#ifndef QT_NO_BEARERMANAGEMENT
|
||||
connect(this, SIGNAL(networkSessionConnected()),
|
||||
reply, SLOT(_q_networkSessionConnected()));
|
||||
#endif
|
||||
return reply;
|
||||
}
|
||||
#endif // QT_NO_HTTP
|
||||
|
||||
// first step: create the reply
|
||||
QUrl url = request.url();
|
||||
QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
|
||||
@ -1055,42 +1073,43 @@ void QNetworkAccessManagerPrivate::createCookieJar() const
|
||||
}
|
||||
}
|
||||
|
||||
void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend *backend,
|
||||
QAuthenticator *authenticator)
|
||||
void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authenticator,
|
||||
QNetworkReply *reply,
|
||||
bool synchronous,
|
||||
QUrl &url,
|
||||
QUrl *urlForLastAuthentication)
|
||||
{
|
||||
Q_Q(QNetworkAccessManager);
|
||||
|
||||
// FIXME: Add support for domains (i.e., the leading path)
|
||||
QUrl url = backend->reply->url;
|
||||
|
||||
// don't try the cache for the same URL twice in a row
|
||||
// being called twice for the same URL means the authentication failed
|
||||
// also called when last URL is empty, e.g. on first call
|
||||
if (backend->reply->urlForLastAuthentication.isEmpty()
|
||||
|| url != backend->reply->urlForLastAuthentication) {
|
||||
if (urlForLastAuthentication->isEmpty()
|
||||
|| url != *urlForLastAuthentication) {
|
||||
QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedCredentials(url, authenticator);
|
||||
if (!cred.isNull()) {
|
||||
authenticator->setUser(cred.user);
|
||||
authenticator->setPassword(cred.password);
|
||||
backend->reply->urlForLastAuthentication = url;
|
||||
*urlForLastAuthentication = url;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if we emit a signal here in synchronous mode, the user might spin
|
||||
// an event loop, which might recurse and lead to problems
|
||||
if (backend->isSynchronous())
|
||||
if (synchronous)
|
||||
return;
|
||||
|
||||
backend->reply->urlForLastAuthentication = url;
|
||||
emit q->authenticationRequired(backend->reply->q_func(), authenticator);
|
||||
*urlForLastAuthentication = url;
|
||||
emit q->authenticationRequired(reply, authenticator);
|
||||
authenticationManager->cacheCredentials(url, authenticator);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBackend *backend,
|
||||
const QNetworkProxy &proxy,
|
||||
QAuthenticator *authenticator)
|
||||
void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(const QNetworkProxy &proxy,
|
||||
bool synchronous,
|
||||
QAuthenticator *authenticator,
|
||||
QNetworkProxy *lastProxyAuthentication)
|
||||
{
|
||||
Q_Q(QNetworkAccessManager);
|
||||
// ### FIXME Tracking of successful authentications
|
||||
@ -1100,7 +1119,7 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBac
|
||||
// proxyAuthenticationRequired gets emitted again
|
||||
// possible solution: some tracking inside the authenticator
|
||||
// or a new function proxyAuthenticationSucceeded(true|false)
|
||||
if (proxy != backend->reply->lastProxyAuthentication) {
|
||||
if (proxy != *lastProxyAuthentication) {
|
||||
QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
|
||||
if (!cred.isNull()) {
|
||||
authenticator->setUser(cred.user);
|
||||
@ -1111,10 +1130,10 @@ void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBac
|
||||
|
||||
// if we emit a signal here in synchronous mode, the user might spin
|
||||
// an event loop, which might recurse and lead to problems
|
||||
if (backend->isSynchronous())
|
||||
if (synchronous)
|
||||
return;
|
||||
|
||||
backend->reply->lastProxyAuthentication = proxy;
|
||||
*lastProxyAuthentication = proxy;
|
||||
emit q->proxyAuthenticationRequired(proxy, authenticator);
|
||||
authenticationManager->cacheProxyCredentials(proxy, authenticator);
|
||||
}
|
||||
|
@ -160,6 +160,7 @@ protected:
|
||||
private:
|
||||
friend class QNetworkReplyImplPrivate;
|
||||
friend class QNetworkAccessHttpBackend;
|
||||
friend class QNetworkReplyHttpImpl;
|
||||
|
||||
Q_DECLARE_PRIVATE(QNetworkAccessManager)
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_replyFinished())
|
||||
|
@ -94,14 +94,20 @@ public:
|
||||
QNetworkReply *postProcess(QNetworkReply *reply);
|
||||
void createCookieJar() const;
|
||||
|
||||
void authenticationRequired(QNetworkAccessBackend *backend, QAuthenticator *authenticator);
|
||||
void authenticationRequired(QAuthenticator *authenticator,
|
||||
QNetworkReply *reply,
|
||||
bool synchronous,
|
||||
QUrl &url,
|
||||
QUrl *urlForLastAuthentication);
|
||||
void cacheCredentials(const QUrl &url, const QAuthenticator *auth);
|
||||
QNetworkAuthenticationCredential *fetchCachedCredentials(const QUrl &url,
|
||||
const QAuthenticator *auth = 0);
|
||||
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
void proxyAuthenticationRequired(QNetworkAccessBackend *backend, const QNetworkProxy &proxy,
|
||||
QAuthenticator *authenticator);
|
||||
void proxyAuthenticationRequired(const QNetworkProxy &proxy,
|
||||
bool synchronous,
|
||||
QAuthenticator *authenticator,
|
||||
QNetworkProxy *lastProxyAuthentication);
|
||||
void cacheProxyCredentials(const QNetworkProxy &proxy, const QAuthenticator *auth);
|
||||
QNetworkAuthenticationCredential *fetchCachedProxyCredentials(const QNetworkProxy &proxy,
|
||||
const QAuthenticator *auth = 0);
|
||||
|
@ -395,8 +395,8 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
|
||||
// qdtext = <any TEXT except <">>
|
||||
// quoted-pair = "\" CHAR
|
||||
|
||||
// If its NAME=VALUE, retain the value as is
|
||||
// refer to ttp://bugreports.qt.nokia.com/browse/QTBUG-17746
|
||||
// If it is NAME=VALUE, retain the value as is
|
||||
// refer to http://bugreports.qt.nokia.com/browse/QTBUG-17746
|
||||
if (isNameValue)
|
||||
second += '"';
|
||||
++i;
|
||||
@ -432,7 +432,9 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
|
||||
position = i;
|
||||
for ( ; i < length; ++i) {
|
||||
register char c = text.at(i);
|
||||
if (c == ',' || c == ';' || isLWS(c))
|
||||
// for name value pairs, we want to parse until reaching the next ';'
|
||||
// and not break when reaching a space char
|
||||
if (c == ',' || c == ';' || ((isNameValue && (c == '\n' || c == '\r')) || (!isNameValue && isLWS(c))))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -487,7 +489,6 @@ QByteArray QNetworkCookie::toRawForm(RawForm form) const
|
||||
result += '=';
|
||||
if ((d->value.contains(';') ||
|
||||
d->value.contains(',') ||
|
||||
d->value.contains(' ') ||
|
||||
d->value.contains('"')) &&
|
||||
(!d->value.startsWith('"') &&
|
||||
!d->value.endsWith('"'))) {
|
||||
|
1983
src/network/access/qnetworkreplyhttpimpl.cpp
Normal file
1983
src/network/access/qnetworkreplyhttpimpl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
309
src/network/access/qnetworkreplyhttpimpl_p.h
Normal file
309
src/network/access/qnetworkreplyhttpimpl_p.h
Normal file
@ -0,0 +1,309 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QNETWORKREPLYHTTPIMPL_P_H
|
||||
#define QNETWORKREPLYHTTPIMPL_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists for the convenience
|
||||
// of the Network Access API. This header file may change from
|
||||
// version to version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "qnetworkrequest.h"
|
||||
#include "qnetworkreply.h"
|
||||
|
||||
#include "QtCore/qpointer.h"
|
||||
#include "QtCore/qdatetime.h"
|
||||
#include "QtCore/qsharedpointer.h"
|
||||
#include "qatomic.h"
|
||||
|
||||
#include <QtNetwork/QNetworkCacheMetaData>
|
||||
#include <private/qhttpnetworkrequest_p.h>
|
||||
#include <private/qbytedata_p.h>
|
||||
#include <private/qnetworkreply_p.h>
|
||||
#include <QtNetwork/QNetworkProxy>
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#include <QtNetwork/QSslConfiguration>
|
||||
#endif
|
||||
|
||||
#ifndef QT_NO_HTTP
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QIODevice;
|
||||
|
||||
class QNetworkReplyHttpImplPrivate;
|
||||
class QNetworkReplyHttpImpl: public QNetworkReply
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QNetworkReplyHttpImpl(QNetworkAccessManager* const, const QNetworkRequest&, QNetworkAccessManager::Operation&, QIODevice* outgoingData);
|
||||
virtual ~QNetworkReplyHttpImpl();
|
||||
|
||||
void close();
|
||||
void abort();
|
||||
qint64 bytesAvailable() const;
|
||||
bool isSequential () const;
|
||||
qint64 size() const;
|
||||
qint64 readData(char*, qint64);
|
||||
void setReadBufferSize(qint64 size);
|
||||
bool canReadLine () const;
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
void ignoreSslErrors();
|
||||
// ### Qt5 Add proper virtual
|
||||
Q_INVOKABLE void ignoreSslErrorsImplementation(const QList<QSslError> &errors);
|
||||
// ### Qt5 Add proper virtual
|
||||
Q_INVOKABLE void setSslConfigurationImplementation(const QSslConfiguration &configuration);
|
||||
// ### Qt5 Add proper virtual
|
||||
Q_INVOKABLE QSslConfiguration sslConfigurationImplementation() const;
|
||||
#endif
|
||||
|
||||
Q_DECLARE_PRIVATE(QNetworkReplyHttpImpl)
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_startOperation())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_cacheLoadReadyRead())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingData())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingDataFinished())
|
||||
#ifndef QT_NO_BEARERMANAGEMENT
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_networkSessionConnected())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_networkSessionFailed())
|
||||
#endif
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_finished())
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_error(QNetworkReply::NetworkError, const QString &))
|
||||
|
||||
// From reply
|
||||
Q_PRIVATE_SLOT(d_func(), void replyDownloadData(QByteArray))
|
||||
Q_PRIVATE_SLOT(d_func(), void replyFinished())
|
||||
Q_PRIVATE_SLOT(d_func(), void replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64))
|
||||
Q_PRIVATE_SLOT(d_func(), void replyDownloadProgressSlot(qint64,qint64))
|
||||
Q_PRIVATE_SLOT(d_func(), void httpAuthenticationRequired(const QHttpNetworkRequest &, QAuthenticator *))
|
||||
Q_PRIVATE_SLOT(d_func(), void httpError(QNetworkReply::NetworkError, const QString &))
|
||||
#ifndef QT_NO_OPENSSL
|
||||
Q_PRIVATE_SLOT(d_func(), void replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *))
|
||||
Q_PRIVATE_SLOT(d_func(), void replySslConfigurationChanged(const QSslConfiguration&))
|
||||
#endif
|
||||
Q_PRIVATE_SLOT(d_func(), void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth))
|
||||
|
||||
Q_PRIVATE_SLOT(d_func(), void resetUploadDataSlot(bool *r))
|
||||
Q_PRIVATE_SLOT(d_func(), void wantUploadDataSlot(qint64))
|
||||
Q_PRIVATE_SLOT(d_func(), void sentUploadDataSlot(qint64))
|
||||
Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64))
|
||||
|
||||
|
||||
|
||||
signals:
|
||||
// To HTTP thread:
|
||||
void startHttpRequest();
|
||||
void abortHttpRequest();
|
||||
|
||||
void startHttpRequestSynchronously();
|
||||
|
||||
void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
|
||||
};
|
||||
|
||||
class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate
|
||||
{
|
||||
public:
|
||||
|
||||
static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& prio);
|
||||
|
||||
enum State {
|
||||
Idle, // The reply is idle.
|
||||
Buffering, // The reply is buffering outgoing data.
|
||||
Working, // The reply is uploading/downloading data.
|
||||
Finished, // The reply has finished.
|
||||
Aborted, // The reply has been aborted.
|
||||
WaitingForSession, // The reply is waiting for the session to open before connecting.
|
||||
Reconnecting // The reply will reconnect to once roaming has completed.
|
||||
};
|
||||
|
||||
QNetworkReplyHttpImplPrivate();
|
||||
~QNetworkReplyHttpImplPrivate();
|
||||
|
||||
bool start();
|
||||
void _q_startOperation();
|
||||
|
||||
void _q_cacheLoadReadyRead();
|
||||
|
||||
void _q_bufferOutgoingData();
|
||||
void _q_bufferOutgoingDataFinished();
|
||||
|
||||
#ifndef QT_NO_BEARERMANAGEMENT
|
||||
void _q_networkSessionConnected();
|
||||
void _q_networkSessionFailed();
|
||||
#endif
|
||||
void _q_finished();
|
||||
|
||||
|
||||
// FIXME
|
||||
void finished();
|
||||
void error(QNetworkReply::NetworkError code, const QString &errorString);
|
||||
void _q_error(QNetworkReply::NetworkError code, const QString &errorString);
|
||||
void metaDataChanged();
|
||||
|
||||
void redirectionRequested(const QUrl &target);
|
||||
void checkForRedirect(const int statusCode);
|
||||
|
||||
|
||||
// incoming from user
|
||||
QNetworkAccessManager *manager;
|
||||
QNetworkAccessManagerPrivate *managerPrivate;
|
||||
QNetworkRequest request;
|
||||
QNetworkAccessManager::Operation operation; // FIXME already in replyprivate?
|
||||
QHttpNetworkRequest httpRequest; // There is also a copy in the HTTP thread
|
||||
bool synchronous;
|
||||
|
||||
State state;
|
||||
|
||||
// from http thread
|
||||
int statusCode;
|
||||
QString reasonPhrase;
|
||||
|
||||
// upload
|
||||
QNonContiguousByteDevice* createUploadByteDevice();
|
||||
QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
|
||||
QIODevice *outgoingData;
|
||||
QSharedPointer<QRingBuffer> outgoingDataBuffer;
|
||||
void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal); // dup?
|
||||
qint64 bytesUploaded;
|
||||
|
||||
|
||||
// cache
|
||||
void createCache();
|
||||
void completeCacheSave();
|
||||
void setCachingEnabled(bool enable);
|
||||
bool isCachingEnabled() const;
|
||||
void initCacheSaveDevice();
|
||||
QAbstractNetworkCache *networkCache() const;
|
||||
QIODevice *cacheLoadDevice;
|
||||
bool loadingFromCache;
|
||||
|
||||
QIODevice *cacheSaveDevice;
|
||||
bool cacheEnabled; // is this for saving?
|
||||
|
||||
|
||||
QUrl urlForLastAuthentication;
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
QNetworkProxy lastProxyAuthentication;
|
||||
QList<QNetworkProxy> proxyList;
|
||||
#endif
|
||||
|
||||
|
||||
bool migrateBackend();
|
||||
bool canResume() const;
|
||||
void setResumeOffset(quint64 offset);
|
||||
quint64 resumeOffset;
|
||||
qint64 preMigrationDownloaded;
|
||||
|
||||
// Used for normal downloading. For "zero copy" the downloadZerocopyBuffer is used
|
||||
QByteDataBuffer downloadMultiBuffer;
|
||||
QByteDataBuffer pendingDownloadData; // For signal compression
|
||||
qint64 bytesDownloaded;
|
||||
qint64 lastBytesDownloaded;
|
||||
void setDownloadBuffer(QSharedPointer<char> sp, qint64 size);
|
||||
char* getDownloadBuffer(qint64 size);
|
||||
|
||||
// only used when the "zero copy" style is used. Else downloadMultiBuffer is used.
|
||||
// Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
|
||||
qint64 downloadBufferReadPosition;
|
||||
qint64 downloadBufferCurrentSize;
|
||||
qint64 downloadBufferMaximumSize;
|
||||
QSharedPointer<char> downloadBufferPointer;
|
||||
char* downloadZerocopyBuffer;
|
||||
|
||||
// Will be increased by HTTP thread:
|
||||
QSharedPointer<QAtomicInt> pendingDownloadDataEmissions;
|
||||
QSharedPointer<QAtomicInt> pendingDownloadProgressEmissions;
|
||||
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
QSslConfiguration sslConfiguration;
|
||||
bool pendingIgnoreAllSslErrors;
|
||||
QList<QSslError> pendingIgnoreSslErrorsList;
|
||||
#endif
|
||||
|
||||
|
||||
bool loadFromCacheIfAllowed(QHttpNetworkRequest &httpRequest);
|
||||
void invalidateCache();
|
||||
bool sendCacheContents(const QNetworkCacheMetaData &metaData);
|
||||
QNetworkCacheMetaData fetchCacheMetaData(const QNetworkCacheMetaData &metaData) const;
|
||||
|
||||
|
||||
void postRequest();
|
||||
|
||||
|
||||
|
||||
public:
|
||||
// From HTTP thread:
|
||||
void replyDownloadData(QByteArray);
|
||||
void replyFinished();
|
||||
void replyDownloadMetaData(QList<QPair<QByteArray,QByteArray> >,int,QString,bool,QSharedPointer<char>,qint64);
|
||||
void replyDownloadProgressSlot(qint64,qint64);
|
||||
void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth);
|
||||
void httpError(QNetworkReply::NetworkError error, const QString &errorString);
|
||||
#ifndef QT_NO_OPENSSL
|
||||
void replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *);
|
||||
void replySslConfigurationChanged(const QSslConfiguration&);
|
||||
#endif
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth);
|
||||
#endif
|
||||
|
||||
// From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread:
|
||||
void resetUploadDataSlot(bool *r);
|
||||
void wantUploadDataSlot(qint64);
|
||||
void sentUploadDataSlot(qint64);
|
||||
|
||||
Q_DECLARE_PUBLIC(QNetworkReplyHttpImpl)
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_HTTP
|
||||
|
||||
#endif
|
@ -47,7 +47,6 @@
|
||||
#include "QtCore/qdatetime.h"
|
||||
#include "QtNetwork/qsslconfiguration.h"
|
||||
#include "QtNetwork/qnetworksession.h"
|
||||
#include "qnetworkaccesshttpbackend_p.h"
|
||||
#include "qnetworkaccessmanager_p.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
@ -356,7 +355,7 @@ void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const
|
||||
// for HTTP, we want to send out the request as fast as possible to the network, without
|
||||
// invoking methods in a QueuedConnection
|
||||
#ifndef QT_NO_HTTP
|
||||
if (qobject_cast<QNetworkAccessHttpBackend *>(backend) || (backend && backend->isSynchronous())) {
|
||||
if (backend && backend->isSynchronous()) {
|
||||
_q_startOperation();
|
||||
} else {
|
||||
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
|
||||
@ -1043,11 +1042,7 @@ bool QNetworkReplyImplPrivate::migrateBackend()
|
||||
}
|
||||
|
||||
#ifndef QT_NO_HTTP
|
||||
if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
|
||||
_q_startOperation();
|
||||
} else {
|
||||
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
|
||||
}
|
||||
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
|
||||
#else
|
||||
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
|
||||
#endif // QT_NO_HTTP
|
||||
|
@ -247,10 +247,13 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
\value AlwaysNetwork always load from network and do not
|
||||
check if the cache has a valid entry (similar to the
|
||||
"Reload" feature in browsers)
|
||||
"Reload" feature in browsers); in addition, force intermediate
|
||||
caches to re-validate.
|
||||
|
||||
\value PreferNetwork default value; load from the network
|
||||
if the cached entry is older than the network entry
|
||||
if the cached entry is older than the network entry. This will never
|
||||
return stale data from the cache, but revalidate resources that
|
||||
have become stale.
|
||||
|
||||
\value PreferCache load from cache if available,
|
||||
otherwise load from network. Note that this can return possibly
|
||||
|
@ -233,7 +233,7 @@ void QSslConfiguration::setProtocol(QSsl::SslProtocol protocol)
|
||||
client), and whether it should require that this certificate is valid.
|
||||
|
||||
The default mode is AutoVerifyPeer, which tells QSslSocket to use
|
||||
VerifyPeer for clients, QueryPeer for clients.
|
||||
VerifyPeer for clients, QueryPeer for servers.
|
||||
|
||||
\sa setPeerVerifyMode()
|
||||
*/
|
||||
@ -249,7 +249,7 @@ QSslSocket::PeerVerifyMode QSslConfiguration::peerVerifyMode() const
|
||||
client), and whether it should require that this certificate is valid.
|
||||
|
||||
The default mode is AutoVerifyPeer, which tells QSslSocket to use
|
||||
VerifyPeer for clients, QueryPeer for clients.
|
||||
VerifyPeer for clients, QueryPeer for servers.
|
||||
|
||||
\sa peerVerifyMode()
|
||||
*/
|
||||
|
@ -137,6 +137,7 @@ static bool AlwaysFalse = false;
|
||||
|
||||
Q_DECLARE_METATYPE(QNetworkRequest::CacheLoadControl)
|
||||
|
||||
|
||||
void tst_QAbstractNetworkCache::initTestCase()
|
||||
{
|
||||
#ifndef QT_NO_BEARERMANAGEMENT
|
||||
@ -150,6 +151,7 @@ void tst_QAbstractNetworkCache::initTestCase()
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void tst_QAbstractNetworkCache::expires_data()
|
||||
{
|
||||
QTest::addColumn<QNetworkRequest::CacheLoadControl>("cacheLoadControl");
|
||||
@ -261,14 +263,14 @@ void tst_QAbstractNetworkCache::cacheControl_data()
|
||||
|
||||
QTest::newRow("200-2") << QNetworkRequest::AlwaysNetwork << "httpcachetest_cachecontrol.cgi?no-cache" << AlwaysFalse;
|
||||
QTest::newRow("200-3") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?no-cache" << false;
|
||||
QTest::newRow("200-4") << QNetworkRequest::AlwaysCache << "httpcachetest_cachecontrol.cgi?no-cache" << false;//AlwaysTrue;
|
||||
QTest::newRow("200-4") << QNetworkRequest::AlwaysCache << "httpcachetest_cachecontrol.cgi?no-cache" << false;
|
||||
QTest::newRow("200-5") << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol.cgi?no-cache" << false;
|
||||
|
||||
QTest::newRow("304-0") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?max-age=1000" << true;
|
||||
|
||||
QTest::newRow("304-1") << QNetworkRequest::AlwaysNetwork << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << AlwaysFalse;
|
||||
QTest::newRow("304-2") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << true;
|
||||
QTest::newRow("304-3") << QNetworkRequest::AlwaysCache << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << AlwaysTrue;
|
||||
QTest::newRow("304-3") << QNetworkRequest::AlwaysCache << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << false;
|
||||
QTest::newRow("304-4") << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol.cgi?max-age=1000, must-revalidate" << true;
|
||||
|
||||
// see QTBUG-7060
|
||||
|
@ -182,6 +182,14 @@ void tst_QNetworkCookie::parseSingleCookie_data()
|
||||
cookie.setValue("\"\\\"a, b; c\\\"\"");
|
||||
QTest::newRow("with-value-with-special5") << "a = \"\\\"a, b; c\\\"\"" << cookie;
|
||||
|
||||
cookie.setValue("b c");
|
||||
QTest::newRow("with-value-with-whitespace") << "a = b c" << cookie;
|
||||
|
||||
cookie.setValue("\"b\"");
|
||||
QTest::newRow("quoted-value") << "a = \"b\"" << cookie;
|
||||
cookie.setValue("\"b c\"");
|
||||
QTest::newRow("quoted-value-with-whitespace") << "a = \"b c\"" << cookie;
|
||||
|
||||
cookie.setValue("b");
|
||||
cookie.setSecure(true);
|
||||
QTest::newRow("secure") << "a=b;secure" << cookie;
|
||||
|
@ -3237,16 +3237,16 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data()
|
||||
QTest::newRow("must-revalidate,200,prefer-network")
|
||||
<< reply200 << "Reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << false << true;
|
||||
QTest::newRow("must-revalidate,200,prefer-cache")
|
||||
<< reply200 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
|
||||
<< reply200 << "Reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << false << true;
|
||||
QTest::newRow("must-revalidate,200,always-cache")
|
||||
<< reply200 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
|
||||
<< reply200 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
|
||||
|
||||
QTest::newRow("must-revalidate,304,prefer-network")
|
||||
<< reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferNetwork) << QStringList() << true << true;
|
||||
QTest::newRow("must-revalidate,304,prefer-cache")
|
||||
<< reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << false;
|
||||
<< reply304 << "Not-reloaded" << content << int(QNetworkRequest::PreferCache) << QStringList() << true << true;
|
||||
QTest::newRow("must-revalidate,304,always-cache")
|
||||
<< reply304 << "Not-reloaded" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << true << false;
|
||||
<< reply304 << "" << content << int(QNetworkRequest::AlwaysCache) << QStringList() << false << false;
|
||||
|
||||
//
|
||||
// Partial content
|
||||
@ -4162,6 +4162,7 @@ public:
|
||||
|
||||
if (serverSocket->setSocketDescriptor(socketDescriptor)) {
|
||||
connect(serverSocket, SIGNAL(encrypted()), this, SLOT(encryptedSlot()));
|
||||
connect(serverSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
|
||||
serverSocket->setProtocol(QSsl::AnyProtocol);
|
||||
connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError>&)), serverSocket, SLOT(ignoreSslErrors()));
|
||||
serverSocket->setLocalCertificate(SRCDIR "/certs/server.pem");
|
||||
@ -4178,6 +4179,11 @@ public slots:
|
||||
socket = (QSslSocket*) sender();
|
||||
emit newEncryptedConnection();
|
||||
}
|
||||
void readyReadSlot() {
|
||||
// for the incoming sockets, not the server socket
|
||||
//qDebug() << static_cast<QSslSocket*>(sender())->bytesAvailable() << static_cast<QSslSocket*>(sender())->encryptedBytesAvailable();
|
||||
}
|
||||
|
||||
public:
|
||||
QSslSocket *socket;
|
||||
};
|
||||
@ -4185,8 +4191,15 @@ public:
|
||||
// very similar to ioPostToHttpUploadProgress but for SSL
|
||||
void tst_QNetworkReply::ioPostToHttpsUploadProgress()
|
||||
{
|
||||
QFile sourceFile(SRCDIR "/bigfile");
|
||||
QVERIFY(sourceFile.open(QIODevice::ReadOnly));
|
||||
//QFile sourceFile(SRCDIR "/bigfile");
|
||||
//QVERIFY(sourceFile.open(QIODevice::ReadOnly));
|
||||
qint64 wantedSize = 2*1024*1024; // 2 MB
|
||||
QByteArray sourceFile;
|
||||
// And in the case of SSL, the compression can fool us and let the
|
||||
// server send the data much faster than expected.
|
||||
// So better provide random data that cannot be compressed.
|
||||
for (int i = 0; i < wantedSize; ++i)
|
||||
sourceFile += (char)qrand();
|
||||
|
||||
// emulate a minimal https server
|
||||
SslServer server;
|
||||
@ -4195,8 +4208,10 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
|
||||
// create the request
|
||||
QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort()));
|
||||
QNetworkRequest request(url);
|
||||
|
||||
request.setRawHeader("Content-Type", "application/octet-stream");
|
||||
QNetworkReplyPtr reply = manager.post(request, &sourceFile);
|
||||
QNetworkReplyPtr reply = manager.post(request, sourceFile);
|
||||
|
||||
QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64)));
|
||||
connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
connect(reply, SIGNAL(sslErrors(const QList<QSslError>&)), reply, SLOT(ignoreSslErrors()));
|
||||
@ -4215,26 +4230,17 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress()
|
||||
QVERIFY(!spy.isEmpty());
|
||||
QList<QVariant> args = spy.last();
|
||||
QVERIFY(args.at(0).toLongLong() > 0);
|
||||
|
||||
// but not everything!
|
||||
QVERIFY(args.at(0).toLongLong() != sourceFile.size());
|
||||
|
||||
incomingSocket->setReadBufferSize(32*1024);
|
||||
incomingSocket->read(16*1024);
|
||||
QTestEventLoop::instance().enterLoop(2);
|
||||
// some more progress than before
|
||||
QVERIFY(!spy.isEmpty());
|
||||
QList<QVariant> args2 = spy.last();
|
||||
QVERIFY(args2.at(0).toLongLong() > args.at(0).toLongLong());
|
||||
|
||||
// set the read buffer to unlimited
|
||||
incomingSocket->setReadBufferSize(0);
|
||||
QTestEventLoop::instance().enterLoop(10);
|
||||
// progress should be finished
|
||||
QVERIFY(!spy.isEmpty());
|
||||
QList<QVariant> args3 = spy.last();
|
||||
QVERIFY(args3.at(0).toLongLong() > args2.at(0).toLongLong());
|
||||
QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong());
|
||||
QCOMPARE(args3.at(0).toLongLong(), sourceFile.size());
|
||||
QCOMPARE(args3.at(0).toLongLong(), qint64(sourceFile.size()));
|
||||
|
||||
// after sending this, the QNAM should emit finished()
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
|
Loading…
x
Reference in New Issue
Block a user