1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef HTTP2FRAMES_P_H |
5 | #define HTTP2FRAMES_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists for the convenience |
12 | // of the Network Access API. This header file may change from |
13 | // version to version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include "http2protocol_p.h" |
19 | #include "hpack_p.h" |
20 | |
21 | #include <QtCore/qendian.h> |
22 | #include <QtCore/qglobal.h> |
23 | |
24 | #include <algorithm> |
25 | #include <vector> |
26 | |
27 | QT_BEGIN_NAMESPACE |
28 | |
29 | class QHttp2ProtocolHandler; |
30 | class QAbstractSocket; |
31 | |
32 | namespace Http2 |
33 | { |
34 | |
35 | struct Q_AUTOTEST_EXPORT Frame |
36 | { |
37 | Frame(); |
38 | // Reading these values without first forming a valid frame (either reading |
39 | // it from a socket or building it) will result in undefined behavior: |
40 | FrameType type() const; |
41 | quint32 streamID() const; |
42 | FrameFlags flags() const; |
43 | quint32 payloadSize() const; |
44 | uchar padding() const; |
45 | // In HTTP/2 a stream's priority is specified by its weight and a stream |
46 | // (id) it depends on: |
47 | bool priority(quint32 *streamID = nullptr, |
48 | uchar *weight = nullptr) const; |
49 | |
50 | FrameStatus () const; |
51 | FrameStatus validatePayload() const; |
52 | |
53 | // Number of payload bytes without padding and/or priority. |
54 | quint32 dataSize() const; |
55 | // HEADERS data size for HEADERS, PUSH_PROMISE and CONTINUATION streams: |
56 | quint32 hpackBlockSize() const; |
57 | // Beginning of payload without priority/padding bytes. |
58 | const uchar *dataBegin() const; |
59 | // HEADERS data beginning for HEADERS, PUSH_PROMISE and CONTINUATION streams: |
60 | const uchar *hpackBlockBegin() const; |
61 | |
62 | std::vector<uchar> buffer; |
63 | }; |
64 | |
65 | class Q_AUTOTEST_EXPORT FrameReader |
66 | { |
67 | public: |
68 | FrameStatus read(QAbstractSocket &socket); |
69 | |
70 | Frame &inboundFrame() |
71 | { |
72 | return frame; |
73 | } |
74 | private: |
75 | bool (QAbstractSocket &socket); |
76 | bool readPayload(QAbstractSocket &socket); |
77 | |
78 | quint32 offset = 0; |
79 | Frame frame; |
80 | }; |
81 | |
82 | class Q_AUTOTEST_EXPORT FrameWriter |
83 | { |
84 | public: |
85 | using payload_type = std::vector<uchar>; |
86 | using size_type = payload_type::size_type; |
87 | |
88 | FrameWriter(); |
89 | FrameWriter(FrameType type, FrameFlags flags, quint32 streamID); |
90 | |
91 | Frame &outboundFrame() |
92 | { |
93 | return frame; |
94 | } |
95 | |
96 | void setOutboundFrame(Frame &&newFrame); |
97 | |
98 | // Frame 'builders': |
99 | void start(FrameType type, FrameFlags flags, quint32 streamID); |
100 | void setPayloadSize(quint32 size); |
101 | void setType(FrameType type); |
102 | void setFlags(FrameFlags flags); |
103 | void addFlag(FrameFlag flag); |
104 | |
105 | // All append functions also update frame's payload length. |
106 | template<typename ValueType> |
107 | void append(ValueType val) |
108 | { |
109 | uchar wired[sizeof val] = {}; |
110 | qToBigEndian(val, wired); |
111 | append(wired, wired + sizeof val); |
112 | } |
113 | void append(uchar val) |
114 | { |
115 | frame.buffer.push_back(x: val); |
116 | updatePayloadSize(); |
117 | } |
118 | void append(Settings identifier) |
119 | { |
120 | append(val: quint16(identifier)); |
121 | } |
122 | void append(const payload_type &payload) |
123 | { |
124 | append(begin: &payload[0], end: &payload[0] + payload.size()); |
125 | } |
126 | |
127 | void append(const uchar *begin, const uchar *end); |
128 | |
129 | // Write as a single frame: |
130 | bool write(QAbstractSocket &socket) const; |
131 | // Two types of frames we are sending are affected by frame size limits: |
132 | // HEADERS and DATA. HEADERS' payload (hpacked HTTP headers, following a |
133 | // frame header) is always in our 'buffer', we send the initial HEADERS |
134 | // frame first and then CONTINUTATION frame(s) if needed: |
135 | bool (QAbstractSocket &socket, quint32 sizeLimit); |
136 | // With DATA frames the actual payload is never in our 'buffer', it's a |
137 | // 'readPointer' from QNonContiguousData. We split this payload as needed |
138 | // into DATA frames with correct payload size fitting into frame size limit: |
139 | bool writeDATA(QAbstractSocket &socket, quint32 sizeLimit, |
140 | const uchar *src, quint32 size); |
141 | private: |
142 | void updatePayloadSize(); |
143 | Frame frame; |
144 | }; |
145 | |
146 | } |
147 | |
148 | QT_END_NAMESPACE |
149 | |
150 | #endif |
151 | |