|
| 1 | +diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp |
| 2 | +index d1b5dfda2e2..ee04a1856c6 100644 |
| 3 | +--- a/src/network/access/qhttp2protocolhandler.cpp |
| 4 | ++++ b/src/network/access/qhttp2protocolhandler.cpp |
| 5 | +@@ -375,12 +375,12 @@ bool QHttp2ProtocolHandler::sendRequest() |
| 6 | + } |
| 7 | + } |
| 8 | + |
| 9 | +- if (!prefaceSent && !sendClientPreface()) |
| 10 | +- return false; |
| 11 | +- |
| 12 | + if (!requests.size()) |
| 13 | + return true; |
| 14 | + |
| 15 | ++ if (!prefaceSent && !sendClientPreface()) |
| 16 | ++ return false; |
| 17 | ++ |
| 18 | + m_channel->state = QHttpNetworkConnectionChannel::WritingState; |
| 19 | + // Check what was promised/pushed, maybe we do not have to send a request |
| 20 | + // and have a response already? |
| 21 | +diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp |
| 22 | +index bd2f32e3528..6f3bd807a09 100644 |
| 23 | +--- a/src/network/access/qhttpnetworkconnectionchannel.cpp |
| 24 | ++++ b/src/network/access/qhttpnetworkconnectionchannel.cpp |
| 25 | +@@ -255,6 +255,10 @@ void QHttpNetworkConnectionChannel::abort() |
| 26 | + bool QHttpNetworkConnectionChannel::sendRequest() |
| 27 | + { |
| 28 | + Q_ASSERT(!protocolHandler.isNull()); |
| 29 | ++ if (waitingForPotentialAbort) { |
| 30 | ++ needInvokeSendRequest = true; |
| 31 | ++ return false; // this return value is unused |
| 32 | ++ } |
| 33 | + return protocolHandler->sendRequest(); |
| 34 | + } |
| 35 | + |
| 36 | +@@ -267,21 +271,28 @@ bool QHttpNetworkConnectionChannel::sendRequest() |
| 37 | + void QHttpNetworkConnectionChannel::sendRequestDelayed() |
| 38 | + { |
| 39 | + QMetaObject::invokeMethod(this, [this] { |
| 40 | +- Q_ASSERT(!protocolHandler.isNull()); |
| 41 | + if (reply) |
| 42 | +- protocolHandler->sendRequest(); |
| 43 | ++ sendRequest(); |
| 44 | + }, Qt::ConnectionType::QueuedConnection); |
| 45 | + } |
| 46 | + |
| 47 | + void QHttpNetworkConnectionChannel::_q_receiveReply() |
| 48 | + { |
| 49 | + Q_ASSERT(!protocolHandler.isNull()); |
| 50 | ++ if (waitingForPotentialAbort) { |
| 51 | ++ needInvokeReceiveReply = true; |
| 52 | ++ return; |
| 53 | ++ } |
| 54 | + protocolHandler->_q_receiveReply(); |
| 55 | + } |
| 56 | + |
| 57 | + void QHttpNetworkConnectionChannel::_q_readyRead() |
| 58 | + { |
| 59 | + Q_ASSERT(!protocolHandler.isNull()); |
| 60 | ++ if (waitingForPotentialAbort) { |
| 61 | ++ needInvokeReadyRead = true; |
| 62 | ++ return; |
| 63 | ++ } |
| 64 | + protocolHandler->_q_readyRead(); |
| 65 | + } |
| 66 | + |
| 67 | +@@ -1289,7 +1300,18 @@ void QHttpNetworkConnectionChannel::_q_encrypted() |
| 68 | + // Similar to HTTP/1.1 counterpart below: |
| 69 | + const auto &pairs = spdyRequestsToSend.values(); // (request, reply) |
| 70 | + const auto &pair = pairs.first(); |
| 71 | ++ waitingForPotentialAbort = true; |
| 72 | + emit pair.second->encrypted(); |
| 73 | ++ |
| 74 | ++ // We don't send or handle any received data until any effects from |
| 75 | ++ // emitting encrypted() have been processed. This is necessary |
| 76 | ++ // because the user may have called abort(). We may also abort the |
| 77 | ++ // whole connection if the request has been aborted and there is |
| 78 | ++ // no more requests to send. |
| 79 | ++ QMetaObject::invokeMethod(this, |
| 80 | ++ &QHttpNetworkConnectionChannel::checkAndResumeCommunication, |
| 81 | ++ Qt::QueuedConnection); |
| 82 | ++ |
| 83 | + // In case our peer has sent us its settings (window size, max concurrent streams etc.) |
| 84 | + // let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection). |
| 85 | + QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); |
| 86 | +@@ -1307,6 +1329,26 @@ void QHttpNetworkConnectionChannel::_q_encrypted() |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | ++void QHttpNetworkConnectionChannel::checkAndResumeCommunication() |
| 91 | ++{ |
| 92 | ++ Q_ASSERT(connection->connectionType() > QHttpNetworkConnection::ConnectionTypeHTTP); |
| 93 | ++ |
| 94 | ++ // Because HTTP/2 requires that we send a SETTINGS frame as the first thing we do, and respond |
| 95 | ++ // to a SETTINGS frame with an ACK, we need to delay any handling until we can ensure that any |
| 96 | ++ // effects from emitting encrypted() have been processed. |
| 97 | ++ // This function is called after encrypted() was emitted, so check for changes. |
| 98 | ++ |
| 99 | ++ if (!reply && spdyRequestsToSend.isEmpty()) |
| 100 | ++ abort(); |
| 101 | ++ waitingForPotentialAbort = false; |
| 102 | ++ if (needInvokeReadyRead) |
| 103 | ++ _q_readyRead(); |
| 104 | ++ if (needInvokeReceiveReply) |
| 105 | ++ _q_receiveReply(); |
| 106 | ++ if (needInvokeSendRequest) |
| 107 | ++ sendRequest(); |
| 108 | ++} |
| 109 | ++ |
| 110 | + void QHttpNetworkConnectionChannel::requeueSpdyRequests() |
| 111 | + { |
| 112 | + QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values(); |
| 113 | +diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h |
| 114 | +index 6be0c51f9fe..613fda7bc31 100644 |
| 115 | +--- a/src/network/access/qhttpnetworkconnectionchannel_p.h |
| 116 | ++++ b/src/network/access/qhttpnetworkconnectionchannel_p.h |
| 117 | +@@ -107,6 +107,10 @@ public: |
| 118 | + QAbstractSocket *socket; |
| 119 | + bool ssl; |
| 120 | + bool isInitialized; |
| 121 | ++ bool waitingForPotentialAbort = false; |
| 122 | ++ bool needInvokeReceiveReply = false; |
| 123 | ++ bool needInvokeReadyRead = false; |
| 124 | ++ bool needInvokeSendRequest = false; |
| 125 | + ChannelState state; |
| 126 | + QHttpNetworkRequest request; // current request, only used for HTTP |
| 127 | + QHttpNetworkReply *reply; // current reply for this request, only used for HTTP |
| 128 | +@@ -187,6 +191,8 @@ public: |
| 129 | + void closeAndResendCurrentRequest(); |
| 130 | + void resendCurrentRequest(); |
| 131 | + |
| 132 | ++ void checkAndResumeCommunication(); |
| 133 | ++ |
| 134 | + bool isSocketBusy() const; |
| 135 | + bool isSocketWriting() const; |
| 136 | + bool isSocketWaiting() const; |
0 commit comments