/src/qtbase/src/network/access/qhttp2configuration.cpp
Line | Count | Source |
1 | | // Copyright (C) 2019 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 | | // Qt-Security score:significant reason:default |
4 | | |
5 | | #include "qhttp2configuration.h" |
6 | | |
7 | | #include "private/http2protocol_p.h" |
8 | | #include "private/hpack_p.h" |
9 | | |
10 | | #include "qdebug.h" |
11 | | |
12 | | QT_BEGIN_NAMESPACE |
13 | | |
14 | | /*! |
15 | | \class QHttp2Configuration |
16 | | \brief The QHttp2Configuration class controls HTTP/2 parameters and settings. |
17 | | \since 5.14 |
18 | | |
19 | | \reentrant |
20 | | \inmodule QtNetwork |
21 | | \ingroup network |
22 | | \ingroup shared |
23 | | |
24 | | QHttp2Configuration controls HTTP/2 parameters and settings that |
25 | | QNetworkAccessManager will use to send requests and process responses |
26 | | when the HTTP/2 protocol is enabled. |
27 | | |
28 | | The HTTP/2 parameters that QHttp2Configuration currently supports include: |
29 | | |
30 | | \list |
31 | | \li The session window size for connection-level flow control. |
32 | | Will be sent to a remote peer when needed as 'WINDOW_UPDATE' |
33 | | frames on the stream with an identifier 0. |
34 | | \li The stream receiving window size for stream-level flow control. |
35 | | Sent as 'SETTINGS_INITIAL_WINDOW_SIZE' parameter in the initial |
36 | | SETTINGS frame and, when needed, 'WINDOW_UPDATE' frames will be |
37 | | sent on streams that QNetworkAccessManager opens. |
38 | | \li The maximum frame size. This parameter limits the maximum payload |
39 | | a frame coming from the remote peer can have. Sent by QNetworkAccessManager |
40 | | as 'SETTINGS_MAX_FRAME_SIZE' parameter in the initial 'SETTINGS' |
41 | | frame. |
42 | | \li The server push. Allows to enable or disable server push. Sent |
43 | | as 'SETTINGS_ENABLE_PUSH' parameter in the initial 'SETTINGS' |
44 | | frame. |
45 | | \endlist |
46 | | |
47 | | The QHttp2Configuration class also controls if the header compression |
48 | | algorithm (HPACK) is additionally using Huffman coding for string |
49 | | compression. |
50 | | |
51 | | \note The configuration must be set before the first request |
52 | | was sent to a given host (and thus an HTTP/2 session established). |
53 | | |
54 | | \note Details about flow control, server push and 'SETTINGS' |
55 | | can be found in \l {https://httpwg.org/specs/rfc7540.html}{RFC 7540}. |
56 | | Different modes and parameters of the HPACK compression algorithm |
57 | | are described in \l {https://httpwg.org/specs/rfc7541.html}{RFC 7541}. |
58 | | |
59 | | \sa QNetworkRequest::setHttp2Configuration(), QNetworkRequest::http2Configuration(), QNetworkAccessManager |
60 | | */ |
61 | | |
62 | | class QHttp2ConfigurationPrivate : public QSharedData |
63 | | { |
64 | | public: |
65 | | unsigned sessionWindowSize = Http2::defaultSessionWindowSize; |
66 | | unsigned streamWindowSize = Http2::defaultSessionWindowSize; |
67 | | |
68 | | unsigned maxFrameSize = Http2::minPayloadLimit; // Initial (default) value of 16Kb. |
69 | | |
70 | | unsigned maxConcurrentStreams = Http2::maxConcurrentStreams; |
71 | | |
72 | | bool pushEnabled = false; |
73 | | // TODO: for now those two below are noop. |
74 | | bool huffmanCompressionEnabled = true; |
75 | | }; |
76 | | |
77 | | /*! |
78 | | Default constructs a QHttp2Configuration object. |
79 | | |
80 | | Such a configuration has the following values: |
81 | | \list |
82 | | \li Server push is disabled |
83 | | \li Huffman string compression is enabled |
84 | | \li Window size for connection-level flow control is 65535 octets |
85 | | \li Window size for stream-level flow control is 65535 octets |
86 | | \li Frame size is 16384 octets |
87 | | \endlist |
88 | | */ |
89 | | QHttp2Configuration::QHttp2Configuration() |
90 | 0 | : d(new QHttp2ConfigurationPrivate) |
91 | 0 | { |
92 | 0 | } |
93 | | |
94 | | /*! |
95 | | Copy-constructs this QHttp2Configuration. |
96 | | */ |
97 | 0 | QHttp2Configuration::QHttp2Configuration(const QHttp2Configuration &) = default; |
98 | | |
99 | | /*! |
100 | | Move-constructs this QHttp2Configuration from \a other |
101 | | */ |
102 | | QHttp2Configuration::QHttp2Configuration(QHttp2Configuration &&other) noexcept |
103 | 0 | { |
104 | 0 | swap(other); |
105 | 0 | } |
106 | | |
107 | | /*! |
108 | | Copy-assigns \a other to this QHttp2Configuration. |
109 | | */ |
110 | 0 | QHttp2Configuration &QHttp2Configuration::operator=(const QHttp2Configuration &) = default; |
111 | | |
112 | | /*! |
113 | | Move-assigns \a other to this QHttp2Configuration. |
114 | | */ |
115 | 0 | QHttp2Configuration &QHttp2Configuration::operator=(QHttp2Configuration &&) noexcept = default; |
116 | | |
117 | | /*! |
118 | | Destructor. |
119 | | */ |
120 | | QHttp2Configuration::~QHttp2Configuration() |
121 | 0 | { |
122 | 0 | } |
123 | | |
124 | | /*! |
125 | | If \a enable is \c true, a remote server can potentially |
126 | | use server push to send responses in advance. |
127 | | |
128 | | \sa serverPushEnabled |
129 | | */ |
130 | | void QHttp2Configuration::setServerPushEnabled(bool enable) |
131 | 0 | { |
132 | 0 | d->pushEnabled = enable; |
133 | 0 | } |
134 | | |
135 | | /*! |
136 | | Returns true if server push was enabled. |
137 | | |
138 | | \note By default, QNetworkAccessManager disables server |
139 | | push via the 'SETTINGS' frame. |
140 | | |
141 | | \sa setServerPushEnabled |
142 | | */ |
143 | | bool QHttp2Configuration::serverPushEnabled() const |
144 | 0 | { |
145 | 0 | return d->pushEnabled; |
146 | 0 | } |
147 | | |
148 | | /*! |
149 | | If \a enable is \c true, HPACK compression will additionally |
150 | | compress string using the Huffman coding. Enabled by default. |
151 | | |
152 | | \note This parameter only affects 'HEADERS' frames that |
153 | | QNetworkAccessManager is sending. |
154 | | |
155 | | \sa huffmanCompressionEnabled |
156 | | */ |
157 | | void QHttp2Configuration::setHuffmanCompressionEnabled(bool enable) |
158 | 0 | { |
159 | 0 | d->huffmanCompressionEnabled = enable; |
160 | 0 | } |
161 | | |
162 | | /*! |
163 | | Returns \c true if the Huffman coding in HPACK is enabled. |
164 | | |
165 | | \sa setHuffmanCompressionEnabled |
166 | | */ |
167 | | bool QHttp2Configuration::huffmanCompressionEnabled() const |
168 | 0 | { |
169 | 0 | return d->huffmanCompressionEnabled; |
170 | 0 | } |
171 | | |
172 | | /*! |
173 | | Sets the window size for connection-level flow control. |
174 | | \a size cannot be 0 and must not exceed 2147483647 octets. |
175 | | |
176 | | Returns \c true on success, \c false otherwise. |
177 | | |
178 | | \sa sessionReceiveWindowSize |
179 | | */ |
180 | | bool QHttp2Configuration::setSessionReceiveWindowSize(unsigned size) |
181 | 0 | { |
182 | 0 | if (!size || size > Http2::maxSessionReceiveWindowSize) { // RFC-7540, 6.9 |
183 | 0 | qCWarning(QT_HTTP2) << "Invalid session window size"; |
184 | 0 | return false; |
185 | 0 | } |
186 | | |
187 | 0 | d->sessionWindowSize = size; |
188 | 0 | return true; |
189 | 0 | } |
190 | | |
191 | | /*! |
192 | | Returns the window size for connection-level flow control. |
193 | | The default value QNetworkAccessManager will be using is |
194 | | 2147483647 octets. |
195 | | */ |
196 | | unsigned QHttp2Configuration::sessionReceiveWindowSize() const |
197 | 0 | { |
198 | 0 | return d->sessionWindowSize; |
199 | 0 | } |
200 | | |
201 | | /*! |
202 | | Sets the window size for stream-level flow control. |
203 | | \a size cannot be 0 and must not exceed 2147483647 octets. |
204 | | |
205 | | Returns \c true on success, \c false otherwise. |
206 | | |
207 | | \sa streamReceiveWindowSize |
208 | | */ |
209 | | bool QHttp2Configuration::setStreamReceiveWindowSize(unsigned size) |
210 | 0 | { |
211 | 0 | if (!size || size > Http2::maxSessionReceiveWindowSize) { // RFC-7540, 6.9 |
212 | 0 | qCWarning(QT_HTTP2) << "Invalid stream window size"; |
213 | 0 | return false; |
214 | 0 | } |
215 | | |
216 | 0 | d->streamWindowSize = size; |
217 | 0 | return true; |
218 | 0 | } |
219 | | |
220 | | /*! |
221 | | Returns the window size for stream-level flow control. |
222 | | The default value QNetworkAccessManager will be using is |
223 | | 214748364 octets (see \l {https://httpwg.org/specs/rfc7540.html#SettingValues}{RFC 7540}). |
224 | | */ |
225 | | unsigned QHttp2Configuration::streamReceiveWindowSize() const |
226 | 0 | { |
227 | 0 | return d->streamWindowSize; |
228 | 0 | } |
229 | | |
230 | | /*! |
231 | | Sets the maximum frame size that QNetworkAccessManager |
232 | | will advertise to the server when sending its initial SETTINGS frame. |
233 | | \note While this \a size is required to be within a range between |
234 | | 16384 and 16777215 inclusive, the actual payload size in frames |
235 | | that carry payload maybe be less than 16384. |
236 | | |
237 | | Returns \c true on success, \c false otherwise. |
238 | | */ |
239 | | bool QHttp2Configuration::setMaxFrameSize(unsigned size) |
240 | 0 | { |
241 | 0 | if (size < Http2::minPayloadLimit || size > Http2::maxPayloadSize) { |
242 | 0 | qCWarning(QT_HTTP2) << "Maximum frame size to advertise is invalid"; |
243 | 0 | return false; |
244 | 0 | } |
245 | | |
246 | 0 | d->maxFrameSize = size; |
247 | 0 | return true; |
248 | 0 | } |
249 | | |
250 | | /*! |
251 | | Returns the maximum payload size that HTTP/2 frames can |
252 | | have. The default (initial) value is 16384 octets. |
253 | | */ |
254 | | unsigned QHttp2Configuration::maxFrameSize() const |
255 | 0 | { |
256 | 0 | return d->maxFrameSize; |
257 | 0 | } |
258 | | |
259 | | /*! |
260 | | \since 6.9 |
261 | | |
262 | | Sets \a value as the maximum number of concurrent streams that |
263 | | will be advertised to the peer when sending SETTINGS frame. |
264 | | |
265 | | \sa maxConcurrentStreams() |
266 | | */ |
267 | | void QHttp2Configuration::setMaxConcurrentStreams(unsigned value) |
268 | 0 | { |
269 | 0 | d->maxConcurrentStreams = value; |
270 | 0 | } |
271 | | |
272 | | /*! |
273 | | \since 6.9 |
274 | | |
275 | | Returns the maximum number of concurrent streams. |
276 | | |
277 | | \sa setMaxConcurrentStreams() |
278 | | */ |
279 | | unsigned QHttp2Configuration::maxConcurrentStreams() const |
280 | 0 | { |
281 | 0 | return d->maxConcurrentStreams; |
282 | 0 | } |
283 | | |
284 | | /*! |
285 | | \memberswap{configuration} |
286 | | */ |
287 | | void QHttp2Configuration::swap(QHttp2Configuration &other) noexcept |
288 | 0 | { |
289 | 0 | d.swap(other.d); |
290 | 0 | } |
291 | | |
292 | | /*! |
293 | | \fn bool QHttp2Configuration::operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs) noexcept |
294 | | Returns \c true if \a lhs and \a rhs have the same set of HTTP/2 |
295 | | parameters. |
296 | | */ |
297 | | |
298 | | /*! |
299 | | \fn bool QHttp2Configuration::operator!=(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs) noexcept |
300 | | Returns \c true if \a lhs and \a rhs do not have the same set of HTTP/2 |
301 | | parameters. |
302 | | */ |
303 | | |
304 | | /*! |
305 | | \internal |
306 | | */ |
307 | | bool QHttp2Configuration::isEqual(const QHttp2Configuration &other) const noexcept |
308 | 0 | { |
309 | 0 | if (d == other.d) |
310 | 0 | return true; |
311 | | |
312 | 0 | return d->pushEnabled == other.d->pushEnabled |
313 | 0 | && d->huffmanCompressionEnabled == other.d->huffmanCompressionEnabled |
314 | 0 | && d->sessionWindowSize == other.d->sessionWindowSize |
315 | 0 | && d->streamWindowSize == other.d->streamWindowSize |
316 | 0 | && d->maxConcurrentStreams == other.d->maxConcurrentStreams; |
317 | 0 | } |
318 | | |
319 | | QT_END_NAMESPACE |