summaryrefslogtreecommitdiffstats
path: root/src/network/access
diff options
context:
space:
mode:
authorMårten Nordheim <marten.nordheim@qt.io>2020-06-23 17:07:37 +0200
committerMårten Nordheim <marten.nordheim@qt.io>2020-08-27 18:58:21 +0200
commitbba0bdb35c2806bcdde8e89965e99b3d412b8d3a (patch)
tree90b695e41a6257b5c2fce295dfbcb732a1d8a896 /src/network/access
parentf7f79483e73fed5664763a125b3d27861586b7d2 (diff)
Redo QNetworkAccessBackend and various cleanups around it
Makes the QNetworkAccessBackendFactory a real interface to be used in plugins. Requires exporting some classes but they're not made public yet. Removes unused features and functions. Some things are likely still unused due to being specific for HTTP but the HTTP network replies don't use this backend system. Changes QNetworkAccessBackend to use a more traditional read(char*, qint64) function for the "downloaded" data. And an optional readPointer if supported. So far no backends have it so it's somewhat useless, but it may be useful going forward. If not it shall be deleted Converts all current backends to the new setup Easy enough, also gets rid of some unused functions. Task-number: QTBUG-80340 Change-Id: I9339e6c6eb394c471c921f5cafd3af6175936399 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/network/access')
-rw-r--r--src/network/access/qnetworkaccessauthenticationmanager_p.h1
-rw-r--r--src/network/access/qnetworkaccessbackend.cpp634
-rw-r--r--src/network/access/qnetworkaccessbackend_p.h229
-rw-r--r--src/network/access/qnetworkaccesscachebackend.cpp27
-rw-r--r--src/network/access/qnetworkaccesscachebackend_p.h9
-rw-r--r--src/network/access/qnetworkaccessdebugpipebackend.cpp89
-rw-r--r--src/network/access/qnetworkaccessdebugpipebackend_p.h8
-rw-r--r--src/network/access/qnetworkaccessfilebackend.cpp81
-rw-r--r--src/network/access/qnetworkaccessfilebackend_p.h8
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp34
-rw-r--r--src/network/access/qnetworkaccessmanager_p.h4
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp2
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp116
-rw-r--r--src/network/access/qnetworkreplyimpl_p.h6
14 files changed, 791 insertions, 457 deletions
diff --git a/src/network/access/qnetworkaccessauthenticationmanager_p.h b/src/network/access/qnetworkaccessauthenticationmanager_p.h
index 361b17b594..bf57dffbb0 100644
--- a/src/network/access/qnetworkaccessauthenticationmanager_p.h
+++ b/src/network/access/qnetworkaccessauthenticationmanager_p.h
@@ -54,7 +54,6 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include "qnetworkaccessmanager.h"
#include "qnetworkaccesscache_p.h"
-#include "qnetworkaccessbackend_p.h"
#include "QtNetwork/qnetworkproxy.h"
#include "QtCore/QMutex"
diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp
index 8013785cc1..f7e29340d9 100644
--- a/src/network/access/qnetworkaccessbackend.cpp
+++ b/src/network/access/qnetworkaccessbackend.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qnetworkaccessbackend_p.h"
+#include "qnetworkreplyimpl_p.h"
#include "qnetworkaccessmanager_p.h"
#include "qnetworkrequest.h"
#include "qnetworkreply.h"
@@ -73,22 +74,24 @@ public:
Q_GLOBAL_STATIC(QNetworkAccessBackendFactoryData, factoryData)
QBasicAtomicInt QNetworkAccessBackendFactoryData::valid = Q_BASIC_ATOMIC_INITIALIZER(0);
-QNetworkAccessBackendFactory::QNetworkAccessBackendFactory()
-{
- QMutexLocker locker(&factoryData()->mutex);
- factoryData()->append(this);
-}
-
-QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory()
+class QNetworkAccessBackendPrivate : public QObjectPrivate
{
- if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
- QMutexLocker locker(&factoryData()->mutex);
- factoryData()->removeAll(this);
- }
-}
+public:
+ QNetworkAccessBackend::TargetTypes m_targetTypes;
+ QNetworkAccessBackend::SecurityFeatures m_securityFeatures;
+ QNetworkAccessBackend::IOFeatures m_ioFeatures;
+ QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
+ QIODevice *wrappedUploadByteDevice;
+ QNetworkReplyImplPrivate *m_reply = nullptr;
+ QNetworkAccessManagerPrivate *m_manager = nullptr;
+
+ bool m_canCache = false;
+ bool m_isSynchronous = false;
+};
-QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessManager::Operation op,
- const QNetworkRequest &request)
+QNetworkAccessBackend *
+QNetworkAccessManagerPrivate::findBackend(QNetworkAccessManager::Operation op,
+ const QNetworkRequest &request)
{
if (QNetworkAccessBackendFactoryData::valid.loadRelaxed()) {
QMutexLocker locker(&factoryData()->mutex);
@@ -97,7 +100,7 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM
while (it != end) {
QNetworkAccessBackend *backend = (*it)->create(op, request);
if (backend) {
- backend->manager = this;
+ backend->setManagerPrivate(this);
return backend; // found a factory that handled our request
}
++it;
@@ -122,260 +125,619 @@ QStringList QNetworkAccessManagerPrivate::backendSupportedSchemes() const
return QStringList();
}
-QNonContiguousByteDevice* QNetworkAccessBackend::createUploadByteDevice()
-{
- if (reply->outgoingDataBuffer)
- uploadByteDevice = QNonContiguousByteDeviceFactory::createShared(reply->outgoingDataBuffer);
- else if (reply->outgoingData) {
- uploadByteDevice = QNonContiguousByteDeviceFactory::createShared(reply->outgoingData);
- } else {
- return nullptr;
- }
+/*!
+ \enum QNetworkAccessBackend::TargetType
+
+ Use the values in this enum to specify what type of target
+ the plugin supports. Setting the right type can be important,
+ for example: proxyList() is only available for a Networked
+ plugin.
+
+ \value Networked
+ The plugin supports and expect to connect to networked
+ resources. E.g. over TCP, UDP or similar.
+ \value Local
+ The plugin supports and expects to access local files,
+ generate data and/or locally connected devices.
+*/
- // We want signal emissions only for normal asynchronous uploads
- if (!isSynchronous())
- connect(uploadByteDevice.data(), SIGNAL(readProgress(qint64,qint64)), this, SLOT(emitReplyUploadProgress(qint64,qint64)));
+/*!
+ \enum QNetworkAccessBackend::SecurityFeature
- return uploadByteDevice.data();
-}
+ Use the values in this enum to specify what type of security
+ features the plugin may utilize. Setting the right type(s)
+ can be important, for example: setSslConfiguration() may not
+ be called for any plugin that do not claim to support TLS.
+
+ \value None
+ No specific features are claimed to be supported.
+ \value TLS
+ The plugin supports and expects to use TLS.
+*/
+
+/*!
+ \enum QNetworkAccessBackend::IOFeature
+
+ Use the values in this enum to specify what type of IO
+ features the plugin may utilize.
+
+ \value None
+ No specific features are claimed to be supported.
+ \value ZeroCopy
+ The plugin will have raw data available in contiguous
+ segments and can return a pointer to the data at request.
+ Claiming to support this requires implementing readPointer()
+ and advanceReadPointer().
+ \value NeedResetableUpload
+ The plugin may encounter scenarios where data to upload that
+ has already been consumed needs to be restored and re-sent.
+ E.g. some data was consumed and sent before a redirect
+ response was received, and after the redirect the
+ previously-consumed data needs to be re-sent.
+ \omitvalue SupportsSynchronousMode
+*/
+
+/*!
+ Constructs the QNetworkAccessBackend.
+ You can opt in to specific backend behaviors with \a targetTypes,
+ \a securityFeatures and \a ioFeatures.
+ See their respective enums and values for more information.
-// need to have this function since the reply is a private member variable
-// and the special backends need to access this.
-void QNetworkAccessBackend::emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal)
+ \sa TargetType, SecurityFeature, IOFeature
+*/
+QNetworkAccessBackend::QNetworkAccessBackend(TargetTypes targetTypes,
+ SecurityFeatures securityFeatures,
+ IOFeatures ioFeatures)
+ : QObject(*(new QNetworkAccessBackendPrivate), nullptr)
{
- if (reply->isFinished)
- return;
- reply->emitUploadProgress(bytesSent, bytesTotal);
+ Q_D(QNetworkAccessBackend);
+ d->m_targetTypes = targetTypes;
+ d->m_securityFeatures = securityFeatures;
+ d->m_ioFeatures = ioFeatures;
}
-QNetworkAccessBackend::QNetworkAccessBackend()
- : manager(nullptr)
- , reply(nullptr)
- , synchronous(false)
+/*!
+ \overload
+*/
+QNetworkAccessBackend::QNetworkAccessBackend(TargetTypes targetTypes)
+ : QNetworkAccessBackend(targetTypes, SecurityFeature::None, IOFeature::None)
{
}
-QNetworkAccessBackend::~QNetworkAccessBackend()
+/*!
+ \overload
+*/
+QNetworkAccessBackend::QNetworkAccessBackend(TargetTypes targetTypes,
+ SecurityFeatures securityFeatures)
+ : QNetworkAccessBackend(targetTypes, securityFeatures, IOFeature::None)
{
}
-void QNetworkAccessBackend::downstreamReadyWrite()
+/*!
+ \overload
+*/
+QNetworkAccessBackend::QNetworkAccessBackend(TargetTypes targetTypes, IOFeatures ioFeatures)
+ : QNetworkAccessBackend(targetTypes, SecurityFeature::None, ioFeatures)
{
- // do nothing
}
-void QNetworkAccessBackend::setDownstreamLimited(bool b)
+/*!
+ Destructs the QNetworkAccessBackend base class.
+*/
+QNetworkAccessBackend::~QNetworkAccessBackend() { }
+
+/*!
+ Returns the security related features that the backend claims to
+ support.
+
+ \sa SecurityFeature
+*/
+QNetworkAccessBackend::SecurityFeatures QNetworkAccessBackend::securityFeatures() const noexcept
{
- Q_UNUSED(b);
- // do nothing
+ return d_func()->m_securityFeatures;
}
-void QNetworkAccessBackend::copyFinished(QIODevice *)
+/*!
+ Returns the TargetTypes that the backend claims to target.
+
+ \sa TargetType
+*/
+QNetworkAccessBackend::TargetTypes QNetworkAccessBackend::targetTypes() const noexcept
{
- // do nothing
+ return d_func()->m_targetTypes;
}
-void QNetworkAccessBackend::ignoreSslErrors()
+/*!
+ Returns the I/O features that the backend claims to support.
+
+ \sa IOFeature
+*/
+QNetworkAccessBackend::IOFeatures QNetworkAccessBackend::ioFeatures() const noexcept
{
- // do nothing
+ return d_func()->m_ioFeatures;
}
-void QNetworkAccessBackend::ignoreSslErrors(const QList<QSslError> &errors)
+/*!
+ Prepares the backend and calls open().
+ E.g. for TargetType::Networked it will prepare proxyList().
+
+ \sa TargetType, targetTypes
+*/
+bool QNetworkAccessBackend::start()
{
- Q_UNUSED(errors);
- // do nothing
+ Q_D(QNetworkAccessBackend);
+#ifndef QT_NO_NETWORKPROXY
+ if (targetTypes() & QNetworkAccessBackend::TargetType::Networked)
+ d->m_reply->proxyList = d->m_manager->queryProxy(QNetworkProxyQuery(url()));
+#endif
+
+ // now start the request
+ open();
+ return true;
}
-void QNetworkAccessBackend::fetchSslConfiguration(QSslConfiguration &) const
+#if QT_CONFIG(ssl)
+/*!
+ Passes a \a configuration with the user's desired TLS
+ configuration. If you don't have the TLS security feature this
+ may not be called.
+
+ \sa SecurityFeature, securityFeatures
+*/
+void QNetworkAccessBackend::setSslConfiguration(const QSslConfiguration &configuration)
{
- // do nothing
+ Q_UNUSED(configuration);
+ if (securityFeatures() & SecurityFeature::TLS) {
+ qWarning("Backend (%s) claiming to use TLS hasn't overridden setSslConfiguration.",
+ metaObject()->className());
+ }
}
-void QNetworkAccessBackend::setSslConfiguration(const QSslConfiguration &)
+/*!
+ Override this and return the QSslConfiguration used if you
+ have the TLS security feature
+
+ \sa SecurityFeature, securityFeatures
+*/
+QSslConfiguration QNetworkAccessBackend::sslConfiguration() const
{
- // do nothing
+ if (securityFeatures() & SecurityFeature::TLS) {
+ qWarning("Backend (%s) claiming to use TLS hasn't overridden sslConfiguration.",
+ metaObject()->className());
+ }
+ return {};
}
+#endif
-QNetworkCacheMetaData QNetworkAccessBackend::fetchCacheMetaData(const QNetworkCacheMetaData &) const
+/*!
+ This function will be called when the user wants to ignore
+ all TLS handshake errors. Derive this function if TLS is
+ supported.
+
+ \sa SecurityFeature, securityFeatures
+*/
+void QNetworkAccessBackend::ignoreSslErrors()
{
- return QNetworkCacheMetaData();
+ if (securityFeatures() & SecurityFeature::TLS) {
+ qWarning("Backend (%s) claiming to use TLS hasn't overridden ignoreSslErrors.",
+ metaObject()->className());
+ }
}
-QNetworkAccessManager::Operation QNetworkAccessBackend::operation() const
+/*!
+ This function will be called when the user wants to ignore
+ specific \a errors. Derive this function if TLS is supported.
+
+ \sa SecurityFeature, securityFeatures
+*/
+void QNetworkAccessBackend::ignoreSslErrors(const QList<QSslError> &errors)
{
- return reply->operation;
+ Q_UNUSED(errors);
+ if (securityFeatures() & SecurityFeature::TLS) {
+ qWarning("Backend (%s) claiming to use TLS hasn't overridden ignoreSslErrors.",
+ metaObject()->className());
+ }
}
-QNetworkRequest QNetworkAccessBackend::request() const
+/*!
+ The data which the returned value views must stay valid until
+ at least the next call to a non-const function. advanceReadPointer
+ will be called if any of the data was used.
+
+ Note: This will only be called if IOFeature::ZeroCopy was
+ specified in the call to the constructor.
+
+ \sa advanceReadPointer, read
+*/
+QByteArrayView QNetworkAccessBackend::readPointer()
{
- return reply->request;
+ if (ioFeatures() & IOFeature::ZeroCopy) {
+ qWarning("Backend (%s) claiming to support ZeroCopy hasn't overridden readPointer.",
+ metaObject()->className());
+ }
+ return {};
}
-#ifndef QT_NO_NETWORKPROXY
-QList<QNetworkProxy> QNetworkAccessBackend::proxyList() const
+/*!
+ This function is to notify your class that \a distance
+ bytes have been read using readPointer and next time
+ readPointer() is called those bytes should not be included.
+
+ Note: This will only be called if IOFeature::ZeroCopy was
+ specified in the call to the constructor.
+
+ \sa readPointer
+*/
+void QNetworkAccessBackend::advanceReadPointer(qint64 distance)
{
- return reply->proxyList;
+ Q_UNUSED(distance);
+ if (ioFeatures() & IOFeature::ZeroCopy) {
+ qWarning("Backend (%s) claiming to support ZeroCopy hasn't overridden advanceReadPointer.",
+ metaObject()->className());
+ }
}
-#endif
-QAbstractNetworkCache *QNetworkAccessBackend::networkCache() const
+/*!
+ Implement this function to support reading from the resource
+ made available by your plugin.
+ Store data in \a data, up to a maximum of \a maxlen bytes.
+ Then return the total amount of bytes that was copied.
+
+ \sa readPointer, wantToRead
+*/
+qint64 QNetworkAccessBackend::read(char *data, qint64 maxlen)
{
- if (!manager)
- return nullptr;
- return manager->networkCache;
+ Q_UNUSED(data);
+ Q_UNUSED(maxlen);
+ if ((ioFeatures() & IOFeature::ZeroCopy) == 0) {
+ qWarning("Backend (%s) is not ZeroCopy and has not implemented read(...)!",
+ metaObject()->className());
+ }
+ return 0;
}
-void QNetworkAccessBackend::setCachingEnabled(bool enable)
+/*!
+ This is called before we read if there are no bytes available
+ and we are ready to read more. Return \c true if new data was
+ made available.
+
+ \sa read, readPointer
+*/
+bool QNetworkAccessBackend::wantToRead()
{
- reply->setCachingEnabled(enable);
+ // Base implementation does nothing
+ return false;
}
-bool QNetworkAccessBackend::isCachingEnabled() const
+#if QT_CONFIG(networkproxy)
+/*!
+ Returns a list of proxies configured for the URL returned by
+ url().
+
+ It is only valid to call this function if TargetType::Networked
+ was specified in the call to the constructor.
+*/
+QList<QNetworkProxy> QNetworkAccessBackend::proxyList() const
{
- return reply->isCachingEnabled();
+ Q_ASSERT(targetTypes() & TargetType::Networked);
+ return d_func()->m_reply->proxyList;
}
+#endif
-qint64 QNetworkAccessBackend::nextDownstreamBlockSize() const
+/*!
+ Returns the current URL of the reply
+*/
+QUrl QNetworkAccessBackend::url() const
{
- return reply->nextDownstreamBlockSize();
+ return d_func()->m_reply->url;
}
-void QNetworkAccessBackend::writeDownstreamData(QByteDataBuffer &list)
+/*!
+ Sets the URL of the reply. This could e.g. be needed if a
+ redirect or similar was performed.
+*/
+void QNetworkAccessBackend::setUrl(const QUrl &url)
{
- reply->appendDownstreamData(list);
+ d_func()->m_reply->url = url;
}
-void QNetworkAccessBackend::writeDownstreamData(QIODevice *data)
+/*!
+ Returns the value of the \a header.
+ If no such header was known it returns a default-constructed
+ QVariant.
+
+ \sa setHeader, rawHeader, setRawHeader
+*/
+QVariant QNetworkAccessBackend::header(QNetworkRequest::KnownHeaders header) const
{
- reply->appendDownstreamData(data);
+ return d_func()->m_reply->cookedHeaders.value(header);
}
-// not actually appending data, it was already written to the user buffer
-void QNetworkAccessBackend::writeDownstreamDataDownloadBuffer(qint64 bytesReceived, qint64 bytesTotal)
+/*!
+ Sets the value of the \a header to \a value.
+ This can be queried on the QNetworkReply instance which was
+ returned when calling one of the appropriate functions on
+ QNetworkAccessManager.
+
+ \sa header, rawHeader, setRawHeader
+*/
+void QNetworkAccessBackend::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
{
- reply->appendDownstreamDataDownloadBuffer(bytesReceived, bytesTotal);
+ d_func()->m_reply->setCookedHeader(header, value);
}
-char* QNetworkAccessBackend::getDownloadBuffer(qint64 size)
+/*!
+ Returns the value of the \a header.
+ If no such header was known it returns a default-constructed
+ QVariant.
+
+ \sa setHeader, rawHeader, setRawHeader
+*/
+QByteArray QNetworkAccessBackend::rawHeader(const QByteArray &header) const
{
- return reply->getDownloadBuffer(size);
+ return d_func()->m_reply->q_func()->rawHeader(header);
}
-QVariant QNetworkAccessBackend::header(QNetworkRequest::KnownHeaders header) const
+/*!
+ Sets the value of the \a header to \a value.
+
+ This value is accessible on the QNetworkReply instance which was
+ returned when calling one of the appropriate functions on
+ QNetworkAccessManager.
+
+ \sa header, rawHeader, setRawHeader
+*/
+void QNetworkAccessBackend::setRawHeader(const QByteArray &header, const QByteArray &value)
{
- return reply->q_func()->header(header);
+ d_func()->m_reply->setRawHeader(header, value);
}
-void QNetworkAccessBackend::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
+/*!
+ Returns the operation which was requested when calling
+ QNetworkAccessManager.
+*/
+QNetworkAccessManager::Operation QNetworkAccessBackend::operation() const
{
- reply->setCookedHeader(header, value);
+ return d_func()->m_reply->operation;
}
-bool QNetworkAccessBackend::hasRawHeader(const QByteArray &headerName) const
+/*!
+ Returns \c true if setCachingEnabled was previously called with \c true.
+ Returns \c false otherwise, which is the default value.
+
+ \sa setCachingEnabled
+*/
+bool QNetworkAccessBackend::isCachingEnabled() const
{
- return reply->q_func()->hasRawHeader(headerName);
+ return d_func()->m_canCache;
}
-QByteArray QNetworkAccessBackend::rawHeader(const QByteArray &headerName) const
+/*!
+ If \a canCache is \c true then this hints to us that we can cache
+ the reply that is created.
+
+ \sa isCachingEnabled
+*/
+void QNetworkAccessBackend::setCachingEnabled(bool canCache)
{
- return reply->q_func()->rawHeader(headerName);
+ d_func()->m_canCache = canCache;
}
-QList<QByteArray> QNetworkAccessBackend::rawHeaderList() const
+/*!
+ Set \a attribute to \a value. If \c{value.isValid()} returns
+ \c false then the attribute is unset.
+
+ This value is accessible on the QNetworkReply instance which was
+ returned when calling one of the appropriate functions on
+ QNetworkAccessManager.
+*/
+void QNetworkAccessBackend::setAttribute(QNetworkRequest::Attribute attribute,
+ const QVariant &value)
{
- return reply->q_func()->rawHeaderList();
+ Q_D(QNetworkAccessBackend);
+ if (value.isValid())
+ d->m_reply->attributes.insert(attribute, value);
+ else
+ d->m_reply->attributes.remove(attribute);
}
-void QNetworkAccessBackend::setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
+/*!
+ Creates a QIODevice for the data provided to upload, if any.
+
+ Emission of upload progress is handled internally as the device
+ gets read from.
+
+ Returns a pointer to a device with data or nullptr if there was
+ no data to upload.
+*/
+QIODevice *QNetworkAccessBackend::createUploadByteDevice()
{
- reply->setRawHeader(headerName, headerValue);
+ Q_D(QNetworkAccessBackend);
+
+ if (d->m_reply->outgoingDataBuffer)
+ d->uploadByteDevice =
+ QNonContiguousByteDeviceFactory::createShared(d->m_reply->outgoingDataBuffer);
+ else if (d->m_reply->outgoingData) {
+ d->uploadByteDevice =
+ QNonContiguousByteDeviceFactory::createShared(d->m_reply->outgoingData);
+ } else {
+ return nullptr;
+ }
+
+ // We want signal emissions only for normal asynchronous uploads
+ if (!isSynchronous()) {
+ connect(d->uploadByteDevice.data(), &QNonContiguousByteDevice::readProgress, this,
+ [this](qint64 a, qint64 b) {
+ Q_D(QNetworkAccessBackend);
+ if (!d->m_reply->isFinished)
+ d->m_reply->emitUploadProgress(a, b);
+ });
+ }
+
+ d->wrappedUploadByteDevice = QNonContiguousByteDeviceFactory::wrap(d->uploadByteDevice.data());
+ return d->wrappedUploadByteDevice;
}
-QVariant QNetworkAccessBackend::attribute(QNetworkRequest::Attribute code) const
+/*!
+ Returns the upload byte device associated with the current
+ request. This does not create the request but simply returns
+ the pointer stored in this base class so it doesn't need to be
+ stored in the subclass too.
+*/
+QIODevice *QNetworkAccessBackend::uploadByteDevice()
{
- return reply->q_func()->attribute(code);
+ return d_func()->wrappedUploadByteDevice;
}
-void QNetworkAccessBackend::setAttribute(QNetworkRequest::Attribute code, const QVariant &value)
+/*!
+ \internal
+ Returns \c true if synchronous mode is enabled.
+ If it is disabled or not supported it will return \c {false}.
+*/
+bool QNetworkAccessBackend::isSynchronous() const
{
- if (value.isValid())
- reply->attributes.insert(code, value);
- else
- reply->attributes.remove(code);
+ return d_func()->m_isSynchronous;
}
-QUrl QNetworkAccessBackend::url() const
+
+/*!
+ \internal
+ Enables or disables synchronous mode depending on \a synchronous
+ if the backend supports it. Otherwise it will always be disabled.
+*/
+void QNetworkAccessBackend::setSynchronous(bool synchronous)
{
- return reply->url;
+ if ((ioFeatures() & IOFeature::SupportsSynchronousMode) == 0)
+ return;
+ d_func()->m_isSynchronous = synchronous;
}
-void QNetworkAccessBackend::setUrl(const QUrl &url)
+/*!
+ Call this slot when you have more data available to notify
+ the backend that we can attempt to read again.
+*/
+void QNetworkAccessBackend::readyRead()
{
- reply->url = url;
+ d_func()->m_reply->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
}
+/*!
+ Call this slot when there will be no more data available,
+ regardless of whether the transfer was successful or unsuccessful.
+ For unsuccessful transfers make sure to call error() first!
+*/
void QNetworkAccessBackend::finished()
{
- reply->finished();
+ d_func()->m_reply->finished();
}
+/*!
+ Call this slot if an error occurs. An error would be something
+ you cannot recover from (e.g. the file requested is missing).
+ The \a code and \a errorString is transferred to and stored in
+ the QNetworkReply and the \a code is emitted through the
+ QNetworkReply::errorOccurred() signal.
+*/
void QNetworkAccessBackend::error(QNetworkReply::NetworkError code, const QString &errorString)
{
- reply->error(code, errorString);
+ Q_ASSERT(!d_func()->m_reply->isFinished);
+ d_func()->m_reply->error(code, errorString);
}
#ifndef QT_NO_NETWORKPROXY
+/*!
+ Call this slot if, when connecting through a proxy, it requests
+ authentication. This may cause the
+ QNetworkAccessManager::proxyAuthenticationRequired() signal to be
+ emitted if the credentials are not already stored in an internal
+ cache.
+ To be able to make the lookup in the cache and potentially the
+ subsequent request the \a proxy needs to be known. The credentials
+ will be stored in \a authenticator. While \a authenticator is a
+ pointer, passing \c nullptr is invalid.
+*/
void QNetworkAccessBackend::proxyAuthenticationRequired(const QNetworkProxy &proxy,
QAuthenticator *authenticator)
{
- manager->proxyAuthenticationRequired(QUrl(), proxy, synchronous, authenticator, &reply->lastProxyAuthentication);
+ Q_D(QNetworkAccessBackend);
+ Q_ASSERT(authenticator);
+ d->m_manager->proxyAuthenticationRequired(QUrl(), proxy, isSynchronous(), authenticator,
+ &d->m_reply->lastProxyAuthentication);
}
#endif
+/*!
+ Call this slot if the remote resource requests authentication.
+ This may cause the
+ QNetworkAccessManager::authenticationRequired() signal to be
+ emitted if the credentials are not already stored in an internal
+ cache.
+ The credentials will be stored in \a authenticator. While
+ \a authenticator is a pointer, passing \c nullptr is invalid.
+*/
void QNetworkAccessBackend::authenticationRequired(QAuthenticator *authenticator)
{
- manager->authenticationRequired(authenticator, reply->q_func(), synchronous, reply->url, &reply->urlForLastAuthentication);
+ Q_D(QNetworkAccessBackend);
+ Q_ASSERT(authenticator);
+ d->m_manager->authenticationRequired(authenticator, d->m_reply->q_func(), isSynchronous(),
+ d->m_reply->url, &d->m_reply->urlForLastAuthentication);
}
+/*!
+ Call this slot, if appropriate, after having processed and
+ updated metadata (e.g. headers).
+*/
void QNetworkAccessBackend::metaDataChanged()
{
- reply->metaDataChanged();
+ d_func()->m_reply->metaDataChanged();
}
-void QNetworkAccessBackend::redirectionRequested(const QUrl &target)
+/*!
+ Call this slot if, when connecting to the resource, a redirect
+ to \a destination was requested.
+*/
+void QNetworkAccessBackend::redirectionRequested(const QUrl &destination)
{
- reply->redirectionRequested(target);
+ d_func()->m_reply->redirectionRequested(destination);
}
-void QNetworkAccessBackend::encrypted()
+/*!
+ \internal
+*/
+void QNetworkAccessBackend::setReplyPrivate(QNetworkReplyImplPrivate *reply)
{
-#ifndef QT_NO_SSL
- reply->encrypted();
-#endif
+ d_func()->m_reply = reply;
}
-void QNetworkAccessBackend::sslErrors(const QList<QSslError> &errors)
+/*!
+ \internal
+*/
+void QNetworkAccessBackend::setManagerPrivate(QNetworkAccessManagerPrivate *manager)
{
-#ifndef QT_NO_SSL
- reply->sslErrors(errors);
-#else
- Q_UNUSED(errors);
-#endif
+ d_func()->m_manager = manager;
}
/*!
- Starts the backend. Returns \c true if the backend is started. Returns \c false if the backend
- could not be started due to an unopened or roaming session. The caller should recall this
- function once the session has been opened or the roaming process has finished.
+ Returns the network cache object that was available when the
+ request was started. Returns \c nullptr if none was available.
*/
-bool QNetworkAccessBackend::start()
+QAbstractNetworkCache *QNetworkAccessBackend::networkCache() const
{
-#ifndef QT_NO_NETWORKPROXY
- reply->proxyList = manager->queryProxy(QNetworkProxyQuery(url()));
-#endif
+ return d_func()->m_manager->networkCache;
+}
- // now start the request
- open();
- return true;
+// -- QNetworkAccessBackendFactory
+/*!
+ Constructs QNetworkAccessBackendFactory
+*/
+QNetworkAccessBackendFactory::QNetworkAccessBackendFactory()
+{
+ if (factoryData())
+ factoryData->append(this);
}
+/*!
+ Destructs QNetworkAccessBackendFactory
+*/
+QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory() = default;
+
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessbackend_p.h b/src/network/access/qnetworkaccessbackend_p.h
index b18f30c287..0f7b21684a 100644
--- a/src/network/access/qnetworkaccessbackend_p.h
+++ b/src/network/access/qnetworkaccessbackend_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -40,153 +40,108 @@
#ifndef QNETWORKACCESSBACKEND_P_H
#define QNETWORKACCESSBACKEND_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 <QtNetwork/private/qtnetworkglobal_p.h>
-#include "qnetworkreplyimpl_p.h"
-#include "QtCore/qobject.h"
-Q_MOC_INCLUDE(<QAuthenticator>)
-Q_MOC_INCLUDE(<QtNetwork/QSslError>)
+#include <QtNetwork/qtnetworkglobal.h>
-QT_BEGIN_NAMESPACE
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QtNetwork/qnetworkreply.h>
-class QNetworkProxy;
-class QNetworkProxyQuery;
-class QNetworkRequest;
-class QStringList;
-class QUrl;
-class QSslConfiguration;
+#include <QtCore/qobject.h>
+#include <QtCore/qflags.h>
+#include <QtCore/qbytearrayview.h>
+
+#if QT_CONFIG(ssl)
+#include <QtNetwork/qsslconfiguration.h>
+#endif
+
+QT_BEGIN_NAMESPACE
-class QNetworkAccessManagerPrivate;
class QNetworkReplyImplPrivate;
-class QAbstractNetworkCache;
-class QNetworkCacheMetaData;
-class QNonContiguousByteDevice;
-
-// Should support direct file upload from disk or download to disk.
-//
-// - The HTTP handler will use two QIODevices for communication (pull mechanism)
-// - KIO uses a pull mechanism too (data/dataReq signals)
-class QNetworkAccessBackend : public QObject
+class QNetworkAccessManagerPrivate;
+class QNetworkAccessBackendPrivate;
+class Q_NETWORK_EXPORT QNetworkAccessBackend : public QObject
{
Q_OBJECT
+ Q_DECLARE_PRIVATE(QNetworkAccessBackend);
+
public:
- QNetworkAccessBackend();
+ enum class TargetType {
+ Networked = 0x1, // We need to query for proxy in case it is needed
+ Local = 0x2, // Local file, generated data or local device
+ };
+ Q_ENUM(TargetType)
+ Q_DECLARE_FLAGS(TargetTypes, TargetType)
+
+ enum class SecurityFeature {
+ None = 0x0,
+ TLS = 0x1, // We need to set QSslConfiguration
+ };
+ Q_ENUM(SecurityFeature)
+ Q_DECLARE_FLAGS(SecurityFeatures, SecurityFeature)
+
+ enum class IOFeature {
+ None = 0x0,
+ ZeroCopy = 0x1, // readPointer and advanceReadPointer() is available!
+ NeedResetableUpload = 0x2, // Need to buffer upload data
+ SupportsSynchronousMode = 0x4, // Used for XMLHttpRequest
+ };
+ Q_ENUM(IOFeature)
+ Q_DECLARE_FLAGS(IOFeatures, IOFeature)
+
+ QNetworkAccessBackend(TargetTypes targetTypes, SecurityFeatures securityFeatures,
+ IOFeatures ioFeatures);
+ QNetworkAccessBackend(TargetTypes targetTypes);
+ QNetworkAccessBackend(TargetTypes targetTypes, SecurityFeatures securityFeatures);
+ QNetworkAccessBackend(TargetTypes targetTypes, IOFeatures ioFeatures);
virtual ~QNetworkAccessBackend();
- // To avoid mistaking with QIODevice names, the functions here
- // have different names. The Connection has two streams:
- //
- // - Upstream:
- // The upstream uses a QNonContiguousByteDevice provided
- // by the backend. This device emits the usual readyRead()
- // signal when the backend has data available for the connection
- // to write. The different backends can listen on this signal
- // and then pull upload data from the QNonContiguousByteDevice and
- // deal with it.
- //
- //
- // - Downstream:
- // Downstream is the data that is being read from this
- // connection and is given to the user. Downstream operates in a
- // semi-"push" mechanism: the Connection object pushes the data
- // it gets from the network, but it should avoid writing too
- // much if the data isn't being used fast enough. The value
- // returned by suggestedDownstreamBlockSize() can be used to
- // determine how much should be written at a time. The
- // downstreamBytesConsumed() function will be called when the
- // downstream buffer is consumed by the user -- the Connection
- // may choose to re-fill it with more data it has ready or get
- // more data from the network (for instance, by reading from its
- // socket).
+ SecurityFeatures securityFeatures() const noexcept;
+ TargetTypes targetTypes() const noexcept;
+ IOFeatures ioFeatures() const noexcept;
- virtual void open() = 0;
- virtual bool start();
- virtual void closeDownstreamChannel() = 0;
+ inline bool needsResetableUploadData() const noexcept
+ {
+ return ioFeatures() & IOFeature::NeedResetableUpload;
+ }
- // slot-like:
- virtual void downstreamReadyWrite();
- virtual void setDownstreamLimited(bool b);
- virtual void copyFinished(QIODevice *);
+ virtual bool start();
+ virtual void open() = 0;
+ virtual void close() = 0;
+#if QT_CONFIG(ssl)
+ virtual void setSslConfiguration(const QSslConfiguration &configuration);
+ virtual QSslConfiguration sslConfiguration() const;
+#endif
virtual void ignoreSslErrors();
virtual void ignoreSslErrors(const QList<QSslError> &errors);
+ virtual qint64 bytesAvailable() const = 0;
+ virtual QByteArrayView readPointer();
+ virtual void advanceReadPointer(qint64 distance);
+ virtual qint64 read(char *data, qint64 maxlen);
+ virtual bool wantToRead();
- virtual void fetchSslConfiguration(QSslConfiguration &configuration) const;
- virtual void setSslConfiguration(const QSslConfiguration &configuration);
-
- virtual QNetworkCacheMetaData fetchCacheMetaData(const QNetworkCacheMetaData &metaData) const;
-
- // information about the request
- QNetworkAccessManager::Operation operation() const;
- QNetworkRequest request() const;
-#ifndef QT_NO_NETWORKPROXY
+#if QT_CONFIG(networkproxy)
QList<QNetworkProxy> proxyList() const;
#endif
-
- QAbstractNetworkCache *networkCache() const;
- void setCachingEnabled(bool enable);
- bool isCachingEnabled() const;
-
- // information about the reply
QUrl url() const;
void setUrl(const QUrl &url);
-
- // "cooked" headers
QVariant header(QNetworkRequest::KnownHeaders header) const;
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
+ QByteArray rawHeader(const QByteArray &header) const;
+ void setRawHeader(const QByteArray &header, const QByteArray &value);
+ QNetworkAccessManager::Operation operation() const;
- // raw headers:
- bool hasRawHeader(const QByteArray &headerName) const;
- QList<QByteArray> rawHeaderList() const;
- QByteArray rawHeader(const QByteArray &headerName) const;
- void setRawHeader(const QByteArray &headerName, const QByteArray &value);
-
- // attributes:
- QVariant attribute(QNetworkRequest::Attribute code) const;
- void setAttribute(QNetworkRequest::Attribute code, const QVariant &value);
-
- bool isSynchronous() { return synchronous; }
- void setSynchronous(bool sync) { synchronous = sync; }
-
- // return true if the QNonContiguousByteDevice of the upload
- // data needs to support reset(). Currently needed for HTTP.
- // This will possibly enable buffering of the upload data.
- virtual bool needsResetableUploadData() { return false; }
-
- // Returns \c true if backend is able to resume downloads.
- virtual bool canResume() const { return false; }
- virtual void setResumeOffset(quint64 offset) { Q_UNUSED(offset); }
-
- virtual bool processRequestSynchronously() { return false; }
-
-protected:
- // Create the device used for reading the upload data
- QNonContiguousByteDevice* createUploadByteDevice();
+ bool isCachingEnabled() const;
+ void setCachingEnabled(bool canCache);
- // these functions control the downstream mechanism
- // that is, data that has come via the connection and is going out the backend
- qint64 nextDownstreamBlockSize() const;
- void writeDownstreamData(QByteDataBuffer &list);
+ void setAttribute(QNetworkRequest::Attribute attribute, const QVariant &value);
- // not actually appending data, it was already written to the user buffer
- void writeDownstreamDataDownloadBuffer(qint64, qint64);
- char* getDownloadBuffer(qint64);
+ QIODevice *createUploadByteDevice();
+ QIODevice *uploadByteDevice();
- QSharedPointer<QNonContiguousByteDevice> uploadByteDevice;
+ QAbstractNetworkCache *networkCache() const;
public slots:
- // for task 251801, needs to be a slot to be called asynchronously
- void writeDownstreamData(QIODevice *data);
-
+ void readyRead();
protected slots:
void finished();
void error(QNetworkReply::NetworkError code, const QString &errorString);
@@ -196,26 +151,21 @@ protected slots:
void authenticationRequired(QAuthenticator *auth);
void metaDataChanged();
void redirectionRequested(const QUrl &destination);
- void encrypted();
- void sslErrors(const QList<QSslError> &errors);
- void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal);
-
-protected:
- // FIXME In the long run we should get rid of our QNAM architecture
- // and scrap this ReplyImpl/Backend distinction.
- QNetworkAccessManagerPrivate *manager;
- QNetworkReplyImplPrivate *reply;
private:
- friend class QNetworkAccessManager;
- friend class QNetworkAccessManagerPrivate;
- friend class QNetworkReplyImplPrivate;
-
- bool synchronous;
+ void setReplyPrivate(QNetworkReplyImplPrivate *reply);
+ void setManagerPrivate(QNetworkAccessManagerPrivate *manager);
+ bool isSynchronous() const;
+ void setSynchronous(bool synchronous);
+
+ friend class QNetworkAccessManager; // for setReplyPrivate
+ friend class QNetworkAccessManagerPrivate; // for setManagerPrivate
+ friend class QNetworkReplyImplPrivate; // for {set,is}Synchronous()
};
-class QNetworkAccessBackendFactory
+class Q_NETWORK_EXPORT QNetworkAccessBackendFactory : public QObject
{
+ Q_OBJECT
public:
QNetworkAccessBackendFactory();
virtual ~QNetworkAccessBackendFactory();
@@ -224,7 +174,8 @@ public:
const QNetworkRequest &request) const = 0;
};
-QT_END_NAMESPACE
+#define QNetworkAccessBackendFactory_iid "org.qt-project.Qt.NetworkAccessBackendFactory"
+Q_DECLARE_INTERFACE(QNetworkAccessBackendFactory, QNetworkAccessBackendFactory_iid);
+QT_END_NAMESPACE
#endif
-
diff --git a/src/network/access/qnetworkaccesscachebackend.cpp b/src/network/access/qnetworkaccesscachebackend.cpp
index 1a4ef27dd6..9ed951751a 100644
--- a/src/network/access/qnetworkaccesscachebackend.cpp
+++ b/src/network/access/qnetworkaccesscachebackend.cpp
@@ -48,7 +48,7 @@
QT_BEGIN_NAMESPACE
QNetworkAccessCacheBackend::QNetworkAccessCacheBackend()
- : QNetworkAccessBackend()
+ : QNetworkAccessBackend(QNetworkAccessBackend::TargetType::Local)
{
}
@@ -107,11 +107,11 @@ bool QNetworkAccessCacheBackend::sendCacheContents()
metaDataChanged();
if (operation() == QNetworkAccessManager::GetOperation) {
- QIODevice *contents = nc->data(url());
- if (!contents)
+ device = nc->data(url());
+ if (!device)
return false;
- contents->setParent(this);
- writeDownstreamData(contents);
+ device->setParent(this);
+ readyRead();
}
#if defined(QNETWORKACCESSCACHEBACKEND_DEBUG)
@@ -126,23 +126,16 @@ bool QNetworkAccessCacheBackend::start()
return true;
}
-void QNetworkAccessCacheBackend::closeDownstreamChannel()
-{
-}
-
-void QNetworkAccessCacheBackend::closeUpstreamChannel()
-{
- Q_ASSERT_X(false, Q_FUNC_INFO, "This function show not have been called!");
-}
+void QNetworkAccessCacheBackend::close() { }
-void QNetworkAccessCacheBackend::upstreamReadyRead()
+qint64 QNetworkAccessCacheBackend::bytesAvailable() const
{
- Q_ASSERT_X(false, Q_FUNC_INFO, "This function show not have been called!");
+ return device ? device->bytesAvailable() : qint64(0);
}
-void QNetworkAccessCacheBackend::downstreamReadyWrite()
+qint64 QNetworkAccessCacheBackend::read(char *data, qint64 maxlen)
{
- Q_ASSERT_X(false, Q_FUNC_INFO, "This function show not have been called!");
+ return device ? device->read(data, maxlen) : qint64(0);
}
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccesscachebackend_p.h b/src/network/access/qnetworkaccesscachebackend_p.h
index ceb02946dc..fc26dda454 100644
--- a/src/network/access/qnetworkaccesscachebackend_p.h
+++ b/src/network/access/qnetworkaccesscachebackend_p.h
@@ -66,16 +66,15 @@ public:
~QNetworkAccessCacheBackend();
void open() override;
- void closeDownstreamChannel() override;
- void closeUpstreamChannel();
+ void close() override;
bool start() override;
-
- void upstreamReadyRead();
- void downstreamReadyWrite() override;
+ qint64 bytesAvailable() const override;
+ qint64 read(char *data, qint64 maxlen) override;
private:
bool sendCacheContents();
+ QIODevice *device = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp
index 0029df41fe..51c13b7241 100644
--- a/src/network/access/qnetworkaccessdebugpipebackend.cpp
+++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp
@@ -80,8 +80,13 @@ QNetworkAccessDebugPipeBackendFactory::create(QNetworkAccessManager::Operation o
}
QNetworkAccessDebugPipeBackend::QNetworkAccessDebugPipeBackend()
- : bareProtocol(false), hasUploadFinished(false), hasDownloadFinished(false),
- hasEverythingFinished(false), bytesDownloaded(0), bytesUploaded(0)
+ : QNetworkAccessBackend(QNetworkAccessBackend::TargetType::Networked),
+ bareProtocol(false),
+ hasUploadFinished(false),
+ hasDownloadFinished(false),
+ hasEverythingFinished(false),
+ bytesDownloaded(0),
+ bytesUploaded(0)
{
}
@@ -108,65 +113,46 @@ void QNetworkAccessDebugPipeBackend::open()
if (operation() == QNetworkAccessManager::PutOperation) {
createUploadByteDevice();
- QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot()));
+ QObject::connect(uploadByteDevice(), SIGNAL(readyRead()), this,
+ SLOT(uploadReadyReadSlot()));
QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection);
}
}
void QNetworkAccessDebugPipeBackend::socketReadyRead()
{
- pushFromSocketToDownstream();
+ readyRead();
}
-void QNetworkAccessDebugPipeBackend::downstreamReadyWrite()
+qint64 QNetworkAccessDebugPipeBackend::read(char *data, qint64 maxlen)
{
- pushFromSocketToDownstream();
+ qint64 haveRead = socket.read(data, maxlen);
+
+ if (haveRead == -1) {
+ hasDownloadFinished = true;
+ // this ensures a good last downloadProgress is emitted
+ setHeader(QNetworkRequest::ContentLengthHeader, QVariant());
+ possiblyFinish();
+ return haveRead;
+ }
+
+ bytesDownloaded += haveRead;
+ return haveRead;
}
-void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64)
+qint64 QNetworkAccessDebugPipeBackend::bytesAvailable() const
{
- pushFromUpstreamToSocket();
+ return socket.bytesAvailable();
}
-void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot()
+void QNetworkAccessDebugPipeBackend::socketBytesWritten(qint64)
{
pushFromUpstreamToSocket();
}
-void QNetworkAccessDebugPipeBackend::pushFromSocketToDownstream()
+void QNetworkAccessDebugPipeBackend::uploadReadyReadSlot()
{
- QByteArray buffer;
-
- if (socket.state() == QAbstractSocket::ConnectingState) {
- return;
- }
-
- forever {
- if (hasDownloadFinished)
- return;
-
- buffer.resize(ReadBufferSize);
- qint64 haveRead = socket.read(buffer.data(), ReadBufferSize);
-
- if (haveRead == -1) {
- hasDownloadFinished = true;
- // this ensures a good last downloadProgress is emitted
- setHeader(QNetworkRequest::ContentLengthHeader, QVariant());
- possiblyFinish();
- break;
- } else if (haveRead == 0) {
- break;
- } else {
- // have read something
- buffer.resize(haveRead);
- bytesDownloaded += haveRead;
-
- QByteDataBuffer list;
- list.append(buffer);
- buffer.clear(); // important because of implicit sharing!
- writeDownstreamData(list);
- }
- }
+ pushFromUpstreamToSocket();
}
void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket()
@@ -180,20 +166,20 @@ void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket()
if (socket.bytesToWrite() >= WriteBufferSize)
return;
- qint64 haveRead;
- const char *readPointer = uploadByteDevice->readPointer(WriteBufferSize, haveRead);
+ QByteArray data(WriteBufferSize, Qt::Uninitialized);
+ qint64 haveRead = uploadByteDevice()->peek(data.data(), data.size());
if (haveRead == -1) {
// EOF
hasUploadFinished = true;
- emitReplyUploadProgress(bytesUploaded, bytesUploaded);
possiblyFinish();
break;
- } else if (haveRead == 0 || readPointer == nullptr) {
+ } else if (haveRead == 0) {
// nothing to read right now, we will be called again later
break;
} else {
qint64 haveWritten;
- haveWritten = socket.write(readPointer, haveRead);
+ data.truncate(haveRead);
+ haveWritten = socket.write(std::move(data));
if (haveWritten < 0) {
// write error!
@@ -203,13 +189,11 @@ void QNetworkAccessDebugPipeBackend::pushFromUpstreamToSocket()
finished();
return;
} else {
- uploadByteDevice->advanceReadPointer(haveWritten);
+ uploadByteDevice()->skip(haveWritten);
bytesUploaded += haveWritten;
- emitReplyUploadProgress(bytesUploaded, -1);
}
//QCoreApplication::processEvents();
-
}
}
}
@@ -232,7 +216,7 @@ void QNetworkAccessDebugPipeBackend::possiblyFinish()
}
-void QNetworkAccessDebugPipeBackend::closeDownstreamChannel()
+void QNetworkAccessDebugPipeBackend::close()
{
qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());;
//if (operation() == QNetworkAccessManager::GetOperation)
@@ -266,11 +250,10 @@ void QNetworkAccessDebugPipeBackend::socketError()
void QNetworkAccessDebugPipeBackend::socketDisconnected()
{
- pushFromSocketToDownstream();
-
if (socket.bytesToWrite() == 0) {
// normal close
} else {
+ readyRead(); // @todo this is odd
// abnormal close
QString msg = QNetworkAccessDebugPipeBackend::tr("Remote host closed the connection prematurely on %1")
.arg(url().toString());
diff --git a/src/network/access/qnetworkaccessdebugpipebackend_p.h b/src/network/access/qnetworkaccessdebugpipebackend_p.h
index 761c7055b8..50ef5cea7d 100644
--- a/src/network/access/qnetworkaccessdebugpipebackend_p.h
+++ b/src/network/access/qnetworkaccessdebugpipebackend_p.h
@@ -68,13 +68,13 @@ public:
QNetworkAccessDebugPipeBackend();
virtual ~QNetworkAccessDebugPipeBackend();
- virtual void open() override;
- virtual void closeDownstreamChannel() override;
+ void open() override;
+ void close() override;
- virtual void downstreamReadyWrite() override;
+ qint64 read(char *data, qint64 maxlen) override;
+ qint64 bytesAvailable() const override;
protected:
- void pushFromSocketToDownstream();
void pushFromUpstreamToSocket();
void possiblyFinish();
diff --git a/src/network/access/qnetworkaccessfilebackend.cpp b/src/network/access/qnetworkaccessfilebackend.cpp
index 046a16162a..c5f1826203 100644
--- a/src/network/access/qnetworkaccessfilebackend.cpp
+++ b/src/network/access/qnetworkaccessfilebackend.cpp
@@ -95,8 +95,12 @@ QNetworkAccessFileBackendFactory::create(QNetworkAccessManager::Operation op,
return nullptr;
}
+// We pass TargetType::Local even though it's kind of Networked but we're using a QFile to access
+// the resource so it cannot use proxies anyway
QNetworkAccessFileBackend::QNetworkAccessFileBackend()
- : totalBytes(0), hasUploadFinished(false)
+ : QNetworkAccessBackend(QNetworkAccessBackend::TargetType::Local),
+ totalBytes(0),
+ hasUploadFinished(false)
{
}
@@ -152,7 +156,7 @@ void QNetworkAccessFileBackend::open()
case QNetworkAccessManager::PutOperation:
mode = QIODevice::WriteOnly | QIODevice::Truncate;
createUploadByteDevice();
- QObject::connect(uploadByteDevice.data(), SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot()));
+ QObject::connect(uploadByteDevice(), SIGNAL(readyRead()), this, SLOT(uploadReadyReadSlot()));
QMetaObject::invokeMethod(this, "uploadReadyReadSlot", Qt::QueuedConnection);
break;
default:
@@ -163,6 +167,8 @@ void QNetworkAccessFileBackend::open()
mode |= QIODevice::Unbuffered;
bool opened = file.open(mode);
+ if (file.isSequential())
+ connect(&file, &QIODevice::readChannelFinished, this, [this]() { finished(); });
// could we open the file?
if (!opened) {
@@ -186,8 +192,8 @@ void QNetworkAccessFileBackend::uploadReadyReadSlot()
return;
forever {
- qint64 haveRead;
- const char *readPointer = uploadByteDevice->readPointer(-1, haveRead);
+ QByteArray data(16 * 1024, Qt::Uninitialized);
+ qint64 haveRead = uploadByteDevice()->peek(data.data(), data.size());
if (haveRead == -1) {
// EOF
hasUploadFinished = true;
@@ -195,12 +201,13 @@ void QNetworkAccessFileBackend::uploadReadyReadSlot()
file.close();
finished();
break;
- } else if (haveRead == 0 || readPointer == nullptr) {
+ } else if (haveRead == 0) {
// nothing to read right now, we will be called again later
break;
} else {
qint64 haveWritten;
- haveWritten = file.write(readPointer, haveRead);
+ data.truncate(haveRead);
+ haveWritten = file.write(data);
if (haveWritten < 0) {
// write error!
@@ -211,7 +218,7 @@ void QNetworkAccessFileBackend::uploadReadyReadSlot()
finished();
return;
} else {
- uploadByteDevice->advanceReadPointer(haveWritten);
+ uploadByteDevice()->skip(haveWritten);
}
@@ -220,21 +227,13 @@ void QNetworkAccessFileBackend::uploadReadyReadSlot()
}
}
-void QNetworkAccessFileBackend::closeDownstreamChannel()
+void QNetworkAccessFileBackend::close()
{
if (operation() == QNetworkAccessManager::GetOperation) {
file.close();
}
}
-void QNetworkAccessFileBackend::downstreamReadyWrite()
-{
- Q_ASSERT_X(operation() == QNetworkAccessManager::GetOperation, "QNetworkAccessFileBackend",
- "We're being told to download data but operation isn't GET!");
-
- readMoreFromFile();
-}
-
bool QNetworkAccessFileBackend::loadFileInfo()
{
QFileInfo fi(file);
@@ -254,40 +253,36 @@ bool QNetworkAccessFileBackend::loadFileInfo()
return true;
}
-bool QNetworkAccessFileBackend::readMoreFromFile()
+qint64 QNetworkAccessFileBackend::bytesAvailable() const
{
- qint64 wantToRead;
- while ((wantToRead = nextDownstreamBlockSize()) > 0) {
- // ### FIXME!!
- // Obtain a pointer from the ringbuffer!
- // Avoid extra copy
- QByteArray data;
- data.reserve(wantToRead);
- qint64 actuallyRead = file.read(data.data(), wantToRead);
- if (actuallyRead <= 0) {
- // EOF or error
- if (file.error() != QFile::NoError) {
- QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Read error reading from %1: %2")
- .arg(url().toString(), file.errorString());
- error(QNetworkReply::ProtocolFailure, msg);
+ if (operation() != QNetworkAccessManager::GetOperation)
+ return 0;
+ return file.bytesAvailable();
+}
- finished();
- return false;
- }
+qint64 QNetworkAccessFileBackend::read(char *data, qint64 maxlen)
+{
+ if (operation() != QNetworkAccessManager::GetOperation)
+ return 0;
+ qint64 actuallyRead = file.read(data, maxlen);
+ if (actuallyRead <= 0) {
+ // EOF or error
+ if (file.error() != QFile::NoError) {
+ QString msg = QCoreApplication::translate("QNetworkAccessFileBackend", "Read error reading from %1: %2")
+ .arg(url().toString(), file.errorString());
+ error(QNetworkReply::ProtocolFailure, msg);
finished();
- return true;
+ return -1;
}
- data.resize(actuallyRead);
- totalBytes += actuallyRead;
-
- QByteDataBuffer list;
- list.append(data);
- data.clear(); // important because of implicit sharing!
- writeDownstreamData(list);
+ finished();
+ return actuallyRead;
}
- return true;
+ if (!file.isSequential() && file.atEnd())
+ finished();
+ totalBytes += actuallyRead;
+ return actuallyRead;
}
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkaccessfilebackend_p.h b/src/network/access/qnetworkaccessfilebackend_p.h
index 2204958ee0..32b2102abc 100644
--- a/src/network/access/qnetworkaccessfilebackend_p.h
+++ b/src/network/access/qnetworkaccessfilebackend_p.h
@@ -66,10 +66,11 @@ public:
QNetworkAccessFileBackend();
virtual ~QNetworkAccessFileBackend();
- virtual void open() override;
- virtual void closeDownstreamChannel() override;
+ void open() override;
+ void close() override;
- virtual void downstreamReadyWrite() override;
+ qint64 bytesAvailable() const;
+ qint64 read(char *data, qint64 maxlen);
public slots:
void uploadReadyReadSlot();
@@ -79,7 +80,6 @@ private:
bool hasUploadFinished;
bool loadFileInfo();
- bool readMoreFromFile();
};
class QNetworkAccessFileBackendFactory: public QNetworkAccessBackendFactory
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index b56da732e2..99c929d6a2 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -60,6 +60,9 @@
#include "qnetworkreplydataimpl_p.h"
#include "qnetworkreplyfileimpl_p.h"
+#include "qnetworkaccessbackend_p.h"
+#include "qnetworkreplyimpl_p.h"
+
#include "QtCore/qbuffer.h"
#include "QtCore/qlist.h"
#include "QtCore/qurl.h"
@@ -77,6 +80,8 @@
#include <QHostInfo>
+#include <QtCore/private/qfactoryloader_p.h>
+
#if defined(Q_OS_MACOS)
#include <CoreServices/CoreServices.h>
#include <SystemConfiguration/SystemConfiguration.h>
@@ -96,6 +101,9 @@ Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
#endif
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QNetworkAccessBackendFactory_iid,
+ QLatin1String("/networkaccessbackends")))
#if defined(Q_OS_MACOS)
bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password)
{
@@ -396,6 +404,7 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
: QObject(*new QNetworkAccessManagerPrivate, parent)
{
ensureInitialized();
+ d_func()->ensureBackendPluginsLoaded();
qRegisterMetaType<QNetworkReply::NetworkError>();
#ifndef QT_NO_NETWORKPROXY
@@ -1171,9 +1180,9 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
QNetworkReplyImplPrivate *priv = reply->d_func();
priv->manager = this;
priv->backend = new QNetworkAccessCacheBackend();
- priv->backend->manager = this->d_func();
+ priv->backend->setManagerPrivate(this->d_func());
priv->backend->setParent(reply);
- priv->backend->reply = priv;
+ priv->backend->setReplyPrivate(priv);
priv->setup(op, req, outgoingData);
return reply;
}
@@ -1251,7 +1260,7 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
if (priv->backend) {
priv->backend->setParent(reply);
- priv->backend->reply = priv;
+ priv->backend->setReplyPrivate(priv);
}
#ifndef QT_NO_SSL
@@ -1685,6 +1694,25 @@ QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkReq
}
#endif // QT_CONFIG(http)
+/*!
+ \internal
+ Go through the instances so the factories will be created and
+ register themselves to QNetworkAccessBackendFactoryData
+*/
+void QNetworkAccessManagerPrivate::ensureBackendPluginsLoaded()
+{
+ static QBasicMutex mutex;
+ std::unique_lock locker(mutex);
+ if (!loader())
+ return;
+#if QT_CONFIG(library)
+ loader->update();
+#endif
+ int index = 0;
+ while (loader->instance(index))
+ ++index;
+}
+
QT_END_NAMESPACE
#include "moc_qnetworkaccessmanager.cpp"
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index da9f6fd0bd..5433876385 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -130,6 +130,8 @@ public:
QNetworkRequest prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart);
#endif
+ void ensureBackendPluginsLoaded();
+
// this is the cache for storing downloaded files
QAbstractNetworkCache *networkCache;
@@ -153,8 +155,6 @@ public:
// this cache can be used by individual backends to cache e.g. their TCP connections to a server
// and use the connections for multiple requests.
QNetworkAccessCache objectCache;
- static inline QNetworkAccessCache *getObjectCache(QNetworkAccessBackend *backend)
- { return &backend->manager->objectCache; }
Q_AUTOTEST_EXPORT static void clearAuthenticationCache(QNetworkAccessManager *manager);
Q_AUTOTEST_EXPORT static void clearConnectionCache(QNetworkAccessManager *manager);
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 88969c6483..bdb81ee0b1 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -61,6 +61,8 @@
#include "qnetworkcookiejar.h"
#include "qnetconmonitor_p.h"
+#include "qnetworkreplyimpl_p.h"
+
#include <string.h> // for strchr
QT_BEGIN_NAMESPACE
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 400cfff8d3..61745155f5 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -56,7 +56,7 @@ inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
copyDevice(nullptr),
cacheEnabled(false), cacheSaveDevice(nullptr),
notificationHandlingPaused(false),
- bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1),
+ bytesDownloaded(0), bytesUploaded(-1),
httpStatusCode(0),
state(Idle)
, downloadBufferReadPosition(0)
@@ -124,7 +124,7 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead()
// FIXME Optimize to use download buffer if it is a QBuffer.
// Needs to be done where sendCacheContents() (?) of HTTP is emitting
// metaDataChanged ?
-
+ qint64 lastBytesDownloaded = bytesDownloaded;
forever {
qint64 bytesToRead = nextDownstreamBlockSize();
if (bytesToRead == 0)
@@ -135,13 +135,11 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead()
qint64 bytesActuallyRead = copyDevice->read(buffer.reserve(bytesToRead), bytesToRead);
if (bytesActuallyRead == -1) {
buffer.chop(bytesToRead);
- backendNotify(NotifyCopyFinished);
break;
}
buffer.chop(bytesToRead - bytesActuallyRead);
if (!copyDevice->isSequential() && copyDevice->atEnd()) {
- backendNotify(NotifyCopyFinished);
bytesDownloaded += bytesActuallyRead;
break;
}
@@ -154,7 +152,6 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead()
return;
}
- lastBytesDownloaded = bytesDownloaded;
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
pauseNotificationHandling();
// emit readyRead before downloadProgress incase this will cause events to be
@@ -323,22 +320,16 @@ void QNetworkReplyImplPrivate::handleNotifications()
return;
switch (notification) {
case NotifyDownstreamReadyWrite:
- if (copyDevice)
+ if (copyDevice) {
_q_copyReadyRead();
- else
- backend->downstreamReadyWrite();
- break;
-
- case NotifyCloseDownstreamChannel:
- backend->closeDownstreamChannel();
- break;
-
- case NotifyCopyFinished: {
- QIODevice *dev = qExchange(copyDevice, nullptr);
- backend->copyFinished(dev);
+ } else if (backend) {
+ if (backend->bytesAvailable() > 0)
+ readFromBackend();
+ else if (backend->wantToRead())
+ readFromBackend();
+ }
break;
}
- }
}
}
@@ -463,7 +454,8 @@ void QNetworkReplyImplPrivate::initCacheSaveDevice()
// save the meta data
QNetworkCacheMetaData metaData;
metaData.setUrl(url);
- metaData = backend->fetchCacheMetaData(metaData);
+ // @todo @future: fetchCacheMetaData is not currently implemented in any backend, but can be useful again in the future
+ // metaData = backend->fetchCacheMetaData(metaData);
// save the redirect request also in the cache
QVariant redirectionTarget = q->attribute(QNetworkRequest::RedirectionTargetAttribute);
@@ -512,7 +504,6 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data)
data.clear();
bytesDownloaded += bytesWritten;
- lastBytesDownloaded = bytesDownloaded;
appendDownstreamDataSignalEmissions();
}
@@ -562,16 +553,6 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data)
_q_copyReadyRead();
}
-void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data)
-{
- Q_UNUSED(data);
- // TODO implement
-
- // TODO call
-
- qFatal("QNetworkReplyImplPrivate::appendDownstreamData not implemented");
-}
-
static void downloadBufferDeleter(char *ptr)
{
delete[] ptr;
@@ -620,16 +601,11 @@ void QNetworkReplyImplPrivate::appendDownstreamDataDownloadBuffer(qint64 bytesRe
initCacheSaveDevice();
if (cacheSaveDevice && bytesReceived == bytesTotal) {
-// if (lastBytesDownloaded == -1)
-// lastBytesDownloaded = 0;
-// cacheSaveDevice->write(downloadBuffer + lastBytesDownloaded, bytesReceived - lastBytesDownloaded);
-
// Write everything in one go if we use a download buffer. might be more performant.
cacheSaveDevice->write(downloadBuffer, bytesTotal);
}
bytesDownloaded = bytesReceived;
- lastBytesDownloaded = bytesReceived;
downloadBufferCurrentSize = bytesReceived;
@@ -748,6 +724,30 @@ void QNetworkReplyImplPrivate::sslErrors(const QList<QSslError> &errors)
#endif
}
+void QNetworkReplyImplPrivate::readFromBackend()
+{
+ Q_Q(QNetworkReplyImpl);
+ if (!backend)
+ return;
+
+ if (backend->ioFeatures() & QNetworkAccessBackend::IOFeature::ZeroCopy) {
+ if (backend->bytesAvailable())
+ emit q->readyRead();
+ } else {
+ while (backend->bytesAvailable()
+ && (!readBufferMaxSize || buffer.size() < readBufferMaxSize)) {
+ qint64 toRead = qMin(nextDownstreamBlockSize(), backend->bytesAvailable());
+ if (toRead == 0)
+ toRead = 16 * 1024; // try to read something
+ char *data = buffer.reserve(toRead);
+ qint64 bytesRead = backend->read(data, toRead);
+ Q_ASSERT(bytesRead <= toRead);
+ buffer.chop(toRead - bytesRead);
+ emit q->readyRead();
+ }
+ }
+}
+
QNetworkReplyImpl::QNetworkReplyImpl(QObject *parent)
: QNetworkReply(*new QNetworkReplyImplPrivate, parent)
{
@@ -799,7 +799,7 @@ void QNetworkReplyImpl::close()
// stop the download
if (d->backend)
- d->backend->closeDownstreamChannel();
+ d->backend->close();
if (d->copyDevice)
disconnect(d->copyDevice, nullptr, this, nullptr);
@@ -823,21 +823,16 @@ qint64 QNetworkReplyImpl::bytesAvailable() const
qint64 maxAvail = d->downloadBufferCurrentSize - d->downloadBufferReadPosition;
return QNetworkReply::bytesAvailable() + maxAvail;
}
-
- return QNetworkReply::bytesAvailable();
+ return QNetworkReply::bytesAvailable() + (d->backend ? d->backend->bytesAvailable() : 0);
}
void QNetworkReplyImpl::setReadBufferSize(qint64 size)
{
Q_D(QNetworkReplyImpl);
- if (size > d->readBufferMaxSize &&
- size > d->buffer.size())
- d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
-
+ qint64 oldMaxSize = d->readBufferMaxSize;
QNetworkReply::setReadBufferSize(size);
-
- if (d->backend)
- d->backend->setDownstreamLimited(d->readBufferMaxSize > 0);
+ if (size > oldMaxSize && size > d->buffer.size())
+ d->readFromBackend();
}
#ifndef QT_NO_SSL
@@ -845,7 +840,7 @@ void QNetworkReplyImpl::sslConfigurationImplementation(QSslConfiguration &config
{
Q_D(const QNetworkReplyImpl);
if (d->backend)
- d->backend->fetchSslConfiguration(configuration);
+ configuration = d->backend->sslConfiguration();
}
void QNetworkReplyImpl::setSslConfigurationImplementation(const QSslConfiguration &config)
@@ -877,6 +872,35 @@ qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen)
{
Q_D(QNetworkReplyImpl);
+ if (d->backend
+ && d->backend->ioFeatures().testFlag(QNetworkAccessBackend::IOFeature::ZeroCopy)) {
+ qint64 bytesRead = 0;
+ while (d->backend->bytesAvailable()) {
+ QByteArrayView view = d->backend->readPointer();
+ if (view.size()) {
+ qint64 bytesToCopy = qMin(qint64(view.size()), maxlen - bytesRead);
+ memcpy(data + bytesRead, view.data(), bytesToCopy); // from zero to one copy
+
+ // We might have to cache this
+ if (d->cacheEnabled && !d->cacheSaveDevice)
+ d->initCacheSaveDevice();
+ if (d->cacheEnabled && d->cacheSaveDevice)
+ d->cacheSaveDevice->write(view.data(), view.size());
+
+ bytesRead += bytesToCopy;
+ d->backend->advanceReadPointer(bytesToCopy);
+ } else {
+ break;
+ }
+ }
+ QVariant totalSize = d->cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
+ emit downloadProgress(bytesRead,
+ totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
+ return bytesRead;
+ } else if (d->backend && d->backend->bytesAvailable()) {
+ return d->backend->read(data, maxlen);
+ }
+
// Special case code if we have the "zero copy" download buffer
if (d->downloadBuffer) {
qint64 maxAvail = qMin<qint64>(d->downloadBufferCurrentSize - d->downloadBufferReadPosition, maxlen);
diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h
index bb5afe49d6..7d014f9173 100644
--- a/src/network/access/qnetworkreplyimpl_p.h
+++ b/src/network/access/qnetworkreplyimpl_p.h
@@ -106,8 +106,6 @@ class QNetworkReplyImplPrivate: public QNetworkReplyPrivate
public:
enum InternalNotifications {
NotifyDownstreamReadyWrite,
- NotifyCloseDownstreamChannel,
- NotifyCopyFinished
};
QNetworkReplyImplPrivate();
@@ -139,7 +137,6 @@ public:
void appendDownstreamDataSignalEmissions();
void appendDownstreamData(QByteDataBuffer &data);
void appendDownstreamData(QIODevice *data);
- void appendDownstreamData(const QByteArray &data);
void setDownloadBuffer(QSharedPointer<char> sp, qint64 size);
char* getDownloadBuffer(qint64 size);
@@ -152,6 +149,8 @@ public:
void encrypted();
void sslErrors(const QList<QSslError> &errors);
+ void readFromBackend();
+
QNetworkAccessBackend *backend;
QIODevice *outgoingData;
QSharedPointer<QRingBuffer> outgoingDataBuffer;
@@ -171,7 +170,6 @@ public:
#endif
qint64 bytesDownloaded;
- qint64 lastBytesDownloaded;
qint64 bytesUploaded;
QString httpReasonPhrase;