summaryrefslogtreecommitdiffstats
path: root/src/network/access/http2/http2protocol.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/http2/http2protocol.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/http2/http2protocol.cpp')
-rw-r--r--src/network/access/http2/http2protocol.cpp47
1 files changed, 47 insertions, 0 deletions
diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp
index 7f788a6f42..9f05e926c9 100644
--- a/src/network/access/http2/http2protocol.cpp
+++ b/src/network/access/http2/http2protocol.cpp
@@ -37,9 +37,12 @@
**
****************************************************************************/
+#include <QtCore/qbytearray.h>
#include <QtCore/qstring.h>
+#include "private/qhttpnetworkrequest_p.h"
#include "http2protocol_p.h"
+#include "http2frames_p.h"
QT_BEGIN_NAMESPACE
@@ -57,6 +60,37 @@ const char Http2clientPreface[clientPrefaceLength] =
0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a,
0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a};
+QByteArray qt_default_SETTINGS_to_Base64()
+{
+ FrameWriter frame(qt_default_SETTINGS_frame());
+ // SETTINGS frame's payload consists of pairs:
+ // 2-byte-identifier | 4-byte-value - multiple of 6.
+ // Also it's allowed to be empty.
+ Q_ASSERT(!(frame.payloadSize() % 6));
+ const char *src = reinterpret_cast<const char *>(&frame.rawFrameBuffer()[frameHeaderSize]);
+ const QByteArray wrapper(QByteArray::fromRawData(src, int(frame.payloadSize())));
+ // 3.2.1
+ // The content of the HTTP2-Settings header field is the payload
+ // of a SETTINGS frame (Section 6.5), encoded as a base64url string
+ // (that is, the URL- and filename-safe Base64 encoding described in
+ // Section 5 of [RFC4648], with any trailing '=' characters omitted).
+ return wrapper.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
+}
+
+void qt_add_ProtocolUpgradeRequest(QHttpNetworkRequest &request)
+{
+ // RFC 2616, 14.10
+ QByteArray value(request.headerField("Connection"));
+ if (value.size())
+ value += ", ";
+
+ value += "Upgrade, HTTP2-Settings";
+ request.setHeaderField("Connection", value);
+ // This we just (re)write.
+ request.setHeaderField("Upgrade", "h2c");
+ // This we just (re)write.
+ request.setHeaderField("HTTP2-Settings", qt_default_SETTINGS_to_Base64());
+}
void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error,
QString &errorMessage)
@@ -151,6 +185,19 @@ QNetworkReply::NetworkError qt_error(quint32 errorCode)
return error;
}
+FrameWriter qt_default_SETTINGS_frame()
+{
+ // 6.5 SETTINGS
+ FrameWriter frame(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID);
+ // MAX frame size (16 kb), disable PUSH
+ frame.append(Settings::MAX_FRAME_SIZE_ID);
+ frame.append(quint32(maxFrameSize));
+ frame.append(Settings::ENABLE_PUSH_ID);
+ frame.append(quint32(0));
+
+ return frame;
+}
+
}
QT_END_NAMESPACE