1 | // Copyright (C) 2021 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 HTTP2PROTOCOL_P_H |
5 | #define HTTP2PROTOCOL_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 <QtNetwork/qnetworkreply.h> |
19 | #include <QtCore/qloggingcategory.h> |
20 | #include <QtCore/qmetatype.h> |
21 | #include <QtCore/private/qglobal_p.h> |
22 | #include <QtCore/qmap.h> |
23 | |
24 | // Different HTTP/2 constants/values as defined by RFC 7540. |
25 | |
26 | QT_BEGIN_NAMESPACE |
27 | |
28 | class QHttpNetworkRequest; |
29 | class QHttp2Configuration; |
30 | class QHttpNetworkReply; |
31 | class QByteArray; |
32 | class QString; |
33 | |
34 | namespace Http2 |
35 | { |
36 | |
37 | enum class Settings : quint16 |
38 | { |
39 | = 0x1, |
40 | ENABLE_PUSH_ID = 0x2, |
41 | MAX_CONCURRENT_STREAMS_ID = 0x3, |
42 | INITIAL_WINDOW_SIZE_ID = 0x4, |
43 | MAX_FRAME_SIZE_ID = 0x5, |
44 | = 0x6 |
45 | }; |
46 | |
47 | enum class FrameType : uchar |
48 | { |
49 | DATA = 0x0, |
50 | = 0x1, |
51 | PRIORITY = 0x2, |
52 | RST_STREAM = 0x3, |
53 | SETTINGS = 0x4, |
54 | PUSH_PROMISE = 0x5, |
55 | PING = 0x6, |
56 | GOAWAY = 0x7, |
57 | WINDOW_UPDATE = 0x8, |
58 | CONTINUATION = 0x9, |
59 | // ATTENTION: enumerators must be sorted. |
60 | // We use LAST_FRAME_TYPE to check if |
61 | // frame type is known, if not - this frame |
62 | // must be ignored, HTTP/2 5.1). |
63 | LAST_FRAME_TYPE |
64 | }; |
65 | |
66 | enum class FrameFlag : uchar |
67 | { |
68 | EMPTY = 0x0, // Valid for any frame type. |
69 | ACK = 0x1, // Valid for PING, SETTINGS |
70 | END_STREAM = 0x1, // Valid for HEADERS, DATA |
71 | = 0x4, // Valid for PUSH_PROMISE, HEADERS, |
72 | PADDED = 0x8, // Valid for PUSH_PROMISE, HEADERS, DATA |
73 | PRIORITY = 0x20 // Valid for HEADERS, |
74 | }; |
75 | |
76 | Q_DECLARE_FLAGS(FrameFlags, FrameFlag) |
77 | Q_DECLARE_OPERATORS_FOR_FLAGS(FrameFlags) |
78 | |
79 | enum Http2PredefinedParameters |
80 | { |
81 | // Old-style enum, so we |
82 | // can use as Http2::frameHeaderSize for example. |
83 | clientPrefaceLength = 24, // HTTP/2, 3.5 |
84 | connectionStreamID = 0, // HTTP/2, 5.1.1 |
85 | = 9, // HTTP/2, 4.1 |
86 | |
87 | // The initial allowed payload size. We would use it as an |
88 | // upper limit for a frame payload we send, until our peer |
89 | // updates us with a larger SETTINGS_MAX_FRAME_SIZE. |
90 | |
91 | // The initial maximum payload size that an HTTP/2 frame |
92 | // can contain is 16384. It's also the minimal size that |
93 | // can be advertised via 'SETTINGS' frames. A real frame |
94 | // can have a payload smaller than 16384. |
95 | minPayloadLimit = 16384, // HTTP/2 6.5.2 |
96 | // The maximum allowed payload size. |
97 | maxPayloadSize = (1 << 24) - 1, // HTTP/2 6.5.2 |
98 | |
99 | defaultSessionWindowSize = 65535, // HTTP/2 6.5.2 |
100 | maxConcurrentStreams = 100 // HTTP/2, 6.5.2 |
101 | }; |
102 | |
103 | // These are ints, const, they have internal linkage, it's ok to have them in |
104 | // headers - no ODR violation. |
105 | const quint32 lastValidStreamID((quint32(1) << 31) - 1); // HTTP/2, 5.1.1 |
106 | |
107 | // The default size of 64K is too small and limiting: if we use it, we end up |
108 | // sending WINDOW_UPDATE frames on a stream/session all the time, for each |
109 | // 2 DATE frames of size 16K (also default) we'll send a WINDOW_UPDATE frame |
110 | // for a given stream and have a download speed order of magnitude lower than |
111 | // our own HTTP/1.1 protocol handler. We choose a bigger window size: normally, |
112 | // HTTP/2 servers are not afraid to immediately set it to the possible max, |
113 | // we do the same and split this window size between our concurrent streams. |
114 | const qint32 maxSessionReceiveWindowSize((quint32(1) << 31) - 1); |
115 | // Presumably, we never use up to 100 streams so let it be 10 simultaneous: |
116 | const qint32 qtDefaultStreamReceiveWindowSize = maxSessionReceiveWindowSize / 10; |
117 | |
118 | struct Frame configurationToSettingsFrame(const QHttp2Configuration &configuration); |
119 | QByteArray settingsFrameToBase64(const Frame &settingsFrame); |
120 | void (const QHttp2Configuration &configuration, QHttpNetworkRequest *request); |
121 | |
122 | extern const Q_AUTOTEST_EXPORT char Http2clientPreface[clientPrefaceLength]; |
123 | |
124 | enum class FrameStatus |
125 | { |
126 | protocolError, |
127 | sizeError, |
128 | incompleteFrame, |
129 | goodFrame |
130 | }; |
131 | |
132 | enum Http2Error |
133 | { |
134 | // Old-style enum to avoid excessive name |
135 | // qualification ... |
136 | // NB: |
137 | // I use the last enumerator to check |
138 | // that errorCode (quint32) is valid, |
139 | // so it needs to be the highest-numbered! |
140 | // HTTP/2 7: |
141 | HTTP2_NO_ERROR = 0x0, |
142 | PROTOCOL_ERROR = 0x1, |
143 | INTERNAL_ERROR = 0x2, |
144 | FLOW_CONTROL_ERROR = 0x3, |
145 | SETTINGS_TIMEOUT = 0x4, |
146 | STREAM_CLOSED = 0x5, |
147 | FRAME_SIZE_ERROR = 0x6, |
148 | REFUSE_STREAM = 0x7, |
149 | CANCEL = 0x8, |
150 | COMPRESSION_ERROR = 0x9, |
151 | CONNECT_ERROR = 0xa, |
152 | ENHANCE_YOUR_CALM = 0xb, |
153 | INADEQUATE_SECURITY = 0xc, |
154 | HTTP_1_1_REQUIRED = 0xd |
155 | }; |
156 | |
157 | void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error, QString &errorString); |
158 | QString qt_error_string(quint32 errorCode); |
159 | QNetworkReply::NetworkError qt_error(quint32 errorCode); |
160 | bool is_protocol_upgraded(const QHttpNetworkReply &reply); |
161 | |
162 | } // namespace Http2 |
163 | |
164 | Q_DECLARE_LOGGING_CATEGORY(QT_HTTP2) |
165 | |
166 | QT_END_NAMESPACE |
167 | |
168 | QT_DECL_METATYPE_EXTERN_TAGGED(Http2::Settings, Http2__Settings, Q_NETWORK_EXPORT) |
169 | |
170 | #endif |
171 | |