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:
Qt Continuous Integration System 2011-05-06 18:41:31 +10:00
commit 33558a886d
15 changed files with 2406 additions and 68 deletions

View File

@ -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 \

View File

@ -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()

View File

@ -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);

View File

@ -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);
}

View File

@ -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())

View File

@ -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);

View File

@ -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('"'))) {

File diff suppressed because it is too large Load Diff

View 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

View File

@ -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

View File

@ -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

View File

@ -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()
*/

View File

@ -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

View File

@ -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;

View File

@ -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()));