From 536cab1a93850c80e18f44872ecca7decdeb7eea Mon Sep 17 00:00:00 2001 From: Lorn Potter Date: Mon, 29 Jul 2019 10:07:31 +1000 Subject: wasm: add network object checking This should help when things are moving fast, and downloads and network object are destroyed before the callbacks finishes. Change-Id: I1f65965bd61efc2e641d03eb071f23e684dd5c44 Reviewed-by: Edward Welbourne --- src/network/access/qnetworkreplywasmimpl.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/network/access') diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp index 53784407d8..f28b8415d1 100644 --- a/src/network/access/qnetworkreplywasmimpl.cpp +++ b/src/network/access/qnetworkreplywasmimpl.cpp @@ -63,6 +63,8 @@ static void q_requestErrorCallback(val event) return; val xhr = event["target"]; + if (xhr.isNull() || xhr.isUndefined()) + return; quintptr func = xhr["data-handler"].as(); QNetworkReplyWasmImplPrivate *reply = reinterpret_cast(func); @@ -84,6 +86,8 @@ static void q_progressCallback(val event) return; val xhr = event["target"]; + if (xhr.isNull() || xhr.isUndefined()) + return; QNetworkReplyWasmImplPrivate *reply = reinterpret_cast(xhr["data-handler"].as()); @@ -99,6 +103,8 @@ static void q_loadCallback(val event) return; val xhr = event["target"]; + if (xhr.isNull() || xhr.isUndefined()) + return; QNetworkReplyWasmImplPrivate *reply = reinterpret_cast(xhr["data-handler"].as()); @@ -123,8 +129,13 @@ static void q_loadCallback(val event) } else if (responseType == "arraybuffer" || responseType == "blob") { // handle this data in the FileReader, triggered by the call to readAsArrayBuffer val blob = xhr["response"]; + if (blob.isNull() || blob.isUndefined()) + return; val reader = val::global("FileReader").new_(); + if (reader.isNull() || reader.isUndefined()) + return; + reader.set("onload", val::module_property("qt_QNetworkReplyWasmImplPrivate_readBinary")); reader.set("data-handler", xhr["data-handler"]); @@ -151,6 +162,8 @@ static void q_responseHeadersCallback(val event) return; val xhr = event["target"]; + if (xhr.isNull() || xhr.isUndefined()) + return; if (xhr["readyState"].as() == 2) { // HEADERS_RECEIVED std::string responseHeaders = xhr.call("getAllResponseHeaders"); @@ -170,6 +183,8 @@ static void q_readBinary(val event) return; val fileReader = event["target"]; + if (fileReader.isNull() || fileReader.isUndefined()) + return; QNetworkReplyWasmImplPrivate *reply = reinterpret_cast(fileReader["data-handler"].as()); @@ -180,6 +195,9 @@ static void q_readBinary(val event) // Set up source typed array val result = fileReader["result"]; // ArrayBuffer + if (result.isNull() || result.isUndefined()) + return; + val Uint8Array = val::global("Uint8Array"); val sourceTypedArray = Uint8Array.new_(result); -- cgit v1.2.3 From 02a62094876c51b71f5922d168305ffc970f24c6 Mon Sep 17 00:00:00 2001 From: Rainer Keller Date: Wed, 28 Aug 2019 09:57:51 +0200 Subject: Fix invalid end range appended to HTTP request When the end range of a byte range in a HTTP request is skipped the download manager adds 0 it its place when resuming that download. When there is no end range given the value is skipped. Task-number: QTBUG-77867 Change-Id: I52358c94cf56c88217fcc91abb102ed393ac7242 Reviewed-by: Timur Pocheptsov --- src/network/access/qnetworkreplyhttpimpl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/network/access') diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 2d7649fa61..9d338f9003 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -752,8 +752,9 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq quint64 requestStartOffset = requestRange.left(index).toULongLong(); quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong(); + // In case an end offset is not given it is skipped from the request range requestRange = "bytes=" + QByteArray::number(resumeOffset + requestStartOffset) + - '-' + QByteArray::number(requestEndOffset); + '-' + (requestEndOffset ? QByteArray::number(requestEndOffset) : QByteArray()); httpRequest.setHeaderField("Range", requestRange); } else { -- cgit v1.2.3 From dbfa374a8610948f6e03ea1b3f3bc2905ce05be0 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Mon, 2 Sep 2019 10:43:29 +0200 Subject: QHttpNetworkConnectionChannel - avoid re-connecting on 'disconnected' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _q_error slot has a special case for RemoteHostClosedError, where the current channel's state is 'idle' and no request/reply is in progress. The comment states that: "Not actually an error, it is normal for Keep-Alive connections to close after some time if no request is sent on them. No need to error the other replies below. Just bail out here. The _q_disconnected will handle the possibly pipelined replies." _q_disconnected, indeed, takes care about pipelined replies ... calling 'ensureConnected' even if we have 0 replies in pipeline, which makes zero sense to me and results in QNAM endlessly trying to re-connect to the server. Fixes: QTBUG-77852 Change-Id: I6dcb43b36a6d432bc940246a08f65e1ee903fd24 Reviewed-by: Volker Hilsheimer Reviewed-by: Mårten Nordheim Reviewed-by: Timur Pocheptsov --- src/network/access/qhttpnetworkconnectionchannel.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/network/access') diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 38adca2633..e7af7b648e 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -849,8 +849,11 @@ void QHttpNetworkConnectionChannel::_q_disconnected() QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); } state = QHttpNetworkConnectionChannel::IdleState; - - requeueCurrentlyPipelinedRequests(); + if (alreadyPipelinedRequests.length()) { + // If nothing was in a pipeline, no need in calling + // _q_startNextRequest (which it does): + requeueCurrentlyPipelinedRequests(); + } pendingEncrypt = false; } -- cgit v1.2.3 From 543769666f18f79bd6ebd6119a39834aafc2b0df Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 4 Sep 2019 15:00:31 +0200 Subject: A follow-up to a recent fix in QHttpNetworkConnectionChannel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While working with HTTP/2, we are not re-sending failed requests. In case we receive a GOAWAY frame, we properly handle it by processing some active streams if possible, and aborting streams that will not proceed further with ContentResendError. But it's possible that some server failed to send us GOAWAY (for example, it died) or closed the connection not finishing the streams that were still active and valid (ID <= value from GOAWAY frame). Now that we will not re-connect, there is no reason to be quiet about us not progressing - emit RemoteHostClosedError on any remaining active stream/request we cannot process further. Fixes: QTBUG-77852 Change-Id: I4cd68a1c8c103b1fbe36c20a1cc406ab2e20dd12 Reviewed-by: Mårten Nordheim Reviewed-by: Timur Pocheptsov --- src/network/access/qhttp2protocolhandler.cpp | 25 ++++++++++++++++++++++ src/network/access/qhttp2protocolhandler_p.h | 2 ++ .../access/qhttpnetworkconnectionchannel.cpp | 13 ++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'src/network/access') diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index c1053882af..9bf5547f15 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -58,6 +58,8 @@ #include #endif +#include + #include #include @@ -195,6 +197,29 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan } } +void QHttp2ProtocolHandler::handleConnectionClosure() +{ + // The channel has just received RemoteHostClosedError and since it will + // not try (for HTTP/2) to re-connect, it's time to finish all replies + // with error. + + // Maybe we still have some data to read and can successfully finish + // a stream/request? + _q_receiveReply(); + + // Finish all still active streams. If we previously had GOAWAY frame, + // we probably already closed some (or all) streams with ContentReSend + // error, but for those still active, not having any data to finish, + // we now report RemoteHostClosedError. + const auto errorString = QCoreApplication::translate("QHttp", "Connection closed"); + for (auto it = activeStreams.begin(), eIt = activeStreams.end(); it != eIt; ++it) + finishStreamWithError(it.value(), QNetworkReply::RemoteHostClosedError, errorString); + + // Make sure we'll never try to read anything later: + activeStreams.clear(); + goingAway = true; +} + void QHttp2ProtocolHandler::_q_uploadDataReadyRead() { if (!sender()) // QueuedConnection, firing after sender (byte device) was deleted. diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h index 1943827e23..43fdb136cd 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -92,6 +92,8 @@ public: QHttp2ProtocolHandler &operator = (const QHttp2ProtocolHandler &rhs) = delete; QHttp2ProtocolHandler &operator = (QHttp2ProtocolHandler &&rhs) = delete; + Q_INVOKABLE void handleConnectionClosure(); + private slots: void _q_uploadDataReadyRead(); void _q_replyDestroyed(QObject* reply); diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 716ea6c8b2..6ff2c47eb4 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -977,7 +977,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket if (!reply && state == QHttpNetworkConnectionChannel::IdleState) { // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request // is sent on them. No need to error the other replies below. Just bail out here. - // The _q_disconnected will handle the possibly pipelined replies + // The _q_disconnected will handle the possibly pipelined replies. HTTP/2 is special for now, + // we do not resend, but must report errors if any request is in progress (note, while + // not in its sendRequest(), protocol handler switches the channel to IdleState, thus + // this check is under this condition in 'if'): + if (protocolHandler.data()) { + if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct + || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) { + auto h2Handler = static_cast(protocolHandler.data()); + h2Handler->handleConnectionClosure(); + protocolHandler.reset(); + } + } return; } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) { // Try to reconnect/resend before sending an error. -- cgit v1.2.3 From d1a22bd29856807805fa56608d2953c072df0cf1 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 4 Sep 2019 15:00:31 +0200 Subject: A follow-up to a recent fix in QHttpNetworkConnectionChannel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While working with HTTP/2, we are not re-sending failed requests. In case we receive a GOAWAY frame, we properly handle it by processing some active streams if possible, and aborting streams that will not proceed further with ContentResendError. But it's possible that some server failed to send us GOAWAY (for example, it died) or closed the connection not finishing the streams that were still active and valid (ID <= value from GOAWAY frame). Now that we will not re-connect, there is no reason to be quiet about us not progressing - emit RemoteHostClosedError on any remaining active stream/request we cannot process further. Fixes: QTBUG-77852 Change-Id: I4cd68a1c8c103b1fbe36c20a1cc406ab2e20dd12 Reviewed-by: Mårten Nordheim Reviewed-by: Timur Pocheptsov (cherry picked from commit 543769666f18f79bd6ebd6119a39834aafc2b0df) --- src/network/access/qhttp2protocolhandler.cpp | 25 ++++++++++++++++++++++ src/network/access/qhttp2protocolhandler_p.h | 2 ++ .../access/qhttpnetworkconnectionchannel.cpp | 13 ++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'src/network/access') diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 5d7fc7506e..6609aa0594 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -55,6 +55,8 @@ #include #endif +#include + #include #include @@ -211,6 +213,29 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan } } +void QHttp2ProtocolHandler::handleConnectionClosure() +{ + // The channel has just received RemoteHostClosedError and since it will + // not try (for HTTP/2) to re-connect, it's time to finish all replies + // with error. + + // Maybe we still have some data to read and can successfully finish + // a stream/request? + _q_receiveReply(); + + // Finish all still active streams. If we previously had GOAWAY frame, + // we probably already closed some (or all) streams with ContentReSend + // error, but for those still active, not having any data to finish, + // we now report RemoteHostClosedError. + const auto errorString = QCoreApplication::translate("QHttp", "Connection closed"); + for (auto it = activeStreams.begin(), eIt = activeStreams.end(); it != eIt; ++it) + finishStreamWithError(it.value(), QNetworkReply::RemoteHostClosedError, errorString); + + // Make sure we'll never try to read anything later: + activeStreams.clear(); + goingAway = true; +} + void QHttp2ProtocolHandler::_q_uploadDataReadyRead() { if (!sender()) // QueuedConnection, firing after sender (byte device) was deleted. diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h index 9165808302..d91853f613 100644 --- a/src/network/access/qhttp2protocolhandler_p.h +++ b/src/network/access/qhttp2protocolhandler_p.h @@ -90,6 +90,8 @@ public: QHttp2ProtocolHandler &operator = (const QHttp2ProtocolHandler &rhs) = delete; QHttp2ProtocolHandler &operator = (QHttp2ProtocolHandler &&rhs) = delete; + Q_INVOKABLE void handleConnectionClosure(); + private slots: void _q_uploadDataReadyRead(); void _q_replyDestroyed(QObject* reply); diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index e7af7b648e..1fac24ab49 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -967,7 +967,18 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket if (!reply && state == QHttpNetworkConnectionChannel::IdleState) { // Not actually an error, it is normal for Keep-Alive connections to close after some time if no request // is sent on them. No need to error the other replies below. Just bail out here. - // The _q_disconnected will handle the possibly pipelined replies + // The _q_disconnected will handle the possibly pipelined replies. HTTP/2 is special for now, + // we do not resend, but must report errors if any request is in progress (note, while + // not in its sendRequest(), protocol handler switches the channel to IdleState, thus + // this check is under this condition in 'if'): + if (protocolHandler.data()) { + if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct + || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) { + auto h2Handler = static_cast(protocolHandler.data()); + h2Handler->handleConnectionClosure(); + protocolHandler.reset(); + } + } return; } else if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) { // Try to reconnect/resend before sending an error. -- cgit v1.2.3 From 66a4001fa28de5d3eac03c2662556d2d5511b0a3 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 9 Sep 2019 17:09:45 +0200 Subject: Fix qdoc warnings src/corelib/global/qnamespace.qdoc:3279: (qdoc) warning: Can't link to 'QGuiApplication::setHighDdpiScaleFactorRoundingPolicy()' src/corelib/time/qislamiccivilcalendar.cpp:49: (qdoc) warning: Can't link to 'QJijriCalendar' src/network/ssl/qsslsocket.cpp:1510: (qdoc) warning: Can't link to 'QSslConfiguration::defaultCaCertificates()' src/network/access/qhttp2configuration.cpp:49: (qdoc) warning: '\brief' statement does not end with a full stop. src/gui/text/qtextformat.cpp:532: (qdoc) warning: Undocumented enum item 'TableBorderCollapse' in QTextFormat::Property src/gui/text/qtextdocument.cpp:2066: (qdoc) warning: Undocumented enum item 'UnknownResource' in QTextDocument::ResourceType src/gui/kernel/qguiapplication.cpp:3500: (qdoc) warning: Undocumented parameter 'policy' in QGuiApplication::setHighDpiScaleFactorRoundingPolicy() Change-Id: I3573ef98cf9b58d16525c356270fe009fdffcf45 Reviewed-by: Shawn Rutledge --- src/network/access/qhttp2configuration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/network/access') diff --git a/src/network/access/qhttp2configuration.cpp b/src/network/access/qhttp2configuration.cpp index a32bccfd09..bd4318d4e9 100644 --- a/src/network/access/qhttp2configuration.cpp +++ b/src/network/access/qhttp2configuration.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE /*! \class QHttp2Configuration - \brief The QHttp2Configuration class controls HTTP/2 parameters and settings + \brief The QHttp2Configuration class controls HTTP/2 parameters and settings. \since 5.14 \reentrant -- cgit v1.2.3 From 0fd6595d5e63fe1db429a0f242c7e98c6d2855f7 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 10 Sep 2019 09:39:59 +0200 Subject: Add a missing ConnectionTypeHttp2Direct in several if statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found while preparing SPDY retirement. Change-Id: I30f923fdeb0f6f0b5e808a3e7b7d81ddb9c4ef12 Reviewed-by: Mårten Nordheim Reviewed-by: Edward Welbourne --- src/network/access/qhttpnetworkconnection.cpp | 3 ++- src/network/access/qhttpnetworkconnectionchannel.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/network/access') diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 9b1e63520d..294273d751 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -1232,7 +1232,8 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info) emitReplyError(channels[0].socket, channels[0].reply, QNetworkReply::HostNotFoundError); networkLayerState = QHttpNetworkConnectionPrivate::Unknown; } else if (connectionType == QHttpNetworkConnection::ConnectionTypeSPDY - || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2) { + || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2 + || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { for (const HttpMessagePair &spdyPair : qAsConst(channels[0].spdyRequestsToSend)) { // emit error for all replies QHttpNetworkReply *currentReply = spdyPair.second; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index d91fd8d2e6..8f94cef32b 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -1096,6 +1096,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket || !connection->d_func()->lowPriorityQueue.isEmpty()); if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 + || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct #ifndef QT_NO_SSL || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY #endif -- cgit v1.2.3 From 447ee95d5e050c5db1636c5d3bd0edbf59f26108 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 11 Sep 2019 09:25:51 +0200 Subject: QHttpThreadDelegate - remove unneeded code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found while cleaning up SPDY remains: I've noticed that for H2 case I never check if incomingSslConfiguration is nullptr or not, but the code several lines below - does it, which looks kind of moronic. This configuration is initialized when the delegate is created, so no need to have this if-statement. Instead, assert, making this behavior a requirement. Change-Id: I90fb84337be925a3288252aa2491b4c23d6c6cbb Reviewed-by: Mårten Nordheim --- src/network/access/qhttpthreaddelegate.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/network/access') diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 3d1849010b..46a6615f4d 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -297,6 +297,11 @@ void QHttpThreadDelegate::startRequest() connectionType = QHttpNetworkConnection::ConnectionTypeHTTP2Direct; } +#if QT_CONFIG(ssl) + // See qnetworkreplyhttpimpl, delegate's initialization code. + Q_ASSERT(!ssl || incomingSslConfiguration.data()); +#endif // QT_CONFIG(ssl) + const bool isH2 = httpRequest.isHTTP2Allowed() || httpRequest.isHTTP2Direct(); if (isH2) { #if QT_CONFIG(ssl) @@ -316,9 +321,6 @@ void QHttpThreadDelegate::startRequest() } #ifndef QT_NO_SSL - if (ssl && !incomingSslConfiguration.data()) - incomingSslConfiguration.reset(new QSslConfiguration); - if (!isH2 && httpRequest.isSPDYAllowed() && ssl) { connectionType = QHttpNetworkConnection::ConnectionTypeSPDY; urlCopy.setScheme(QStringLiteral("spdy")); // to differentiate SPDY requests from HTTPS requests -- cgit v1.2.3 From f59f67287fa17e8d4edf6a231c010f768d1b76e8 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 11 Sep 2019 11:39:18 +0200 Subject: QNetworkRequest: deprecate SPDY-related attributes for 5.15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As they will be removed in Qt 6. Also, two H2-related attributes will be replaced by the new ones with their names corrected. Docs updated. Change-Id: I14eeb5fc077a101ca5d177c9369a088bdcb8297e Task-number: QTBUG-78255 Reviewed-by: Paul Wicking Reviewed-by: Edward Welbourne Reviewed-by: Mårten Nordheim --- src/network/access/qnetworkrequest.cpp | 13 ++++++++++--- src/network/access/qnetworkrequest.h | 12 +++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'src/network/access') diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 118fb6b1fb..cedb1597de 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -277,23 +277,30 @@ QT_BEGIN_NAMESPACE Indicates whether the QNetworkAccessManager code is allowed to use SPDY with this request. This applies only to SSL requests, and depends on the server supporting SPDY. + Obsolete, use Http2 instead of Spdy. \value SpdyWasUsedAttribute Replies only, type: QMetaType::Bool Indicates whether SPDY was used for receiving - this reply. + this reply. Obsolete, use Http2 instead of Spdy. - \value HTTP2AllowedAttribute + \value Http2AllowedAttribute Requests only, type: QMetaType::Bool (default: false) Indicates whether the QNetworkAccessManager code is allowed to use HTTP/2 with this request. This applies to SSL requests or 'cleartext' HTTP/2. - \value HTTP2WasUsedAttribute + \value Http2WasUsedAttribute Replies only, type: QMetaType::Bool (default: false) Indicates whether HTTP/2 was used for receiving this reply. (This value was introduced in 5.9.) + \value HTTP2AllowedAttribute + Obsolete alias for Http2AllowedAttribute. + + \value HTTP2WasUsedAttribute + Obsolete alias for Http2WasUsedAttribute. + \value EmitAllUploadProgressSignalsAttribute Requests only, type: QMetaType::Bool (default: false) Indicates whether all upload signals should be emitted. diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index e09ff8aaae..72a6555d91 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -89,12 +89,18 @@ public: DownloadBufferAttribute, // internal SynchronousRequestAttribute, // internal BackgroundRequestAttribute, +#if QT_DEPRECATED_SINCE(5, 15) SpdyAllowedAttribute, SpdyWasUsedAttribute, - EmitAllUploadProgressSignalsAttribute, +#endif // QT_DEPRECATED_SINCE(5, 15) + EmitAllUploadProgressSignalsAttribute = BackgroundRequestAttribute + 3, FollowRedirectsAttribute, - HTTP2AllowedAttribute, - HTTP2WasUsedAttribute, + Http2AllowedAttribute, + Http2WasUsedAttribute, +#if QT_DEPRECATED_SINCE(5, 15) + HTTP2AllowedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2AllowedAttribute") = Http2AllowedAttribute, + HTTP2WasUsedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2WasUsedAttribute"), +#endif // QT_DEPRECATED_SINCE(5, 15) OriginalContentLengthAttribute, RedirectPolicyAttribute, Http2DirectAttribute, -- cgit v1.2.3 From 13e0a36626bd75e631dd9536e795a494432b1945 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 10 Sep 2019 09:04:17 +0200 Subject: Retire SPDY protocol implementation (Qt6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it was superseded by HTTP/2. Bye, Speedy. Since it's Qt 6, we also fix the attribute's enumerator to fit our coding convention with HTTP2AllowedAttribute becoming Http2AllowedAttribute, and the same for HTTP2WasUsedAttribute. tst_qnetworkreply in 'benchmark' directory of qtbase/tests was updated - we have the logic they tested in preConnectEncrypted in tst_http2 now. Manual qnetworkreply test was updated (instead of SPDY in NPN failure we can use H2, the second test was deleted - again, auto-tested in tst_http2). Change-Id: I559c140c333ddf72664911c6e275b1d0d2b980a9 Task-number: QTBUG-78255 Reviewed-by: Mårten Nordheim --- src/network/access/access.pri | 7 - src/network/access/qhttp2protocolhandler.cpp | 12 +- src/network/access/qhttpnetworkconnection.cpp | 54 +- src/network/access/qhttpnetworkconnection_p.h | 2 - .../access/qhttpnetworkconnectionchannel.cpp | 76 +- .../access/qhttpnetworkconnectionchannel_p.h | 7 +- src/network/access/qhttpnetworkreply.cpp | 14 +- src/network/access/qhttpnetworkreply_p.h | 12 +- src/network/access/qhttpnetworkrequest.cpp | 14 +- src/network/access/qhttpnetworkrequest_p.h | 4 - src/network/access/qhttpthreaddelegate.cpp | 19 +- src/network/access/qhttpthreaddelegate_p.h | 2 +- src/network/access/qnetworkaccessmanager.cpp | 8 +- src/network/access/qnetworkreplyhttpimpl.cpp | 22 +- src/network/access/qnetworkrequest.cpp | 18 - src/network/access/qnetworkrequest.h | 8 - src/network/access/qspdyprotocolhandler.cpp | 1304 -------------------- src/network/access/qspdyprotocolhandler_p.h | 232 ---- 18 files changed, 81 insertions(+), 1734 deletions(-) delete mode 100644 src/network/access/qspdyprotocolhandler.cpp delete mode 100644 src/network/access/qspdyprotocolhandler_p.h (limited to 'src/network/access') diff --git a/src/network/access/access.pri b/src/network/access/access.pri index cfb20dcd71..083fbbf5fd 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -114,11 +114,4 @@ qtConfig(http) { access/qhttpthreaddelegate_p.h \ access/qnetworkreplyhttpimpl_p.h \ access/qhttp2configuration.h - - qtConfig(ssl) { - SOURCES += \ - access/qspdyprotocolhandler.cpp - HEADERS += \ - access/qspdyprotocolhandler_p.h - } } diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 9bf5547f15..ee6d493e85 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -332,13 +332,13 @@ bool QHttp2ProtocolHandler::sendRequest() // so we cannot create new streams. m_channel->emitFinishedWithError(QNetworkReply::ProtocolUnknownError, "GOAWAY received, cannot start a request"); - m_channel->spdyRequestsToSend.clear(); + m_channel->h2RequestsToSend.clear(); return false; } // Process 'fake' (created by QNetworkAccessManager::connectToHostEncrypted()) // requests first: - auto &requests = m_channel->spdyRequestsToSend; + auto &requests = m_channel->h2RequestsToSend; for (auto it = requests.begin(), endIt = requests.end(); it != endIt;) { const auto &pair = *it; const QString scheme(pair.first.url().scheme()); @@ -862,7 +862,7 @@ void QHttp2ProtocolHandler::handleGOAWAY() m_channel->emitFinishedWithError(QNetworkReply::ProtocolUnknownError, "GOAWAY received, cannot start a request"); // Also, prevent further calls to sendRequest: - m_channel->spdyRequestsToSend.clear(); + m_channel->h2RequestsToSend.clear(); QNetworkReply::NetworkError error = QNetworkReply::NoError; QString message; @@ -1281,7 +1281,7 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, b const auto replyPrivate = reply->d_func(); replyPrivate->connection = m_connection; replyPrivate->connectionChannel = m_channel; - reply->setSpdyWasUsed(true); + reply->setHttp2WasUsed(true); streamIDs.insert(reply, newStreamID); connect(reply, SIGNAL(destroyed(QObject*)), this, SLOT(_q_replyDestroyed(QObject*))); @@ -1390,7 +1390,7 @@ void QHttp2ProtocolHandler::deleteActiveStream(quint32 streamID) } removeFromSuspended(streamID); - if (m_channel->spdyRequestsToSend.size()) + if (m_channel->h2RequestsToSend.size()) QMetaObject::invokeMethod(this, "sendRequest", Qt::QueuedConnection); } @@ -1509,7 +1509,7 @@ void QHttp2ProtocolHandler::initReplyFromPushPromise(const HttpMessagePair &mess Q_ASSERT(promisedData.contains(cacheKey)); auto promise = promisedData.take(cacheKey); Q_ASSERT(message.second); - message.second->setSpdyWasUsed(true); + message.second->setHttp2WasUsed(true); qCDebug(QT_HTTP2) << "found cached/promised response on stream" << promise.reservedID; diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 21c6359807..795efc91d7 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -82,9 +82,6 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true) , activeChannelCount(type == QHttpNetworkConnection::ConnectionTypeHTTP2 || type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct -#ifndef QT_NO_SSL - || type == QHttpNetworkConnection::ConnectionTypeSPDY -#endif ? 1 : defaultHttpChannelCount) , channelCount(defaultHttpChannelCount) #ifndef QT_NO_NETWORKPROXY @@ -93,9 +90,9 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host , preConnectRequests(0) , connectionType(type) { - // We allocate all 6 channels even if it's SPDY or HTTP/2 enabled - // connection: in case the protocol negotiation via NPN/ALPN fails, - // we will have normally working HTTP/1.1. + // We allocate all 6 channels even if it's HTTP/2 enabled connection: + // in case the protocol negotiation via NPN/ALPN fails, we will have + // normally working HTTP/1.1. Q_ASSERT(channelCount >= activeChannelCount); channels = new QHttpNetworkConnectionChannel[channelCount]; } @@ -641,10 +638,10 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::queueRequest(const QHttpNetwor break; } } - else { // SPDY, HTTP/2 ('h2' mode) + else { // HTTP/2 ('h2' mode) if (!pair.second->d_func()->requestIsPrepared) prepareRequest(pair); - channels[0].spdyRequestsToSend.insert(request.priority(), pair); + channels[0].h2RequestsToSend.insert(request.priority(), pair); } #ifndef Q_OS_WINRT @@ -680,7 +677,7 @@ void QHttpNetworkConnectionPrivate::fillHttp2Queue() for (auto &pair : highPriorityQueue) { if (!pair.second->d_func()->requestIsPrepared) prepareRequest(pair); - channels[0].spdyRequestsToSend.insert(QHttpNetworkRequest::HighPriority, pair); + channels[0].h2RequestsToSend.insert(QHttpNetworkRequest::HighPriority, pair); } highPriorityQueue.clear(); @@ -688,7 +685,7 @@ void QHttpNetworkConnectionPrivate::fillHttp2Queue() for (auto &pair : lowPriorityQueue) { if (!pair.second->d_func()->requestIsPrepared) prepareRequest(pair); - channels[0].spdyRequestsToSend.insert(pair.first.priority(), pair); + channels[0].h2RequestsToSend.insert(pair.first.priority(), pair); } lowPriorityQueue.clear(); @@ -984,12 +981,12 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply) } } #ifndef QT_NO_SSL - // is the reply inside the SPDY pipeline of this channel already? - QMultiMap::iterator it = channels[i].spdyRequestsToSend.begin(); - QMultiMap::iterator end = channels[i].spdyRequestsToSend.end(); + // is the reply inside the H2 pipeline of this channel already? + QMultiMap::iterator it = channels[i].h2RequestsToSend.begin(); + QMultiMap::iterator end = channels[i].h2RequestsToSend.end(); for (; it != end; ++it) { if (it.value().second == reply) { - channels[i].spdyRequestsToSend.remove(it.key()); + channels[i].h2RequestsToSend.remove(it.key()); QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); return; @@ -1068,9 +1065,8 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() break; } case QHttpNetworkConnection::ConnectionTypeHTTP2Direct: - case QHttpNetworkConnection::ConnectionTypeHTTP2: - case QHttpNetworkConnection::ConnectionTypeSPDY: { - if (channels[0].spdyRequestsToSend.isEmpty() && channels[0].switchedToHttp2) + case QHttpNetworkConnection::ConnectionTypeHTTP2: { + if (channels[0].h2RequestsToSend.isEmpty() && channels[0].switchedToHttp2) return; if (networkLayerState == IPv4) @@ -1079,7 +1075,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() channels[0].networkLayerPreference = QAbstractSocket::IPv6Protocol; channels[0].ensureConnection(); if (channels[0].socket && channels[0].socket->state() == QAbstractSocket::ConnectedState - && !channels[0].pendingEncrypt && channels[0].spdyRequestsToSend.size()) + && !channels[0].pendingEncrypt && channels[0].h2RequestsToSend.size()) channels[0].sendRequest(); break; } @@ -1234,19 +1230,18 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info) if (dequeueRequest(channels[0].socket)) { emitReplyError(channels[0].socket, channels[0].reply, QNetworkReply::HostNotFoundError); networkLayerState = QHttpNetworkConnectionPrivate::Unknown; - } else if (connectionType == QHttpNetworkConnection::ConnectionTypeSPDY - || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2 + } else if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2 || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { - for (const HttpMessagePair &spdyPair : qAsConst(channels[0].spdyRequestsToSend)) { + for (const HttpMessagePair &h2Pair : qAsConst(channels[0].h2RequestsToSend)) { // emit error for all replies - QHttpNetworkReply *currentReply = spdyPair.second; + QHttpNetworkReply *currentReply = h2Pair.second; Q_ASSERT(currentReply); emitReplyError(channels[0].socket, currentReply, QNetworkReply::HostNotFoundError); } } else { // Should not happen: we start a host lookup before sending a request, - // so it's natural to have requests either in SPDY/HTTP/2 queue, - // or in low/high priority queues. + // so it's natural to have requests either in HTTP/2 queue, or in low/high + // priority queues. qWarning("QHttpNetworkConnectionPrivate::_q_hostLookupFinished" " could not de-queue request, failed to report HostNotFoundError"); networkLayerState = QHttpNetworkConnectionPrivate::Unknown; @@ -1576,17 +1571,12 @@ void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpN pauseConnection(); QHttpNetworkReply *reply; if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2 - || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct -#if QT_CONFIG(ssl) - || connectionType == QHttpNetworkConnection::ConnectionTypeSPDY -#endif - ) { - + || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { // we choose the reply to emit the proxyAuth signal from somewhat arbitrarily, // but that does not matter because the signal will ultimately be emitted // by the QNetworkAccessManager. - Q_ASSERT(chan->spdyRequestsToSend.count() > 0); - reply = chan->spdyRequestsToSend.cbegin().value().second; + Q_ASSERT(chan->h2RequestsToSend.count() > 0); + reply = chan->h2RequestsToSend.cbegin().value().second; } else { // HTTP reply = chan->reply; } diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index 6808a0c0ac..fee84bb6c0 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -96,7 +96,6 @@ public: enum ConnectionType { ConnectionTypeHTTP, - ConnectionTypeSPDY, ConnectionTypeHTTP2, ConnectionTypeHTTP2Direct }; @@ -172,7 +171,6 @@ private: friend class QHttpNetworkConnectionChannel; friend class QHttp2ProtocolHandler; friend class QHttpProtocolHandler; - friend class QSpdyProtocolHandler; Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest()) Q_PRIVATE_SLOT(d_func(), void _q_hostLookupFinished(QHostInfo)) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 39f392a79b..c6470622ab 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -48,7 +48,6 @@ #include #include -#include #include #ifndef QT_NO_SSL @@ -931,7 +930,7 @@ void QHttpNetworkConnectionChannel::_q_connected() } else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { state = QHttpNetworkConnectionChannel::IdleState; protocolHandler.reset(new QHttp2ProtocolHandler(this)); - if (spdyRequestsToSend.count() > 0) { + if (h2RequestsToSend.count() > 0) { // In case our peer has sent us its settings (window size, max concurrent streams etc.) // let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection). QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); @@ -1108,15 +1107,11 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket || !connection->d_func()->lowPriorityQueue.isEmpty()); if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 - || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct -#ifndef QT_NO_SSL - || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY -#endif - ) { - QList spdyPairs = spdyRequestsToSend.values(); - for (int a = 0; a < spdyPairs.count(); ++a) { + || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { + QList h2Pairs = h2RequestsToSend.values(); + for (int a = 0; a < h2Pairs.count(); ++a) { // emit error for all replies - QHttpNetworkReply *currentReply = spdyPairs.at(a).second; + QHttpNetworkReply *currentReply = h2Pairs.at(a).second; Q_ASSERT(currentReply); emit currentReply->finishedWithError(errorCode, errorString); } @@ -1143,12 +1138,8 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth) { if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 - || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct -#ifndef QT_NO_SSL - || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY -#endif - ) { - if (spdyRequestsToSend.count() > 0) + || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { + if (h2RequestsToSend.count() > 0) connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth); } else { // HTTP // Need to dequeue the request before we can emit the error. @@ -1171,9 +1162,9 @@ void QHttpNetworkConnectionChannel::emitFinishedWithError(QNetworkReply::Network { if (reply) emit reply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message)); - QList spdyPairs = spdyRequestsToSend.values(); - for (int a = 0; a < spdyPairs.count(); ++a) { - QHttpNetworkReply *currentReply = spdyPairs.at(a).second; + QList h2Pairs = h2RequestsToSend.values(); + for (int a = 0; a < h2Pairs.count(); ++a) { + QHttpNetworkReply *currentReply = h2Pairs.at(a).second; Q_ASSERT(currentReply); emit currentReply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message)); } @@ -1195,12 +1186,6 @@ void QHttpNetworkConnectionChannel::_q_encrypted() QByteArray nextProtocol = sslSocket->sslConfiguration().nextNegotiatedProtocol(); if (nextProtocol == QSslConfiguration::NextProtocolHttp1_1) { // fall through to create a QHttpProtocolHandler - } else if (nextProtocol == QSslConfiguration::NextProtocolSpdy3_0) { - protocolHandler.reset(new QSpdyProtocolHandler(this)); - connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeSPDY); - // no need to re-queue requests, if SPDY was enabled on the request it - // has gone to the SPDY queue already - break; } else if (nextProtocol == QSslConfiguration::ALPNProtocolHTTP2) { switchedToHttp2 = true; protocolHandler.reset(new QHttp2ProtocolHandler(this)); @@ -1229,8 +1214,6 @@ void QHttpNetworkConnectionChannel::_q_encrypted() // it again on other channels that our connection can create/open. if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) protocols.removeAll(QSslConfiguration::ALPNProtocolHTTP2); - else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY) - protocols.removeAll(QSslConfiguration::NextProtocolSpdy3_0); if (nProtocols > protocols.size()) { sslConfiguration->setAllowedNextProtocols(protocols); @@ -1240,13 +1223,13 @@ void QHttpNetworkConnectionChannel::_q_encrypted() } connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeHTTP); - // We use only one channel for SPDY or HTTP/2, but normally six for + // We use only one channel for HTTP/2, but normally six for // HTTP/1.1 - let's restore this number to the reserved number of // channels: if (connection->d_func()->activeChannelCount < connection->d_func()->channelCount) { connection->d_func()->activeChannelCount = connection->d_func()->channelCount; - // re-queue requests from SPDY queue to HTTP queue, if any - requeueSpdyRequests(); + // re-queue requests from HTTP/2 queue to HTTP queue, if any + requeueHttp2Requests(); } break; } @@ -1266,11 +1249,9 @@ void QHttpNetworkConnectionChannel::_q_encrypted() state = QHttpNetworkConnectionChannel::IdleState; pendingEncrypt = false; - if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY || - connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 || + if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) { - // we call setSpdyWasUsed(true) on the replies in the SPDY handler when the request is sent - if (spdyRequestsToSend.count() > 0) { + if (h2RequestsToSend.count() > 0) { // In case our peer has sent us its settings (window size, max concurrent streams etc.) // let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection). QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); @@ -1279,7 +1260,7 @@ void QHttpNetworkConnectionChannel::_q_encrypted() if (!reply) connection->d_func()->dequeueRequest(socket); if (reply) { - reply->setSpdyWasUsed(false); + reply->setHttp2WasUsed(false); Q_ASSERT(reply->d_func()->connectionChannel == this); emit reply->encrypted(); } @@ -1288,13 +1269,12 @@ void QHttpNetworkConnectionChannel::_q_encrypted() } } -void QHttpNetworkConnectionChannel::requeueSpdyRequests() +void QHttpNetworkConnectionChannel::requeueHttp2Requests() { - QList spdyPairs = spdyRequestsToSend.values(); - for (int a = 0; a < spdyPairs.count(); ++a) { - connection->d_func()->requeueRequest(spdyPairs.at(a)); - } - spdyRequestsToSend.clear(); + QList h2Pairs = h2RequestsToSend.values(); + for (int a = 0; a < h2Pairs.count(); ++a) + connection->d_func()->requeueRequest(h2Pairs.at(a)); + h2RequestsToSend.clear(); } void QHttpNetworkConnectionChannel::_q_sslErrors(const QList &errors) @@ -1312,11 +1292,11 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList &errors) emit reply->sslErrors(errors); } #ifndef QT_NO_SSL - else { // SPDY - QList spdyPairs = spdyRequestsToSend.values(); - for (int a = 0; a < spdyPairs.count(); ++a) { + else { // HTTP/2 + QList h2Pairs = h2RequestsToSend.values(); + for (int a = 0; a < h2Pairs.count(); ++a) { // emit SSL errors for all replies - QHttpNetworkReply *currentReply = spdyPairs.at(a).second; + QHttpNetworkReply *currentReply = h2Pairs.at(a).second; Q_ASSERT(currentReply); emit currentReply->sslErrors(errors); } @@ -1336,10 +1316,10 @@ void QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired(QSslPr if (reply) emit reply->preSharedKeyAuthenticationRequired(authenticator); } else { - QList spdyPairs = spdyRequestsToSend.values(); - for (int a = 0; a < spdyPairs.count(); ++a) { + QList h2Pairs = h2RequestsToSend.values(); + for (int a = 0; a < h2Pairs.count(); ++a) { // emit SSL errors for all replies - QHttpNetworkReply *currentReply = spdyPairs.at(a).second; + QHttpNetworkReply *currentReply = h2Pairs.at(a).second; Q_ASSERT(currentReply); emit currentReply->preSharedKeyAuthenticationRequired(authenticator); } diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 270b3eb9ba..44ad2d7959 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -123,10 +123,7 @@ public: bool authenticationCredentialsSent; bool proxyCredentialsSent; QScopedPointer protocolHandler; - // SPDY or HTTP/2 requests; SPDY is TLS-only, but - // HTTP/2 can be cleartext also, that's why it's - // outside of QT_NO_SSL section. Sorted by priority: - QMultiMap spdyRequestsToSend; + QMultiMap h2RequestsToSend; bool switchedToHttp2 = false; #ifndef QT_NO_SSL bool ignoreAllSslErrors; @@ -135,7 +132,7 @@ public: void ignoreSslErrors(); void ignoreSslErrors(const QList &errors); void setSslConfiguration(const QSslConfiguration &config); - void requeueSpdyRequests(); // when we wanted SPDY but got HTTP + void requeueHttp2Requests(); // when we wanted HTTP/2 but got HTTP/1.1 #endif // to emit the signal for all in-flight replies: void emitFinishedWithError(QNetworkReply::NetworkError error, const char *message); diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp index a8b635c45a..8982b7c745 100644 --- a/src/network/access/qhttpnetworkreply.cpp +++ b/src/network/access/qhttpnetworkreply.cpp @@ -287,14 +287,14 @@ bool QHttpNetworkReply::isPipeliningUsed() const return d_func()->pipeliningUsed; } -bool QHttpNetworkReply::isSpdyUsed() const +bool QHttpNetworkReply::isHttp2Used() const { - return d_func()->spdyUsed; + return d_func()->h2Used; } -void QHttpNetworkReply::setSpdyWasUsed(bool spdy) +void QHttpNetworkReply::setHttp2WasUsed(bool h2) { - d_func()->spdyUsed = spdy; + d_func()->h2Used = h2; } qint64 QHttpNetworkReply::removedContentLength() const @@ -324,15 +324,11 @@ QHttpNetworkReplyPrivate::QHttpNetworkReplyPrivate(const QUrl &newUrl) forceConnectionCloseEnabled(false), lastChunkRead(false), currentChunkSize(0), currentChunkRead(0), readBufferMaxSize(0), - windowSizeDownload(65536), // 64K initial window size according to SPDY standard - windowSizeUpload(65536), // 64K initial window size according to SPDY standard - currentlyReceivedDataInWindow(0), - currentlyUploadedDataInWindow(0), totallyUploadedData(0), removedContentLength(-1), connection(0), autoDecompress(false), responseData(), requestIsPrepared(false) - ,pipeliningUsed(false), spdyUsed(false), downstreamLimited(false) + ,pipeliningUsed(false), h2Used(false), downstreamLimited(false) ,userProvidedDownloadBuffer(0) #ifndef QT_NO_COMPRESS ,inflateStrm(0) diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h index 12cfe359aa..82128f656e 100644 --- a/src/network/access/qhttpnetworkreply_p.h +++ b/src/network/access/qhttpnetworkreply_p.h @@ -137,8 +137,8 @@ public: bool isFinished() const; bool isPipeliningUsed() const; - bool isSpdyUsed() const; - void setSpdyWasUsed(bool spdy); + bool isHttp2Used() const; + void setHttp2WasUsed(bool h2Used); qint64 removedContentLength() const; bool isRedirecting() const; @@ -251,11 +251,7 @@ public: qint64 currentChunkSize; qint64 currentChunkRead; qint64 readBufferMaxSize; - qint32 windowSizeDownload; // only for SPDY - qint32 windowSizeUpload; // only for SPDY - qint32 currentlyReceivedDataInWindow; // only for SPDY - qint32 currentlyUploadedDataInWindow; // only for SPDY - qint64 totallyUploadedData; // only for SPDY + qint64 totallyUploadedData; // HTTP/2 qint64 removedContentLength; QPointer connection; QPointer connectionChannel; @@ -267,7 +263,7 @@ public: bool requestIsPrepared; bool pipeliningUsed; - bool spdyUsed; + bool h2Used; bool downstreamLimited; char* userProvidedDownloadBuffer; diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index a3f71b8d2f..f81924d5d3 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Operation op, QHttpNetworkRequest::Priority pri, const QUrl &newUrl) : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0), - autoDecompress(false), pipeliningAllowed(false), spdyAllowed(false), http2Allowed(false), + autoDecompress(false), pipeliningAllowed(false), http2Allowed(false), http2Direct(false), withCredentials(true), preConnect(false), redirectCount(0), redirectPolicy(QNetworkRequest::ManualRedirectPolicy) { @@ -59,7 +59,6 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest uploadByteDevice(other.uploadByteDevice), autoDecompress(other.autoDecompress), pipeliningAllowed(other.pipeliningAllowed), - spdyAllowed(other.spdyAllowed), http2Allowed(other.http2Allowed), http2Direct(other.http2Direct), withCredentials(other.withCredentials), @@ -83,7 +82,6 @@ bool QHttpNetworkRequestPrivate::operator==(const QHttpNetworkRequestPrivate &ot && (uploadByteDevice == other.uploadByteDevice) && (autoDecompress == other.autoDecompress) && (pipeliningAllowed == other.pipeliningAllowed) - && (spdyAllowed == other.spdyAllowed) && (http2Allowed == other.http2Allowed) && (http2Direct == other.http2Direct) // we do not clear the customVerb in setOperation @@ -339,16 +337,6 @@ void QHttpNetworkRequest::setPipeliningAllowed(bool b) d->pipeliningAllowed = b; } -bool QHttpNetworkRequest::isSPDYAllowed() const -{ - return d->spdyAllowed; -} - -void QHttpNetworkRequest::setSPDYAllowed(bool b) -{ - d->spdyAllowed = b; -} - bool QHttpNetworkRequest::isHTTP2Allowed() const { return d->http2Allowed; diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h index fb4896195b..f263e348ef 100644 --- a/src/network/access/qhttpnetworkrequest_p.h +++ b/src/network/access/qhttpnetworkrequest_p.h @@ -116,9 +116,6 @@ public: bool isPipeliningAllowed() const; void setPipeliningAllowed(bool b); - bool isSPDYAllowed() const; - void setSPDYAllowed(bool b); - bool isHTTP2Allowed() const; void setHTTP2Allowed(bool b); @@ -176,7 +173,6 @@ public: mutable QNonContiguousByteDevice* uploadByteDevice; bool autoDecompress; bool pipeliningAllowed; - bool spdyAllowed; bool http2Allowed; bool http2Direct; bool withCredentials; diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 63a3c4f204..2933d75d2c 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -236,7 +236,7 @@ QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) : , synchronous(false) , incomingStatusCode(0) , isPipeliningUsed(false) - , isSpdyUsed(false) + , isHttp2Used(false) , incomingContentLength(-1) , removedContentLength(-1) , incomingErrorCode(QNetworkReply::NoError) @@ -320,17 +320,6 @@ void QHttpThreadDelegate::startRequest() } } -#ifndef QT_NO_SSL - if (!isH2 && httpRequest.isSPDYAllowed() && ssl) { - connectionType = QHttpNetworkConnection::ConnectionTypeSPDY; - urlCopy.setScheme(QStringLiteral("spdy")); // to differentiate SPDY requests from HTTPS requests - QList nextProtocols; - nextProtocols << QSslConfiguration::NextProtocolSpdy3_0 - << QSslConfiguration::NextProtocolHttp1_1; - incomingSslConfiguration->setAllowedNextProtocols(nextProtocols); - } -#endif // QT_NO_SSL - #ifndef QT_NO_NETWORKPROXY if (transparentProxy.type() != QNetworkProxy::NoProxy) cacheKey = makeCacheKey(urlCopy, &transparentProxy, httpRequest.peerVerifyName()); @@ -652,7 +641,7 @@ void QHttpThreadDelegate::headerChangedSlot() isPipeliningUsed = httpReply->isPipeliningUsed(); incomingContentLength = httpReply->contentLength(); removedContentLength = httpReply->removedContentLength(); - isSpdyUsed = httpReply->isSpdyUsed(); + isHttp2Used = httpReply->isHttp2Used(); emit downloadMetaData(incomingHeaders, incomingStatusCode, @@ -661,7 +650,7 @@ void QHttpThreadDelegate::headerChangedSlot() downloadBuffer, incomingContentLength, removedContentLength, - isSpdyUsed); + isHttp2Used); } void QHttpThreadDelegate::synchronousHeaderChangedSlot() @@ -677,7 +666,7 @@ void QHttpThreadDelegate::synchronousHeaderChangedSlot() incomingStatusCode = httpReply->statusCode(); incomingReasonPhrase = httpReply->reasonPhrase(); isPipeliningUsed = httpReply->isPipeliningUsed(); - isSpdyUsed = httpReply->isSpdyUsed(); + isHttp2Used = httpReply->isHttp2Used(); incomingContentLength = httpReply->contentLength(); } diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index 355d1afc30..208b2cb149 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -112,7 +112,7 @@ public: int incomingStatusCode; QString incomingReasonPhrase; bool isPipeliningUsed; - bool isSpdyUsed; + bool isHttp2Used; qint64 incomingContentLength; qint64 removedContentLength; QNetworkReply::NetworkError incomingErrorCode; diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 76b95b5823..125427493d 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1237,12 +1237,10 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin if (sslConfiguration != QSslConfiguration::defaultConfiguration()) request.setSslConfiguration(sslConfiguration); - // There is no way to enable SPDY/HTTP2 via a request, so we need to check - // the ssl configuration whether SPDY/HTTP2 is allowed here. + // There is no way to enable HTTP2 via a request, so we need to check + // the ssl configuration whether HTTP2 is allowed here. if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2)) - request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true); - else if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::NextProtocolSpdy3_0)) - request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true); + request.setAttribute(QNetworkRequest::Http2AllowedAttribute, true); request.setPeerVerifyName(peerName); get(request); diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 8ac81d1780..0bd7825186 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -774,10 +774,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq if (newHttpRequest.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool()) httpRequest.setPipeliningAllowed(true); - if (request.attribute(QNetworkRequest::SpdyAllowedAttribute).toBool()) - httpRequest.setSPDYAllowed(true); - - if (request.attribute(QNetworkRequest::HTTP2AllowedAttribute).toBool()) + if (request.attribute(QNetworkRequest::Http2AllowedAttribute).toBool()) httpRequest.setHTTP2Allowed(true); if (request.attribute(QNetworkRequest::Http2DirectAttribute).toBool()) { @@ -968,7 +965,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq QSharedPointer(), delegate->incomingContentLength, delegate->removedContentLength, - delegate->isSpdyUsed); + delegate->isHttp2Used); replyDownloadData(delegate->synchronousDownloadData); httpError(delegate->incomingErrorCode, delegate->incomingErrorDetail); } else { @@ -980,7 +977,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq QSharedPointer(), delegate->incomingContentLength, delegate->removedContentLength, - delegate->isSpdyUsed); + delegate->isHttp2Used); replyDownloadData(delegate->synchronousDownloadData); } @@ -1254,7 +1251,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList db, qint64 contentLength, qint64 removedContentLength, - bool spdyWasUsed) + bool h2Used) { Q_Q(QNetworkReplyHttpImpl); Q_UNUSED(contentLength); @@ -1280,16 +1277,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QListsetAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu); - const QVariant http2Allowed = request.attribute(QNetworkRequest::HTTP2AllowedAttribute); - const QVariant http2Direct = request.attribute(QNetworkRequest::Http2DirectAttribute); - if ((http2Allowed.isValid() && http2Allowed.toBool()) - || (http2Direct.isValid() && http2Direct.toBool())) { - q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, spdyWasUsed); - q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, false); - } else { - q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, spdyWasUsed); - q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, false); - } + q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, h2Used); // reconstruct the HTTP header QList > headerMap = hm; diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index cedb1597de..af1e0b7278 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -272,18 +272,6 @@ QT_BEGIN_NAMESPACE The QNetworkSession ConnectInBackground property will be set according to this attribute. - \value SpdyAllowedAttribute - Requests only, type: QMetaType::Bool (default: false) - Indicates whether the QNetworkAccessManager code is - allowed to use SPDY with this request. This applies only - to SSL requests, and depends on the server supporting SPDY. - Obsolete, use Http2 instead of Spdy. - - \value SpdyWasUsedAttribute - Replies only, type: QMetaType::Bool - Indicates whether SPDY was used for receiving - this reply. Obsolete, use Http2 instead of Spdy. - \value Http2AllowedAttribute Requests only, type: QMetaType::Bool (default: false) Indicates whether the QNetworkAccessManager code is @@ -295,12 +283,6 @@ QT_BEGIN_NAMESPACE Indicates whether HTTP/2 was used for receiving this reply. (This value was introduced in 5.9.) - \value HTTP2AllowedAttribute - Obsolete alias for Http2AllowedAttribute. - - \value HTTP2WasUsedAttribute - Obsolete alias for Http2WasUsedAttribute. - \value EmitAllUploadProgressSignalsAttribute Requests only, type: QMetaType::Bool (default: false) Indicates whether all upload signals should be emitted. diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 72a6555d91..95b5dc89b5 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -89,18 +89,10 @@ public: DownloadBufferAttribute, // internal SynchronousRequestAttribute, // internal BackgroundRequestAttribute, -#if QT_DEPRECATED_SINCE(5, 15) - SpdyAllowedAttribute, - SpdyWasUsedAttribute, -#endif // QT_DEPRECATED_SINCE(5, 15) EmitAllUploadProgressSignalsAttribute = BackgroundRequestAttribute + 3, FollowRedirectsAttribute, Http2AllowedAttribute, Http2WasUsedAttribute, -#if QT_DEPRECATED_SINCE(5, 15) - HTTP2AllowedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2AllowedAttribute") = Http2AllowedAttribute, - HTTP2WasUsedAttribute Q_DECL_ENUMERATOR_DEPRECATED_X("Use Http2WasUsedAttribute"), -#endif // QT_DEPRECATED_SINCE(5, 15) OriginalContentLengthAttribute, RedirectPolicyAttribute, Http2DirectAttribute, diff --git a/src/network/access/qspdyprotocolhandler.cpp b/src/network/access/qspdyprotocolhandler.cpp deleted file mode 100644 index f845235bf7..0000000000 --- a/src/network/access/qspdyprotocolhandler.cpp +++ /dev/null @@ -1,1304 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 BlackBerry Limited. All rights reserved. -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include - -#if !defined(QT_NO_SSL) - -QT_BEGIN_NAMESPACE - -static const char spdyDictionary[] = { - 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, // ....opti - 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, // ons....h - 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, // ead....p - 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, // ost....p - 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, // ut....de - 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, // lete.... - 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, // trace... - 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, // .accept. - 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep - 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // t-charse - 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, // t....acc - 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ept-enco - 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, // ding.... - 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, // accept-l - 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, // anguage. - 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, // ...accep - 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, // t-ranges - 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, // ....age. - 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, // ...allow - 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, // ....auth - 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, // orizatio - 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, // n....cac - 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, // he-contr - 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, // ol....co - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, // nnection - 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, // ....cont - 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, // ent-base - 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, // ....cont - 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, // ent-enco - 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, // ding.... - 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, // content- - 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, // language - 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, // ....cont - 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, // ent-leng - 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, // th....co - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, // ntent-lo - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, // cation.. - 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten - 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, // t-md5... - 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, // .content - 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, // -range.. - 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, // ..conten - 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, // t-type.. - 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, // ..date.. - 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, // ..etag.. - 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, // ..expect - 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, // ....expi - 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, // res....f - 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, // rom....h - 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, // ost....i - 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, // f-match. - 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, // ...if-mo - 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, // dified-s - 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, // ince.... - 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, // if-none- - 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, // match... - 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, // .if-rang - 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, // e....if- - 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, // unmodifi - 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, // ed-since - 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, // ....last - 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, // -modifie - 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, // d....loc - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, // ation... - 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, // .max-for - 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, // wards... - 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, // .pragma. - 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, // ...proxy - 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, // -authent - 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, // icate... - 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, // .proxy-a - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, // uthoriza - 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, // tion.... - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, // range... - 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, // .referer - 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, // ....retr - 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, // y-after. - 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, // ...serve - 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, // r....te. - 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, // ...trail - 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, // er....tr - 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, // ansfer-e - 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, // ncoding. - 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, // ...upgra - 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, // de....us - 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, // er-agent - 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, // ....vary - 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, // ....via. - 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, // ...warni - 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, // ng....ww - 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, // w-authen - 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, // ticate.. - 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, // ..method - 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, // ....get. - 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, // ...statu - 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, // s....200 - 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, // .OK....v - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, // ersion.. - 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, // ..HTTP.1 - 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, // .1....ur - 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, // l....pub - 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, // lic....s - 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, // et-cooki - 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, // e....kee - 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, // p-alive. - 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, // ...origi - 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, // n1001012 - 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, // 01202205 - 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, // 20630030 - 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, // 23033043 - 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, // 05306307 - 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, // 40240540 - 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, // 64074084 - 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, // 09410411 - 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, // 41241341 - 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, // 44154164 - 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, // 17502504 - 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, // 505203.N - 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, // on-Autho - 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, // ritative - 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, // .Informa - 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, // tion204. - 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, // No.Conte - 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, // nt301.Mo - 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, // ved.Perm - 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, // anently4 - 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, // 00.Bad.R - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, // equest40 - 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, // 1.Unauth - 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, // orized40 - 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, // 3.Forbid - 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, // den404.N - 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, // ot.Found - 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, // 500.Inte - 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, // rnal.Ser - 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, // ver.Erro - 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, // r501.Not - 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, // .Impleme - 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, // nted503. - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, // Service. - 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, // Unavaila - 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, // bleJan.F - 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, // eb.Mar.A - 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, // pr.May.J - 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, // un.Jul.A - 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, // ug.Sept. - 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, // Oct.Nov. - 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, // Dec.00.0 - 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, // 0.00.Mon - 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, // ..Tue..W - 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, // ed..Thu. - 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, // .Fri..Sa - 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, // t..Sun.. - 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, // GMTchunk - 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, // ed.text. - 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, // html.ima - 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, // ge.png.i - 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, // mage.jpg - 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, // .image.g - 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // if.appli - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x - 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, // ml.appli - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, // cation.x - 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, // html.xml - 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, // .text.pl - 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, // ain.text - 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, // .javascr - 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, // ipt.publ - 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, // icprivat - 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, // emax-age - 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, // .gzip.de - 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, // flate.sd - 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, // chcharse - 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, // t.utf-8c - 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, // harset.i - 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, // so-8859- - 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, // 1.utf-.. - 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e // .enq.0. -}; - -// uncomment to debug -//static void printHex(const QByteArray &ba) -//{ -// QByteArray hex; -// QByteArray clearText; -// for (int a = 0; a < ba.count(); ++a) { -// QByteArray currentHexChar = QByteArray(1, ba.at(a)).toHex().rightJustified(2, ' '); -// QByteArray currentChar; -// if (ba.at(a) >= 32 && ba.at(a) < 126) { // if ASCII, print the letter -// currentChar = QByteArray(1, ba.at(a)); -// } else { -// currentChar = " "; -// } -// clearText.append(currentChar.rightJustified(2, ' ')); -// hex.append(currentHexChar); -// hex.append(' '); -// clearText.append(' '); -// } -// int chunkSize = 102; // 12 == 4 bytes per line -// for (int a = 0; a < hex.count(); a += chunkSize) { -// qDebug() << hex.mid(a, chunkSize); -// qDebug() << clearText.mid(a, chunkSize); -// } -//} - -QSpdyProtocolHandler::QSpdyProtocolHandler(QHttpNetworkConnectionChannel *channel) - : QObject(0), QAbstractProtocolHandler(channel), - m_nextStreamID(-1), - m_maxConcurrentStreams(100), // 100 is recommended in the SPDY RFC - m_initialWindowSize(0), - m_waitingForCompleteStream(false) -{ - m_inflateStream.zalloc = Z_NULL; - m_inflateStream.zfree = Z_NULL; - m_inflateStream.opaque = Z_NULL; - int zlibRet = inflateInit(&m_inflateStream); - Q_ASSERT(zlibRet == Z_OK); - - m_deflateStream.zalloc = Z_NULL; - m_deflateStream.zfree = Z_NULL; - m_deflateStream.opaque = Z_NULL; - - // Do actually not compress (i.e. compression level = 0) - // when sending the headers because of the CRIME attack - zlibRet = deflateInit(&m_deflateStream, /* compression level = */ 0); - Q_ASSERT(zlibRet == Z_OK); - Q_UNUSED(zlibRet); // silence -Wunused-variable -} - -QSpdyProtocolHandler::~QSpdyProtocolHandler() -{ - deflateEnd(&m_deflateStream); - deflateEnd(&m_inflateStream); -} - -bool QSpdyProtocolHandler::sendRequest() -{ - Q_ASSERT(!m_reply); - - int maxPossibleRequests = m_maxConcurrentStreams - m_inFlightStreams.count(); - Q_ASSERT(maxPossibleRequests >= 0); - if (maxPossibleRequests == 0) - return true; // return early if max concurrent requests are exceeded - - m_channel->state = QHttpNetworkConnectionChannel::WritingState; - - int requestsToSend = qMin(m_channel->spdyRequestsToSend.size(), maxPossibleRequests); - - QMultiMap::iterator it = m_channel->spdyRequestsToSend.begin(); - // requests will be ordered by priority (see QMultiMap doc) - for (int a = 0; a < requestsToSend; ++a) { - HttpMessagePair currentPair = *it; - QHttpNetworkRequest currentRequest = currentPair.first; - QHttpNetworkReply *currentReply = currentPair.second; - - currentReply->setSpdyWasUsed(true); - qint32 streamID = generateNextStreamID(); - m_streamIDs.insert(currentReply, streamID); - - currentReply->setRequest(currentRequest); - currentReply->d_func()->connection = m_connection; - currentReply->d_func()->connectionChannel = m_channel; - m_inFlightStreams.insert(streamID, currentPair); - connect(currentReply, SIGNAL(destroyed(QObject*)), this, SLOT(_q_replyDestroyed(QObject*))); - - sendSYN_STREAM(currentPair, streamID, /* associatedToStreamID = */ 0); - m_channel->spdyRequestsToSend.erase(it++); - } - m_channel->state = QHttpNetworkConnectionChannel::IdleState; - return true; -} - -void QSpdyProtocolHandler::_q_replyDestroyed(QObject* reply) -{ - qint32 streamID = m_streamIDs.take(reply); - if (m_inFlightStreams.remove(streamID)) - sendRST_STREAM(streamID, RST_STREAM_CANCEL); -} - -void QSpdyProtocolHandler::_q_receiveReply() -{ - Q_ASSERT(m_socket); - - // only run when the QHttpNetworkConnection is not currently being destructed, e.g. - // this function is called from _q_disconnected which is called because - // of ~QHttpNetworkConnectionPrivate - if (!qobject_cast(m_connection)) { - return; - } - - if (bytesAvailable() < 8) - return; // cannot read frame headers, wait for more data - - char frameHeadersRaw[8]; - if (!readNextChunk(8, frameHeadersRaw)) - return; // this should not happen, we just checked - - const QByteArray frameHeaders(frameHeadersRaw, 8); // ### try without memcpy - if (frameHeadersRaw[0] & 0x80) { - handleControlFrame(frameHeaders); - } else { - handleDataFrame(frameHeaders); - } - - // after handling the current frame, check whether there is more data waiting - if (m_socket->bytesAvailable() > 0) - QMetaObject::invokeMethod(m_channel, "_q_receiveReply", Qt::QueuedConnection); -} - -void QSpdyProtocolHandler::_q_readyRead() -{ - _q_receiveReply(); -} - -static qint16 twoBytesToInt(const char *bytes) -{ - return qFromBigEndian(bytes); -} - -static qint32 threeBytesToInt(const char *bytes) -{ - return qFromBigEndian(bytes) >> 8; -} - -static qint32 fourBytesToInt(const char *bytes) -{ - return qFromBigEndian(bytes); -} - -static void appendIntToThreeBytes(char *output, qint32 number) -{ - qToBigEndian(number, output + 1); - qToBigEndian(number >> 16, output); -} - -static void appendIntToFourBytes(char *output, qint32 number) -{ - qToBigEndian(number, output); -} - -static QByteArray intToFourBytes(qint32 number) // ### try to use appendIntToFourBytes where possible -{ - char data[4]; - qToBigEndian(number, data); - QByteArray ret(data, 4); - return ret; -} - -static QByteArray intToThreeBytes(qint32 number) -{ - char data[4]; - qToBigEndian(number << 8, data); - QByteArray ret(data, 3); - return ret; -} - -static qint32 getStreamID(const char *bytes) -{ - // eliminate most significant bit; it might be 0 or 1 depending on whether - // we are dealing with a control or data frame - return fourBytesToInt(bytes) & 0x3fffffff; -} - -static QByteArray headerField(const QByteArray &name, const QByteArray &value) -{ - QByteArray ret; - ret.reserve(name.count() + value.count() + 8); // 4 byte for length each - ret.append(intToFourBytes(name.count())); - ret.append(name); - ret.append(intToFourBytes(value.count())); - ret.append(value); - return ret; -} - -bool QSpdyProtocolHandler::uncompressHeader(const QByteArray &input, QByteArray *output) -{ - const size_t chunkSize = 1024; - char outputRaw[chunkSize]; - // input bytes will not be changed by zlib, so it is safe to const_cast here - m_inflateStream.next_in = const_cast(reinterpret_cast(input.constData())); - m_inflateStream.avail_in = input.count(); - m_inflateStream.total_in = input.count(); - int zlibRet; - - do { - m_inflateStream.next_out = reinterpret_cast(outputRaw); - m_inflateStream.avail_out = chunkSize; - zlibRet = inflate(&m_inflateStream, Z_SYNC_FLUSH); - if (zlibRet == Z_NEED_DICT) { - zlibRet = inflateSetDictionary(&m_inflateStream, - reinterpret_cast(spdyDictionary), - /* dictionaryLength = */ 1423); - Q_ASSERT(zlibRet == Z_OK); - continue; - } - switch (zlibRet) { - case Z_BUF_ERROR: { - if (m_inflateStream.avail_in == 0) { - int outputSize = chunkSize - m_inflateStream.avail_out; - output->append(outputRaw, outputSize); - m_inflateStream.avail_out = chunkSize; - } - break; - } - case Z_OK: { - int outputSize = chunkSize - m_inflateStream.avail_out; - output->append(outputRaw, outputSize); - break; - } - default: { - qWarning("got unexpected zlib return value: %d", zlibRet); - return false; - } - } - } while (m_inflateStream.avail_in > 0 && zlibRet != Z_STREAM_END); - - Q_ASSERT(m_inflateStream.avail_in == 0); - return true; -} - -QByteArray QSpdyProtocolHandler::composeHeader(const QHttpNetworkRequest &request) -{ - QByteArray uncompressedHeader; - uncompressedHeader.reserve(300); // rough estimate - - // calculate additional headers first, because we need to know the size - // ### do not partially copy the list, but restrict the set header fields - // in QHttpNetworkConnection - QVector > additionalHeaders; - for (int a = 0; a < request.header().count(); ++a) { - QByteArray key = request.header().at(a).first; - if (key == "Connection" || key == "Host" || key == "Keep-Alive" - || key == "Proxy-Connection" || key == "Transfer-Encoding") - continue; // those headers are not valid (section 3.2.1) - additionalHeaders.append(request.header().at(a)); - } - - qint32 numberOfHeaderPairs = 5 + additionalHeaders.count(); // 5 mandatory below + the additional ones - uncompressedHeader.append(intToFourBytes(numberOfHeaderPairs)); - - // mandatory header fields: - - uncompressedHeader.append(headerField(":method", request.methodName())); -#ifndef QT_NO_NETWORKPROXY - bool useProxy = m_connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy; - uncompressedHeader.append(headerField(":path", request.uri(useProxy))); -#else - uncompressedHeader.append(headerField(":path", request.uri(false))); -#endif - uncompressedHeader.append(headerField(":version", "HTTP/1.1")); - - uncompressedHeader.append(headerField(":host", request.url().authority(QUrl::FullyEncoded | QUrl::RemoveUserInfo).toLatin1())); - - uncompressedHeader.append(headerField(":scheme", request.url().scheme().toLatin1())); - - // end of mandatory header fields - - // now add the additional headers - for (int a = 0; a < additionalHeaders.count(); ++a) { - uncompressedHeader.append(headerField(additionalHeaders.at(a).first.toLower(), - additionalHeaders.at(a).second)); - } - - m_deflateStream.total_in = uncompressedHeader.count(); - m_deflateStream.avail_in = uncompressedHeader.count(); - m_deflateStream.next_in = reinterpret_cast(uncompressedHeader.data()); - int outputBytes = uncompressedHeader.count() + 30; // 30 bytes of compression header overhead - m_deflateStream.avail_out = outputBytes; - unsigned char *out = new unsigned char[outputBytes]; - m_deflateStream.next_out = out; - int availOutBefore = m_deflateStream.avail_out; - int zlibRet = deflate(&m_deflateStream, Z_SYNC_FLUSH); // do everything in one go since we use no compression - int compressedHeaderSize = availOutBefore - m_deflateStream.avail_out; - Q_ASSERT(zlibRet == Z_OK); // otherwise, we need to allocate more outputBytes - Q_UNUSED(zlibRet); // silence -Wunused-variable - Q_ASSERT(m_deflateStream.avail_in == 0); - QByteArray compressedHeader(reinterpret_cast(out), compressedHeaderSize); - delete[] out; - - return compressedHeader; -} - -quint64 QSpdyProtocolHandler::bytesAvailable() const -{ - Q_ASSERT(m_socket); - return m_spdyBuffer.byteAmount() + m_socket->bytesAvailable(); -} - -bool QSpdyProtocolHandler::readNextChunk(qint64 length, char *sink) -{ - qint64 expectedReadBytes = length; - qint64 requiredBytesFromBuffer = 0; - - if (m_waitingForCompleteStream) { - requiredBytesFromBuffer = qMin(length, m_spdyBuffer.byteAmount()); - // ### if next chunk from buffer bigger than what we want to read, - // we have to call read() (which memcpy's). Otherwise, we can just - // read the next chunk without memcpy'ing. - qint64 bytesReadFromBuffer = m_spdyBuffer.read(sink, requiredBytesFromBuffer); - Q_ASSERT(bytesReadFromBuffer == requiredBytesFromBuffer); - if (length <= bytesReadFromBuffer) { - return true; // buffer > required size -> no need to read from socket - } - expectedReadBytes -= requiredBytesFromBuffer; - } - qint64 readBytes = m_socket->read(sink + requiredBytesFromBuffer, expectedReadBytes); - - if (readBytes < expectedReadBytes) { - m_waitingForCompleteStream = true; - // ### this is inefficient, we should not put back so much data into the buffer - QByteArray temp(sink, requiredBytesFromBuffer + readBytes); - m_spdyBuffer.append(temp); - return false; - } else { - return true; // buffer must be cleared by calling function - } -} - -void QSpdyProtocolHandler::sendControlFrame(FrameType type, - ControlFrameFlags flags, - const char *data, - quint32 length) -{ - // frame type and stream ID - char header[8]; - header[0] = 0x80u; // leftmost bit == 1 -> is a control frame - header[1] = 0x03; // 3 bit == version 3 - header[2] = 0; - switch (type) { - case FrameType_CREDENTIAL: { - qWarning("sending SPDY CREDENTIAL frame is not yet implemented"); // QTBUG-36188 - return; - } - default: - header[3] = type; - } - - // flags - header[4] = 0; - if (flags & ControlFrame_FLAG_FIN || length == 0) { - Q_ASSERT(type == FrameType_SYN_STREAM || type == FrameType_SYN_REPLY - || type == FrameType_HEADERS || length == 0); - header[4] |= ControlFrame_FLAG_FIN; - } - if (flags & ControlFrame_FLAG_UNIDIRECTIONAL) { - Q_ASSERT(type == FrameType_SYN_STREAM); - header[4] |= ControlFrame_FLAG_UNIDIRECTIONAL; - } - - // length - appendIntToThreeBytes(header + 5, length); - - qint64 written = m_socket->write(header, 8); - Q_ASSERT(written == 8); - written = m_socket->write(data, length); - Q_ASSERT(written == length); - Q_UNUSED(written); // silence -Wunused-variable -} - -void QSpdyProtocolHandler::sendSYN_STREAM(const HttpMessagePair &messagePair, - qint32 streamID, qint32 associatedToStreamID) -{ - QHttpNetworkRequest request = messagePair.first; - QHttpNetworkReply *reply = messagePair.second; - - ControlFrameFlags flags = 0; - - if (!request.uploadByteDevice()) { - // no upload -> this is the last frame, send the FIN flag - flags |= ControlFrame_FLAG_FIN; - reply->d_func()->state = QHttpNetworkReplyPrivate::SPDYHalfClosed; - } else { - reply->d_func()->state = QHttpNetworkReplyPrivate::SPDYUploading; - - // hack: set the stream ID on the device directly, so when we get - // the signal for uploading we know which stream we are sending on - m_streamIDs.insert(request.uploadByteDevice(), streamID); - - QObject::connect(request.uploadByteDevice(), SIGNAL(readyRead()), this, - SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection); - QObject::connect(request.uploadByteDevice(), SIGNAL(destroyed(QObject*)), this, - SLOT(_q_uploadDataDestroyed(QObject *))); - } - - QByteArray namesAndValues = composeHeader(request); - quint32 length = namesAndValues.count() + 10; // 10 == 4 for Stream-ID + 4 for Associated-To-Stream-ID - // + 2 for Priority, Unused and Slot - - QByteArray wireData; - wireData.reserve(length); - wireData.append(intToFourBytes(streamID)); - wireData.append(intToFourBytes(associatedToStreamID)); - - // priority (3 bits) / unused (5 bits) / slot (8 bits) - char prioAndSlot[2]; - switch (request.priority()) { - case QHttpNetworkRequest::HighPriority: - prioAndSlot[0] = 0x00; // == prio 0 (highest) - break; - case QHttpNetworkRequest::NormalPriority: - prioAndSlot[0] = 0x80u; // == prio 4 - break; - case QHttpNetworkRequest::LowPriority: - prioAndSlot[0] = 0xe0u; // == prio 7 (lowest) - break; - } - prioAndSlot[1] = 0x00; // slot in client certificates (not supported currently) - wireData.append(prioAndSlot, 2); - - wireData.append(namesAndValues); - - sendControlFrame(FrameType_SYN_STREAM, flags, wireData.constData(), length); - - if (reply->d_func()->state == QHttpNetworkReplyPrivate::SPDYUploading) - uploadData(streamID); -} - -void QSpdyProtocolHandler::_q_uploadDataDestroyed(QObject *uploadData) -{ - m_streamIDs.remove(uploadData); -} - -void QSpdyProtocolHandler::sendRST_STREAM(qint32 streamID, RST_STREAM_STATUS_CODE statusCode) -{ - char wireData[8]; - appendIntToFourBytes(wireData, streamID); - appendIntToFourBytes(wireData + 4, statusCode); - sendControlFrame(FrameType_RST_STREAM, /* flags = */ 0, wireData, /* length = */ 8); -} - -void QSpdyProtocolHandler::sendPING(quint32 pingID) -{ - char rawData[4]; - appendIntToFourBytes(rawData, pingID); - sendControlFrame(FrameType_PING, /* flags = */ 0, rawData, /* length = */ 4); -} - -bool QSpdyProtocolHandler::uploadData(qint32 streamID) -{ - // we only rely on SPDY flow control here and don't care about TCP buffers - if (!m_inFlightStreams.contains(streamID)) { - sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM); - return false; - } - - HttpMessagePair messagePair = m_inFlightStreams.value(streamID); - QHttpNetworkRequest request = messagePair.first; - QHttpNetworkReply *reply = messagePair.second; - Q_ASSERT(reply); - QHttpNetworkReplyPrivate *replyPrivate = reply->d_func(); - Q_ASSERT(replyPrivate); - - if (reply->d_func()->state == QHttpNetworkReplyPrivate::SPDYHalfClosed || reply->d_func()->state == QHttpNetworkReplyPrivate::SPDYClosed) { - qWarning("Trying to upload to closed stream"); - return false; - } - - qint32 dataLeftInWindow = replyPrivate->windowSizeUpload - - replyPrivate->currentlyUploadedDataInWindow; - - while (dataLeftInWindow > 0 && !request.uploadByteDevice()->atEnd()) { - - // get pointer to upload data - qint64 currentReadSize = 0; - const char *readPointer = request.uploadByteDevice()->readPointer(dataLeftInWindow, - currentReadSize); - - if (currentReadSize == -1) { - // premature eof happened - m_connection->d_func()->emitReplyError(m_socket, reply, - QNetworkReply::UnknownNetworkError); - return false; - } else if (readPointer == 0 || currentReadSize == 0) { - // nothing to read currently, break the loop - break; - } else { - DataFrameFlags flags = 0; - // we will send the FIN flag later if appropriate - qint64 currentWriteSize = sendDataFrame(streamID, flags, currentReadSize, readPointer); - if (currentWriteSize == -1 || currentWriteSize != currentReadSize) { - // socket broke down - m_connection->d_func()->emitReplyError(m_socket, reply, - QNetworkReply::UnknownNetworkError); - return false; - } else { - replyPrivate->currentlyUploadedDataInWindow += currentWriteSize; - replyPrivate->totallyUploadedData += currentWriteSize; - dataLeftInWindow = replyPrivate->windowSizeUpload - - replyPrivate->currentlyUploadedDataInWindow; - request.uploadByteDevice()->advanceReadPointer(currentWriteSize); - - emit reply->dataSendProgress(replyPrivate->totallyUploadedData, - request.contentLength()); - } - } - } - if (replyPrivate->totallyUploadedData == request.contentLength()) { - DataFrameFlags finFlag = DataFrame_FLAG_FIN; - qint64 writeSize = sendDataFrame(streamID, finFlag, 0, 0); - Q_ASSERT(writeSize == 0); - Q_UNUSED(writeSize); // silence -Wunused-variable - replyPrivate->state = QHttpNetworkReplyPrivate::SPDYHalfClosed; - if (reply->request().uploadByteDevice()) - reply->request().uploadByteDevice()->disconnect(this); - // ### this will not work if the content length is not known, but - // then again many servers will fail in this case anyhow according - // to the SPDY RFC - } - return true; -} - -void QSpdyProtocolHandler::_q_uploadDataReadyRead() -{ - QNonContiguousByteDevice *device = qobject_cast(sender()); - Q_ASSERT(device); - qint32 streamID = m_streamIDs.value(device); - Q_ASSERT(streamID > 0); - uploadData(streamID); -} - -void QSpdyProtocolHandler::sendWINDOW_UPDATE(qint32 streamID, quint32 deltaWindowSize) -{ - char windowUpdateData[8]; - appendIntToFourBytes(windowUpdateData, streamID); - appendIntToFourBytes(windowUpdateData + 4, deltaWindowSize); - - sendControlFrame(FrameType_WINDOW_UPDATE, /* flags = */ 0, windowUpdateData, /* length = */ 8); -} - -qint64 QSpdyProtocolHandler::sendDataFrame(qint32 streamID, DataFrameFlags flags, - quint32 length, const char *data) -{ - QByteArray wireData; - wireData.reserve(8); - - wireData.append(intToFourBytes(streamID)); - wireData.append(flags); - wireData.append(intToThreeBytes(length)); - - Q_ASSERT(m_socket); - m_socket->write(wireData); - - if (data) { - qint64 ret = m_socket->write(data, length); - return ret; - } else { - return 0; // nothing to write, e.g. FIN flag - } -} - -void QSpdyProtocolHandler::handleControlFrame(const QByteArray &frameHeaders) // ### make it char * -{ - Q_ASSERT(frameHeaders.count() >= 8); - qint16 version = twoBytesToInt(frameHeaders.constData()); - version &= 0x3fff; // eliminate most significant bit to determine version - Q_ASSERT(version == 3); - - qint16 type = twoBytesToInt(frameHeaders.constData() + 2); - - char flags = frameHeaders.at(4); - qint32 length = threeBytesToInt(frameHeaders.constData() + 5); - Q_ASSERT(length > 0); - - QByteArray frameData; - frameData.resize(length); - if (!readNextChunk(length, frameData.data())) { - // put back the frame headers to the buffer - m_spdyBuffer.prepend(frameHeaders); - return; // we couldn't read the whole frame and need to wait - } else { - m_spdyBuffer.clear(); - m_waitingForCompleteStream = false; - } - - switch (type) { - case FrameType_SYN_STREAM: { - handleSYN_STREAM(flags, length, frameData); - break; - } - case FrameType_SYN_REPLY: { - handleSYN_REPLY(flags, length, frameData); - break; - } - case FrameType_RST_STREAM: { - handleRST_STREAM(flags, length, frameData); - break; - } - case FrameType_SETTINGS: { - handleSETTINGS(flags, length, frameData); - break; - } - case FrameType_PING: { - handlePING(flags, length, frameData); - break; - } - case FrameType_GOAWAY: { - handleGOAWAY(flags, length, frameData); - break; - } - case FrameType_HEADERS: { - handleHEADERS(flags, length, frameData); - break; - } - case FrameType_WINDOW_UPDATE: { - handleWINDOW_UPDATE(flags, length, frameData); - break; - } - default: - qWarning("cannot handle frame of type %d", int(type)); - } -} - -void QSpdyProtocolHandler::handleSYN_STREAM(char /*flags*/, quint32 /*length*/, - const QByteArray &frameData) -{ - // not implemented; will be implemented when servers start using it - // we just tell the server that we do not accept that - - qint32 streamID = getStreamID(frameData.constData()); - - sendRST_STREAM(streamID, RST_STREAM_REFUSED_STREAM); -} - -void QSpdyProtocolHandler::handleSYN_REPLY(char flags, quint32 /*length*/, const QByteArray &frameData) -{ - parseHttpHeaders(flags, frameData); -} - -void QSpdyProtocolHandler::parseHttpHeaders(char flags, const QByteArray &frameData) -{ - qint32 streamID = getStreamID(frameData.constData()); - const auto it = m_inFlightStreams.constFind(streamID); - if (it == m_inFlightStreams.cend()) { - sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM); - return; - } - - flags &= 0x3f; - bool flag_fin = flags & 0x01; - - QByteArray headerValuePairs = frameData.mid(4); - - HttpMessagePair pair = it.value(); - QHttpNetworkReply *httpReply = pair.second; - Q_ASSERT(httpReply != 0); - - if (httpReply->d_func()->state == QHttpNetworkReplyPrivate::SPDYClosed) { - sendRST_STREAM(streamID, RST_STREAM_STREAM_ALREADY_CLOSED); - return; - } - - QByteArray uncompressedHeader; - if (!uncompressHeader(headerValuePairs, &uncompressedHeader)) { - qWarning("error reading header from SYN_REPLY message"); - return; - } - - qint32 headerCount = fourBytesToInt(uncompressedHeader.constData()); - if (headerCount * 8 > uncompressedHeader.size()) { - qWarning("error parsing header from SYN_REPLY message"); - sendRST_STREAM(streamID, RST_STREAM_PROTOCOL_ERROR); - return; - } - qint32 readPointer = 4; - for (qint32 a = 0; a < headerCount; ++a) { - qint32 count = fourBytesToInt(uncompressedHeader.constData() + readPointer); - readPointer += 4; - QByteArray name = uncompressedHeader.mid(readPointer, count); - readPointer += count; - if (readPointer > uncompressedHeader.size()) { - qWarning("error parsing header from SYN_REPLY message"); - sendRST_STREAM(streamID, RST_STREAM_PROTOCOL_ERROR); - return; - } - count = fourBytesToInt(uncompressedHeader.constData() + readPointer); - readPointer += 4; - QByteArray value = uncompressedHeader.mid(readPointer, count); - readPointer += count; - if (readPointer > uncompressedHeader.size()) { - qWarning("error parsing header from SYN_REPLY message"); - sendRST_STREAM(streamID, RST_STREAM_PROTOCOL_ERROR); - return; - } - if (name == ":status") { - httpReply->setStatusCode(value.left(3).toInt()); - httpReply->d_func()->reasonPhrase = QString::fromLatin1(value.mid(4)); - } else if (name == ":version") { - int majorVersion = value.at(5) - 48; - int minorVersion = value.at(7) - 48; - httpReply->d_func()->majorVersion = majorVersion; - httpReply->d_func()->minorVersion = minorVersion; - } else if (name == "content-length") { - httpReply->setContentLength(value.toLongLong()); - } else { - value.replace('\0', name == "set-cookie" ? "\n" : ", "); - httpReply->setHeaderField(name, value); - } - } - emit httpReply->headerChanged(); - - if (flag_fin) { - if (httpReply->d_func()->state != QHttpNetworkReplyPrivate::SPDYHalfClosed) - sendDataFrame(streamID, DataFrame_FLAG_FIN, 0, 0); - replyFinished(httpReply, streamID); - } -} - -void QSpdyProtocolHandler::handleRST_STREAM(char /*flags*/, quint32 length, - const QByteArray &frameData) -{ - // flags are ignored - - Q_ASSERT(length == 8); - Q_UNUSED(length); // silence -Wunused-parameter - qint32 streamID = getStreamID(frameData.constData()); - QHttpNetworkReply *httpReply = m_inFlightStreams.value(streamID).second; - - qint32 statusCodeInt = fourBytesToInt(frameData.constData() + 4); - RST_STREAM_STATUS_CODE statusCode = static_cast(statusCodeInt); - QNetworkReply::NetworkError errorCode; - QByteArray errorMessage; - - switch (statusCode) { - case RST_STREAM_PROTOCOL_ERROR: - errorCode = QNetworkReply::ProtocolFailure; - errorMessage = "SPDY protocol error"; - break; - case RST_STREAM_INVALID_STREAM: - errorCode = QNetworkReply::ProtocolFailure; - errorMessage = "SPDY stream is not active"; - break; - case RST_STREAM_REFUSED_STREAM: - errorCode = QNetworkReply::ProtocolFailure; - errorMessage = "SPDY stream was refused"; - break; - case RST_STREAM_UNSUPPORTED_VERSION: - errorCode = QNetworkReply::ProtocolUnknownError; - errorMessage = "SPDY version is unknown to the server"; - break; - case RST_STREAM_CANCEL: - errorCode = QNetworkReply::ProtocolFailure; - errorMessage = "SPDY stream is no longer needed"; - break; - case RST_STREAM_INTERNAL_ERROR: - errorCode = QNetworkReply::InternalServerError; - errorMessage = "Internal server error"; - break; - case RST_STREAM_FLOW_CONTROL_ERROR: - errorCode = QNetworkReply::ProtocolFailure; - errorMessage = "peer violated the flow control protocol"; - break; - case RST_STREAM_STREAM_IN_USE: - errorCode = QNetworkReply::ProtocolFailure; - errorMessage = "server received a SYN_REPLY for an already open stream"; - break; - case RST_STREAM_STREAM_ALREADY_CLOSED: - errorCode = QNetworkReply::ProtocolFailure; - errorMessage = "server received data or a SYN_REPLY for an already half-closed stream"; - break; - case RST_STREAM_INVALID_CREDENTIALS: - errorCode = QNetworkReply::ContentAccessDenied; - errorMessage = "server received invalid credentials"; - break; - case RST_STREAM_FRAME_TOO_LARGE: - errorCode = QNetworkReply::ProtocolFailure; - errorMessage = "server cannot process the frame because it is too large"; - break; - default: - qWarning("could not understand servers RST_STREAM status code"); - errorCode = QNetworkReply::ProtocolFailure; - errorMessage = "got SPDY RST_STREAM message with unknown error code"; - } - if (httpReply) - replyFinishedWithError(httpReply, streamID, errorCode, errorMessage.constData()); -} - -void QSpdyProtocolHandler::handleSETTINGS(char flags, quint32 /*length*/, const QByteArray &frameData) -{ - Q_ASSERT(frameData.count() > 0); - - SETTINGS_Flags settingsFlags = static_cast(flags); - if (settingsFlags & FLAG_SETTINGS_CLEAR_SETTINGS) { - // ### clear all persistent settings; since we do not persist settings - // as of now, we don't need to clear anything either - } - - qint32 numberOfEntries = fourBytesToInt(frameData.constData()); - Q_ASSERT(numberOfEntries > 0); - for (int a = 0, frameDataIndex = 4; a < numberOfEntries; ++a, frameDataIndex += 8) { - SETTINGS_ID_Flag idFlag = static_cast(frameData[frameDataIndex]); - if (idFlag & FLAG_SETTINGS_PERSIST_VALUE) { - // ### we SHOULD persist the settings here according to the RFC, but we don't have to, - // so implement that later - } // the other value is only sent by us, but not received - - quint32 uniqueID = static_cast( - threeBytesToInt(frameData.constData() + frameDataIndex + 1)); - quint32 value = fourBytesToInt(frameData.constData() + frameDataIndex + 4); - switch (uniqueID) { - case SETTINGS_UPLOAD_BANDWIDTH: { - // ignored for now, just an estimated informative value - break; - } - case SETTINGS_DOWNLOAD_BANDWIDTH: { - // ignored for now, just an estimated informative value - break; - } - case SETTINGS_ROUND_TRIP_TIME: { - // ignored for now, just an estimated informative value - break; - } - case SETTINGS_MAX_CONCURRENT_STREAMS: { - m_maxConcurrentStreams = value; - break; - } - case SETTINGS_CURRENT_CWND: { - // ignored for now, just an informative value - break; - } - case SETTINGS_DOWNLOAD_RETRANS_RATE: { - // ignored for now, just an estimated informative value - break; - } - case SETTINGS_INITIAL_WINDOW_SIZE: { - m_initialWindowSize = value; - break; - } - case SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE: { - // client certificates are not supported - break; - } - default: - qWarning("found unknown settings value %u", uint(value)); - } - } -} - -void QSpdyProtocolHandler::handlePING(char /*flags*/, quint32 length, const QByteArray &frameData) -{ - // flags are ignored - - Q_ASSERT(length == 4); - Q_UNUSED(length); // silence -Wunused-parameter - quint32 pingID = fourBytesToInt(frameData.constData()); - - // odd numbered IDs must be ignored - if ((pingID & 1) == 0) // is even? - sendPING(pingID); -} - -void QSpdyProtocolHandler::handleGOAWAY(char /*flags*/, quint32 /*length*/, - const QByteArray &frameData) -{ - // flags are ignored - - qint32 statusCode = static_cast(fourBytesToInt(frameData.constData() + 4)); - QNetworkReply::NetworkError errorCode; - switch (statusCode) { - case GOAWAY_OK: { - errorCode = QNetworkReply::NoError; - break; - } - case GOAWAY_PROTOCOL_ERROR: { - errorCode = QNetworkReply::ProtocolFailure; - break; - } - case GOAWAY_INTERNAL_ERROR: { - errorCode = QNetworkReply::InternalServerError; - break; - } - default: - qWarning("unexpected status code %d", int(statusCode)); - errorCode = QNetworkReply::ProtocolUnknownError; - } - - qint32 lastGoodStreamID = getStreamID(frameData.constData()); - - // emit errors for all replies after the last good stream ID - Q_ASSERT(m_connection); - for (qint32 currentStreamID = lastGoodStreamID + 2; currentStreamID <= m_nextStreamID; - ++currentStreamID) { - QHttpNetworkReply *reply = m_inFlightStreams.value(currentStreamID).second; - Q_ASSERT(reply); - m_connection->d_func()->emitReplyError(m_socket, reply, errorCode); - } - // ### we could make sure a new session is initiated anyhow -} - -void QSpdyProtocolHandler::handleHEADERS(char flags, quint32 /*length*/, - const QByteArray &frameData) -{ - parseHttpHeaders(flags, frameData); -} - -void QSpdyProtocolHandler::handleWINDOW_UPDATE(char /*flags*/, quint32 /*length*/, - const QByteArray &frameData) -{ - qint32 streamID = getStreamID(frameData.constData()); - qint32 deltaWindowSize = fourBytesToInt(frameData.constData() + 4); - - const auto it = m_inFlightStreams.constFind(streamID); - if (it == m_inFlightStreams.cend()) { - sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM); - return; - } - - QHttpNetworkReply *reply = it.value().second; - Q_ASSERT(reply); - QHttpNetworkReplyPrivate *replyPrivate = reply->d_func(); - Q_ASSERT(replyPrivate); - - // Ignore WINDOW_UPDATE if we are already done. - if (replyPrivate->state == QHttpNetworkReplyPrivate::SPDYHalfClosed || replyPrivate->state == QHttpNetworkReplyPrivate::SPDYClosed) - return; - - replyPrivate->currentlyUploadedDataInWindow = replyPrivate->windowSizeUpload - deltaWindowSize; - uploadData(streamID); // we hopefully can continue to upload -} - - -void QSpdyProtocolHandler::handleDataFrame(const QByteArray &frameHeaders) -{ - Q_ASSERT(frameHeaders.count() >= 8); - - qint32 streamID = getStreamID(frameHeaders.constData()); - const auto it = m_inFlightStreams.constFind(streamID); - if (it == m_inFlightStreams.cend()) { - sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM); - return; - } - - unsigned char flags = static_cast(frameHeaders.at(4)); - flags &= 0x3f; - bool flag_fin = flags & 0x01; - bool flag_compress = flags & 0x02; - qint32 length = threeBytesToInt(frameHeaders.constData() + 5); - - QByteArray data; - data.resize(length); - if (!readNextChunk(length, data.data())) { - // put back the frame headers to the buffer - m_spdyBuffer.prepend(frameHeaders); - return; // we couldn't read the whole frame and need to wait - } else { - m_spdyBuffer.clear(); - m_waitingForCompleteStream = false; - } - - HttpMessagePair pair = it.value(); - QHttpNetworkRequest httpRequest = pair.first; - QHttpNetworkReply *httpReply = pair.second; - Q_ASSERT(httpReply != 0); - - QHttpNetworkReplyPrivate *replyPrivate = httpReply->d_func(); - - if (replyPrivate->state == QHttpNetworkReplyPrivate::SPDYClosed) { - sendRST_STREAM(streamID, RST_STREAM_STREAM_ALREADY_CLOSED); - return; - } - - // check whether we need to send WINDOW_UPDATE (i.e. tell the sender it can send more) - replyPrivate->currentlyReceivedDataInWindow += length; - qint32 dataLeftInWindow = replyPrivate->windowSizeDownload - replyPrivate->currentlyReceivedDataInWindow; - - if (replyPrivate->currentlyReceivedDataInWindow > 0 - && dataLeftInWindow < replyPrivate->windowSizeDownload / 2) { - - // socket read buffer size is 64K actually, hard coded in the channel - // We can read way more than 64K per socket, because the window size - // here is per stream. - if (replyPrivate->windowSizeDownload >= m_socket->readBufferSize()) { - replyPrivate->windowSizeDownload = m_socket->readBufferSize(); - } else { - replyPrivate->windowSizeDownload *= 1.5; - } - QMetaObject::invokeMethod(this, "sendWINDOW_UPDATE", Qt::QueuedConnection, - Q_ARG(qint32, streamID), - Q_ARG(quint32, replyPrivate->windowSizeDownload)); - // setting the current data count to 0 is a race condition, - // because we call sendWINDOW_UPDATE through the event loop. - // But then again, the whole situation is a race condition because - // we don't know when the packet will arrive at the server; so - // this is most likely good enough here. - replyPrivate->currentlyReceivedDataInWindow = 0; - } - - httpReply->d_func()->compressedData.append(data); - - - replyPrivate->totalProgress += length; - - if (httpRequest.d->autoDecompress && httpReply->d_func()->isCompressed()) { - QByteDataBuffer inDataBuffer; // ### should we introduce one in the http reply? - inDataBuffer.append(data); - qint64 compressedCount = httpReply->d_func()->uncompressBodyData(&inDataBuffer, - &replyPrivate->responseData); - Q_ASSERT(compressedCount >= 0); - Q_UNUSED(compressedCount); // silence -Wunused-variable - } else { - replyPrivate->responseData.append(data); - } - - if (replyPrivate->shouldEmitSignals()) { - emit httpReply->readyRead(); - emit httpReply->dataReadProgress(replyPrivate->totalProgress, replyPrivate->bodyLength); - } - - if (flag_compress) { - qWarning("SPDY level compression is not supported"); - } - - if (flag_fin) { - if (httpReply->d_func()->state != QHttpNetworkReplyPrivate::SPDYHalfClosed) - sendDataFrame(streamID, DataFrame_FLAG_FIN, 0, 0); - replyFinished(httpReply, streamID); - } -} - -void QSpdyProtocolHandler::replyFinished(QHttpNetworkReply *httpReply, qint32 streamID) -{ - httpReply->d_func()->state = QHttpNetworkReplyPrivate::SPDYClosed; - httpReply->disconnect(this); - if (httpReply->request().uploadByteDevice()) - httpReply->request().uploadByteDevice()->disconnect(this); - int streamsRemoved = m_inFlightStreams.remove(streamID); - Q_ASSERT(streamsRemoved == 1); - Q_UNUSED(streamsRemoved); // silence -Wunused-variable - emit httpReply->finished(); -} - -void QSpdyProtocolHandler::replyFinishedWithError(QHttpNetworkReply *httpReply, qint32 streamID, - QNetworkReply::NetworkError errorCode, const char *errorMessage) -{ - Q_ASSERT(httpReply); - httpReply->d_func()->state = QHttpNetworkReplyPrivate::SPDYClosed; - httpReply->disconnect(this); - if (httpReply->request().uploadByteDevice()) - httpReply->request().uploadByteDevice()->disconnect(this); - int streamsRemoved = m_inFlightStreams.remove(streamID); - Q_ASSERT(streamsRemoved == 1); - Q_UNUSED(streamsRemoved); // silence -Wunused-variable - emit httpReply->finishedWithError(errorCode, QSpdyProtocolHandler::tr(errorMessage)); -} - -qint32 QSpdyProtocolHandler::generateNextStreamID() -{ - // stream IDs initiated by the client must be odd - m_nextStreamID += 2; - return m_nextStreamID; -} - -QT_END_NAMESPACE - -#endif // !defined(QT_NO_SSL) diff --git a/src/network/access/qspdyprotocolhandler_p.h b/src/network/access/qspdyprotocolhandler_p.h deleted file mode 100644 index 14e2ff388a..0000000000 --- a/src/network/access/qspdyprotocolhandler_p.h +++ /dev/null @@ -1,232 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 BlackBerry Limited. All rights reserved. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtNetwork module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSPDYPROTOCOLHANDLER_H -#define QSPDYPROTOCOLHANDLER_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 -#include -#include -#include - -#include - -QT_REQUIRE_CONFIG(http); - -#if !defined(QT_NO_SSL) - -QT_BEGIN_NAMESPACE - -class QHttpNetworkRequest; - -#ifndef HttpMessagePair -typedef QPair HttpMessagePair; -#endif - -class QSpdyProtocolHandler : public QObject, public QAbstractProtocolHandler { - Q_OBJECT -public: - QSpdyProtocolHandler(QHttpNetworkConnectionChannel *channel); - ~QSpdyProtocolHandler(); - - enum DataFrameFlag { - DataFrame_FLAG_FIN = 0x01, - DataFrame_FLAG_COMPRESS = 0x02 - }; - - Q_DECLARE_FLAGS(DataFrameFlags, DataFrameFlag) - - enum ControlFrameFlag { - ControlFrame_FLAG_FIN = 0x01, - ControlFrame_FLAG_UNIDIRECTIONAL = 0x02 - }; - - Q_DECLARE_FLAGS(ControlFrameFlags, ControlFrameFlag) - - enum SETTINGS_Flag { - FLAG_SETTINGS_CLEAR_SETTINGS = 0x01 - }; - - Q_DECLARE_FLAGS(SETTINGS_Flags, SETTINGS_Flag) - - enum SETTINGS_ID_Flag { - FLAG_SETTINGS_PERSIST_VALUE = 0x01, - FLAG_SETTINGS_PERSISTED = 0x02 - }; - - Q_DECLARE_FLAGS(SETTINGS_ID_Flags, SETTINGS_ID_Flag) - - virtual void _q_receiveReply() override; - virtual void _q_readyRead() override; - virtual bool sendRequest() override; - -private slots: - void _q_uploadDataReadyRead(); - void _q_replyDestroyed(QObject*); - void _q_uploadDataDestroyed(QObject *); - -private: - - enum FrameType { - FrameType_SYN_STREAM = 1, - FrameType_SYN_REPLY = 2, - FrameType_RST_STREAM = 3, - FrameType_SETTINGS = 4, - FrameType_PING = 6, - FrameType_GOAWAY = 7, - FrameType_HEADERS = 8, - FrameType_WINDOW_UPDATE = 9, - FrameType_CREDENTIAL // has a special type - }; - - enum StatusCode { - StatusCode_PROTOCOL_ERROR = 1, - StatusCode_INVALID_STREAM = 2, - StatusCode_REFUSED_STREAM = 3, - StatusCode_UNSUPPORTED_VERSION = 4, - StatusCode_CANCEL = 5, - StatusCode_INTERNAL_ERROR = 6, - StatusCode_FLOW_CONTROL_ERROR = 7, - StatusCode_STREAM_IN_USE = 8, - StatusCode_STREAM_ALREADY_CLOSED = 9, - StatusCode_INVALID_CREDENTIALS = 10, - StatusCode_FRAME_TOO_LARGE = 11 - }; - - enum SETTINGS_ID { - SETTINGS_UPLOAD_BANDWIDTH = 1, - SETTINGS_DOWNLOAD_BANDWIDTH = 2, - SETTINGS_ROUND_TRIP_TIME = 3, - SETTINGS_MAX_CONCURRENT_STREAMS = 4, - SETTINGS_CURRENT_CWND = 5, - SETTINGS_DOWNLOAD_RETRANS_RATE = 6, - SETTINGS_INITIAL_WINDOW_SIZE = 7, - SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8 - }; - - enum GOAWAY_STATUS { - GOAWAY_OK = 0, - GOAWAY_PROTOCOL_ERROR = 1, - GOAWAY_INTERNAL_ERROR = 11 - }; - - enum RST_STREAM_STATUS_CODE { - RST_STREAM_PROTOCOL_ERROR = 1, - RST_STREAM_INVALID_STREAM = 2, - RST_STREAM_REFUSED_STREAM = 3, - RST_STREAM_UNSUPPORTED_VERSION = 4, - RST_STREAM_CANCEL = 5, - RST_STREAM_INTERNAL_ERROR = 6, - RST_STREAM_FLOW_CONTROL_ERROR = 7, - RST_STREAM_STREAM_IN_USE = 8, - RST_STREAM_STREAM_ALREADY_CLOSED = 9, - RST_STREAM_INVALID_CREDENTIALS = 10, - RST_STREAM_FRAME_TOO_LARGE = 11 - }; - - quint64 bytesAvailable() const; - bool readNextChunk(qint64 length, char *sink); - - void sendControlFrame(FrameType type, ControlFrameFlags flags, const char *data, quint32 length); - - void sendSYN_STREAM(const HttpMessagePair &pair, qint32 streamID, - qint32 associatedToStreamID); - void sendRST_STREAM(qint32 streamID, RST_STREAM_STATUS_CODE statusCode); - void sendPING(quint32 pingID); - - bool uploadData(qint32 streamID); - Q_INVOKABLE void sendWINDOW_UPDATE(qint32 streamID, quint32 deltaWindowSize); - - qint64 sendDataFrame(qint32 streamID, DataFrameFlags flags, quint32 length, - const char *data); - - QByteArray composeHeader(const QHttpNetworkRequest &request); - bool uncompressHeader(const QByteArray &input, QByteArray *output); - - void handleControlFrame(const QByteArray &frameHeaders); - void handleDataFrame(const QByteArray &frameHeaders); - - void handleSYN_STREAM(char, quint32, const QByteArray &frameData); - void handleSYN_REPLY(char flags, quint32, const QByteArray &frameData); - void handleRST_STREAM(char flags, quint32 length, const QByteArray &frameData); - void handleSETTINGS(char flags, quint32 length, const QByteArray &frameData); - void handlePING(char, quint32 length, const QByteArray &frameData); - void handleGOAWAY(char flags, quint32, const QByteArray &frameData); - void handleHEADERS(char flags, quint32, const QByteArray &frameData); - void handleWINDOW_UPDATE(char, quint32, const QByteArray &frameData); - - qint32 generateNextStreamID(); - void parseHttpHeaders(char flags, const QByteArray &frameData); - - void replyFinished(QHttpNetworkReply *httpReply, qint32 streamID); - void replyFinishedWithError(QHttpNetworkReply *httpReply, qint32 streamID, - QNetworkReply::NetworkError errorCode, const char *errorMessage); - - qint32 m_nextStreamID; - QHash m_inFlightStreams; - qint32 m_maxConcurrentStreams; - quint32 m_initialWindowSize; - QByteDataBuffer m_spdyBuffer; - bool m_waitingForCompleteStream; - z_stream m_deflateStream; - z_stream m_inflateStream; - QHash m_streamIDs; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::DataFrameFlags) -Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::ControlFrameFlags) -Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::SETTINGS_Flags) -Q_DECLARE_OPERATORS_FOR_FLAGS(QSpdyProtocolHandler::SETTINGS_ID_Flags) - -QT_END_NAMESPACE - -#endif // !defined(QT_NO_SSL) - -#endif // QSPDYPROTOCOLHANDLER_H -- cgit v1.2.3 From 6e203824a22bfb424032f27e11a5914c26bf0068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Nordheim?= Date: Tue, 1 Oct 2019 12:13:47 +0200 Subject: Move away from recently deprecated HTTP2 attributes Amends f59f67287fa17e8d4edf6a231c010f768d1b76e8 Change-Id: I74045c558e9d20f9f45f150a91f181a04e9b8c69 Reviewed-by: Friedemann Kleint --- src/network/access/qnetworkaccessmanager.cpp | 2 +- src/network/access/qnetworkreplyhttpimpl.cpp | 8 ++++---- src/network/access/qnetworkrequest.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/network/access') diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 76b95b5823..98c82c81ae 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1240,7 +1240,7 @@ void QNetworkAccessManager::connectToHostEncrypted(const QString &hostName, quin // There is no way to enable SPDY/HTTP2 via a request, so we need to check // the ssl configuration whether SPDY/HTTP2 is allowed here. if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::ALPNProtocolHTTP2)) - request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true); + request.setAttribute(QNetworkRequest::Http2AllowedAttribute, true); else if (sslConfiguration.allowedNextProtocols().contains(QSslConfiguration::NextProtocolSpdy3_0)) request.setAttribute(QNetworkRequest::SpdyAllowedAttribute, true); diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index 8ac81d1780..44c1d3e422 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -777,7 +777,7 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq if (request.attribute(QNetworkRequest::SpdyAllowedAttribute).toBool()) httpRequest.setSPDYAllowed(true); - if (request.attribute(QNetworkRequest::HTTP2AllowedAttribute).toBool()) + if (request.attribute(QNetworkRequest::Http2AllowedAttribute).toBool()) httpRequest.setHTTP2Allowed(true); if (request.attribute(QNetworkRequest::Http2DirectAttribute).toBool()) { @@ -1280,15 +1280,15 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QListsetAttribute(QNetworkRequest::HttpPipeliningWasUsedAttribute, pu); - const QVariant http2Allowed = request.attribute(QNetworkRequest::HTTP2AllowedAttribute); + const QVariant http2Allowed = request.attribute(QNetworkRequest::Http2AllowedAttribute); const QVariant http2Direct = request.attribute(QNetworkRequest::Http2DirectAttribute); if ((http2Allowed.isValid() && http2Allowed.toBool()) || (http2Direct.isValid() && http2Direct.toBool())) { - q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, spdyWasUsed); + q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, spdyWasUsed); q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, false); } else { q->setAttribute(QNetworkRequest::SpdyWasUsedAttribute, spdyWasUsed); - q->setAttribute(QNetworkRequest::HTTP2WasUsedAttribute, false); + q->setAttribute(QNetworkRequest::Http2WasUsedAttribute, false); } // reconstruct the HTTP header diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index cedb1597de..7899bce32b 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -336,7 +336,7 @@ QT_BEGIN_NAMESPACE server supports HTTP/2. The attribute works with SSL or 'cleartext' HTTP/2. If a server turns out to not support HTTP/2, when HTTP/2 direct was specified, QNetworkAccessManager gives up, without attempting to - fall back to HTTP/1.1. If both HTTP2AllowedAttribute and + fall back to HTTP/1.1. If both Http2AllowedAttribute and Http2DirectAttribute are set, Http2DirectAttribute takes priority. (This value was introduced in 5.11.) -- cgit v1.2.3 From 3afe4a402c18a0956cab31169d843018d1b7a6d3 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Thu, 3 Oct 2019 17:08:13 +0200 Subject: Convert a few sizeof(array)/sizeof(element0) fors to range fors Increases readability Change-Id: I81ea915517fd2cd6bc2780f37ba8d8097c63f44b Reviewed-by: Thiago Macieira Reviewed-by: Volker Hilsheimer --- src/network/access/qhttp2protocolhandler.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'src/network/access') diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 9bf5547f15..dce51d4fd5 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -1339,14 +1339,13 @@ void QHttp2ProtocolHandler::markAsReset(quint32 streamID) quint32 QHttp2ProtocolHandler::popStreamToResume() { quint32 streamID = connectionStreamID; - const int nQ = sizeof suspendedStreams / sizeof suspendedStreams[0]; using QNR = QHttpNetworkRequest; - const QNR::Priority ranks[nQ] = {QNR::HighPriority, - QNR::NormalPriority, - QNR::LowPriority}; + const QNR::Priority ranks[] = {QNR::HighPriority, + QNR::NormalPriority, + QNR::LowPriority}; - for (int i = 0; i < nQ; ++i) { - auto &queue = suspendedStreams[ranks[i]]; + for (const QNR::Priority rank : ranks) { + auto &queue = suspendedStreams[rank]; auto it = queue.begin(); for (; it != queue.end(); ++it) { if (!activeStreams.contains(*it)) @@ -1367,9 +1366,7 @@ quint32 QHttp2ProtocolHandler::popStreamToResume() void QHttp2ProtocolHandler::removeFromSuspended(quint32 streamID) { - const int nQ = sizeof suspendedStreams / sizeof suspendedStreams[0]; - for (int i = 0; i < nQ; ++i) { - auto &q = suspendedStreams[i]; + for (auto &q : suspendedStreams) { q.erase(std::remove(q.begin(), q.end(), streamID), q.end()); } } -- cgit v1.2.3 From bfed3cf41947baec29e88585cfdebf8ebae6ad39 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Wed, 2 Oct 2019 12:10:28 +0200 Subject: Get rid of QList forward declarations Include qcontainerfwd.h instead where required. This prepares for unifying QList and QVector. Change-Id: I6c85e2bdd44fb41aedd884b0d551f682760df5b5 Reviewed-by: Thiago Macieira --- src/network/access/qabstractnetworkcache.h | 1 - src/network/access/qhsts_p.h | 1 - src/network/access/qnetworkaccessmanager.h | 1 - 3 files changed, 3 deletions(-) (limited to 'src/network/access') diff --git a/src/network/access/qabstractnetworkcache.h b/src/network/access/qabstractnetworkcache.h index e357dfe58f..a4048c5b8f 100644 --- a/src/network/access/qabstractnetworkcache.h +++ b/src/network/access/qabstractnetworkcache.h @@ -52,7 +52,6 @@ QT_BEGIN_NAMESPACE class QIODevice; class QDateTime; class QUrl; -template class QList; class QNetworkCacheMetaDataPrivate; class Q_NETWORK_EXPORT QNetworkCacheMetaData diff --git a/src/network/access/qhsts_p.h b/src/network/access/qhsts_p.h index c219d9eab5..b5be4ff455 100644 --- a/src/network/access/qhsts_p.h +++ b/src/network/access/qhsts_p.h @@ -66,7 +66,6 @@ QT_BEGIN_NAMESPACE -template class QList; template class QVector; class Q_AUTOTEST_EXPORT QHstsCache diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 98498d07d2..a74ece6d5b 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -56,7 +56,6 @@ class QIODevice; class QAbstractNetworkCache; class QAuthenticator; class QByteArray; -template class QList; class QNetworkCookie; class QNetworkCookieJar; class QNetworkReply; -- cgit v1.2.3