diff options
Diffstat (limited to 'src/network/access/http2/http2protocol.cpp')
-rw-r--r-- | src/network/access/http2/http2protocol.cpp | 116 |
1 files changed, 24 insertions, 92 deletions
diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp index 0be72042c6..31da6fd616 100644 --- a/src/network/access/http2/http2protocol.cpp +++ b/src/network/access/http2/http2protocol.cpp @@ -43,6 +43,8 @@ #include "private/qhttpnetworkrequest_p.h" #include "private/qhttpnetworkreply_p.h" +#include <access/qhttp2configuration.h> + #include <QtCore/qbytearray.h> #include <QtCore/qstring.h> @@ -62,88 +64,29 @@ const char Http2clientPreface[clientPrefaceLength] = 0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a, 0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a}; -// TODO: (in 5.11) - remove it! -const char *http2ParametersPropertyName = "QT_HTTP2_PARAMETERS_PROPERTY"; - -ProtocolParameters::ProtocolParameters() -{ - settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID] = qtDefaultStreamReceiveWindowSize; - settingsFrameData[Settings::ENABLE_PUSH_ID] = 0; -} - -bool ProtocolParameters::validate() const +Frame configurationToSettingsFrame(const QHttp2Configuration &config) { - // 0. Huffman/indexing: any values are valid and allowed. - - // 1. Session receive window size (client side): HTTP/2 starts from the - // default value of 64Kb, if a client code tries to set lesser value, - // the delta would become negative, but this is not allowed. - if (maxSessionReceiveWindowSize < qint32(defaultSessionWindowSize)) { - qCWarning(QT_HTTP2, "Session receive window must be at least 65535 bytes"); - return false; - } - - // 2. HEADER_TABLE_SIZE: we do not validate HEADER_TABLE_SIZE, considering - // all values as valid. RFC 7540 and 7541 do not provide any lower/upper - // limits. If it's 0 - we do not index anything, if it's too huge - a user - // who provided such a value can potentially have a huge memory footprint, - // up to them to decide. - - // 3. SETTINGS_ENABLE_PUSH: RFC 7540, 6.5.2, a value other than 0 or 1 will - // be treated by our peer as a PROTOCOL_ERROR. - if (settingsFrameData.contains(Settings::ENABLE_PUSH_ID) - && settingsFrameData[Settings::ENABLE_PUSH_ID] > 1) { - qCWarning(QT_HTTP2, "SETTINGS_ENABLE_PUSH can be only 0 or 1"); - return false; - } - - // 4. SETTINGS_MAX_CONCURRENT_STREAMS : RFC 7540 recommends 100 as the lower - // limit, says nothing about the upper limit. The RFC allows 0, but this makes - // no sense to us at all: there is no way a user can change this later and - // we'll not be able to get any responses on such a connection. - if (settingsFrameData.contains(Settings::MAX_CONCURRENT_STREAMS_ID) - && !settingsFrameData[Settings::MAX_CONCURRENT_STREAMS_ID]) { - qCWarning(QT_HTTP2, "MAX_CONCURRENT_STREAMS must be a positive number"); - return false; - } - - // 5. SETTINGS_INITIAL_WINDOW_SIZE. - if (settingsFrameData.contains(Settings::INITIAL_WINDOW_SIZE_ID)) { - const quint32 value = settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID]; - // RFC 7540, 6.5.2 (the upper limit). The lower limit is our own - we send - // SETTINGS frame only once and will not be able to change this 0, thus - // we'll suspend all streams. - if (!value || value > quint32(maxSessionReceiveWindowSize)) { - qCWarning(QT_HTTP2, "INITIAL_WINDOW_SIZE must be in the range " - "(0, 2^31-1]"); - return false; - } - } - - // 6. SETTINGS_MAX_FRAME_SIZE: RFC 7540, 6.5.2, a value outside of the range - // [2^14-1, 2^24-1] will be treated by our peer as a PROTOCOL_ERROR. - if (settingsFrameData.contains(Settings::MAX_FRAME_SIZE_ID)) { - const quint32 value = settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID]; - if (value < maxFrameSize || value > maxPayloadSize) { - qCWarning(QT_HTTP2, "MAX_FRAME_SIZE must be in the range [2^14, 2^24-1]"); - return false; - } + // 6.5 SETTINGS + FrameWriter builder(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID); + // Server push: + builder.append(Settings::ENABLE_PUSH_ID); + builder.append(int(config.serverPushEnabled())); + // Stream receive window size: + builder.append(Settings::INITIAL_WINDOW_SIZE_ID); + builder.append(config.streamReceiveWindowSize()); + + if (config.maxFrameSize() != minPayloadLimit) { + builder.append(Settings::MAX_FRAME_SIZE_ID); + builder.append(config.maxFrameSize()); } - - // For SETTINGS_MAX_HEADER_LIST_SIZE RFC 7540 does not provide any specific - // numbers. It's clear, if a value is too small, no header can ever be sent - // by our peer at all. The default value is unlimited and we normally do not - // change this. - // - // Note: the size is calculated as the length of uncompressed (no HPACK) - // name + value + 32 bytes. - - return true; + // TODO: In future, if the need is proven, we can + // also send decoding table size and header list size. + // For now, defaults suffice. + return builder.outboundFrame(); } -QByteArray ProtocolParameters::settingsFrameToBase64() const +QByteArray settingsFrameToBase64(const Frame &frame) { - Frame frame(settingsFrame()); // SETTINGS frame's payload consists of pairs: // 2-byte-identifier | 4-byte-value == multiple of 6. Q_ASSERT(frame.payloadSize() && !(frame.payloadSize() % 6)); @@ -157,20 +100,7 @@ QByteArray ProtocolParameters::settingsFrameToBase64() const return wrapper.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); } -Frame ProtocolParameters::settingsFrame() const -{ - // 6.5 SETTINGS - FrameWriter builder(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID); - for (auto it = settingsFrameData.cbegin(), end = settingsFrameData.cend(); - it != end; ++it) { - builder.append(it.key()); - builder.append(it.value()); - } - - return builder.outboundFrame(); -} - -void ProtocolParameters::addProtocolUpgradeHeaders(QHttpNetworkRequest *request) const +void appendProtocolUpgradeHeaders(const QHttp2Configuration &config, QHttpNetworkRequest *request) { Q_ASSERT(request); // RFC 2616, 14.10 @@ -184,8 +114,10 @@ void ProtocolParameters::addProtocolUpgradeHeaders(QHttpNetworkRequest *request) request->setHeaderField("Connection", value); // This we just (re)write. request->setHeaderField("Upgrade", "h2c"); + + const Frame frame(configurationToSettingsFrame(config)); // This we just (re)write. - request->setHeaderField("HTTP2-Settings", settingsFrameToBase64()); + request->setHeaderField("HTTP2-Settings", settingsFrameToBase64(frame)); } void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error, |