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