diff options
Diffstat (limited to 'src/network/access/http2')
-rw-r--r-- | src/network/access/http2/http2frames.cpp | 33 | ||||
-rw-r--r-- | src/network/access/http2/http2frames_p.h | 35 | ||||
-rw-r--r-- | src/network/access/http2/http2protocol_p.h | 4 | ||||
-rw-r--r-- | src/network/access/http2/http2streams.cpp | 11 | ||||
-rw-r--r-- | src/network/access/http2/http2streams_p.h | 25 |
5 files changed, 88 insertions, 20 deletions
diff --git a/src/network/access/http2/http2frames.cpp b/src/network/access/http2/http2frames.cpp index 978bee09b1..5a684c2f41 100644 --- a/src/network/access/http2/http2frames.cpp +++ b/src/network/access/http2/http2frames.cpp @@ -244,6 +244,24 @@ quint32 Frame::dataSize() const return size; } +quint32 Frame::hpackBlockSize() const +{ + Q_ASSERT(validatePayload() == FrameStatus::goodFrame); + + const auto frameType = type(); + Q_ASSERT(frameType == FrameType::HEADERS || + frameType == FrameType::PUSH_PROMISE || + frameType == FrameType::CONTINUATION); + + quint32 size = dataSize(); + if (frameType == FrameType::PUSH_PROMISE) { + Q_ASSERT(size >= 4); + size -= 4; + } + + return size; +} + const uchar *Frame::dataBegin() const { Q_ASSERT(validatePayload() == FrameStatus::goodFrame); @@ -260,6 +278,21 @@ const uchar *Frame::dataBegin() const return src; } +const uchar *Frame::hpackBlockBegin() const +{ + Q_ASSERT(validatePayload() == FrameStatus::goodFrame); + + const auto frameType = type(); + Q_ASSERT(frameType == FrameType::HEADERS || + frameType == FrameType::PUSH_PROMISE || + frameType == FrameType::CONTINUATION); + + const uchar *begin = dataBegin(); + if (frameType == FrameType::PUSH_PROMISE) + begin += 4; // That's a promised stream, skip it. + return begin; +} + FrameStatus FrameReader::read(QAbstractSocket &socket) { if (offset < frameHeaderSize) { diff --git a/src/network/access/http2/http2frames_p.h b/src/network/access/http2/http2frames_p.h index 84ba9c3662..e5f6d46c67 100644 --- a/src/network/access/http2/http2frames_p.h +++ b/src/network/access/http2/http2frames_p.h @@ -71,27 +71,29 @@ namespace Http2 struct Q_AUTOTEST_EXPORT Frame { Frame(); - // Reading these values without first forming a valid frame - // (either reading it from a socket or building it) will result - // in undefined behavior: + // Reading these values without first forming a valid frame (either reading + // it from a socket or building it) will result in undefined behavior: FrameType type() const; quint32 streamID() const; FrameFlags flags() const; quint32 payloadSize() const; uchar padding() const; - // In HTTP/2 a stream's priority is specified by its weight - // and a stream (id) it depends on: + // In HTTP/2 a stream's priority is specified by its weight and a stream + // (id) it depends on: bool priority(quint32 *streamID = nullptr, uchar *weight = nullptr) const; FrameStatus validateHeader() const; FrameStatus validatePayload() const; - // Number of payload bytes without padding and/or priority + // Number of payload bytes without padding and/or priority. quint32 dataSize() const; - // Beginning of payload without priority/padding - // bytes. + // HEADERS data size for HEADERS, PUSH_PROMISE and CONTINUATION streams: + quint32 hpackBlockSize() const; + // Beginning of payload without priority/padding bytes. const uchar *dataBegin() const; + // HEADERS data beginning for HEADERS, PUSH_PROMISE and CONTINUATION streams: + const uchar *hpackBlockBegin() const; std::vector<uchar> buffer; }; @@ -134,8 +136,7 @@ public: void setFlags(FrameFlags flags); void addFlag(FrameFlag flag); - // All append functions also update frame's payload - // length. + // All append functions also update frame's payload length. template<typename ValueType> void append(ValueType val) { @@ -161,16 +162,14 @@ public: // Write as a single frame: bool write(QAbstractSocket &socket) const; - // Two types of frames we are sending are affected by - // frame size limits: HEADERS and DATA. HEADERS' payload - // (hpacked HTTP headers, following a frame header) - // is always in our 'buffer', we send the initial HEADERS + // Two types of frames we are sending are affected by frame size limits: + // HEADERS and DATA. HEADERS' payload (hpacked HTTP headers, following a + // frame header) is always in our 'buffer', we send the initial HEADERS // frame first and then CONTINUTATION frame(s) if needed: bool writeHEADERS(QAbstractSocket &socket, quint32 sizeLimit); - // With DATA frames the actual payload is never in our 'buffer', - // it's a 'readPointer' from QNonContiguousData. We split - // this payload as needed into DATA frames with correct - // payload size fitting into frame size limit: + // With DATA frames the actual payload is never in our 'buffer', it's a + // 'readPointer' from QNonContiguousData. We split this payload as needed + // into DATA frames with correct payload size fitting into frame size limit: bool writeDATA(QAbstractSocket &socket, quint32 sizeLimit, const uchar *src, quint32 size); private: diff --git a/src/network/access/http2/http2protocol_p.h b/src/network/access/http2/http2protocol_p.h index 5c46949e23..5d730404bb 100644 --- a/src/network/access/http2/http2protocol_p.h +++ b/src/network/access/http2/http2protocol_p.h @@ -127,6 +127,10 @@ enum Http2PredefinedParameters maxConcurrentStreams = 100 // HTTP/2, 6.5.2 }; +// It's int, it has internal linkage, it's ok to have it in headers - +// no ODR violation is possible. +const quint32 lastValidStreamID((quint32(1) << 31) - 1); // HTTP/2, 5.1.1 + extern const Q_AUTOTEST_EXPORT char Http2clientPreface[clientPrefaceLength]; enum class FrameStatus diff --git a/src/network/access/http2/http2streams.cpp b/src/network/access/http2/http2streams.cpp index 660100f5e4..fa39c1d57b 100644 --- a/src/network/access/http2/http2streams.cpp +++ b/src/network/access/http2/http2streams.cpp @@ -61,6 +61,15 @@ Stream::Stream(const HttpMessagePair &message, quint32 id, qint32 sendSize, qint { } +Stream::Stream(const QString &cacheKey, quint32 id, qint32 recvSize) + : streamID(id), + // sendWindow is 0, this stream only receives data + recvWindow(recvSize), + state(remoteReserved), + key(cacheKey) +{ +} + QHttpNetworkReply *Stream::reply() const { return httpPair.second; @@ -99,6 +108,6 @@ QNonContiguousByteDevice *Stream::data() const return httpPair.first.uploadByteDevice(); } -} +} // namespace Http2 QT_END_NAMESPACE diff --git a/src/network/access/http2/http2streams_p.h b/src/network/access/http2/http2streams_p.h index 8a825a5457..8465486ae8 100644 --- a/src/network/access/http2/http2streams_p.h +++ b/src/network/access/http2/http2streams_p.h @@ -51,10 +51,16 @@ // We mean it. // +#include "http2frames_p.h" +#include "hpack_p.h" + #include <private/qhttpnetworkconnectionchannel_p.h> #include <private/qhttpnetworkrequest_p.h> #include <QtCore/qglobal.h> +#include <QtCore/qstring.h> + +#include <vector> QT_BEGIN_NAMESPACE @@ -70,12 +76,16 @@ struct Q_AUTOTEST_EXPORT Stream open, halfClosedLocal, halfClosedRemote, + remoteReserved, closed }; Stream(); + // That's a ctor for a client-initiated stream: Stream(const HttpMessagePair &message, quint32 streamID, qint32 sendSize, qint32 recvSize); + // That's a reserved stream, created by PUSH_PROMISE from a server: + Stream(const QString &key, quint32 streamID, qint32 recvSize); QHttpNetworkReply *reply() const; const QHttpNetworkRequest &request() const; @@ -92,9 +102,22 @@ struct Q_AUTOTEST_EXPORT Stream qint32 recvWindow = 65535; StreamState state = idle; + QString key; // for PUSH_PROMISE +}; + +struct PushPromise +{ + quint32 reservedID = 0; + // PUSH_PROMISE has its own HEADERS, + // usually similar to what request has: + HPack::HttpHeader pushHeader; + // Response has its own (normal) HEADERS: + HPack::HttpHeader responseHeader; + // DATA frames on a promised stream: + std::vector<Frame> dataFrames; }; -} +} // namespace Http2 QT_END_NAMESPACE |