summaryrefslogtreecommitdiffstats
path: root/src/network/access/qhttp2protocolhandler.cpp
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2017-07-27 14:34:39 +0200
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2017-08-27 04:54:55 +0000
commit53357f01561d7c2b50e0a656ca250f5e3c1af923 (patch)
tree28ac5a34217efb50a4844d498794baedc72d66ae /src/network/access/qhttp2protocolhandler.cpp
parentfabedd399ebe4d28d6eb62c8a863f1bbcce78d3a (diff)
HTTP/2 - implement the proper 'h2c' (protocol upgrade)
Without TLS (and thus ALPN/NPN negotiation) HTTP/2 requires a protocol upgrade procedure, as described in RFC 7540, 3.2. We start as HTTP/1.1 (and thus we create QHttpProtocolHandler first), augmenting the headers we send with 'Upgrade: h2c'. In case we receive HTTP/1.1 response with status code 101 ('Switching Protocols'), we continue as HTTP/2 session, creating QHttp2ProtocolHandler and pretending the first request we sent was HTTP/2 request on a real HTTP/2 stream. If the first response is something different from 101, we continue as HTTP/1.1. This change also required auto-test update: our toy-server now has to respond to the initial HTTP/1.1 request on a platform without ALPN/NPN. As a bonus a subtle flakyness in 'goaway' auto-test went away (well, it was fixed). [ChangeLog][QtNetwork][HTTP/2] In case of clear text HTTP/2 we now initiate a required protocol upgrade procedure instead of 'H2Direct' connection. Task-number: QTBUG-61397 Change-Id: I573fa304fdaf661490159037dc47775d97c8ea5b Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'src/network/access/qhttp2protocolhandler.cpp')
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp38
1 files changed, 24 insertions, 14 deletions
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index 44ab637da8..5032f6017f 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -170,10 +170,22 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan
decoder(HPack::FieldLookupTable::DefaultSize),
encoder(HPack::FieldLookupTable::DefaultSize, true)
{
+ Q_ASSERT(channel);
continuedFrames.reserve(20);
- bool ok = false;
- const int env = qEnvironmentVariableIntValue("QT_HTTP2_ENABLE_PUSH_PROMISE", &ok);
- pushPromiseEnabled = ok && env;
+ pushPromiseEnabled = is_PUSH_PROMISE_enabled();
+
+ if (!channel->ssl) {
+ // We upgraded from HTTP/1.1 to HTTP/2. channel->request was already sent
+ // as HTTP/1.1 request. The response with status code 101 triggered
+ // protocol switch and now we are waiting for the real response, sent
+ // as HTTP/2 frames.
+ Q_ASSERT(channel->reply);
+ const quint32 initialStreamID = createNewStream(HttpMessagePair(channel->request, channel->reply),
+ true /* uploaded by HTTP/1.1 */);
+ Q_ASSERT(initialStreamID == 1);
+ Stream &stream = activeStreams[initialStreamID];
+ stream.state = Stream::halfClosedLocal;
+ }
}
void QHttp2ProtocolHandler::_q_uploadDataReadyRead()
@@ -356,12 +368,8 @@ bool QHttp2ProtocolHandler::sendClientPreface()
return false;
// 6.5 SETTINGS
- frameWriter.start(FrameType::SETTINGS, FrameFlag::EMPTY, Http2::connectionStreamID);
- // MAX frame size (16 kb), enable/disable PUSH
- frameWriter.append(Settings::MAX_FRAME_SIZE_ID);
- frameWriter.append(quint32(Http2::maxFrameSize));
- frameWriter.append(Settings::ENABLE_PUSH_ID);
- frameWriter.append(quint32(pushPromiseEnabled));
+ frameWriter.setOutboundFrame(default_SETTINGS_frame());
+ Q_ASSERT(frameWriter.outboundFrame().payloadSize());
if (!frameWriter.write(*m_socket))
return false;
@@ -1157,7 +1165,7 @@ void QHttp2ProtocolHandler::finishStreamWithError(Stream &stream, QNetworkReply:
<< "finished with error:" << message;
}
-quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message)
+quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message, bool uploadDone)
{
const qint32 newStreamID = allocateStreamID();
if (!newStreamID)
@@ -1178,10 +1186,12 @@ quint32 QHttp2ProtocolHandler::createNewStream(const HttpMessagePair &message)
streamInitialSendWindowSize,
streamInitialRecvWindowSize);
- if (auto src = newStream.data()) {
- connect(src, SIGNAL(readyRead()), this,
- SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection);
- src->setProperty("HTTP2StreamID", newStreamID);
+ if (!uploadDone) {
+ if (auto src = newStream.data()) {
+ connect(src, SIGNAL(readyRead()), this,
+ SLOT(_q_uploadDataReadyRead()), Qt::QueuedConnection);
+ src->setProperty("HTTP2StreamID", newStreamID);
+ }
}
activeStreams.insert(newStreamID, newStream);