506 QNetworkRequest::CacheLoadControl CacheLoadControlAttribute =
507 (QNetworkRequest::CacheLoadControl)request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt();
509 auto requestHeaders = request.headers();
510 if (CacheLoadControlAttribute == QNetworkRequest::AlwaysNetwork) {
513 if (!requestHeaders.contains(QHttpHeaders::WellKnownHeader::CacheControl)) {
514 const auto noCache =
"no-cache"_ba;
515 httpRequest.setHeaderField(cacheControlName(), noCache);
516 httpRequest.setHeaderField(
"Pragma"_ba, noCache);
523 if (requestHeaders.contains(QHttpHeaders::WellKnownHeader::Range))
526 QAbstractNetworkCache *nc = managerPrivate->networkCache;
531 if (!metaData.isValid())
534 if (!metaData.saveToDisk())
539 const auto sizeOpt = QNetworkHeadersPrivate::toInt(
540 cacheHeaders.value(QHttpHeaders::WellKnownHeader::ContentLength));
542 std::unique_ptr<QIODevice> data(nc->data(httpRequest.url()));
543 if (!data || data->size() < sizeOpt.value())
547 auto value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::ETag);
549 httpRequest.setHeaderField(
"If-None-Match"_ba, value.toByteArray());
551 QDateTime lastModified = metaData.lastModified();
552 if (lastModified.isValid())
553 httpRequest.setHeaderField(
"If-Modified-Since"_ba, QNetworkHeadersPrivate::toHttpDate(lastModified));
555 value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::CacheControl);
556 if (!value.empty()) {
557 QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(value);
558 if (cacheControl.contains(
"no-cache"_ba))
562 QDateTime currentDateTime = QDateTime::currentDateTimeUtc();
563 QDateTime expirationDate = metaData.expirationDate();
565 bool response_is_fresh;
566 if (!expirationDate.isValid()) {
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582 const auto ageOpt = QNetworkHeadersPrivate::toInt(
583 cacheHeaders.value(QHttpHeaders::WellKnownHeader::Age));
584 const qint64 age_value = ageOpt.value_or(0);
586 QDateTime dateHeader;
587 qint64 date_value = 0;
588 value = cacheHeaders.value(QHttpHeaders::WellKnownHeader::Date);
589 if (!value.empty()) {
590 dateHeader = QNetworkHeadersPrivate::fromHttpDate(value);
591 date_value = dateHeader.toSecsSinceEpoch();
594 qint64 now = currentDateTime.toSecsSinceEpoch();
595 qint64 request_time = now;
596 qint64 response_time = now;
599 qint64 apparent_age = qMax<qint64>(0, response_time - date_value);
600 qint64 corrected_received_age = qMax(apparent_age, age_value);
601 qint64 response_delay = response_time - request_time;
602 qint64 corrected_initial_age = corrected_received_age + response_delay;
603 qint64 resident_time = now - response_time;
604 qint64 current_age = corrected_initial_age + resident_time;
606 qint64 freshness_lifetime = 0;
609 if (lastModified.isValid() && dateHeader.isValid()) {
610 qint64 diff = lastModified.secsTo(dateHeader);
611 freshness_lifetime = diff / 10;
612 const auto warningHeader =
"Warning"_ba;
613 if (httpRequest.headerField(warningHeader).isEmpty()) {
614 QDateTime dt = currentDateTime.addSecs(current_age);
615 if (currentDateTime.daysTo(dt) > 1)
616 httpRequest.setHeaderField(warningHeader,
"113"_ba);
622 response_is_fresh = (freshness_lifetime > current_age);
625 response_is_fresh = currentDateTime.secsTo(expirationDate) >= 0;
628 if (!response_is_fresh)
631#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG)
632 qDebug() <<
"response_is_fresh" << CacheLoadControlAttribute;
634 return sendCacheContents(metaData);
695 Q_Q(QNetworkReplyHttpImpl);
697 QThread *thread =
nullptr;
700 thread =
new QThread();
701 thread->setObjectName(QStringLiteral(
"Qt HTTP synchronous thread"));
702 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
707 thread = managerPrivate->createThread();
710 QUrl url = newHttpRequest.url();
711 httpRequest.setUrl(url);
712 httpRequest.setRedirectCount(newHttpRequest.maximumRedirectsAllowed());
714 QString scheme = url.scheme();
715 bool ssl = (scheme ==
"https"_L1 || scheme ==
"preconnect-https"_L1);
716 q->setAttribute(QNetworkRequest::ConnectionEncryptedAttribute, ssl);
717 httpRequest.setSsl(ssl);
719 bool preConnect = (scheme ==
"preconnect-http"_L1 || scheme ==
"preconnect-https"_L1);
720 httpRequest.setPreConnect(preConnect);
722#ifndef QT_NO_NETWORKPROXY
723 QNetworkProxy transparentProxy, cacheProxy;
726 const auto proxies = managerPrivate->queryProxy(QNetworkProxyQuery(newHttpRequest.url()));
727 for (
const QNetworkProxy &p : proxies) {
732 && (p.capabilities() & QNetworkProxy::CachingCapability)
733 && (p.type() == QNetworkProxy::HttpProxy ||
734 p.type() == QNetworkProxy::HttpCachingProxy)) {
736 transparentProxy = QNetworkProxy::NoProxy;
739 if (p.isTransparentProxy()) {
740 transparentProxy = p;
741 cacheProxy = QNetworkProxy::NoProxy;
747 if (transparentProxy.type() == QNetworkProxy::DefaultProxy &&
748 cacheProxy.type() == QNetworkProxy::DefaultProxy) {
750 QMetaObject::invokeMethod(q,
"_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection,
751 Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError),
752 Q_ARG(QString, QNetworkReplyHttpImpl::tr(
"No suitable proxy found")));
753 QMetaObject::invokeMethod(q,
"_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection);
758 auto redirectPolicy = QNetworkRequest::NoLessSafeRedirectPolicy;
759 const QVariant value = newHttpRequest.attribute(QNetworkRequest::RedirectPolicyAttribute);
761 redirectPolicy = qvariant_cast<QNetworkRequest::RedirectPolicy>(value);
763 httpRequest.setRedirectPolicy(redirectPolicy);
767 maybeDropUploadDevice(newHttpRequest);
769 httpRequest.setPriority(convert(newHttpRequest.priority()));
773 case QNetworkAccessManager::GetOperation:
774 httpRequest.setOperation(QHttpNetworkRequest::Get);
778 createUploadByteDevice();
779 }
else if (loadFromCacheIfAllowed(httpRequest)) {
784 case QNetworkAccessManager::HeadOperation:
785 httpRequest.setOperation(QHttpNetworkRequest::Head);
786 if (loadFromCacheIfAllowed(httpRequest))
790 case QNetworkAccessManager::PostOperation:
792 httpRequest.setOperation(QHttpNetworkRequest::Post);
793 createUploadByteDevice();
796 case QNetworkAccessManager::PutOperation:
798 httpRequest.setOperation(QHttpNetworkRequest::Put);
799 createUploadByteDevice();
802 case QNetworkAccessManager::DeleteOperation:
804 httpRequest.setOperation(QHttpNetworkRequest::Delete);
807 case QNetworkAccessManager::CustomOperation:
809 httpRequest.setOperation(QHttpNetworkRequest::Custom);
810 createUploadByteDevice();
811 httpRequest.setCustomVerb(newHttpRequest.attribute(
812 QNetworkRequest::CustomVerbAttribute).toByteArray());
819 QHttpHeaders newRequestHeaders = newHttpRequest.headers();
820 if (resumeOffset != 0) {
821 if (newRequestHeaders.contains(QHttpHeaders::WellKnownHeader::Range)) {
825 const auto rangeHeader = newRequestHeaders.value(QHttpHeaders::WellKnownHeader::Range);
826 const auto requestRange = QByteArrayView(rangeHeader).mid(bytesEqualPrefix().size());
828 newRequestHeaders.removeAll(QHttpHeaders::WellKnownHeader::Range);
830 int index = requestRange.indexOf(
'-');
832 quint64 requestStartOffset = requestRange.left(index).toULongLong();
833 quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong();
836 QByteArray newRange = bytesEqualPrefix() + QByteArray::number(resumeOffset + requestStartOffset) +
837 '-' + (requestEndOffset ? QByteArray::number(requestEndOffset) : QByteArray());
839 httpRequest.setHeaderField(rangeName(), newRange);
841 httpRequest.setHeaderField(rangeName(), bytesEqualPrefix() + QByteArray::number(resumeOffset) +
'-');
845 for (
int i = 0; i < newRequestHeaders.size(); i++) {
846 const auto name = newRequestHeaders.nameAt(i);
847 const auto value = newRequestHeaders.valueAt(i);
848 httpRequest.setHeaderField(QByteArray(name.data(), name.size()), value.toByteArray());
851 if (newHttpRequest.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool())
852 httpRequest.setPipeliningAllowed(
true);
854 if (
auto allowed = request.attribute(QNetworkRequest::Http2AllowedAttribute);
855 allowed.isValid() && allowed.canConvert<
bool>()) {
856 httpRequest.setHTTP2Allowed(allowed.value<
bool>());
858 auto h2cAttribute = request.attribute(QNetworkRequest::Http2CleartextAllowedAttribute);
860 if (h2cAttribute.toBool()
861 || (!h2cAttribute.isValid() && qEnvironmentVariableIsSet(
"QT_NETWORK_H2C_ALLOWED"))) {
862 httpRequest.setH2cAllowed(
true);
865 if (request.attribute(QNetworkRequest::Http2DirectAttribute).toBool()) {
867 httpRequest.setHTTP2Direct(
true);
868 httpRequest.setHTTP2Allowed(
false);
871 if (
static_cast<QNetworkRequest::LoadControl>
872 (newHttpRequest.attribute(QNetworkRequest::AuthenticationReuseAttribute,
873 QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual)
874 httpRequest.setWithCredentials(
false);
876 if (request.attribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute).toBool())
877 emitAllUploadProgressSignals =
true;
879 httpRequest.setPeerVerifyName(newHttpRequest.peerVerifyName());
881 if (scheme.startsWith((
"unix"_L1))) {
882 if (QVariant path = newHttpRequest.attribute(QNetworkRequest::FullLocalServerNameAttribute);
883 path.isValid() && path.canConvert<QString>()) {
884 httpRequest.setFullLocalServerName(path.toString());
891 delegate->http2Parameters = request.http2Configuration();
892 delegate->http1Parameters = request.http1Configuration();
894 if (request.attribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute).isValid())
895 delegate->connectionCacheExpiryTimeoutSeconds = request.attribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute).toInt();
899 QMetaObject::Connection threadFinishedConnection =
900 QObject::connect(thread, SIGNAL(finished()), delegate, SLOT(deleteLater()));
906 QObject::connect(delegate, &QObject::destroyed, delegate, [threadFinishedConnection]() {
907 if (
bool(threadFinishedConnection))
908 QObject::disconnect(threadFinishedConnection);
912 delegate->httpRequest = httpRequest;
913#ifndef QT_NO_NETWORKPROXY
914 delegate->cacheProxy = cacheProxy;
915 delegate->transparentProxy = transparentProxy;
920 delegate->incomingSslConfiguration.reset(
new QSslConfiguration(newHttpRequest.sslConfiguration()));
928 delegate->authenticationManager = managerPrivate->authenticationManager;
932 QVariant downloadBufferMaximumSizeAttribute = newHttpRequest.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
933 if (downloadBufferMaximumSizeAttribute.isValid()) {
934 delegate->downloadBufferMaximumSize = downloadBufferMaximumSizeAttribute.toLongLong();
939 delegate->downloadBufferMaximumSize = 128*1024;
944 delegate->pendingDownloadData = pendingDownloadDataEmissions;
945 delegate->pendingDownloadProgress = pendingDownloadProgressEmissions;
948 QObject::connect(delegate, SIGNAL(downloadData(QByteArray)),
949 q, SLOT(replyDownloadData(QByteArray)),
950 Qt::QueuedConnection);
951 QObject::connect(delegate, SIGNAL(downloadFinished()),
952 q, SLOT(replyFinished()),
953 Qt::QueuedConnection);
954 QObject::connect(delegate, &QHttpThreadDelegate::socketStartedConnecting,
955 q, &QNetworkReply::socketStartedConnecting, Qt::QueuedConnection);
956 QObject::connect(delegate, &QHttpThreadDelegate::requestSent,
957 q, &QNetworkReply::requestSent, Qt::QueuedConnection);
958 connect(delegate, &QHttpThreadDelegate::downloadMetaData,
this,
959 &QNetworkReplyHttpImplPrivate::replyDownloadMetaData, Qt::QueuedConnection);
960 QObject::connect(delegate, SIGNAL(downloadProgress(qint64,qint64)),
961 q, SLOT(replyDownloadProgressSlot(qint64,qint64)),
962 Qt::QueuedConnection);
963 QObject::connect(delegate, SIGNAL(error(QNetworkReply::NetworkError,QString)),
964 q, SLOT(httpError(QNetworkReply::NetworkError,QString)),
965 Qt::QueuedConnection);
966 QObject::connect(delegate, SIGNAL(redirected(QUrl,
int,
int)),
967 q, SLOT(onRedirected(QUrl,
int,
int)),
968 Qt::QueuedConnection);
971 QObject::connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)),
972 q, SLOT(replySslConfigurationChanged(QSslConfiguration)),
973 Qt::QueuedConnection);
976 QObject::connect(delegate, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
977 q, SLOT(httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
978 Qt::BlockingQueuedConnection);
979#ifndef QT_NO_NETWORKPROXY
980 QObject::connect(delegate, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
981 q, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
982 Qt::BlockingQueuedConnection);
985 QObject::connect(delegate, SIGNAL(encrypted()), q, SLOT(replyEncrypted()),
986 Qt::BlockingQueuedConnection);
987 QObject::connect(delegate, SIGNAL(sslErrors(QList<QSslError>,
bool*,QList<QSslError>*)),
988 q, SLOT(replySslErrors(QList<QSslError>,
bool*,QList<QSslError>*)),
989 Qt::BlockingQueuedConnection);
990 QObject::connect(delegate, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)),
991 q, SLOT(replyPreSharedKeyAuthenticationRequiredSlot(QSslPreSharedKeyAuthenticator*)),
992 Qt::BlockingQueuedConnection);
995 QObject::connect(q, SIGNAL(startHttpRequest()), delegate, SLOT(startRequest()));
996 QObject::connect(q, SIGNAL(abortHttpRequest()), delegate, SLOT(abortRequest()));
999 QObject::connect(q, SIGNAL(readBufferSizeChanged(qint64)), delegate, SLOT(readBufferSizeChanged(qint64)));
1000 QObject::connect(q, SIGNAL(readBufferFreed(qint64)), delegate, SLOT(readBufferFreed(qint64)));
1002 if (uploadByteDevice) {
1004 new QNonContiguousByteDeviceThreadForwardImpl(uploadByteDevice->atEnd(), uploadByteDevice->size());
1005 forwardUploadDevice->setParent(delegate);
1006 delegate->httpRequest.setUploadByteDevice(forwardUploadDevice);
1009 QObject::connect(uploadByteDevice.get(), SIGNAL(readyRead()),
1010 q, SLOT(uploadByteDeviceReadyReadSlot()),
1011 Qt::QueuedConnection);
1014 QObject::connect(q, SIGNAL(haveUploadData(qint64,QByteArray,
bool,qint64)),
1015 forwardUploadDevice, SLOT(haveDataSlot(qint64,QByteArray,
bool,qint64)), Qt::QueuedConnection);
1016 QObject::connect(uploadByteDevice.get(), SIGNAL(readyRead()),
1017 forwardUploadDevice, SIGNAL(readyRead()),
1018 Qt::QueuedConnection);
1021 QObject::connect(forwardUploadDevice, SIGNAL(wantData(qint64)),
1022 q, SLOT(wantUploadDataSlot(qint64)));
1023 QObject::connect(forwardUploadDevice,SIGNAL(processedData(qint64,qint64)),
1024 q, SLOT(sentUploadDataSlot(qint64,qint64)));
1025 QObject::connect(forwardUploadDevice, SIGNAL(resetData(
bool*)),
1026 q, SLOT(resetUploadDataSlot(
bool*)),
1027 Qt::BlockingQueuedConnection);
1030 QObject::connect(q, SIGNAL(startHttpRequestSynchronously()), delegate, SLOT(startRequestSynchronously()), Qt::BlockingQueuedConnection);
1032 if (uploadByteDevice) {
1039 delegate->httpRequest.setUploadByteDevice(uploadByteDevice.get());
1045 delegate->moveToThread(thread);
1049 downloadProgressSignalChoke.start();
1050 uploadProgressSignalChoke.invalidate();
1054 emit q->startHttpRequestSynchronously();
1056 replyDownloadMetaData
1057 (delegate->incomingHeaders,
1058 delegate->incomingStatusCode,
1059 delegate->incomingReasonPhrase,
1060 delegate->isPipeliningUsed,
1061 QSharedPointer<
char>(),
1062 delegate->incomingContentLength,
1063 delegate->removedContentLength,
1064 delegate->isHttp2Used,
1065 delegate->isCompressed);
1066 replyDownloadData(delegate->synchronousDownloadData);
1068 if (delegate->incomingErrorCode != QNetworkReply::NoError)
1069 httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail);
1072 thread->wait(QDeadlineTimer(5000));
1073 if (thread->isFinished())
1076 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
1080 emit q->startHttpRequest();