summaryrefslogtreecommitdiffstats
path: root/src/network/access/qhttpnetworkconnectionchannel.cpp
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@theqtcompany.com>2016-07-14 16:49:16 +0200
committerTimur Pocheptsov <timur.pocheptsov@theqtcompany.com>2016-08-03 15:31:20 +0000
commit12d71f4ea20415ff2274e1e90f9e4d5a8b935d7f (patch)
tree8ba8d02c73305bb533267bbe3784fc6e607716ad /src/network/access/qhttpnetworkconnectionchannel.cpp
parentd7132c6c6d3bb9d1362744f36b2995b1d2daf4fe (diff)
Implement protocol upgrade for HTTP/2 enabled requests
Without ALPN/NPN (== without OpenSSL) we can negotiate HTTP/2 using the protocol upgrade procedure as described by RFC7540. Since there is no TLS handshake, after our http channel was connected we first send an 'augmented' HTTP/1.1 request - its header contains additional 'HTTP2-Settings' and 'Upgrade' (to 'h2c') fields. If we receive reponse 101 (switch protocol) we re-create a protocol handler and switch to HTTP/2. Task-number: QTBUG-50955 Change-Id: I36e9985e06ba76edaf7fdb22bb43770f8d593c61 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/network/access/qhttpnetworkconnectionchannel.cpp')
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp40
1 files changed, 32 insertions, 8 deletions
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 3a780f636b..3d35fe5f04 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -50,6 +50,7 @@
#include <private/qhttp2protocolhandler_p.h>
#include <private/qhttpprotocolhandler_p.h>
#include <private/qspdyprotocolhandler_p.h>
+#include <private/http2protocol_p.h>
#ifndef QT_NO_SSL
# include <private/qsslsocket_p.h>
@@ -180,6 +181,9 @@ void QHttpNetworkConnectionChannel::init()
sslSocket->setSslConfiguration(sslConfiguration);
} else {
#endif // QT_NO_SSL
+ // Even if connection->connectionType is ConnectionTypeHTTP2,
+ // we first start as HTTP/1.1, asking for a protocol upgrade
+ // in the first response.
protocolHandler.reset(new QHttpProtocolHandler(this));
#ifndef QT_NO_SSL
}
@@ -835,6 +839,16 @@ void QHttpNetworkConnectionChannel::_q_connected()
#endif
} else {
state = QHttpNetworkConnectionChannel::IdleState;
+ if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) {
+ Q_ASSERT(spdyRequestsToSend.size());
+ auto it = spdyRequestsToSend.begin();
+ // Let's inject some magic fields, requesting a protocol upgrade:
+ Http2::qt_add_ProtocolUpgradeRequest(it->first);
+ connection->d_func()->requeueRequest(*it);
+ // Remove it, we never send it again as HTTP/2.
+ spdyRequestsToSend.erase(it);
+ }
+
if (!reply)
connection->d_func()->dequeueRequest(socket);
if (reply)
@@ -972,9 +986,12 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
}
} while (!connection->d_func()->highPriorityQueue.isEmpty()
|| !connection->d_func()->lowPriorityQueue.isEmpty());
+
+ if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
#ifndef QT_NO_SSL
- if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY ||
- connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) {
+ || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY
+#endif
+ ) {
QList<HttpMessagePair> spdyPairs = spdyRequestsToSend.values();
for (int a = 0; a < spdyPairs.count(); ++a) {
// emit error for all replies
@@ -983,7 +1000,6 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
emit currentReply->finishedWithError(errorCode, errorString);
}
}
-#endif // QT_NO_SSL
// send the next request
QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
@@ -1002,23 +1018,31 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
}
}
+void QHttpNetworkConnectionChannel::_q_protocolSwitch()
+{
+ Q_ASSERT(connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2);
+ Q_ASSERT(reply);
+ Q_ASSERT(reply->statusCode() == 101);
+ protocolHandler.reset(new QHttp2ProtocolHandler(this, HttpMessagePair(request, reply)));
+ protocolHandler->_q_receiveReply();
+}
+
#ifndef QT_NO_NETWORKPROXY
void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
{
+ if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
#ifndef QT_NO_SSL
- if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY ||
- connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) {
+ || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY
+#endif
+ ) {
connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
} else { // HTTP
-#endif // QT_NO_SSL
// Need to dequeue the request before we can emit the error.
if (!reply)
connection->d_func()->dequeueRequest(socket);
if (reply)
connection->d_func()->emitProxyAuthenticationRequired(this, proxy, auth);
-#ifndef QT_NO_SSL
}
-#endif // QT_NO_SSL
}
#endif