512 QNetworkRequest::CacheLoadControl CacheLoadControlAttribute =
513 (QNetworkRequest::CacheLoadControl)request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt();
515 auto requestHeaders = request.headers();
516 if (CacheLoadControlAttribute == QNetworkRequest::AlwaysNetwork) {
519 if (!requestHeaders.contains(QHttpHeaders::WellKnownHeader::CacheControl)) {
520 const auto noCache =
"no-cache"_ba;
521 httpRequest.setHeaderField(cacheControlName(), noCache);
522 httpRequest.setHeaderField(
"Pragma"_ba, noCache);
529 if (requestHeaders.contains(QHttpHeaders::WellKnownHeader::Range))
532 QAbstractNetworkCache *nc = managerPrivate->networkCache;
537 if (!metaData.isValid())
540 if (!metaData.saveToDisk())
545 const auto sizeOpt = QNetworkHeadersPrivate::toInt(
546 cacheHeaders.value(QHttpHeaders::WellKnownHeader::ContentLength));
548 std::unique_ptr<QIODevice> data(nc->data(httpRequest.url()));
549 if (!data || data->size() < sizeOpt.value())
553 auto value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::ETag);
555 httpRequest.setHeaderField(
"If-None-Match"_ba, value.toByteArray());
557 QDateTime lastModified = metaData.lastModified();
558 if (lastModified.isValid())
559 httpRequest.setHeaderField(
"If-Modified-Since"_ba, QNetworkHeadersPrivate::toHttpDate(lastModified));
561 value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::CacheControl);
562 if (!value.empty()) {
563 QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(value);
564 if (cacheControl.contains(
"no-cache"_ba))
568 QDateTime currentDateTime = QDateTime::currentDateTimeUtc();
569 QDateTime expirationDate = metaData.expirationDate();
571 bool response_is_fresh;
572 if (!expirationDate.isValid()) {
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588 const auto ageOpt = QNetworkHeadersPrivate::toInt(
589 cacheHeaders.value(QHttpHeaders::WellKnownHeader::Age));
590 const qint64 age_value = ageOpt.value_or(0);
592 QDateTime dateHeader;
593 qint64 date_value = 0;
594 value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::Date);
595 if (!value.empty()) {
596 dateHeader = QNetworkHeadersPrivate::fromHttpDate(value);
597 date_value = dateHeader.toSecsSinceEpoch();
600 qint64 now = currentDateTime.toSecsSinceEpoch();
601 qint64 request_time = now;
602 qint64 response_time = now;
605 qint64 apparent_age = qMax<qint64>(0, response_time - date_value);
606 qint64 corrected_received_age = qMax(apparent_age, age_value);
607 qint64 response_delay = response_time - request_time;
608 qint64 corrected_initial_age = corrected_received_age + response_delay;
609 qint64 resident_time = now - response_time;
610 qint64 current_age = corrected_initial_age + resident_time;
612 qint64 freshness_lifetime = 0;
615 if (lastModified.isValid() && dateHeader.isValid()) {
616 qint64 diff = lastModified.secsTo(dateHeader);
617 freshness_lifetime = diff / 10;
618 const auto warningHeader =
"Warning"_ba;
619 if (httpRequest.headerField(warningHeader).isEmpty()) {
620 QDateTime dt = currentDateTime.addSecs(current_age);
621 if (currentDateTime.daysTo(dt) > 1)
622 httpRequest.setHeaderField(warningHeader,
"113"_ba);
628 response_is_fresh = (freshness_lifetime > current_age);
631 response_is_fresh = currentDateTime.secsTo(expirationDate) >= 0;
634 if (!response_is_fresh)
637#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG)
638 qDebug() <<
"response_is_fresh" << CacheLoadControlAttribute;
640 return sendCacheContents(metaData);
701 Q_Q(QNetworkReplyHttpImpl);
703 QThread *thread =
nullptr;
706 thread =
new QThread();
707 thread->setObjectName(QStringLiteral(
"Qt HTTP synchronous thread"));
708 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
713 thread = managerPrivate->createThread();
716 QUrl url = newHttpRequest.url();
717 httpRequest.setUrl(url);
718 httpRequest.setRedirectCount(newHttpRequest.maximumRedirectsAllowed());
720 QString scheme = url.scheme();
721 bool ssl = (scheme ==
"https"_L1 || scheme ==
"preconnect-https"_L1);
722 q->setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl);
723 httpRequest.setSsl(ssl);
725 bool preConnect = (scheme ==
"preconnect-http"_L1 || scheme ==
"preconnect-https"_L1);
726 httpRequest.setPreConnect(preConnect);
728#ifndef QT_NO_NETWORKPROXY
729 QNetworkProxy transparentProxy, cacheProxy;
732 const auto proxies = managerPrivate->queryProxy(QNetworkProxyQuery(newHttpRequest.url()));
733 for (
const QNetworkProxy &p : proxies) {
738 && (p.capabilities() & QNetworkProxy::CachingCapability)
739 && (p.type() == QNetworkProxy::HttpProxy ||
740 p.type() == QNetworkProxy::HttpCachingProxy)) {
742 transparentProxy = QNetworkProxy::NoProxy;
745 if (p.isTransparentProxy()) {
746 transparentProxy = p;
747 cacheProxy = QNetworkProxy::NoProxy;
753 if (transparentProxy.type() == QNetworkProxy::DefaultProxy &&
754 cacheProxy.type() == QNetworkProxy::DefaultProxy) {
756 QMetaObject::invokeMethod(q,
"_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection,
757 Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError),
758 Q_ARG(QString, QNetworkReplyHttpImpl::tr(
"No suitable proxy found")));
759 QMetaObject::invokeMethod(q,
"_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection);
764 auto redirectPolicy = QNetworkRequest::NoLessSafeRedirectPolicy;
765 const QVariant value = newHttpRequest.attribute(QNetworkRequest::RedirectPolicyAttribute);
767 redirectPolicy = qvariant_cast<QNetworkRequest::RedirectPolicy>(value);
769 httpRequest.setRedirectPolicy(redirectPolicy);
773 maybeDropUploadDevice(newHttpRequest);
775 httpRequest.setPriority(convert(newHttpRequest.priority()));
779 case QNetworkAccessManager::GetOperation:
780 httpRequest.setOperation(QHttpNetworkRequest::Get);
784 createUploadByteDevice();
785 }
else if (loadFromCacheIfAllowed(httpRequest)) {
790 case QNetworkAccessManager::HeadOperation:
791 httpRequest.setOperation(QHttpNetworkRequest::Head);
792 if (loadFromCacheIfAllowed(httpRequest))
796 case QNetworkAccessManager::PostOperation:
798 httpRequest.setOperation(QHttpNetworkRequest::Post);
799 createUploadByteDevice();
802 case QNetworkAccessManager::PutOperation:
804 httpRequest.setOperation(QHttpNetworkRequest::Put);
805 createUploadByteDevice();
808 case QNetworkAccessManager::DeleteOperation:
810 httpRequest.setOperation(QHttpNetworkRequest::Delete);
813 case QNetworkAccessManager::CustomOperation:
815 httpRequest.setOperation(QHttpNetworkRequest::Custom);
816 createUploadByteDevice();
817 httpRequest.setCustomVerb(newHttpRequest.attribute(
818 QNetworkRequest::CustomVerbAttribute).toByteArray());
825 QHttpHeaders newRequestHeaders = newHttpRequest.headers();
826 if (resumeOffset != 0) {
827 if (newRequestHeaders.contains(QHttpHeaders::WellKnownHeader::Range)) {
831 const auto rangeHeader = newRequestHeaders.value(QHttpHeaders::WellKnownHeader::Range);
832 const auto requestRange = QByteArrayView(rangeHeader).mid(bytesEqualPrefix().size());
834 newRequestHeaders.removeAll(QHttpHeaders::WellKnownHeader::Range);
836 int index = requestRange.indexOf(
'-');
838 quint64 requestStartOffset = requestRange.left(index).toULongLong();
839 quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong();
842 QByteArray newRange = bytesEqualPrefix() + QByteArray::number(resumeOffset + requestStartOffset) +
843 '-' + (requestEndOffset ? QByteArray::number(requestEndOffset) : QByteArray());
845 httpRequest.setHeaderField(rangeName(), newRange);
847 httpRequest.setHeaderField(rangeName(), bytesEqualPrefix() + QByteArray::number(resumeOffset) +
'-');
851 for (
int i = 0; i < newRequestHeaders.size(); i++) {
852 const auto name = newRequestHeaders.nameAt(i);
853 const auto value = newRequestHeaders.valueAt(i);
854 httpRequest.setHeaderField(QByteArray(name.data(), name.size()), value.toByteArray());
857 if (newHttpRequest.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool())
858 httpRequest.setPipeliningAllowed(
true);
860 if (
auto allowed = request.attribute(QNetworkRequest::Http2AllowedAttribute);
861 allowed.isValid() && allowed.canConvert<
bool>()) {
862 httpRequest.setHTTP2Allowed(allowed.value<
bool>());
864 auto h2cAttribute = request.attribute(QNetworkRequest::Http2CleartextAllowedAttribute);
866 if (h2cAttribute.toBool()
867 || (!h2cAttribute.isValid() && qEnvironmentVariableIsSet(
"QT_NETWORK_H2C_ALLOWED"))) {
868 httpRequest.setH2cAllowed(
true);
871 if (request.attribute(QNetworkRequest::Http2DirectAttribute).toBool()) {
873 httpRequest.setHTTP2Direct(
true);
874 httpRequest.setHTTP2Allowed(
false);
877 if (
static_cast<QNetworkRequest::LoadControl>
878 (newHttpRequest.attribute(QNetworkRequest::AuthenticationReuseAttribute,
879 QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual)
880 httpRequest.setWithCredentials(
false);
882 if (request.attribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute).toBool())
883 emitAllUploadProgressSignals =
true;
885 httpRequest.setPeerVerifyName(newHttpRequest.peerVerifyName());
887 if (scheme.startsWith((
"unix"_L1))) {
888 if (QVariant path = newHttpRequest.attribute(QNetworkRequest::FullLocalServerNameAttribute);
889 path.isValid() && path.canConvert<QString>()) {
890 httpRequest.setFullLocalServerName(path.toString());
897 delegate->http2Parameters = request.http2Configuration();
898 delegate->http1Parameters = request.http1Configuration();
900 if (request.attribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute).isValid())
901 delegate->connectionCacheExpiryTimeoutSeconds = request.attribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute).toInt();
905 QMetaObject::Connection threadFinishedConnection =
906 QObject::connect(thread, SIGNAL(finished()), delegate, SLOT(deleteLater()));
912 QObject::connect(delegate, &QObject::destroyed, delegate, [threadFinishedConnection]() {
913 if (
bool(threadFinishedConnection))
914 QObject::disconnect(threadFinishedConnection);
918 delegate->httpRequest = httpRequest;
919#ifndef QT_NO_NETWORKPROXY
920 delegate->cacheProxy = cacheProxy;
921 delegate->transparentProxy = transparentProxy;
926 delegate->incomingSslConfiguration.reset(
new QSslConfiguration(newHttpRequest.sslConfiguration()));
934 delegate->authenticationManager = managerPrivate->authenticationManager;
938 QVariant downloadBufferMaximumSizeAttribute = newHttpRequest.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
939 if (downloadBufferMaximumSizeAttribute.isValid()) {
940 delegate->downloadBufferMaximumSize = downloadBufferMaximumSizeAttribute.toLongLong();
945 delegate->downloadBufferMaximumSize = 128*1024;
950 delegate->pendingDownloadData = pendingDownloadDataEmissions;
951 delegate->pendingDownloadProgress = pendingDownloadProgressEmissions;
954 QObject::connect(delegate, SIGNAL(downloadData(QByteArray)),
955 q, SLOT(replyDownloadData(QByteArray)),
956 Qt::QueuedConnection);
957 QObject::connect(delegate, SIGNAL(downloadFinished()),
958 q, SLOT(replyFinished()),
959 Qt::QueuedConnection);
960 QObject::connect(delegate, &QHttpThreadDelegate::socketStartedConnecting,
961 q, &QNetworkReply::socketStartedConnecting, Qt::QueuedConnection);
962 QObject::connect(delegate, &QHttpThreadDelegate::requestSent,
963 q, &QNetworkReply::requestSent, Qt::QueuedConnection);
964 connect(delegate, &QHttpThreadDelegate::downloadMetaData,
this,
965 &QNetworkReplyHttpImplPrivate::replyDownloadMetaData, Qt::QueuedConnection);
966 QObject::connect(delegate, SIGNAL(downloadProgress(qint64,qint64)),
967 q, SLOT(replyDownloadProgressSlot(qint64,qint64)),
968 Qt::QueuedConnection);
969 QObject::connect(delegate, SIGNAL(error(QNetworkReply::NetworkError,QString)),
970 q, SLOT(httpError(QNetworkReply::NetworkError,QString)),
971 Qt::QueuedConnection);
972 QObject::connect(delegate, SIGNAL(redirected(QUrl,
int,
int)),
973 q, SLOT(onRedirected(QUrl,
int,
int)),
974 Qt::QueuedConnection);
977 QObject::connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)),
978 q, SLOT(replySslConfigurationChanged(QSslConfiguration)),
979 Qt::QueuedConnection);
982 QObject::connect(delegate, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
983 q, SLOT(httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
984 Qt::BlockingQueuedConnection);
985#ifndef QT_NO_NETWORKPROXY
986 QObject::connect(delegate, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
987 q, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
988 Qt::BlockingQueuedConnection);
991 QObject::connect(delegate, SIGNAL(encrypted()), q, SLOT(replyEncrypted()),
992 Qt::BlockingQueuedConnection);
993 QObject::connect(delegate, SIGNAL(sslErrors(QList<QSslError>,
bool*,QList<QSslError>*)),
994 q, SLOT(replySslErrors(QList<QSslError>,
bool*,QList<QSslError>*)),
995 Qt::BlockingQueuedConnection);
996 QObject::connect(delegate, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)),
997 q, SLOT(replyPreSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator*)),
998 Qt::BlockingQueuedConnection);
1001 QObject::connect(q, SIGNAL(startHttpRequest()), delegate, SLOT(startRequest()));
1002 QObject::connect(q, SIGNAL(abortHttpRequest()), delegate, SLOT(abortRequest()));
1005 QObject::connect(q, SIGNAL(readBufferSizeChanged(qint64)), delegate, SLOT(readBufferSizeChanged(qint64)));
1006 QObject::connect(q, SIGNAL(readBufferFreed(qint64)), delegate, SLOT(readBufferFreed(qint64)));
1008 if (uploadByteDevice) {
1010 new QNonContiguousByteDeviceThreadForwardImpl(uploadByteDevice->atEnd(), uploadByteDevice->size());
1011 forwardUploadDevice->setParent(delegate);
1012 delegate->httpRequest.setUploadByteDevice(forwardUploadDevice);
1015 QObject::connect(uploadByteDevice.get(), SIGNAL(readyRead()),
1016 q, SLOT(uploadByteDeviceReadyReadSlot()),
1017 Qt::QueuedConnection);
1020 QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,
bool,qint64)),
1021 forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,
bool,qint64)), Qt::QueuedConnection);
1022 QObject::connect(uploadByteDevice.get(), SIGNAL(readyRead()),
1023 forwardUploadDevice, SIGNAL(readyRead()),
1024 Qt::QueuedConnection);
1027 QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
1028 q, SLOT(wantUploadDataSlot(qint64)));
1029 QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64,qint64)),
1030 q, SLOT(sentUploadDataSlot(qint64,qint64)));
1031 QObject::connect(forwardUploadDevice, SIGNAL(resetData(
bool*)),
1032 q, SLOT(resetUploadDataSlot(
bool*)),
1033 Qt::BlockingQueuedConnection);
1036 QObject::connect(q, SIGNAL(startHttpRequestSynchronously()), delegate, SLOT(startRequestSynchronously()), Qt::BlockingQueuedConnection);
1038 if (uploadByteDevice) {
1045 delegate->httpRequest.setUploadByteDevice(uploadByteDevice.get());
1051 delegate->moveToThread(thread);
1055 downloadProgressSignalChoke.start();
1056 uploadProgressSignalChoke.invalidate();
1060 emit q->startHttpRequestSynchronously();
1062 replyDownloadMetaData
1063 (delegate->incomingHeaders,
1064 delegate->incomingStatusCode,
1065 delegate->incomingReasonPhrase,
1066 delegate->isPipeliningUsed,
1067 QSharedPointer<
char>(),
1068 delegate->incomingContentLength,
1069 delegate->removedContentLength,
1070 delegate->isHttp2Used,
1071 delegate->isCompressed);
1072 replyDownloadData(delegate->synchronousDownloadData);
1074 if (delegate->incomingErrorCode != QNetworkReply::NoError)
1075 httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail);
1078 thread->wait(QDeadlineTimer(5000));
1079 if (thread->isFinished())
1082 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
1086 emit q->startHttpRequest();