10#include "QtCore/qcoreapplication.h"
11#include "QtCore/qdatetime.h"
12#include "QtNetwork/qsslconfiguration.h"
15#include <QtCore/QCoreApplication>
19QT_IMPL_METATYPE_EXTERN_TAGGED(QSharedPointer<
char>, QSharedPointer_char)
21inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
22 : backend(
nullptr), outgoingData(
nullptr),
24 cacheEnabled(
false), cacheSaveDevice(
nullptr),
25 notificationHandlingPaused(
false),
26 bytesDownloaded(0), bytesUploaded(-1),
29 , downloadBufferReadPosition(0)
30 , downloadBufferCurrentSize(0)
31 , downloadBufferMaximumSize(0)
32 , downloadBuffer(
nullptr)
34 if (request.attribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute).toBool() ==
true)
35 emitAllUploadProgressSignals =
true;
42 qDebug() <<
"QNetworkReplyImpl::_q_startOperation was called more than once" << url;
51 error(QNetworkReplyImpl::ProtocolUnknownError,
52 QCoreApplication::translate(
"QNetworkReply",
"Protocol \"%1\" is unknown").arg(url.scheme()));
58 qWarning(
"Backend start failed");
60 error(QNetworkReplyImpl::UnknownNetworkError,
61 QCoreApplication::translate(
"QNetworkReply",
"backend start error."));
67 downloadProgressSignalChoke.start();
68 uploadProgressSignalChoke.invalidate();
72 q_func()->setFinished(
true);
74 if (
state != Finished) {
75 if (operation == QNetworkAccessManager::GetOperation)
76 pendingNotifications.push_back(NotifyDownstreamReadyWrite);
85 Q_Q(QNetworkReplyImpl);
88 if (!copyDevice || !q->isOpen())
94 qint64 lastBytesDownloaded = bytesDownloaded;
96 qint64 bytesToRead = nextDownstreamBlockSize();
101 bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable());
102 qint64 bytesActuallyRead = copyDevice->read(buffer.reserve(bytesToRead), bytesToRead);
103 if (bytesActuallyRead == -1) {
104 buffer.chop(bytesToRead);
107 buffer.chop(bytesToRead - bytesActuallyRead);
109 if (!copyDevice->isSequential() && copyDevice->atEnd()) {
110 bytesDownloaded += bytesActuallyRead;
114 bytesDownloaded += bytesActuallyRead;
117 if (bytesDownloaded == lastBytesDownloaded) {
122 const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
123 headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
129 if (downloadProgressSignalChoke.isValid() &&
130 downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
131 downloadProgressSignalChoke.start();
132 emit q->downloadProgress(bytesDownloaded, totalSizeOpt.value_or(-1));
144 Q_Q(QNetworkReplyImpl);
148 if (
state != Buffering)
152 QObject::disconnect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
153 QObject::disconnect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
156 QMetaObject::invokeMethod(q,
"_q_startOperation", Qt::QueuedConnection);
161 Q_Q(QNetworkReplyImpl);
163 if (!outgoingDataBuffer) {
165 outgoingDataBuffer = std::make_shared<QRingBuffer>();
167 QObject::connect(outgoingData, SIGNAL(readyRead()), q, SLOT(_q_bufferOutgoingData()));
168 QObject::connect(outgoingData, SIGNAL(readChannelFinished()), q, SLOT(_q_bufferOutgoingDataFinished()));
171 qint64 bytesBuffered = 0;
172 qint64 bytesToBuffer = 0;
176 bytesToBuffer = outgoingData->bytesAvailable();
178 if (bytesToBuffer <= 0)
179 bytesToBuffer = 2*1024;
181 char *dst = outgoingDataBuffer->reserve(bytesToBuffer);
182 bytesBuffered = outgoingData->read(dst, bytesToBuffer);
184 if (bytesBuffered == -1) {
186 outgoingDataBuffer->chop(bytesToBuffer);
188 _q_bufferOutgoingDataFinished();
190 }
else if (bytesBuffered == 0) {
192 outgoingDataBuffer->chop(bytesToBuffer);
197 outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered);
205 Q_Q(QNetworkReplyImpl);
209 originalRequest = req;
213 q->QIODevice::open(QIODevice::ReadOnly);
216 QVariant synchronousHttpAttribute = req.attribute(
217 static_cast<QNetworkRequest::Attribute>(QNetworkRequest::SynchronousRequestAttribute));
220 if (synchronousHttpAttribute.toBool() && outgoingData) {
221 outgoingDataBuffer = std::make_shared<QRingBuffer>();
222 qint64 previousDataSize = 0;
224 previousDataSize = outgoingDataBuffer->size();
225 outgoingDataBuffer->append(outgoingData->readAll());
226 }
while (outgoingDataBuffer->size() != previousDataSize);
230 backend->setSynchronous(synchronousHttpAttribute.toBool());
233 if (outgoingData && backend && !backend->isSynchronous()) {
236 if (!backend->needsResetableUploadData() || !outgoingData->isSequential()) {
240 QMetaObject::invokeMethod(q,
"_q_startOperation", Qt::QueuedConnection);
242 bool bufferingDisallowed =
243 req.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute,
246 if (bufferingDisallowed) {
249 const auto sizeOpt = QNetworkHeadersPrivate::toInt(
250 headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
253 QMetaObject::invokeMethod(q,
"_q_startOperation", Qt::QueuedConnection);
256 QMetaObject::invokeMethod(q,
"_q_bufferOutgoingData", Qt::QueuedConnection);
261 QMetaObject::invokeMethod(q,
"_q_bufferOutgoingData", Qt::QueuedConnection);
270 QMetaObject::invokeMethod(q,
"_q_startOperation", Qt::QueuedConnection);
276 Q_Q(QNetworkReplyImpl);
277 const auto it = std::find(pendingNotifications.cbegin(), pendingNotifications.cend(), notification);
278 if (it == pendingNotifications.cend())
279 pendingNotifications.push_back(notification);
281 if (pendingNotifications.size() == 1)
282 QCoreApplication::postEvent(q,
new QEvent(QEvent::NetworkReplyUpdated));
290 for (InternalNotifications notification : std::exchange(pendingNotifications, {})) {
291 if (state != Working)
293 switch (notification) {
294 case NotifyDownstreamReadyWrite:
297 }
else if (backend) {
298 if (backend->bytesAvailable() > 0)
300 else if (backend->wantToRead())
318 Q_Q(QNetworkReplyImpl);
320 if (pendingNotifications.size() >= 1)
321 QCoreApplication::postEvent(q,
new QEvent(QEvent::NetworkReplyUpdated));
328 return backend->networkCache();
335 || !request.attribute(QNetworkRequest::CacheSaveControlAttribute,
true).toBool())
353 if (Q_UNLIKELY(bytesDownloaded)) {
355 qCritical(
"QNetworkReplyImpl: backend error: caching was enabled after some bytes had been written");
363 qDebug(
"QNetworkReplyImpl: setCachingEnabled(true) called after setCachingEnabled(false) -- "
364 "backend %s probably needs to be fixed",
365 backend->metaObject()->className());
366 networkCache()->remove(url);
367 cacheSaveDevice =
nullptr;
374 if (cacheEnabled && errorCode != QNetworkReplyImpl::NoError) {
375 networkCache()->remove(url);
376 }
else if (cacheEnabled && cacheSaveDevice) {
377 networkCache()->insert(cacheSaveDevice);
379 cacheSaveDevice =
nullptr;
385 Q_Q(QNetworkReplyImpl);
386 bytesUploaded = bytesSent;
388 if (!emitAllUploadProgressSignals) {
390 if (uploadProgressSignalChoke.isValid()) {
391 if (bytesSent != bytesTotal && uploadProgressSignalChoke.elapsed() < progressSignalInterval) {
395 uploadProgressSignalChoke.start();
399 emit q->uploadProgress(bytesSent, bytesTotal);
406 enum { DesiredBufferSize = 32 * 1024 };
407 if (readBufferMaxSize == 0)
408 return DesiredBufferSize;
410 return qMax<qint64>(0, readBufferMaxSize - buffer.size());
415 Q_Q(QNetworkReplyImpl);
419 if (q->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 206) {
426 metaData.setUrl(url);
431 QVariant redirectionTarget = q->attribute(QNetworkRequest::RedirectionTargetAttribute);
432 if (redirectionTarget.isValid()) {
433 QNetworkCacheMetaData::AttributesMap attributes = metaData.attributes();
434 attributes.insert(QNetworkRequest::RedirectionTargetAttribute, redirectionTarget);
435 metaData.setAttributes(attributes);
438 cacheSaveDevice = networkCache()->prepare(metaData);
440 if (!cacheSaveDevice || !cacheSaveDevice->isOpen()) {
441 if (Q_UNLIKELY(cacheSaveDevice && !cacheSaveDevice->isOpen()))
442 qCritical(
"QNetworkReplyImpl: network cache returned a device that is not open -- "
443 "class %s probably needs to be fixed",
446 networkCache()->remove(url);
447 cacheSaveDevice =
nullptr;
456 Q_Q(QNetworkReplyImpl);
460 if (cacheEnabled && !cacheSaveDevice) {
464 qint64 bytesWritten = 0;
465 for (qsizetype i = 0; i < data.bufferCount(); ++i) {
469 cacheSaveDevice->write(item.constData(), item.size());
472 bytesWritten += item.size();
476 bytesDownloaded += bytesWritten;
483 Q_Q(QNetworkReplyImpl);
485 const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
486 headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
493 if (downloadProgressSignalChoke.isValid() &&
494 downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
495 downloadProgressSignalChoke.start();
496 emit q->downloadProgress(bytesDownloaded, totalSizeOpt.value_or(-1));
501 if (nextDownstreamBlockSize() > 0)
508 Q_Q(QNetworkReplyImpl);
513 if (Q_UNLIKELY(copyDevice)) {
514 qCritical(
"QNetworkReplyImpl: copy from QIODevice already in progress -- "
515 "backend probably needs to be fixed");
520 q->connect(copyDevice, SIGNAL(readyRead()), SLOT(_q_copyReadyRead()));
521 q->connect(copyDevice, SIGNAL(readChannelFinished()), SLOT(_q_copyReadChannelFinished()));
529 Q_Q(QNetworkReplyImpl);
534 QVariant bufferAllocationPolicy = request.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
535 if (bufferAllocationPolicy.isValid() && bufferAllocationPolicy.toLongLong() >= size) {
536 downloadBufferCurrentSize = 0;
537 downloadBufferMaximumSize = size;
539 downloadBufferPointer = QSharedPointer<
char>(downloadBuffer, [](
auto p) {
delete[] p; });
541 q->setAttribute(QNetworkRequest::DownloadBufferAttribute, QVariant::fromValue<QSharedPointer<
char> > (downloadBufferPointer));
550 Q_Q(QNetworkReplyImpl);
552 downloadBufferPointer = sp;
553 downloadBuffer = downloadBufferPointer.data();
554 downloadBufferCurrentSize = 0;
555 downloadBufferMaximumSize = size;
556 q->setAttribute(QNetworkRequest::DownloadBufferAttribute, QVariant::fromValue<QSharedPointer<
char> > (downloadBufferPointer));
562 Q_Q(QNetworkReplyImpl);
566 if (cacheEnabled && !cacheSaveDevice)
569 if (cacheSaveDevice && bytesReceived == bytesTotal) {
571 cacheSaveDevice->write(downloadBuffer, bytesTotal);
574 bytesDownloaded = bytesReceived;
576 downloadBufferCurrentSize = bytesReceived;
581 if (bytesDownloaded > 0)
583 if (downloadProgressSignalChoke.isValid() &&
584 downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
585 downloadProgressSignalChoke.start();
586 emit q->downloadProgress(bytesDownloaded, bytesTotal);
592 Q_Q(QNetworkReplyImpl);
598 const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
599 headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
600 const auto totalSize = totalSizeOpt.value_or(-1);
605 q->setFinished(
true);
607 pendingNotifications.clear();
610 if (totalSize == -1) {
611 emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
613 emit q->downloadProgress(bytesDownloaded, totalSize);
616 if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer))
617 emit q->uploadProgress(0, 0);
621 if (totalSize == -1 || bytesDownloaded == totalSize)
628 emit q->readChannelFinished();
635 Q_Q(QNetworkReplyImpl);
637 if (errorCode != QNetworkReply::NoError) {
638 qWarning(
"QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.");
643 q->setErrorString(errorMessage);
648 emit q->errorOccurred(code);
653 Q_Q(QNetworkReplyImpl);
656 if (!manager.isNull()) {
657 const auto cookiesOpt = QNetworkHeadersPrivate::toSetCookieList(
658 headers().values(QHttpHeaders::WellKnownHeader::SetCookie));
659 const auto cookies = cookiesOpt.value_or(QList<QNetworkCookie>());
661 && request.attribute(QNetworkRequest::CookieSaveControlAttribute,
662 QNetworkRequest::Automatic).toInt() == QNetworkRequest::Automatic) {
663 QNetworkCookieJar *jar = manager->cookieJar();
665 jar->setCookiesFromUrl(cookies, url);
670 emit q->metaDataChanged();
675 attributes.insert(QNetworkRequest::RedirectionTargetAttribute, target);
681 Q_Q(QNetworkReplyImpl);
689 Q_Q(QNetworkReplyImpl);
690 emit q->sslErrors(errors);
698 Q_Q(QNetworkReplyImpl);
702 if (backend->ioFeatures() & QNetworkAccessBackend::IOFeature::ZeroCopy) {
706 bool anyBytesRead =
false;
707 while (backend->bytesAvailable()
708 && (!readBufferMaxSize || buffer.size() < readBufferMaxSize)) {
709 qint64 toRead = qMin(nextDownstreamBlockSize(), backend->bytesAvailable());
712 char *data = buffer.reserve(toRead);
713 qint64 bytesRead =
backend->read(data, toRead);
714 Q_ASSERT(bytesRead <= toRead);
715 buffer.chop(toRead - bytesRead);
716 anyBytesRead |= bytesRead > 0;
724 : QNetworkReply(*
new QNetworkReplyImplPrivate, parent)
730 Q_D(QNetworkReplyImpl);
735 if (d->isCachingEnabled())
736 d->networkCache()->remove(url());
741 Q_D(QNetworkReplyImpl);
742 if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted)
747 disconnect(d->outgoingData,
nullptr,
this,
nullptr);
749 disconnect(d->copyDevice,
nullptr,
this,
nullptr);
751 QNetworkReply::close();
754 d->error(OperationCanceledError, tr(
"Operation canceled"));
756 d->state = QNetworkReplyPrivate::Aborted;
760 d->backend->deleteLater();
761 d->backend =
nullptr;
767 Q_D(QNetworkReplyImpl);
768 if (d->state == QNetworkReplyPrivate::Aborted ||
769 d->state == QNetworkReplyPrivate::Finished)
776 disconnect(d->copyDevice,
nullptr,
this,
nullptr);
778 QNetworkReply::close();
781 d->error(OperationCanceledError, tr(
"Operation canceled"));
786
787
788
791
792
793
794
798 Q_D(
const QNetworkReplyImpl);
799 if (d->downloadBuffer) {
800 qint64 maxAvail = d->downloadBufferCurrentSize - d->downloadBufferReadPosition;
801 return QNetworkReply::bytesAvailable() + maxAvail;
803 return QNetworkReply::bytesAvailable() + (d->backend ? d->backend->bytesAvailable() : 0);
808 Q_D(QNetworkReplyImpl);
809 qint64 oldMaxSize = d->readBufferMaxSize;
810 QNetworkReply::setReadBufferSize(size);
811 if (size > oldMaxSize && size > d->buffer.size())
812 d->readFromBackend();
816void QNetworkReplyImpl::sslConfigurationImplementation(QSslConfiguration &configuration)
const
818 Q_D(
const QNetworkReplyImpl);
820 configuration = d->backend->sslConfiguration();
825 Q_D(QNetworkReplyImpl);
826 if (d->backend && !config.isNull())
827 d->backend->setSslConfiguration(config);
832 Q_D(QNetworkReplyImpl);
834 d->backend->ignoreSslErrors();
839 Q_D(QNetworkReplyImpl);
841 d->backend->ignoreSslErrors(errors);
846
847
850 Q_D(QNetworkReplyImpl);
853 && d->backend->ioFeatures().testFlag(QNetworkAccessBackend::IOFeature::ZeroCopy)) {
854 qint64 bytesRead = 0;
855 while (d->backend->bytesAvailable()) {
856 QByteArrayView view = d->backend->readPointer();
858 qint64 bytesToCopy = qMin(qint64(view.size()), maxlen - bytesRead);
859 memcpy(data + bytesRead, view.data(), bytesToCopy);
862 if (d->cacheEnabled && !d->cacheSaveDevice)
863 d->initCacheSaveDevice();
864 if (d->cacheEnabled && d->cacheSaveDevice)
865 d->cacheSaveDevice->write(view.data(), view.size());
867 bytesRead += bytesToCopy;
868 d->backend->advanceReadPointer(bytesToCopy);
874 const auto totalSizeOpt = QNetworkHeadersPrivate::toInt(
875 headers().value(QHttpHeaders::WellKnownHeader::ContentLength));
876 emit downloadProgress(bytesRead, totalSizeOpt.value_or(-1));
878 }
else if (d->backend && d->backend->bytesAvailable()) {
879 return d->backend->read(data, maxlen);
883 if (d->downloadBuffer) {
884 qint64 maxAvail = qMin<qint64>(d->downloadBufferCurrentSize - d->downloadBufferReadPosition, maxlen);
886 return d->state == QNetworkReplyPrivate::Finished ? -1 : 0;
888 memcpy(data, d->downloadBuffer + d->downloadBufferReadPosition, maxAvail);
889 d->downloadBufferReadPosition += maxAvail;
895 if (d->state == QNetworkReplyPrivate::Finished)
898 d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite);
903
904
907 if (e->type() == QEvent::NetworkReplyUpdated) {
908 d_func()->handleNotifications();
912 return QObject::event(e);
917#include "moc_qnetworkreplyimpl_p.cpp"
void handleNotifications()
void resumeNotificationHandling()
void _q_bufferOutgoingDataFinished()
@ NotifyDownstreamReadyWrite
qint64 nextDownstreamBlockSize() const
void setDownloadBuffer(QSharedPointer< char > sp, qint64 size)
void appendDownstreamDataDownloadBuffer(qint64, qint64)
QNetworkAccessBackend * backend
void _q_bufferOutgoingData()
bool notificationHandlingPaused
void emitUploadProgress(qint64 bytesSent, qint64 bytesTotal)
void backendNotify(InternalNotifications notification)
void appendDownstreamDataSignalEmissions()
void initCacheSaveDevice()
QAbstractNetworkCache * networkCache() const
void appendDownstreamData(QByteDataBuffer &data)
char * getDownloadBuffer(qint64 size)
void _q_copyReadChannelFinished()
bool isCachingEnabled() const
void sslErrors(const QList< QSslError > &errors)
void pauseNotificationHandling()
void redirectionRequested(const QUrl &target)
void setCachingEnabled(bool enable)
virtual qint64 bytesAvailable() const override
Returns the number of bytes available for reading with QIODevice::read().
virtual qint64 readData(char *data, qint64 maxlen) override
virtual void ignoreSslErrorsImplementation(const QList< QSslError > &errors) override
virtual void setReadBufferSize(qint64 size) override
Sets the size of the read buffer to be size bytes.
virtual void close() override
Closes this device for reading.
virtual void abort() override
Aborts the operation immediately and closes any network connections still open.
virtual bool event(QEvent *) override
void void void void _q_bufferOutgoingDataFinished()) protected void setSslConfigurationImplementation(const QSslConfiguration &configuration) override
virtual void ignoreSslErrors() override
If this function is called, SSL errors related to network connection will be ignored,...