QNAM: Start new HTTP backend architecture

This commit is contained in:
Markus Goetz 2011-03-28 14:56:26 +02:00
parent f78640e5c2
commit a0beeac097
6 changed files with 1207 additions and 285 deletions

View File

@ -14,7 +14,6 @@ HEADERS += \
access/qnetworkaccesscache_p.h \ access/qnetworkaccesscache_p.h \
access/qnetworkaccessbackend_p.h \ access/qnetworkaccessbackend_p.h \
access/qnetworkaccessdebugpipebackend_p.h \ access/qnetworkaccessdebugpipebackend_p.h \
access/qnetworkaccesshttpbackend_p.h \
access/qnetworkaccessfilebackend_p.h \ access/qnetworkaccessfilebackend_p.h \
access/qnetworkaccesscachebackend_p.h \ access/qnetworkaccesscachebackend_p.h \
access/qnetworkaccessftpbackend_p.h \ access/qnetworkaccessftpbackend_p.h \
@ -29,6 +28,7 @@ HEADERS += \
access/qnetworkreply_p.h \ access/qnetworkreply_p.h \
access/qnetworkreplyimpl_p.h \ access/qnetworkreplyimpl_p.h \
access/qnetworkreplydataimpl_p.h \ access/qnetworkreplydataimpl_p.h \
access/qnetworkreplyhttpimpl_p.h \
access/qnetworkreplyfileimpl_p.h \ access/qnetworkreplyfileimpl_p.h \
access/qabstractnetworkcache_p.h \ access/qabstractnetworkcache_p.h \
access/qabstractnetworkcache.h \ access/qabstractnetworkcache.h \
@ -54,13 +54,13 @@ SOURCES += \
access/qnetworkaccessfilebackend.cpp \ access/qnetworkaccessfilebackend.cpp \
access/qnetworkaccesscachebackend.cpp \ access/qnetworkaccesscachebackend.cpp \
access/qnetworkaccessftpbackend.cpp \ access/qnetworkaccessftpbackend.cpp \
access/qnetworkaccesshttpbackend.cpp \
access/qnetworkcookie.cpp \ access/qnetworkcookie.cpp \
access/qnetworkcookiejar.cpp \ access/qnetworkcookiejar.cpp \
access/qnetworkrequest.cpp \ access/qnetworkrequest.cpp \
access/qnetworkreply.cpp \ access/qnetworkreply.cpp \
access/qnetworkreplyimpl.cpp \ access/qnetworkreplyimpl.cpp \
access/qnetworkreplydataimpl.cpp \ access/qnetworkreplydataimpl.cpp \
access/qnetworkreplyhttpimpl.cpp \
access/qnetworkreplyfileimpl.cpp \ access/qnetworkreplyfileimpl.cpp \
access/qabstractnetworkcache.cpp \ access/qabstractnetworkcache.cpp \
access/qnetworkdiskcache.cpp \ access/qnetworkdiskcache.cpp \

View File

@ -67,13 +67,12 @@
#include "QtNetwork/qhttpmultipart.h" #include "QtNetwork/qhttpmultipart.h"
#include "qhttpmultipart_p.h" #include "qhttpmultipart_p.h"
#include "qnetworkreplyhttpimpl_p.h"
#include "qthread.h" #include "qthread.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
#ifndef QT_NO_HTTP
Q_GLOBAL_STATIC(QNetworkAccessHttpBackendFactory, httpBackend)
#endif // QT_NO_HTTP
Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend) Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
#ifndef QT_NO_FTP #ifndef QT_NO_FTP
Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend) Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
@ -85,10 +84,6 @@ Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
static void ensureInitialized() static void ensureInitialized()
{ {
#ifndef QT_NO_HTTP
(void) httpBackend();
#endif // QT_NO_HTTP
#ifndef QT_NO_FTP #ifndef QT_NO_FTP
(void) ftpBackend(); (void) ftpBackend();
#endif #endif
@ -356,6 +351,17 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
ensureInitialized(); ensureInitialized();
qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError"); 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 // first step: create the reply
QUrl url = request.url(); QUrl url = request.url();
QNetworkReplyImpl *reply = new QNetworkReplyImpl(this); QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);

View File

@ -160,6 +160,7 @@ protected:
private: private:
friend class QNetworkReplyImplPrivate; friend class QNetworkReplyImplPrivate;
friend class QNetworkAccessHttpBackend; friend class QNetworkAccessHttpBackend;
friend class QNetworkReplyHttpImpl;
Q_DECLARE_PRIVATE(QNetworkAccessManager) Q_DECLARE_PRIVATE(QNetworkAccessManager)
Q_PRIVATE_SLOT(d_func(), void _q_replyFinished()) Q_PRIVATE_SLOT(d_func(), void _q_replyFinished())

File diff suppressed because it is too large Load Diff

View File

@ -39,8 +39,8 @@
** **
****************************************************************************/ ****************************************************************************/
#ifndef QNETWORKACCESSHTTPBACKEND_P_H #ifndef QNETWORKREPLYHTTPIMPL_P_H
#define QNETWORKACCESSHTTPBACKEND_P_H #define QNETWORKREPLYHTTPIMPL_P_H
// //
// W A R N I N G // W A R N I N G
@ -53,53 +53,83 @@
// We mean it. // We mean it.
// //
#include "qhttpnetworkconnection_p.h"
#include "qnetworkaccessbackend_p.h"
#include "qnetworkrequest.h" #include "qnetworkrequest.h"
#include "qnetworkreply.h" #include "qnetworkreply.h"
#include "qabstractsocket.h"
#include "QtCore/qpointer.h" #include "QtCore/qpointer.h"
#include "QtCore/qdatetime.h" #include "QtCore/qdatetime.h"
#include "QtCore/qsharedpointer.h" #include "QtCore/qsharedpointer.h"
#include "qatomic.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 #ifndef QT_NO_HTTP
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QNetworkAccessCachedHttpConnection; class QIODevice;
class QNetworkAccessHttpBackendIODevice; class QNetworkReplyHttpImplPrivate;
class QNetworkReplyHttpImpl: public QNetworkReply
class QNetworkAccessHttpBackend: public QNetworkAccessBackend
{ {
Q_OBJECT Q_OBJECT
public: public:
QNetworkAccessHttpBackend(); QNetworkReplyHttpImpl(QNetworkAccessManager* const, const QNetworkRequest&, QNetworkAccessManager::Operation&, QIODevice* outgoingData);
virtual ~QNetworkAccessHttpBackend(); virtual ~QNetworkReplyHttpImpl();
virtual void open(); void close();
virtual void closeDownstreamChannel(); void abort();
qint64 bytesAvailable() const;
bool isSequential () const;
qint64 size() const;
qint64 readData(char*, qint64);
void setReadBufferSize(qint64 size);
bool canReadLine () const;
virtual void downstreamReadyWrite();
virtual void setDownstreamLimited(bool b);
virtual void copyFinished(QIODevice *);
#ifndef QT_NO_OPENSSL #ifndef QT_NO_OPENSSL
virtual void ignoreSslErrors(); void ignoreSslErrors();
virtual void ignoreSslErrors(const QList<QSslError> &errors); Q_INVOKABLE void ignoreSslErrorsImplementation(const QList<QSslError> &errors);
Q_INVOKABLE void setSslConfigurationImplementation(const QSslConfiguration &configuration);
virtual void fetchSslConfiguration(QSslConfiguration &configuration) const; Q_INVOKABLE QSslConfiguration sslConfigurationImplementation() const;
virtual void setSslConfiguration(const QSslConfiguration &configuration);
#endif #endif
QNetworkCacheMetaData fetchCacheMetaData(const QNetworkCacheMetaData &metaData) const; // Q_INVOKABLE QSslConfiguration sslConfigurationImplementation() const;
// Q_INVOKABLE void setSslConfigurationImplementation(const QSslConfiguration &configuration);
// we return true since HTTP needs to send PUT/POST data again after having authenticated Q_DECLARE_PRIVATE(QNetworkReplyHttpImpl)
bool needsResetableUploadData() { return true; } 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 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))
bool canResume() const;
void setResumeOffset(quint64 offset);
signals: signals:
// To HTTP thread: // To HTTP thread:
@ -109,7 +139,140 @@ signals:
void startHttpRequestSynchronously(); void startHttpRequestSynchronously();
void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize); void haveUploadData(QByteArray dataArray, bool dataAtEnd, qint64 dataSize);
private slots: };
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();
// ?
void consume(qint64 count);
void setDownloadBuffer(QSharedPointer<char> sp, qint64 size);
char* getDownloadBuffer(qint64 size);
// FIXME
void finished();
void error(QNetworkReply::NetworkError code, const QString &errorString);
void metaDataChanged();
void redirectionRequested(const QUrl &target);
QNetworkAccessManager *manager;
QNetworkAccessManagerPrivate *managerPrivate;
QNetworkRequest request;
QNetworkAccessManager::Operation operation;
QNonContiguousByteDevice* createUploadByteDevice();
QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
QIODevice *outgoingData;
QSharedPointer<QRingBuffer> outgoingDataBuffer;
void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal); // dup?
bool migrateBackend();
quint64 resumeOffset;
bool canResume() const;
void setResumeOffset(quint64 offset);
qint64 bytesUploaded;
qint64 preMigrationDownloaded;
void createCache();
void completeCacheSave();
void setCachingEnabled(bool enable);
bool isCachingEnabled() const;
void initCacheSaveDevice();
QAbstractNetworkCache *networkCache() const;
QIODevice *cacheLoadDevice;
bool cacheEnabled; // is this for saving?
QIODevice *cacheSaveDevice;
bool loadingFromCache;
QUrl urlForLastAuthentication;
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy lastProxyAuthentication;
QList<QNetworkProxy> proxyList;
#endif
int statusCode;
QString reasonPhrase;
State state;
// Used for normal downloading. For "zero copy" the downloadZerocopyBuffer is used
QByteDataBuffer downloadMultiBuffer;
QByteDataBuffer pendingDownloadData; // For signal compression
qint64 bytesDownloaded;
qint64 lastBytesDownloaded;
// 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;
QHttpNetworkRequest httpRequest; // There is also a copy in the HTTP thread
// Will be increased by HTTP thread:
QSharedPointer<QAtomicInt> pendingDownloadDataEmissions;
QSharedPointer<QAtomicInt> pendingDownloadProgressEmissions;
bool synchronous;
#ifndef QT_NO_OPENSSL
QSslConfiguration sslConfiguration;
bool pendingIgnoreAllSslErrors;
QList<QSslError> pendingIgnoreSslErrorsList;
#endif
void validateCache(QHttpNetworkRequest &httpRequest, bool &loadedFromCache);
void invalidateCache();
bool sendCacheContents(const QNetworkCacheMetaData &metaData);
QNetworkCacheMetaData fetchCacheMetaData(const QNetworkCacheMetaData &metaData) const;
void postRequest();
void checkForRedirect(const int statusCode);
public:
// From HTTP thread: // From HTTP thread:
void replyDownloadData(QByteArray); void replyDownloadData(QByteArray);
void replyFinished(); void replyFinished();
@ -121,45 +284,19 @@ private slots:
void replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *); void replySslErrors(const QList<QSslError> &, bool *, QList<QSslError> *);
void replySslConfigurationChanged(const QSslConfiguration&); void replySslConfigurationChanged(const QSslConfiguration&);
#endif #endif
#ifndef QT_NO_NETWORKPROXY
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth);
#endif
// From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread: // From QNonContiguousByteDeviceThreadForwardImpl in HTTP thread:
void resetUploadDataSlot(bool *r); void resetUploadDataSlot(bool *r);
void wantUploadDataSlot(qint64); void wantUploadDataSlot(qint64);
void sentUploadDataSlot(qint64); void sentUploadDataSlot(qint64);
bool sendCacheContents(const QNetworkCacheMetaData &metaData);
private:
QHttpNetworkRequest httpRequest; // There is also a copy in the HTTP thread
int statusCode;
QString reasonPhrase;
// Will be increased by HTTP thread:
QSharedPointer<QAtomicInt> pendingDownloadDataEmissions;
QSharedPointer<QAtomicInt> pendingDownloadProgressEmissions;
bool loadingFromCache;
QByteDataBuffer pendingDownloadData;
bool usingZerocopyDownloadBuffer;
#ifndef QT_NO_OPENSSL
QSslConfiguration *pendingSslConfiguration;
bool pendingIgnoreAllSslErrors;
QList<QSslError> pendingIgnoreSslErrorsList;
#endif
quint64 resumeOffset; Q_DECLARE_PUBLIC(QNetworkReplyHttpImpl)
void validateCache(QHttpNetworkRequest &httpRequest, bool &loadedFromCache);
void invalidateCache();
void postRequest();
void readFromHttp();
void checkForRedirect(const int statusCode);
};
class QNetworkAccessHttpBackendFactory : public QNetworkAccessBackendFactory
{
public:
virtual QNetworkAccessBackend *create(QNetworkAccessManager::Operation op,
const QNetworkRequest &request) const;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -47,7 +47,6 @@
#include "QtCore/qdatetime.h" #include "QtCore/qdatetime.h"
#include "QtNetwork/qsslconfiguration.h" #include "QtNetwork/qsslconfiguration.h"
#include "QtNetwork/qnetworksession.h" #include "QtNetwork/qnetworksession.h"
#include "qnetworkaccesshttpbackend_p.h"
#include "qnetworkaccessmanager_p.h" #include "qnetworkaccessmanager_p.h"
#include <QtCore/QCoreApplication> #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 // for HTTP, we want to send out the request as fast as possible to the network, without
// invoking methods in a QueuedConnection // invoking methods in a QueuedConnection
#ifndef QT_NO_HTTP #ifndef QT_NO_HTTP
if (qobject_cast<QNetworkAccessHttpBackend *>(backend) || (backend && backend->isSynchronous())) { if (backend && backend->isSynchronous()) {
_q_startOperation(); _q_startOperation();
} else { } else {
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
@ -1043,11 +1042,7 @@ bool QNetworkReplyImplPrivate::migrateBackend()
} }
#ifndef QT_NO_HTTP #ifndef QT_NO_HTTP
if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) { QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
_q_startOperation();
} else {
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
}
#else #else
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection); QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
#endif // QT_NO_HTTP #endif // QT_NO_HTTP