1 | // Copyright (C) 2022 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 | #include "qnetworkrequest.h" |
5 | #include "qnetworkrequest_p.h" |
6 | #include "qplatformdefs.h" |
7 | #include "qnetworkcookie.h" |
8 | #include "qsslconfiguration.h" |
9 | #if QT_CONFIG(http) |
10 | #include "qhttp1configuration.h" |
11 | #include "qhttp2configuration.h" |
12 | #include "private/http2protocol_p.h" |
13 | #endif |
14 | |
15 | #include "QtCore/qdatetime.h" |
16 | #include "QtCore/qlocale.h" |
17 | #include "QtCore/qshareddata.h" |
18 | #include "QtCore/qtimezone.h" |
19 | #include "QtCore/private/qtools_p.h" |
20 | |
21 | #include <ctype.h> |
22 | #if QT_CONFIG(datestring) |
23 | # include <stdio.h> |
24 | #endif |
25 | |
26 | #include <algorithm> |
27 | |
28 | QT_BEGIN_NAMESPACE |
29 | |
30 | using namespace Qt::StringLiterals; |
31 | |
32 | QT_IMPL_METATYPE_EXTERN(QNetworkRequest) |
33 | QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkRequest::RedirectPolicy, QNetworkRequest__RedirectPolicy) |
34 | |
35 | /*! |
36 | \class QNetworkRequest |
37 | \since 4.4 |
38 | \ingroup network |
39 | \ingroup shared |
40 | \inmodule QtNetwork |
41 | |
42 | \brief The QNetworkRequest class holds a request to be sent with QNetworkAccessManager. |
43 | |
44 | QNetworkRequest is part of the Network Access API and is the class |
45 | holding the information necessary to send a request over the |
46 | network. It contains a URL and some ancillary information that can |
47 | be used to modify the request. |
48 | |
49 | \sa QNetworkReply, QNetworkAccessManager |
50 | */ |
51 | |
52 | /*! |
53 | \enum QNetworkRequest::KnownHeaders |
54 | |
55 | List of known header types that QNetworkRequest parses. Each known |
56 | header is also represented in raw form with its full HTTP name. |
57 | |
58 | \value ContentDispositionHeader Corresponds to the HTTP |
59 | Content-Disposition header and contains a string containing the |
60 | disposition type (for instance, attachment) and a parameter (for |
61 | instance, filename). |
62 | |
63 | \value ContentTypeHeader Corresponds to the HTTP Content-Type |
64 | header and contains a string containing the media (MIME) type and |
65 | any auxiliary data (for instance, charset). |
66 | |
67 | \value ContentLengthHeader Corresponds to the HTTP Content-Length |
68 | header and contains the length in bytes of the data transmitted. |
69 | |
70 | \value LocationHeader Corresponds to the HTTP Location |
71 | header and contains a URL representing the actual location of the |
72 | data, including the destination URL in case of redirections. |
73 | |
74 | \value LastModifiedHeader Corresponds to the HTTP Last-Modified |
75 | header and contains a QDateTime representing the last modification |
76 | date of the contents. |
77 | |
78 | \value IfModifiedSinceHeader Corresponds to the HTTP If-Modified-Since |
79 | header and contains a QDateTime. It is usually added to a |
80 | QNetworkRequest. The server shall send a 304 (Not Modified) response |
81 | if the resource has not changed since this time. |
82 | |
83 | \value ETagHeader Corresponds to the HTTP ETag |
84 | header and contains a QString representing the last modification |
85 | state of the contents. |
86 | |
87 | \value IfMatchHeader Corresponds to the HTTP If-Match |
88 | header and contains a QStringList. It is usually added to a |
89 | QNetworkRequest. The server shall send a 412 (Precondition Failed) |
90 | response if the resource does not match. |
91 | |
92 | \value IfNoneMatchHeader Corresponds to the HTTP If-None-Match |
93 | header and contains a QStringList. It is usually added to a |
94 | QNetworkRequest. The server shall send a 304 (Not Modified) response |
95 | if the resource does match. |
96 | |
97 | \value CookieHeader Corresponds to the HTTP Cookie header |
98 | and contains a QList<QNetworkCookie> representing the cookies to |
99 | be sent back to the server. |
100 | |
101 | \value SetCookieHeader Corresponds to the HTTP Set-Cookie |
102 | header and contains a QList<QNetworkCookie> representing the |
103 | cookies sent by the server to be stored locally. |
104 | |
105 | \value UserAgentHeader The User-Agent header sent by HTTP clients. |
106 | |
107 | \value ServerHeader The Server header received by HTTP clients. |
108 | |
109 | \sa header(), setHeader(), rawHeader(), setRawHeader() |
110 | */ |
111 | |
112 | /*! |
113 | \enum QNetworkRequest::Attribute |
114 | \since 4.7 |
115 | |
116 | Attribute codes for the QNetworkRequest and QNetworkReply. |
117 | |
118 | Attributes are extra meta-data that are used to control the |
119 | behavior of the request and to pass further information from the |
120 | reply back to the application. Attributes are also extensible, |
121 | allowing custom implementations to pass custom values. |
122 | |
123 | The following table explains what the default attribute codes are, |
124 | the QVariant types associated, the default value if said attribute |
125 | is missing and whether it's used in requests or replies. |
126 | |
127 | \value HttpStatusCodeAttribute |
128 | Replies only, type: QMetaType::Int (no default) |
129 | Indicates the HTTP status code received from the HTTP server |
130 | (like 200, 304, 404, 401, etc.). If the connection was not |
131 | HTTP-based, this attribute will not be present. |
132 | |
133 | \value HttpReasonPhraseAttribute |
134 | Replies only, type: QMetaType::QByteArray (no default) |
135 | Indicates the HTTP reason phrase as received from the HTTP |
136 | server (like "Ok", "Found", "Not Found", "Access Denied", |
137 | etc.) This is the human-readable representation of the status |
138 | code (see above). If the connection was not HTTP-based, this |
139 | attribute will not be present. |
140 | |
141 | \value RedirectionTargetAttribute |
142 | Replies only, type: QMetaType::QUrl (no default) |
143 | If present, it indicates that the server is redirecting the |
144 | request to a different URL. The Network Access API does follow |
145 | redirections by default, unless |
146 | QNetworkRequest::ManualRedirectPolicy is used. Additionally, if |
147 | QNetworkRequest::UserVerifiedRedirectPolicy is used, then this |
148 | attribute will be set if the redirect was not followed. |
149 | The returned URL might be relative. Use QUrl::resolved() |
150 | to create an absolute URL out of it. |
151 | |
152 | \value ConnectionEncryptedAttribute |
153 | Replies only, type: QMetaType::Bool (default: false) |
154 | Indicates whether the data was obtained through an encrypted |
155 | (secure) connection. |
156 | |
157 | \value CacheLoadControlAttribute |
158 | Requests only, type: QMetaType::Int (default: QNetworkRequest::PreferNetwork) |
159 | Controls how the cache should be accessed. The possible values |
160 | are those of QNetworkRequest::CacheLoadControl. Note that the |
161 | default QNetworkAccessManager implementation does not support |
162 | caching. However, this attribute may be used by certain |
163 | backends to modify their requests (for example, for caching proxies). |
164 | |
165 | \value CacheSaveControlAttribute |
166 | Requests only, type: QMetaType::Bool (default: true) |
167 | Controls if the data obtained should be saved to cache for |
168 | future uses. If the value is false, the data obtained will not |
169 | be automatically cached. If true, data may be cached, provided |
170 | it is cacheable (what is cacheable depends on the protocol |
171 | being used). |
172 | |
173 | \value SourceIsFromCacheAttribute |
174 | Replies only, type: QMetaType::Bool (default: false) |
175 | Indicates whether the data was obtained from cache |
176 | or not. |
177 | |
178 | \value DoNotBufferUploadDataAttribute |
179 | Requests only, type: QMetaType::Bool (default: false) |
180 | Indicates whether the QNetworkAccessManager code is |
181 | allowed to buffer the upload data, e.g. when doing a HTTP POST. |
182 | When using this flag with sequential upload data, the ContentLengthHeader |
183 | header must be set. |
184 | |
185 | \value HttpPipeliningAllowedAttribute |
186 | Requests only, type: QMetaType::Bool (default: false) |
187 | Indicates whether the QNetworkAccessManager code is |
188 | allowed to use HTTP pipelining with this request. |
189 | |
190 | \value HttpPipeliningWasUsedAttribute |
191 | Replies only, type: QMetaType::Bool |
192 | Indicates whether the HTTP pipelining was used for receiving |
193 | this reply. |
194 | |
195 | \value CustomVerbAttribute |
196 | Requests only, type: QMetaType::QByteArray |
197 | Holds the value for the custom HTTP verb to send (destined for usage |
198 | of other verbs than GET, POST, PUT and DELETE). This verb is set |
199 | when calling QNetworkAccessManager::sendCustomRequest(). |
200 | |
201 | \value CookieLoadControlAttribute |
202 | Requests only, type: QMetaType::Int (default: QNetworkRequest::Automatic) |
203 | Indicates whether to send 'Cookie' headers in the request. |
204 | This attribute is set to false by Qt WebKit when creating a cross-origin |
205 | XMLHttpRequest where withCredentials has not been set explicitly to true by the |
206 | Javascript that created the request. |
207 | See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag}{here} for more information. |
208 | (This value was introduced in 4.7.) |
209 | |
210 | \value CookieSaveControlAttribute |
211 | Requests only, type: QMetaType::Int (default: QNetworkRequest::Automatic) |
212 | Indicates whether to save 'Cookie' headers received from the server in reply |
213 | to the request. |
214 | This attribute is set to false by Qt WebKit when creating a cross-origin |
215 | XMLHttpRequest where withCredentials has not been set explicitly to true by the |
216 | Javascript that created the request. |
217 | See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information. |
218 | (This value was introduced in 4.7.) |
219 | |
220 | \value AuthenticationReuseAttribute |
221 | Requests only, type: QMetaType::Int (default: QNetworkRequest::Automatic) |
222 | Indicates whether to use cached authorization credentials in the request, |
223 | if available. If this is set to QNetworkRequest::Manual and the authentication |
224 | mechanism is 'Basic' or 'Digest', Qt will not send an 'Authorization' HTTP |
225 | header with any cached credentials it may have for the request's URL. |
226 | This attribute is set to QNetworkRequest::Manual by Qt WebKit when creating a cross-origin |
227 | XMLHttpRequest where withCredentials has not been set explicitly to true by the |
228 | Javascript that created the request. |
229 | See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information. |
230 | (This value was introduced in 4.7.) |
231 | |
232 | \omitvalue MaximumDownloadBufferSizeAttribute |
233 | |
234 | \omitvalue DownloadBufferAttribute |
235 | |
236 | \omitvalue SynchronousRequestAttribute |
237 | |
238 | \value BackgroundRequestAttribute |
239 | Type: QMetaType::Bool (default: false) |
240 | Indicates that this is a background transfer, rather than a user initiated |
241 | transfer. Depending on the platform, background transfers may be subject |
242 | to different policies. |
243 | |
244 | \value Http2AllowedAttribute |
245 | Requests only, type: QMetaType::Bool (default: true) |
246 | Indicates whether the QNetworkAccessManager code is |
247 | allowed to use HTTP/2 with this request. This applies |
248 | to SSL requests or 'cleartext' HTTP/2 if Http2CleartextAllowedAttribute |
249 | is set. |
250 | |
251 | \value Http2WasUsedAttribute |
252 | Replies only, type: QMetaType::Bool (default: false) |
253 | Indicates whether HTTP/2 was used for receiving this reply. |
254 | (This value was introduced in 5.9.) |
255 | |
256 | \value EmitAllUploadProgressSignalsAttribute |
257 | Requests only, type: QMetaType::Bool (default: false) |
258 | Indicates whether all upload signals should be emitted. |
259 | By default, the uploadProgress signal is emitted only |
260 | in 100 millisecond intervals. |
261 | (This value was introduced in 5.5.) |
262 | |
263 | \value OriginalContentLengthAttribute |
264 | Replies only, type QMetaType::Int |
265 | Holds the original content-length attribute before being invalidated and |
266 | removed from the header when the data is compressed and the request was |
267 | marked to be decompressed automatically. |
268 | (This value was introduced in 5.9.) |
269 | |
270 | \value RedirectPolicyAttribute |
271 | Requests only, type: QMetaType::Int, should be one of the |
272 | QNetworkRequest::RedirectPolicy values |
273 | (default: NoLessSafeRedirectPolicy). |
274 | (This value was introduced in 5.9.) |
275 | |
276 | \value Http2DirectAttribute |
277 | Requests only, type: QMetaType::Bool (default: false) |
278 | If set, this attribute will force QNetworkAccessManager to use |
279 | HTTP/2 protocol without initial HTTP/2 protocol negotiation. |
280 | Use of this attribute implies prior knowledge that a particular |
281 | server supports HTTP/2. The attribute works with SSL or with 'cleartext' |
282 | HTTP/2 if Http2CleartextAllowedAttribute is set. |
283 | If a server turns out to not support HTTP/2, when HTTP/2 direct |
284 | was specified, QNetworkAccessManager gives up, without attempting to |
285 | fall back to HTTP/1.1. If both Http2AllowedAttribute and |
286 | Http2DirectAttribute are set, Http2DirectAttribute takes priority. |
287 | (This value was introduced in 5.11.) |
288 | |
289 | \omitvalue ResourceTypeAttribute |
290 | |
291 | \value AutoDeleteReplyOnFinishAttribute |
292 | Requests only, type: QMetaType::Bool (default: false) |
293 | If set, this attribute will make QNetworkAccessManager delete |
294 | the QNetworkReply after having emitted "finished". |
295 | (This value was introduced in 5.14.) |
296 | |
297 | \value ConnectionCacheExpiryTimeoutSecondsAttribute |
298 | Requests only, type: QMetaType::Int |
299 | To set when the TCP connections to a server (HTTP1 and HTTP2) should |
300 | be closed after the last pending request had been processed. |
301 | (This value was introduced in 6.3.) |
302 | |
303 | \value Http2CleartextAllowedAttribute |
304 | Requests only, type: QMetaType::Bool (default: false) |
305 | If set, this attribute will tell QNetworkAccessManager to attempt |
306 | an upgrade to HTTP/2 over cleartext (also known as h2c). |
307 | Until Qt 7 the default value for this attribute can be overridden |
308 | to true by setting the QT_NETWORK_H2C_ALLOWED environment variable. |
309 | This attribute is ignored if the Http2AllowedAttribute is not set. |
310 | (This value was introduced in 6.3.) |
311 | |
312 | \value UseCredentialsAttribute |
313 | Requests only, type: QMetaType::Bool (default: false) |
314 | Indicates if the underlying XMLHttpRequest cross-site Access-Control |
315 | requests should be made using credentials. Has no effect on |
316 | same-origin requests. This only affects the WebAssembly platform. |
317 | (This value was introduced in 6.5.) |
318 | |
319 | \value User |
320 | Special type. Additional information can be passed in |
321 | QVariants with types ranging from User to UserMax. The default |
322 | implementation of Network Access will ignore any request |
323 | attributes in this range and it will not produce any |
324 | attributes in this range in replies. The range is reserved for |
325 | extensions of QNetworkAccessManager. |
326 | |
327 | \value UserMax |
328 | Special type. See User. |
329 | */ |
330 | |
331 | /*! |
332 | \enum QNetworkRequest::CacheLoadControl |
333 | |
334 | Controls the caching mechanism of QNetworkAccessManager. |
335 | |
336 | \value AlwaysNetwork always load from network and do not |
337 | check if the cache has a valid entry (similar to the |
338 | "Reload" feature in browsers); in addition, force intermediate |
339 | caches to re-validate. |
340 | |
341 | \value PreferNetwork default value; load from the network |
342 | if the cached entry is older than the network entry. This will never |
343 | return stale data from the cache, but revalidate resources that |
344 | have become stale. |
345 | |
346 | \value PreferCache load from cache if available, |
347 | otherwise load from network. Note that this can return possibly |
348 | stale (but not expired) items from cache. |
349 | |
350 | \value AlwaysCache only load from cache, indicating error |
351 | if the item was not cached (i.e., off-line mode) |
352 | */ |
353 | |
354 | /*! |
355 | \enum QNetworkRequest::LoadControl |
356 | \since 4.7 |
357 | |
358 | Indicates if an aspect of the request's loading mechanism has been |
359 | manually overridden, e.g. by Qt WebKit. |
360 | |
361 | \value Automatic default value: indicates default behaviour. |
362 | |
363 | \value Manual indicates behaviour has been manually overridden. |
364 | */ |
365 | |
366 | /*! |
367 | \enum QNetworkRequest::RedirectPolicy |
368 | \since 5.9 |
369 | |
370 | Indicates whether the Network Access API should automatically follow a |
371 | HTTP redirect response or not. |
372 | |
373 | \value ManualRedirectPolicy Not following any redirects. |
374 | |
375 | \value NoLessSafeRedirectPolicy Default value: Only "http"->"http", |
376 | "http" -> "https" or "https" -> "https" redirects |
377 | are allowed. |
378 | |
379 | \value SameOriginRedirectPolicy Require the same protocol, host and port. |
380 | Note, http://example.com and http://example.com:80 |
381 | will fail with this policy (implicit/explicit ports |
382 | are considered to be a mismatch). |
383 | |
384 | \value UserVerifiedRedirectPolicy Client decides whether to follow each |
385 | redirect by handling the redirected() |
386 | signal, emitting redirectAllowed() on |
387 | the QNetworkReply object to allow |
388 | the redirect or aborting/finishing it to |
389 | reject the redirect. This can be used, |
390 | for example, to ask the user whether to |
391 | accept the redirect, or to decide |
392 | based on some app-specific configuration. |
393 | |
394 | \note When Qt handles redirects it will, for legacy and compatibility |
395 | reasons, issue the redirected request using GET when the server returns |
396 | a 301 or 302 response, regardless of the original method used, unless it was |
397 | HEAD. |
398 | */ |
399 | |
400 | /*! |
401 | \enum QNetworkRequest::TransferTimeoutConstant |
402 | \since 5.15 |
403 | |
404 | A constant that can be used for enabling transfer |
405 | timeouts with a preset value. |
406 | |
407 | \value DefaultTransferTimeoutConstant The transfer timeout in milliseconds. |
408 | Used if setTimeout() is called |
409 | without an argument. |
410 | */ |
411 | |
412 | class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate |
413 | { |
414 | public: |
415 | static const int maxRedirectCount = 50; |
416 | inline QNetworkRequestPrivate() |
417 | : priority(QNetworkRequest::NormalPriority) |
418 | #ifndef QT_NO_SSL |
419 | , sslConfiguration(nullptr) |
420 | #endif |
421 | , maxRedirectsAllowed(maxRedirectCount) |
422 | , transferTimeout(0) |
423 | { qRegisterMetaType<QNetworkRequest>(); } |
424 | ~QNetworkRequestPrivate() |
425 | { |
426 | #ifndef QT_NO_SSL |
427 | delete sslConfiguration; |
428 | #endif |
429 | } |
430 | |
431 | |
432 | QNetworkRequestPrivate(const QNetworkRequestPrivate &other) |
433 | : QSharedData(other), QNetworkHeadersPrivate(other) |
434 | { |
435 | url = other.url; |
436 | priority = other.priority; |
437 | maxRedirectsAllowed = other.maxRedirectsAllowed; |
438 | #ifndef QT_NO_SSL |
439 | sslConfiguration = nullptr; |
440 | if (other.sslConfiguration) |
441 | sslConfiguration = new QSslConfiguration(*other.sslConfiguration); |
442 | #endif |
443 | peerVerifyName = other.peerVerifyName; |
444 | #if QT_CONFIG(http) |
445 | h1Configuration = other.h1Configuration; |
446 | h2Configuration = other.h2Configuration; |
447 | decompressedSafetyCheckThreshold = other.decompressedSafetyCheckThreshold; |
448 | #endif |
449 | transferTimeout = other.transferTimeout; |
450 | } |
451 | |
452 | inline bool operator==(const QNetworkRequestPrivate &other) const |
453 | { |
454 | return url == other.url && |
455 | priority == other.priority && |
456 | rawHeaders == other.rawHeaders && |
457 | attributes == other.attributes && |
458 | maxRedirectsAllowed == other.maxRedirectsAllowed && |
459 | peerVerifyName == other.peerVerifyName |
460 | #if QT_CONFIG(http) |
461 | && h1Configuration == other.h1Configuration |
462 | && h2Configuration == other.h2Configuration |
463 | && decompressedSafetyCheckThreshold == other.decompressedSafetyCheckThreshold |
464 | #endif |
465 | && transferTimeout == other.transferTimeout |
466 | ; |
467 | // don't compare cookedHeaders |
468 | } |
469 | |
470 | QUrl url; |
471 | QNetworkRequest::Priority priority; |
472 | #ifndef QT_NO_SSL |
473 | mutable QSslConfiguration *sslConfiguration; |
474 | #endif |
475 | int maxRedirectsAllowed; |
476 | QString peerVerifyName; |
477 | #if QT_CONFIG(http) |
478 | QHttp1Configuration h1Configuration; |
479 | QHttp2Configuration h2Configuration; |
480 | qint64 decompressedSafetyCheckThreshold = 10ll * 1024ll * 1024ll; |
481 | #endif |
482 | int transferTimeout; |
483 | }; |
484 | |
485 | /*! |
486 | Constructs a QNetworkRequest object with no URL to be requested. |
487 | Use setUrl() to set one. |
488 | |
489 | \sa url(), setUrl() |
490 | */ |
491 | QNetworkRequest::QNetworkRequest() |
492 | : d(new QNetworkRequestPrivate) |
493 | { |
494 | #if QT_CONFIG(http) |
495 | // Initial values proposed by RFC 7540 are quite draconian, but we |
496 | // know about servers configured with this value as maximum possible, |
497 | // rejecting our SETTINGS frame and sending us a GOAWAY frame with the |
498 | // flow control error set. If this causes a problem - the app should |
499 | // set a proper configuration. We'll use our defaults, as documented. |
500 | d->h2Configuration.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize); |
501 | d->h2Configuration.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize); |
502 | d->h2Configuration.setServerPushEnabled(false); |
503 | #endif // QT_CONFIG(http) |
504 | } |
505 | |
506 | /*! |
507 | Constructs a QNetworkRequest object with \a url as the URL to be |
508 | requested. |
509 | |
510 | \sa url(), setUrl() |
511 | */ |
512 | QNetworkRequest::QNetworkRequest(const QUrl &url) |
513 | : QNetworkRequest() |
514 | { |
515 | d->url = url; |
516 | } |
517 | |
518 | /*! |
519 | Creates a copy of \a other. |
520 | */ |
521 | QNetworkRequest::QNetworkRequest(const QNetworkRequest &other) |
522 | : d(other.d) |
523 | { |
524 | } |
525 | |
526 | /*! |
527 | Disposes of the QNetworkRequest object. |
528 | */ |
529 | QNetworkRequest::~QNetworkRequest() |
530 | { |
531 | // QSharedDataPointer auto deletes |
532 | d = nullptr; |
533 | } |
534 | |
535 | /*! |
536 | Returns \c true if this object is the same as \a other (i.e., if they |
537 | have the same URL, same headers and same meta-data settings). |
538 | |
539 | \sa operator!=() |
540 | */ |
541 | bool QNetworkRequest::operator==(const QNetworkRequest &other) const |
542 | { |
543 | return d == other.d || *d == *other.d; |
544 | } |
545 | |
546 | /*! |
547 | \fn bool QNetworkRequest::operator!=(const QNetworkRequest &other) const |
548 | |
549 | Returns \c false if this object is not the same as \a other. |
550 | |
551 | \sa operator==() |
552 | */ |
553 | |
554 | /*! |
555 | Creates a copy of \a other |
556 | */ |
557 | QNetworkRequest &QNetworkRequest::operator=(const QNetworkRequest &other) |
558 | { |
559 | d = other.d; |
560 | return *this; |
561 | } |
562 | |
563 | /*! |
564 | \fn void QNetworkRequest::swap(QNetworkRequest &other) |
565 | \since 5.0 |
566 | |
567 | Swaps this network request with \a other. This function is very |
568 | fast and never fails. |
569 | */ |
570 | |
571 | /*! |
572 | Returns the URL this network request is referring to. |
573 | |
574 | \sa setUrl() |
575 | */ |
576 | QUrl QNetworkRequest::url() const |
577 | { |
578 | return d->url; |
579 | } |
580 | |
581 | /*! |
582 | Sets the URL this network request is referring to be \a url. |
583 | |
584 | \sa url() |
585 | */ |
586 | void QNetworkRequest::setUrl(const QUrl &url) |
587 | { |
588 | d->url = url; |
589 | } |
590 | |
591 | /*! |
592 | Returns the value of the known network header \a header if it is |
593 | present in this request. If it is not present, returns QVariant() |
594 | (i.e., an invalid variant). |
595 | |
596 | \sa KnownHeaders, rawHeader(), setHeader() |
597 | */ |
598 | QVariant QNetworkRequest::(KnownHeaders ) const |
599 | { |
600 | return d->cookedHeaders.value(key: header); |
601 | } |
602 | |
603 | /*! |
604 | Sets the value of the known header \a header to be \a value, |
605 | overriding any previously set headers. This operation also sets |
606 | the equivalent raw HTTP header. |
607 | |
608 | \sa KnownHeaders, setRawHeader(), header() |
609 | */ |
610 | void QNetworkRequest::(KnownHeaders , const QVariant &value) |
611 | { |
612 | d->setCookedHeader(header, value); |
613 | } |
614 | |
615 | /*! |
616 | Returns \c true if the raw header \a headerName is present in this |
617 | network request. |
618 | |
619 | \sa rawHeader(), setRawHeader() |
620 | */ |
621 | bool QNetworkRequest::(const QByteArray &) const |
622 | { |
623 | return d->findRawHeader(key: headerName) != d->rawHeaders.constEnd(); |
624 | } |
625 | |
626 | /*! |
627 | Returns the raw form of header \a headerName. If no such header is |
628 | present, an empty QByteArray is returned, which may be |
629 | indistinguishable from a header that is present but has no content |
630 | (use hasRawHeader() to find out if the header exists or not). |
631 | |
632 | Raw headers can be set with setRawHeader() or with setHeader(). |
633 | |
634 | \sa header(), setRawHeader() |
635 | */ |
636 | QByteArray QNetworkRequest::(const QByteArray &) const |
637 | { |
638 | QNetworkHeadersPrivate::RawHeadersList::ConstIterator it = |
639 | d->findRawHeader(key: headerName); |
640 | if (it != d->rawHeaders.constEnd()) |
641 | return it->second; |
642 | return QByteArray(); |
643 | } |
644 | |
645 | /*! |
646 | Returns a list of all raw headers that are set in this network |
647 | request. The list is in the order that the headers were set. |
648 | |
649 | \sa hasRawHeader(), rawHeader() |
650 | */ |
651 | QList<QByteArray> QNetworkRequest::() const |
652 | { |
653 | return d->rawHeadersKeys(); |
654 | } |
655 | |
656 | /*! |
657 | Sets the header \a headerName to be of value \a headerValue. If \a |
658 | headerName corresponds to a known header (see |
659 | QNetworkRequest::KnownHeaders), the raw format will be parsed and |
660 | the corresponding "cooked" header will be set as well. |
661 | |
662 | For example: |
663 | \snippet code/src_network_access_qnetworkrequest.cpp 0 |
664 | |
665 | will also set the known header LastModifiedHeader to be the |
666 | QDateTime object of the parsed date. |
667 | |
668 | \note Setting the same header twice overrides the previous |
669 | setting. To accomplish the behaviour of multiple HTTP headers of |
670 | the same name, you should concatenate the two values, separating |
671 | them with a comma (",") and set one single raw header. |
672 | |
673 | \sa KnownHeaders, setHeader(), hasRawHeader(), rawHeader() |
674 | */ |
675 | void QNetworkRequest::(const QByteArray &, const QByteArray &) |
676 | { |
677 | d->setRawHeader(key: headerName, value: headerValue); |
678 | } |
679 | |
680 | /*! |
681 | Returns the attribute associated with the code \a code. If the |
682 | attribute has not been set, it returns \a defaultValue. |
683 | |
684 | \note This function does not apply the defaults listed in |
685 | QNetworkRequest::Attribute. |
686 | |
687 | \sa setAttribute(), QNetworkRequest::Attribute |
688 | */ |
689 | QVariant QNetworkRequest::attribute(Attribute code, const QVariant &defaultValue) const |
690 | { |
691 | return d->attributes.value(key: code, defaultValue); |
692 | } |
693 | |
694 | /*! |
695 | Sets the attribute associated with code \a code to be value \a |
696 | value. If the attribute is already set, the previous value is |
697 | discarded. In special, if \a value is an invalid QVariant, the |
698 | attribute is unset. |
699 | |
700 | \sa attribute(), QNetworkRequest::Attribute |
701 | */ |
702 | void QNetworkRequest::setAttribute(Attribute code, const QVariant &value) |
703 | { |
704 | if (value.isValid()) |
705 | d->attributes.insert(key: code, value); |
706 | else |
707 | d->attributes.remove(key: code); |
708 | } |
709 | |
710 | #ifndef QT_NO_SSL |
711 | /*! |
712 | Returns this network request's SSL configuration. By default this is the same |
713 | as QSslConfiguration::defaultConfiguration(). |
714 | |
715 | \sa setSslConfiguration(), QSslConfiguration::defaultConfiguration() |
716 | */ |
717 | QSslConfiguration QNetworkRequest::sslConfiguration() const |
718 | { |
719 | if (!d->sslConfiguration) |
720 | d->sslConfiguration = new QSslConfiguration(QSslConfiguration::defaultConfiguration()); |
721 | return *d->sslConfiguration; |
722 | } |
723 | |
724 | /*! |
725 | Sets this network request's SSL configuration to be \a config. The |
726 | settings that apply are the private key, the local certificate, |
727 | the TLS protocol (e.g. TLS 1.3), the CA certificates and the ciphers that |
728 | the SSL backend is allowed to use. |
729 | |
730 | \sa sslConfiguration(), QSslConfiguration::defaultConfiguration() |
731 | */ |
732 | void QNetworkRequest::setSslConfiguration(const QSslConfiguration &config) |
733 | { |
734 | if (!d->sslConfiguration) |
735 | d->sslConfiguration = new QSslConfiguration(config); |
736 | else |
737 | *d->sslConfiguration = config; |
738 | } |
739 | #endif |
740 | |
741 | /*! |
742 | \since 4.6 |
743 | |
744 | Allows setting a reference to the \a object initiating |
745 | the request. |
746 | |
747 | For example Qt WebKit sets the originating object to the |
748 | QWebFrame that initiated the request. |
749 | |
750 | \sa originatingObject() |
751 | */ |
752 | void QNetworkRequest::setOriginatingObject(QObject *object) |
753 | { |
754 | d->originatingObject = object; |
755 | } |
756 | |
757 | /*! |
758 | \since 4.6 |
759 | |
760 | Returns a reference to the object that initiated this |
761 | network request; returns \nullptr if not set or the object has |
762 | been destroyed. |
763 | |
764 | \sa setOriginatingObject() |
765 | */ |
766 | QObject *QNetworkRequest::originatingObject() const |
767 | { |
768 | return d->originatingObject.data(); |
769 | } |
770 | |
771 | /*! |
772 | \since 4.7 |
773 | |
774 | Return the priority of this request. |
775 | |
776 | \sa setPriority() |
777 | */ |
778 | QNetworkRequest::Priority QNetworkRequest::priority() const |
779 | { |
780 | return d->priority; |
781 | } |
782 | |
783 | /*! \enum QNetworkRequest::Priority |
784 | |
785 | \since 4.7 |
786 | |
787 | This enum lists the possible network request priorities. |
788 | |
789 | \value HighPriority High priority |
790 | \value NormalPriority Normal priority |
791 | \value LowPriority Low priority |
792 | */ |
793 | |
794 | /*! |
795 | \since 4.7 |
796 | |
797 | Set the priority of this request to \a priority. |
798 | |
799 | \note The \a priority is only a hint to the network access |
800 | manager. It can use it or not. Currently it is used for HTTP to |
801 | decide which request should be sent first to a server. |
802 | |
803 | \sa priority() |
804 | */ |
805 | void QNetworkRequest::setPriority(Priority priority) |
806 | { |
807 | d->priority = priority; |
808 | } |
809 | |
810 | /*! |
811 | \since 5.6 |
812 | |
813 | Returns the maximum number of redirects allowed to be followed for this |
814 | request. |
815 | |
816 | \sa setMaximumRedirectsAllowed() |
817 | */ |
818 | int QNetworkRequest::maximumRedirectsAllowed() const |
819 | { |
820 | return d->maxRedirectsAllowed; |
821 | } |
822 | |
823 | /*! |
824 | \since 5.6 |
825 | |
826 | Sets the maximum number of redirects allowed to be followed for this |
827 | request to \a maxRedirectsAllowed. |
828 | |
829 | \sa maximumRedirectsAllowed() |
830 | */ |
831 | void QNetworkRequest::setMaximumRedirectsAllowed(int maxRedirectsAllowed) |
832 | { |
833 | d->maxRedirectsAllowed = maxRedirectsAllowed; |
834 | } |
835 | |
836 | /*! |
837 | \since 5.13 |
838 | |
839 | Returns the host name set for the certificate validation, as set by |
840 | setPeerVerifyName. By default this returns a null string. |
841 | |
842 | \sa setPeerVerifyName |
843 | */ |
844 | QString QNetworkRequest::peerVerifyName() const |
845 | { |
846 | return d->peerVerifyName; |
847 | } |
848 | |
849 | /*! |
850 | \since 5.13 |
851 | |
852 | Sets \a peerName as host name for the certificate validation, instead of the one used for the |
853 | TCP connection. |
854 | |
855 | \sa peerVerifyName |
856 | */ |
857 | void QNetworkRequest::setPeerVerifyName(const QString &peerName) |
858 | { |
859 | d->peerVerifyName = peerName; |
860 | } |
861 | |
862 | #if QT_CONFIG(http) |
863 | /*! |
864 | \since 6.5 |
865 | |
866 | Returns the current parameters that QNetworkAccessManager is |
867 | using for the underlying HTTP/1 connection of this request. |
868 | |
869 | \sa setHttp1Configuration |
870 | */ |
871 | QHttp1Configuration QNetworkRequest::http1Configuration() const |
872 | { |
873 | return d->h1Configuration; |
874 | } |
875 | /*! |
876 | \since 6.5 |
877 | |
878 | Sets request's HTTP/1 parameters from \a configuration. |
879 | |
880 | \sa http1Configuration, QNetworkAccessManager, QHttp1Configuration |
881 | */ |
882 | void QNetworkRequest::setHttp1Configuration(const QHttp1Configuration &configuration) |
883 | { |
884 | d->h1Configuration = configuration; |
885 | } |
886 | |
887 | /*! |
888 | \since 5.14 |
889 | |
890 | Returns the current parameters that QNetworkAccessManager is |
891 | using for this request and its underlying HTTP/2 connection. |
892 | This is either a configuration previously set by an application |
893 | or a default configuration. |
894 | |
895 | The default values that QNetworkAccessManager is using are: |
896 | |
897 | \list |
898 | \li Window size for connection-level flowcontrol is 2147483647 octets |
899 | \li Window size for stream-level flowcontrol is 214748364 octets |
900 | \li Max frame size is 16384 |
901 | \endlist |
902 | |
903 | By default, server push is disabled, Huffman compression and |
904 | string indexing are enabled. |
905 | |
906 | \sa setHttp2Configuration |
907 | */ |
908 | QHttp2Configuration QNetworkRequest::http2Configuration() const |
909 | { |
910 | return d->h2Configuration; |
911 | } |
912 | |
913 | /*! |
914 | \since 5.14 |
915 | |
916 | Sets request's HTTP/2 parameters from \a configuration. |
917 | |
918 | \note The configuration must be set prior to making a request. |
919 | \note HTTP/2 multiplexes several streams in a single HTTP/2 |
920 | connection. This implies that QNetworkAccessManager will use |
921 | the configuration found in the first request from a series |
922 | of requests sent to the same host. |
923 | |
924 | \sa http2Configuration, QNetworkAccessManager, QHttp2Configuration |
925 | */ |
926 | void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configuration) |
927 | { |
928 | d->h2Configuration = configuration; |
929 | } |
930 | |
931 | /*! |
932 | \since 6.2 |
933 | |
934 | Returns the threshold for archive bomb checks. |
935 | |
936 | If the decompressed size of a reply is smaller than this, Qt will simply |
937 | decompress it, without further checking. |
938 | |
939 | \sa setDecompressedSafetyCheckThreshold() |
940 | */ |
941 | qint64 QNetworkRequest::decompressedSafetyCheckThreshold() const |
942 | { |
943 | return d->decompressedSafetyCheckThreshold; |
944 | } |
945 | |
946 | /*! |
947 | \since 6.2 |
948 | |
949 | Sets the \a threshold for archive bomb checks. |
950 | |
951 | Some supported compression algorithms can, in a tiny compressed file, encode |
952 | a spectacularly huge decompressed file. This is only possible if the |
953 | decompressed content is extremely monotonous, which is seldom the case for |
954 | real files being transmitted in good faith: files exercising such insanely |
955 | high compression ratios are typically payloads of buffer-overrun attacks, or |
956 | denial-of-service (by using up too much memory) attacks. Consequently, files |
957 | that decompress to huge sizes, particularly from tiny compressed forms, are |
958 | best rejected as suspected malware. |
959 | |
960 | If a reply's decompressed size is bigger than this threshold (by default, |
961 | 10 MiB, i.e. 10 * 1024 * 1024), Qt will check the compression ratio: if that |
962 | is unreasonably large (40:1 for GZip and Deflate, or 100:1 for Brotli and |
963 | ZStandard), the reply will be treated as an error. Setting the threshold |
964 | to \c{-1} disables this check. |
965 | |
966 | \sa decompressedSafetyCheckThreshold() |
967 | */ |
968 | void QNetworkRequest::setDecompressedSafetyCheckThreshold(qint64 threshold) |
969 | { |
970 | d->decompressedSafetyCheckThreshold = threshold; |
971 | } |
972 | #endif // QT_CONFIG(http) |
973 | |
974 | #if QT_CONFIG(http) || defined (Q_OS_WASM) |
975 | /*! |
976 | \since 5.15 |
977 | |
978 | Returns the timeout used for transfers, in milliseconds. |
979 | |
980 | This timeout is zero if setTransferTimeout hasn't been |
981 | called, which means that the timeout is not used. |
982 | |
983 | \sa setTransferTimeout |
984 | */ |
985 | int QNetworkRequest::transferTimeout() const |
986 | { |
987 | return d->transferTimeout; |
988 | } |
989 | |
990 | /*! |
991 | \since 5.15 |
992 | |
993 | Sets \a timeout as the transfer timeout in milliseconds. |
994 | |
995 | Transfers are aborted if no bytes are transferred before |
996 | the timeout expires. Zero means no timer is set. If no |
997 | argument is provided, the timeout is |
998 | QNetworkRequest::DefaultTransferTimeoutConstant. If this function |
999 | is not called, the timeout is disabled and has the |
1000 | value zero. |
1001 | |
1002 | \sa transferTimeout |
1003 | */ |
1004 | void QNetworkRequest::setTransferTimeout(int timeout) |
1005 | { |
1006 | d->transferTimeout = timeout; |
1007 | } |
1008 | #endif // QT_CONFIG(http) || defined (Q_OS_WASM) |
1009 | |
1010 | static QByteArray (QNetworkRequest::KnownHeaders ) |
1011 | { |
1012 | switch (header) { |
1013 | case QNetworkRequest::ContentTypeHeader: |
1014 | return "Content-Type" ; |
1015 | |
1016 | case QNetworkRequest::ContentLengthHeader: |
1017 | return "Content-Length" ; |
1018 | |
1019 | case QNetworkRequest::LocationHeader: |
1020 | return "Location" ; |
1021 | |
1022 | case QNetworkRequest::LastModifiedHeader: |
1023 | return "Last-Modified" ; |
1024 | |
1025 | case QNetworkRequest::IfModifiedSinceHeader: |
1026 | return "If-Modified-Since" ; |
1027 | |
1028 | case QNetworkRequest::ETagHeader: |
1029 | return "ETag" ; |
1030 | |
1031 | case QNetworkRequest::IfMatchHeader: |
1032 | return "If-Match" ; |
1033 | |
1034 | case QNetworkRequest::IfNoneMatchHeader: |
1035 | return "If-None-Match" ; |
1036 | |
1037 | case QNetworkRequest::CookieHeader: |
1038 | return "Cookie" ; |
1039 | |
1040 | case QNetworkRequest::SetCookieHeader: |
1041 | return "Set-Cookie" ; |
1042 | |
1043 | case QNetworkRequest::ContentDispositionHeader: |
1044 | return "Content-Disposition" ; |
1045 | |
1046 | case QNetworkRequest::UserAgentHeader: |
1047 | return "User-Agent" ; |
1048 | |
1049 | case QNetworkRequest::ServerHeader: |
1050 | return "Server" ; |
1051 | |
1052 | // no default: |
1053 | // if new values are added, this will generate a compiler warning |
1054 | } |
1055 | |
1056 | return QByteArray(); |
1057 | } |
1058 | |
1059 | static QByteArray (QNetworkRequest::KnownHeaders , const QVariant &value) |
1060 | { |
1061 | switch (header) { |
1062 | case QNetworkRequest::ContentTypeHeader: |
1063 | case QNetworkRequest::ContentLengthHeader: |
1064 | case QNetworkRequest::ContentDispositionHeader: |
1065 | case QNetworkRequest::UserAgentHeader: |
1066 | case QNetworkRequest::ServerHeader: |
1067 | case QNetworkRequest::ETagHeader: |
1068 | case QNetworkRequest::IfMatchHeader: |
1069 | case QNetworkRequest::IfNoneMatchHeader: |
1070 | return value.toByteArray(); |
1071 | |
1072 | case QNetworkRequest::LocationHeader: |
1073 | switch (value.userType()) { |
1074 | case QMetaType::QUrl: |
1075 | return value.toUrl().toEncoded(); |
1076 | |
1077 | default: |
1078 | return value.toByteArray(); |
1079 | } |
1080 | |
1081 | case QNetworkRequest::LastModifiedHeader: |
1082 | case QNetworkRequest::IfModifiedSinceHeader: |
1083 | switch (value.userType()) { |
1084 | // Generate RFC 1123/822 dates: |
1085 | case QMetaType::QDate: |
1086 | return QNetworkHeadersPrivate::toHttpDate(dt: value.toDate().startOfDay(zone: QTimeZone::UTC)); |
1087 | case QMetaType::QDateTime: |
1088 | return QNetworkHeadersPrivate::toHttpDate(dt: value.toDateTime()); |
1089 | |
1090 | default: |
1091 | return value.toByteArray(); |
1092 | } |
1093 | |
1094 | case QNetworkRequest::CookieHeader: { |
1095 | QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(v: value); |
1096 | if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>()) |
1097 | cookies << qvariant_cast<QNetworkCookie>(v: value); |
1098 | |
1099 | QByteArray result; |
1100 | bool first = true; |
1101 | for (const QNetworkCookie &cookie : std::as_const(t&: cookies)) { |
1102 | if (!first) |
1103 | result += "; " ; |
1104 | first = false; |
1105 | result += cookie.toRawForm(form: QNetworkCookie::NameAndValueOnly); |
1106 | } |
1107 | return result; |
1108 | } |
1109 | |
1110 | case QNetworkRequest::SetCookieHeader: { |
1111 | QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(v: value); |
1112 | if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>()) |
1113 | cookies << qvariant_cast<QNetworkCookie>(v: value); |
1114 | |
1115 | QByteArray result; |
1116 | bool first = true; |
1117 | for (const QNetworkCookie &cookie : std::as_const(t&: cookies)) { |
1118 | if (!first) |
1119 | result += ", " ; |
1120 | first = false; |
1121 | result += cookie.toRawForm(form: QNetworkCookie::Full); |
1122 | } |
1123 | return result; |
1124 | } |
1125 | } |
1126 | |
1127 | return QByteArray(); |
1128 | } |
1129 | |
1130 | static int (const QByteArray &) |
1131 | { |
1132 | if (headerName.isEmpty()) |
1133 | return -1; |
1134 | |
1135 | auto is = [&](const char *what) { |
1136 | return qstrnicmp(headerName.data(), headerName.size(), what) == 0; |
1137 | }; |
1138 | |
1139 | switch (QtMiscUtils::toAsciiLower(ch: headerName.front())) { |
1140 | case 'c': |
1141 | if (is("content-type" )) |
1142 | return QNetworkRequest::ContentTypeHeader; |
1143 | else if (is("content-length" )) |
1144 | return QNetworkRequest::ContentLengthHeader; |
1145 | else if (is("cookie" )) |
1146 | return QNetworkRequest::CookieHeader; |
1147 | else if (is("content-disposition" )) |
1148 | return QNetworkRequest::ContentDispositionHeader; |
1149 | break; |
1150 | |
1151 | case 'e': |
1152 | if (is("etag" )) |
1153 | return QNetworkRequest::ETagHeader; |
1154 | break; |
1155 | |
1156 | case 'i': |
1157 | if (is("if-modified-since" )) |
1158 | return QNetworkRequest::IfModifiedSinceHeader; |
1159 | if (is("if-match" )) |
1160 | return QNetworkRequest::IfMatchHeader; |
1161 | if (is("if-none-match" )) |
1162 | return QNetworkRequest::IfNoneMatchHeader; |
1163 | break; |
1164 | |
1165 | case 'l': |
1166 | if (is("location" )) |
1167 | return QNetworkRequest::LocationHeader; |
1168 | else if (is("last-modified" )) |
1169 | return QNetworkRequest::LastModifiedHeader; |
1170 | break; |
1171 | |
1172 | case 's': |
1173 | if (is("set-cookie" )) |
1174 | return QNetworkRequest::SetCookieHeader; |
1175 | else if (is("server" )) |
1176 | return QNetworkRequest::ServerHeader; |
1177 | break; |
1178 | |
1179 | case 'u': |
1180 | if (is("user-agent" )) |
1181 | return QNetworkRequest::UserAgentHeader; |
1182 | break; |
1183 | } |
1184 | |
1185 | return -1; // nothing found |
1186 | } |
1187 | |
1188 | static QVariant parseHttpDate(const QByteArray &raw) |
1189 | { |
1190 | QDateTime dt = QNetworkHeadersPrivate::fromHttpDate(value: raw); |
1191 | if (dt.isValid()) |
1192 | return dt; |
1193 | return QVariant(); // transform an invalid QDateTime into a null QVariant |
1194 | } |
1195 | |
1196 | static QVariant (const QByteArray &raw) |
1197 | { |
1198 | QList<QNetworkCookie> result; |
1199 | const QList<QByteArray> cookieList = raw.split(sep: ';'); |
1200 | for (const QByteArray &cookie : cookieList) { |
1201 | QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookieString: cookie.trimmed()); |
1202 | if (parsed.size() != 1) |
1203 | return QVariant(); // invalid Cookie: header |
1204 | |
1205 | result += parsed; |
1206 | } |
1207 | |
1208 | return QVariant::fromValue(value: result); |
1209 | } |
1210 | |
1211 | static QVariant parseETag(const QByteArray &raw) |
1212 | { |
1213 | const QByteArray trimmed = raw.trimmed(); |
1214 | if (!trimmed.startsWith(c: '"') && !trimmed.startsWith(bv: R"(W/")" )) |
1215 | return QVariant(); |
1216 | |
1217 | if (!trimmed.endsWith(c: '"')) |
1218 | return QVariant(); |
1219 | |
1220 | return QString::fromLatin1(ba: trimmed); |
1221 | } |
1222 | |
1223 | static QVariant parseIfMatch(const QByteArray &raw) |
1224 | { |
1225 | const QByteArray trimmedRaw = raw.trimmed(); |
1226 | if (trimmedRaw == "*" ) |
1227 | return QStringList(QStringLiteral("*" )); |
1228 | |
1229 | QStringList tags; |
1230 | const QList<QByteArray> split = trimmedRaw.split(sep: ','); |
1231 | for (const QByteArray &element : split) { |
1232 | const QByteArray trimmed = element.trimmed(); |
1233 | if (!trimmed.startsWith(c: '"')) |
1234 | continue; |
1235 | |
1236 | if (!trimmed.endsWith(c: '"')) |
1237 | continue; |
1238 | |
1239 | tags += QString::fromLatin1(ba: trimmed); |
1240 | } |
1241 | return tags; |
1242 | } |
1243 | |
1244 | static QVariant parseIfNoneMatch(const QByteArray &raw) |
1245 | { |
1246 | const QByteArray trimmedRaw = raw.trimmed(); |
1247 | if (trimmedRaw == "*" ) |
1248 | return QStringList(QStringLiteral("*" )); |
1249 | |
1250 | QStringList tags; |
1251 | const QList<QByteArray> split = trimmedRaw.split(sep: ','); |
1252 | for (const QByteArray &element : split) { |
1253 | const QByteArray trimmed = element.trimmed(); |
1254 | if (!trimmed.startsWith(c: '"') && !trimmed.startsWith(bv: R"(W/")" )) |
1255 | continue; |
1256 | |
1257 | if (!trimmed.endsWith(c: '"')) |
1258 | continue; |
1259 | |
1260 | tags += QString::fromLatin1(ba: trimmed); |
1261 | } |
1262 | return tags; |
1263 | } |
1264 | |
1265 | |
1266 | static QVariant (QNetworkRequest::KnownHeaders , const QByteArray &value) |
1267 | { |
1268 | // header is always a valid value |
1269 | switch (header) { |
1270 | case QNetworkRequest::UserAgentHeader: |
1271 | case QNetworkRequest::ServerHeader: |
1272 | case QNetworkRequest::ContentTypeHeader: |
1273 | case QNetworkRequest::ContentDispositionHeader: |
1274 | // copy exactly, convert to QString |
1275 | return QString::fromLatin1(ba: value); |
1276 | |
1277 | case QNetworkRequest::ContentLengthHeader: { |
1278 | bool ok; |
1279 | qint64 result = value.trimmed().toLongLong(ok: &ok); |
1280 | if (ok) |
1281 | return result; |
1282 | return QVariant(); |
1283 | } |
1284 | |
1285 | case QNetworkRequest::LocationHeader: { |
1286 | QUrl result = QUrl::fromEncoded(url: value, mode: QUrl::StrictMode); |
1287 | if (result.isValid() && !result.scheme().isEmpty()) |
1288 | return result; |
1289 | return QVariant(); |
1290 | } |
1291 | |
1292 | case QNetworkRequest::LastModifiedHeader: |
1293 | case QNetworkRequest::IfModifiedSinceHeader: |
1294 | return parseHttpDate(raw: value); |
1295 | |
1296 | case QNetworkRequest::ETagHeader: |
1297 | return parseETag(raw: value); |
1298 | |
1299 | case QNetworkRequest::IfMatchHeader: |
1300 | return parseIfMatch(raw: value); |
1301 | |
1302 | case QNetworkRequest::IfNoneMatchHeader: |
1303 | return parseIfNoneMatch(raw: value); |
1304 | |
1305 | case QNetworkRequest::CookieHeader: |
1306 | return parseCookieHeader(raw: value); |
1307 | |
1308 | case QNetworkRequest::SetCookieHeader: |
1309 | return QVariant::fromValue(value: QNetworkCookie::parseCookies(cookieString: value)); |
1310 | |
1311 | default: |
1312 | Q_ASSERT(0); |
1313 | } |
1314 | return QVariant(); |
1315 | } |
1316 | |
1317 | QNetworkHeadersPrivate::RawHeadersList::ConstIterator |
1318 | QNetworkHeadersPrivate::(const QByteArray &key) const |
1319 | { |
1320 | RawHeadersList::ConstIterator it = rawHeaders.constBegin(); |
1321 | RawHeadersList::ConstIterator end = rawHeaders.constEnd(); |
1322 | for ( ; it != end; ++it) |
1323 | if (it->first.compare(a: key, cs: Qt::CaseInsensitive) == 0) |
1324 | return it; |
1325 | |
1326 | return end; // not found |
1327 | } |
1328 | |
1329 | QNetworkHeadersPrivate::RawHeadersList QNetworkHeadersPrivate::() const |
1330 | { |
1331 | return rawHeaders; |
1332 | } |
1333 | |
1334 | QList<QByteArray> QNetworkHeadersPrivate::() const |
1335 | { |
1336 | QList<QByteArray> result; |
1337 | result.reserve(asize: rawHeaders.size()); |
1338 | RawHeadersList::ConstIterator it = rawHeaders.constBegin(), |
1339 | end = rawHeaders.constEnd(); |
1340 | for ( ; it != end; ++it) |
1341 | result << it->first; |
1342 | |
1343 | return result; |
1344 | } |
1345 | |
1346 | void QNetworkHeadersPrivate::(const QByteArray &key, const QByteArray &value) |
1347 | { |
1348 | if (key.isEmpty()) |
1349 | // refuse to accept an empty raw header |
1350 | return; |
1351 | |
1352 | setRawHeaderInternal(key, value); |
1353 | parseAndSetHeader(key, value); |
1354 | } |
1355 | |
1356 | /*! |
1357 | \internal |
1358 | Sets the internal raw headers list to match \a list. The cooked headers |
1359 | will also be updated. |
1360 | |
1361 | If \a list contains duplicates, they will be stored, but only the first one |
1362 | is usually accessed. |
1363 | */ |
1364 | void QNetworkHeadersPrivate::(const RawHeadersList &list) |
1365 | { |
1366 | cookedHeaders.clear(); |
1367 | rawHeaders = list; |
1368 | |
1369 | RawHeadersList::ConstIterator it = rawHeaders.constBegin(); |
1370 | RawHeadersList::ConstIterator end = rawHeaders.constEnd(); |
1371 | for ( ; it != end; ++it) |
1372 | parseAndSetHeader(key: it->first, value: it->second); |
1373 | } |
1374 | |
1375 | void QNetworkHeadersPrivate::(QNetworkRequest::KnownHeaders , |
1376 | const QVariant &value) |
1377 | { |
1378 | QByteArray name = headerName(header); |
1379 | if (name.isEmpty()) { |
1380 | // headerName verifies that \a header is a known value |
1381 | qWarning(msg: "QNetworkRequest::setHeader: invalid header value KnownHeader(%d) received" , header); |
1382 | return; |
1383 | } |
1384 | |
1385 | if (value.isNull()) { |
1386 | setRawHeaderInternal(key: name, value: QByteArray()); |
1387 | cookedHeaders.remove(key: header); |
1388 | } else { |
1389 | QByteArray rawValue = headerValue(header, value); |
1390 | if (rawValue.isEmpty()) { |
1391 | qWarning(msg: "QNetworkRequest::setHeader: QVariant of type %s cannot be used with header %s" , |
1392 | value.typeName(), name.constData()); |
1393 | return; |
1394 | } |
1395 | |
1396 | setRawHeaderInternal(key: name, value: rawValue); |
1397 | cookedHeaders.insert(key: header, value); |
1398 | } |
1399 | } |
1400 | |
1401 | void QNetworkHeadersPrivate::(const QByteArray &key, const QByteArray &value) |
1402 | { |
1403 | auto firstEqualsKey = [&key](const RawHeaderPair &) { |
1404 | return header.first.compare(a: key, cs: Qt::CaseInsensitive) == 0; |
1405 | }; |
1406 | rawHeaders.removeIf(pred: firstEqualsKey); |
1407 | |
1408 | if (value.isNull()) |
1409 | return; // only wanted to erase key |
1410 | |
1411 | RawHeaderPair pair; |
1412 | pair.first = key; |
1413 | pair.second = value; |
1414 | rawHeaders.append(t: pair); |
1415 | } |
1416 | |
1417 | void QNetworkHeadersPrivate::parseAndSetHeader(const QByteArray &key, const QByteArray &value) |
1418 | { |
1419 | // is it a known header? |
1420 | const int parsedKeyAsInt = parseHeaderName(headerName: key); |
1421 | if (parsedKeyAsInt != -1) { |
1422 | const QNetworkRequest::KnownHeaders parsedKey |
1423 | = static_cast<QNetworkRequest::KnownHeaders>(parsedKeyAsInt); |
1424 | if (value.isNull()) { |
1425 | cookedHeaders.remove(key: parsedKey); |
1426 | } else if (parsedKey == QNetworkRequest::ContentLengthHeader |
1427 | && cookedHeaders.contains(key: QNetworkRequest::ContentLengthHeader)) { |
1428 | // Only set the cooked header "Content-Length" once. |
1429 | // See bug QTBUG-15311 |
1430 | } else { |
1431 | cookedHeaders.insert(key: parsedKey, value: parseHeaderValue(header: parsedKey, value)); |
1432 | } |
1433 | |
1434 | } |
1435 | } |
1436 | |
1437 | // Fast month string to int conversion. This code |
1438 | // assumes that the Month name is correct and that |
1439 | // the string is at least three chars long. |
1440 | static int name_to_month(const char* month_str) |
1441 | { |
1442 | switch (month_str[0]) { |
1443 | case 'J': |
1444 | switch (month_str[1]) { |
1445 | case 'a': |
1446 | return 1; |
1447 | case 'u': |
1448 | switch (month_str[2] ) { |
1449 | case 'n': |
1450 | return 6; |
1451 | case 'l': |
1452 | return 7; |
1453 | } |
1454 | } |
1455 | break; |
1456 | case 'F': |
1457 | return 2; |
1458 | case 'M': |
1459 | switch (month_str[2] ) { |
1460 | case 'r': |
1461 | return 3; |
1462 | case 'y': |
1463 | return 5; |
1464 | } |
1465 | break; |
1466 | case 'A': |
1467 | switch (month_str[1]) { |
1468 | case 'p': |
1469 | return 4; |
1470 | case 'u': |
1471 | return 8; |
1472 | } |
1473 | break; |
1474 | case 'O': |
1475 | return 10; |
1476 | case 'S': |
1477 | return 9; |
1478 | case 'N': |
1479 | return 11; |
1480 | case 'D': |
1481 | return 12; |
1482 | } |
1483 | |
1484 | return 0; |
1485 | } |
1486 | |
1487 | QDateTime QNetworkHeadersPrivate::(const QByteArray &value) |
1488 | { |
1489 | // HTTP dates have three possible formats: |
1490 | // RFC 1123/822 - ddd, dd MMM yyyy hh:mm:ss "GMT" |
1491 | // RFC 850 - dddd, dd-MMM-yy hh:mm:ss "GMT" |
1492 | // ANSI C's asctime - ddd MMM d hh:mm:ss yyyy |
1493 | // We only handle them exactly. If they deviate, we bail out. |
1494 | |
1495 | int pos = value.indexOf(c: ','); |
1496 | QDateTime dt; |
1497 | #if QT_CONFIG(datestring) |
1498 | if (pos == -1) { |
1499 | // no comma -> asctime(3) format |
1500 | dt = QDateTime::fromString(string: QString::fromLatin1(ba: value), format: Qt::TextDate); |
1501 | } else { |
1502 | // Use sscanf over QLocal/QDateTimeParser for speed reasons. See the |
1503 | // Qt WebKit performance benchmarks to get an idea. |
1504 | if (pos == 3) { |
1505 | char month_name[4]; |
1506 | int day, year, hour, minute, second; |
1507 | #ifdef Q_CC_MSVC |
1508 | // Use secure version to avoid compiler warning |
1509 | if (sscanf_s(value.constData(), "%*3s, %d %3s %d %d:%d:%d 'GMT'" , &day, month_name, 4, &year, &hour, &minute, &second) == 6) |
1510 | #else |
1511 | // The POSIX secure mode is %ms (which allocates memory), too bleeding edge for now |
1512 | // In any case this is already safe as field width is specified. |
1513 | if (sscanf(s: value.constData(), format: "%*3s, %d %3s %d %d:%d:%d 'GMT'" , &day, month_name, &year, &hour, &minute, &second) == 6) |
1514 | #endif |
1515 | dt = QDateTime(QDate(year, name_to_month(month_str: month_name), day), QTime(hour, minute, second)); |
1516 | } else { |
1517 | QLocale c = QLocale::c(); |
1518 | // eat the weekday, the comma and the space following it |
1519 | QString sansWeekday = QString::fromLatin1(ba: value.constData() + pos + 2); |
1520 | // must be RFC 850 date |
1521 | dt = c.toDateTime(string: sansWeekday, format: "dd-MMM-yy hh:mm:ss 'GMT'"_L1 ); |
1522 | } |
1523 | } |
1524 | #endif // datestring |
1525 | |
1526 | if (dt.isValid()) |
1527 | dt.setTimeZone(QTimeZone::UTC); |
1528 | return dt; |
1529 | } |
1530 | |
1531 | QByteArray QNetworkHeadersPrivate::(const QDateTime &dt) |
1532 | { |
1533 | return QLocale::c().toString(dateTime: dt.toUTC(), format: u"ddd, dd MMM yyyy hh:mm:ss 'GMT'" ).toLatin1(); |
1534 | } |
1535 | |
1536 | QT_END_NAMESPACE |
1537 | |