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 by converting
752 them to lowercase. Since Qt 6.12, well-known header field names are
753 instead stored in their canonical IANA form (for example, \c "Content-Type"),
754 and custom header names are stored as provided.
755
756 \sa KnownHeaders, setHeader(), hasRawHeader(), rawHeader()
757*/
758void QNetworkRequest::setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
759{
760 d->setRawHeader(headerName, headerValue);
761}
762
763/*!
764 Returns the attribute associated with the code \a code. If the
765 attribute has not been set, it returns \a defaultValue.
766
767 \note This function does not apply the defaults listed in
768 QNetworkRequest::Attribute.
769
770 \sa setAttribute(), QNetworkRequest::Attribute
771*/
772QVariant QNetworkRequest::attribute(Attribute code, const QVariant &defaultValue) const
773{
774 return d->attributes.value(code, defaultValue);
775}
776
777/*!
778 Sets the attribute associated with code \a code to be value \a
779 value. If the attribute is already set, the previous value is
780 discarded. In special, if \a value is an invalid QVariant, the
781 attribute is unset.
782
783 \sa attribute(), QNetworkRequest::Attribute
784*/
785void QNetworkRequest::setAttribute(Attribute code, const QVariant &value)
786{
787 if (value.isValid())
788 d->attributes.insert(code, value);
789 else
790 d->attributes.remove(code);
791}
792
793#ifndef QT_NO_SSL
794/*!
795 Returns this network request's SSL configuration. By default this is the same
796 as QSslConfiguration::defaultConfiguration().
797
798 \sa setSslConfiguration(), QSslConfiguration::defaultConfiguration()
799*/
800QSslConfiguration QNetworkRequest::sslConfiguration() const
801{
802 if (!d->sslConfiguration)
803 d->sslConfiguration = new QSslConfiguration(QSslConfiguration::defaultConfiguration());
804 return *d->sslConfiguration;
805}
806
807/*!
808 Sets this network request's SSL configuration to be \a config. The
809 settings that apply are the private key, the local certificate,
810 the TLS protocol (e.g. TLS 1.3), the CA certificates and the ciphers that
811 the SSL backend is allowed to use.
812
813 \sa sslConfiguration(), QSslConfiguration::defaultConfiguration()
814*/
815void QNetworkRequest::setSslConfiguration(const QSslConfiguration &config)
816{
817 if (!d->sslConfiguration)
818 d->sslConfiguration = new QSslConfiguration(config);
819 else
820 *d->sslConfiguration = config;
821}
822#endif
823
824/*!
825 \since 4.6
826
827 Allows setting a reference to the \a object initiating
828 the request.
829
830 For example Qt WebKit sets the originating object to the
831 QWebFrame that initiated the request.
832
833 \sa originatingObject()
834*/
835void QNetworkRequest::setOriginatingObject(QObject *object)
836{
837 d->originatingObject = object;
838}
839
840/*!
841 \since 4.6
842
843 Returns a reference to the object that initiated this
844 network request; returns \nullptr if not set or the object has
845 been destroyed.
846
847 \sa setOriginatingObject()
848*/
849QObject *QNetworkRequest::originatingObject() const
850{
851 return d->originatingObject.data();
852}
853
854/*!
855 \since 4.7
856
857 Return the priority of this request.
858
859 \sa setPriority()
860*/
861QNetworkRequest::Priority QNetworkRequest::priority() const
862{
863 return d->priority;
864}
865
866/*! \enum QNetworkRequest::Priority
867
868 \since 4.7
869
870 This enum lists the possible network request priorities.
871
872 \value HighPriority High priority
873 \value NormalPriority Normal priority
874 \value LowPriority Low priority
875 */
876
877/*!
878 \since 4.7
879
880 Set the priority of this request to \a priority.
881
882 \note The \a priority is only a hint to the network access
883 manager. It can use it or not. Currently it is used for HTTP to
884 decide which request should be sent first to a server.
885
886 \sa priority()
887*/
888void QNetworkRequest::setPriority(Priority priority)
889{
890 d->priority = priority;
891}
892
893/*!
894 \since 5.6
895
896 Returns the maximum number of redirects allowed to be followed for this
897 request.
898
899 \sa setMaximumRedirectsAllowed()
900*/
901int QNetworkRequest::maximumRedirectsAllowed() const
902{
903 return d->maxRedirectsAllowed;
904}
905
906/*!
907 \since 5.6
908
909 Sets the maximum number of redirects allowed to be followed for this
910 request to \a maxRedirectsAllowed.
911
912 \sa maximumRedirectsAllowed()
913*/
914void QNetworkRequest::setMaximumRedirectsAllowed(int maxRedirectsAllowed)
915{
916 d->maxRedirectsAllowed = maxRedirectsAllowed;
917}
918
919/*!
920 \since 5.13
921
922 Returns the host name set for the certificate validation, as set by
923 setPeerVerifyName. By default this returns a null string.
924
925 \sa setPeerVerifyName
926*/
927QString QNetworkRequest::peerVerifyName() const
928{
929 return d->peerVerifyName;
930}
931
932/*!
933 \since 5.13
934
935 Sets \a peerName as host name for the certificate validation, instead of the one used for the
936 TCP connection.
937
938 \sa peerVerifyName
939*/
940void QNetworkRequest::setPeerVerifyName(const QString &peerName)
941{
942 d->peerVerifyName = peerName;
943}
944
945#if QT_CONFIG(http)
946/*!
947 \since 6.5
948
949 Returns the current parameters that QNetworkAccessManager is
950 using for the underlying HTTP/1 connection of this request.
951
952 \sa setHttp1Configuration
953*/
954QHttp1Configuration QNetworkRequest::http1Configuration() const
955{
956 return d->h1Configuration;
957}
958/*!
959 \since 6.5
960
961 Sets request's HTTP/1 parameters from \a configuration.
962
963 \sa http1Configuration, QNetworkAccessManager, QHttp1Configuration
964*/
965void QNetworkRequest::setHttp1Configuration(const QHttp1Configuration &configuration)
966{
967 d->h1Configuration = configuration;
968}
969
970/*!
971 \since 5.14
972
973 Returns the current parameters that QNetworkAccessManager is
974 using for this request and its underlying HTTP/2 connection.
975 This is either a configuration previously set by an application
976 or a default configuration.
977
978 The default values that QNetworkAccessManager is using are:
979
980 \list
981 \li Window size for connection-level flowcontrol is 2147483647 octets
982 \li Window size for stream-level flowcontrol is 214748364 octets
983 \li Max frame size is 16384
984 \endlist
985
986 By default, server push is disabled, Huffman compression and
987 string indexing are enabled.
988
989 \sa setHttp2Configuration
990*/
991QHttp2Configuration QNetworkRequest::http2Configuration() const
992{
993 return d->h2Configuration;
994}
995
996/*!
997 \since 5.14
998
999 Sets request's HTTP/2 parameters from \a configuration.
1000
1001 \note The configuration must be set prior to making a request.
1002 \note HTTP/2 multiplexes several streams in a single HTTP/2
1003 connection. This implies that QNetworkAccessManager will use
1004 the configuration found in the first request from a series
1005 of requests sent to the same host.
1006
1007 \sa http2Configuration, QNetworkAccessManager, QHttp2Configuration
1008*/
1009void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configuration)
1010{
1011 d->h2Configuration = configuration;
1012}
1013
1014/*!
1015 \since 6.2
1016
1017 Returns the threshold for archive bomb checks.
1018
1019 If the decompressed size of a reply is smaller than this, Qt will simply
1020 decompress it, without further checking.
1021
1022 \sa setDecompressedSafetyCheckThreshold()
1023*/
1024qint64 QNetworkRequest::decompressedSafetyCheckThreshold() const
1025{
1026 return d->decompressedSafetyCheckThreshold;
1027}
1028
1029/*!
1030 \since 6.2
1031
1032 Sets the \a threshold for archive bomb checks.
1033
1034 Some supported compression algorithms can, in a tiny compressed file, encode
1035 a spectacularly huge decompressed file. This is only possible if the
1036 decompressed content is extremely monotonous, which is seldom the case for
1037 real files being transmitted in good faith: files exercising such insanely
1038 high compression ratios are typically payloads of buffer-overrun attacks, or
1039 denial-of-service (by using up too much memory) attacks. Consequently, files
1040 that decompress to huge sizes, particularly from tiny compressed forms, are
1041 best rejected as suspected malware.
1042
1043 If a reply's decompressed size is bigger than this threshold (by default,
1044 10 MiB, i.e. 10 * 1024 * 1024), Qt will check the compression ratio: if that
1045 is unreasonably large (40:1 for GZip and Deflate, or 100:1 for Brotli and
1046 ZStandard), the reply will be treated as an error. Setting the threshold
1047 to \c{-1} disables this check.
1048
1049 \sa decompressedSafetyCheckThreshold()
1050*/
1051void QNetworkRequest::setDecompressedSafetyCheckThreshold(qint64 threshold)
1052{
1053 d->decompressedSafetyCheckThreshold = threshold;
1054}
1055#endif // QT_CONFIG(http)
1056
1057/*!
1058 \since 6.11
1059
1060 Returns the time the connection needs to remain idle before TCP
1061 starts sending keepalive probes, if the TCP Keepalive functionality has
1062 been turned on.
1063
1064 \sa setTcpKeepAliveIdleTimeBeforeProbes()
1065*/
1066
1067std::chrono::seconds QNetworkRequest::tcpKeepAliveIdleTimeBeforeProbes() const
1068{
1069 return d->idleTimeBeforeProbes;
1070}
1071
1072/*!
1073 \fn void QNetworkRequest::setTcpKeepAliveIdleTimeBeforeProbes(std::chrono::seconds idle)
1074 \since 6.11
1075
1076 Sets the time the connection needs to remain idle before TCP starts
1077 sending keepalive probes to be \a idle, if the TCP Keepalive
1078 functionality has been turned on.
1079
1080 \sa tcpKeepAliveIdleTimeBeforeProbes()
1081*/
1082
1083void QNetworkRequest::doSetIdleTimeBeforeProbes(std::chrono::duration<int> seconds)
1084{
1085 d->idleTimeBeforeProbes = seconds;
1086}
1087
1088/*!
1089 \since 6.11
1090
1091 Returns the time between individual keepalive probes, if the TCP
1092 Keepalive functionality has been turned on.
1093
1094 \sa setTcpKeepAliveIntervalBetweenProbes()
1095*/
1096
1097std::chrono::seconds QNetworkRequest::tcpKeepAliveIntervalBetweenProbes() const
1098{
1099 return d->intervalBetweenProbes;
1100}
1101
1102/*!
1103 \fn void QNetworkRequest::setTcpKeepAliveIntervalBetweenProbes(std::chrono::seconds interval)
1104 \since 6.11
1105
1106 Sets the time between individual keepalive probes to be \a interval,
1107 if the TCP Keepalive functionality has been turned on.
1108
1109 \sa tcpKeepAliveIntervalBetweenProbes()
1110*/
1111
1112void QNetworkRequest::doSetIntervalBetweenProbes(std::chrono::duration<int> seconds)
1113{
1114 d->intervalBetweenProbes = seconds;
1115}
1116
1117/*!
1118 \since 6.11
1119
1120 Returns the maximum number of keepalive probes TCP should send before
1121 dropping the connection, if the TCP Keepalive functionality has been
1122 turned on.
1123
1124 \sa setTcpKeepAliveProbeCount()
1125*/
1126
1127int QNetworkRequest::tcpKeepAliveProbeCount() const
1128{
1129 return d->probeCount;
1130}
1131
1132/*!
1133 \since 6.11
1134
1135 Sets the maximum number of keepalive \a probes TCP should send
1136 before dropping the connection, if the TCP Keepalive functionality has
1137 been turned on.
1138
1139 \sa tcpKeepAliveProbeCount()
1140*/
1141
1142void QNetworkRequest::setTcpKeepAliveProbeCount(int probes)
1143{
1144 d->probeCount = probes;
1145}
1146
1147#if QT_CONFIG(http) || defined (Q_OS_WASM)
1148/*!
1149 \fn int QNetworkRequest::transferTimeout() const
1150 \since 5.15
1151
1152 Returns the timeout used for transfers, in milliseconds.
1153
1154 If transferTimeoutAsDuration().count() cannot be represented in \c{int},
1155 this function returns \c{INT_MAX}/\c{INT_MIN} instead.
1156
1157 \sa setTransferTimeout(), transferTimeoutAsDuration()
1158*/
1159
1160/*!
1161 \fn void QNetworkRequest::setTransferTimeout(int timeout)
1162 \since 5.15
1163
1164 Sets \a timeout as the transfer timeout in milliseconds.
1165
1166 \sa setTransferTimeout(std::chrono::milliseconds),
1167 transferTimeout(), transferTimeoutAsDuration()
1168*/
1169
1170/*!
1171 \since 6.7
1172
1173 Returns the timeout duration after which the transfer is aborted if no
1174 data is exchanged.
1175
1176 The default duration is zero, which means that the timeout is not used.
1177
1178 \sa setTransferTimeout(std::chrono::milliseconds)
1179*/
1180std::chrono::milliseconds QNetworkRequest::transferTimeoutAsDuration() const
1181{
1182 return d->transferTimeout;
1183}
1184
1185/*!
1186 \since 6.7
1187
1188 Sets the timeout \a duration to abort the transfer if no data is exchanged.
1189
1190 Transfers are aborted if no bytes are transferred before
1191 the timeout expires. Zero means no timer is set. If no
1192 argument is provided, the timeout is
1193 QNetworkRequest::DefaultTransferTimeout. If this function
1194 is not called, the timeout is disabled and has the
1195 value zero.
1196
1197 \sa transferTimeoutAsDuration()
1198*/
1199void QNetworkRequest::setTransferTimeout(std::chrono::milliseconds duration)
1200{
1201 d->transferTimeout = duration;
1202}
1203#endif // QT_CONFIG(http) || defined (Q_OS_WASM)
1204
1205namespace {
1206
1207struct HeaderPair {
1208 QHttpHeaders::WellKnownHeader wellKnownHeader;
1209 QNetworkRequest::KnownHeaders knownHeader;
1210};
1211
1212constexpr bool operator<(const HeaderPair &lhs, const HeaderPair &rhs)
1213{
1214 return lhs.wellKnownHeader < rhs.wellKnownHeader;
1215}
1216
1217constexpr bool operator<(const HeaderPair &lhs, QHttpHeaders::WellKnownHeader rhs)
1218{
1219 return lhs.wellKnownHeader < rhs;
1220}
1221
1222constexpr bool operator<(QHttpHeaders::WellKnownHeader lhs, const HeaderPair &rhs)
1223{
1224 return lhs < rhs.wellKnownHeader;
1225}
1226
1227} // anonymous namespace
1228
1229static constexpr HeaderPair knownHeadersArr[] = {
1230 { QHttpHeaders::WellKnownHeader::ContentDisposition, QNetworkRequest::KnownHeaders::ContentDispositionHeader },
1231 { QHttpHeaders::WellKnownHeader::ContentLength, QNetworkRequest::KnownHeaders::ContentLengthHeader },
1232 { QHttpHeaders::WellKnownHeader::ContentType, QNetworkRequest::KnownHeaders::ContentTypeHeader },
1233 { QHttpHeaders::WellKnownHeader::Cookie, QNetworkRequest::KnownHeaders::CookieHeader },
1234 { QHttpHeaders::WellKnownHeader::ETag, QNetworkRequest::KnownHeaders::ETagHeader },
1235 { QHttpHeaders::WellKnownHeader::IfMatch , QNetworkRequest::KnownHeaders::IfMatchHeader },
1236 { QHttpHeaders::WellKnownHeader::IfModifiedSince, QNetworkRequest::KnownHeaders::IfModifiedSinceHeader },
1237 { QHttpHeaders::WellKnownHeader::IfNoneMatch, QNetworkRequest::KnownHeaders::IfNoneMatchHeader },
1238 { QHttpHeaders::WellKnownHeader::LastModified, QNetworkRequest::KnownHeaders::LastModifiedHeader},
1239 { QHttpHeaders::WellKnownHeader::Location, QNetworkRequest::KnownHeaders::LocationHeader},
1240 { QHttpHeaders::WellKnownHeader::Server, QNetworkRequest::KnownHeaders::ServerHeader },
1241 { QHttpHeaders::WellKnownHeader::SetCookie, QNetworkRequest::KnownHeaders::SetCookieHeader },
1242 { QHttpHeaders::WellKnownHeader::UserAgent, QNetworkRequest::KnownHeaders::UserAgentHeader }
1243};
1244
1245static_assert(std::size(knownHeadersArr) == size_t(QNetworkRequest::KnownHeaders::NumKnownHeaders));
1246static_assert(q20::is_sorted(std::begin(knownHeadersArr), std::end(knownHeadersArr)));
1247
1248static std::optional<QNetworkRequest::KnownHeaders> toKnownHeader(QHttpHeaders::WellKnownHeader key)
1249{
1250 const auto it = std::lower_bound(std::begin(knownHeadersArr), std::end(knownHeadersArr), key);
1251 if (it == std::end(knownHeadersArr) || key < *it)
1252 return std::nullopt;
1253 return it->knownHeader;
1254}
1255
1256static std::optional<QHttpHeaders::WellKnownHeader> toWellKnownHeader(QNetworkRequest::KnownHeaders key)
1257{
1258 auto pred = [key](const HeaderPair &pair) { return pair.knownHeader == key; };
1259 const auto it = std::find_if(std::begin(knownHeadersArr), std::end(knownHeadersArr), pred);
1260 if (it == std::end(knownHeadersArr))
1261 return std::nullopt;
1262 return it->wellKnownHeader;
1263}
1264
1265static QByteArray makeCookieHeader(const QList<QNetworkCookie> &cookies,
1266 QNetworkCookie::RawForm type,
1267 QByteArrayView separator)
1268{
1269 QByteArray result;
1270 for (const QNetworkCookie &cookie : cookies) {
1271 result += cookie.toRawForm(type);
1272 result += separator;
1273 }
1274 if (!result.isEmpty())
1275 result.chop(separator.size());
1276 return result;
1277}
1278
1279static QByteArray makeCookieHeader(const QVariant &value, QNetworkCookie::RawForm type,
1280 QByteArrayView separator)
1281{
1282 const QList<QNetworkCookie> *cookies = get_if<QList<QNetworkCookie>>(&value);
1283 if (!cookies)
1284 return {};
1285 return makeCookieHeader(*cookies, type, separator);
1286}
1287
1288static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVariant &value)
1289{
1290 switch (header) {
1291 case QNetworkRequest::ContentTypeHeader:
1292 case QNetworkRequest::ContentLengthHeader:
1293 case QNetworkRequest::ContentDispositionHeader:
1294 case QNetworkRequest::UserAgentHeader:
1295 case QNetworkRequest::ServerHeader:
1296 case QNetworkRequest::ETagHeader:
1297 case QNetworkRequest::IfMatchHeader:
1298 case QNetworkRequest::IfNoneMatchHeader:
1299 return value.toByteArray();
1300
1301 case QNetworkRequest::LocationHeader:
1302 switch (value.userType()) {
1303 case QMetaType::QUrl:
1304 return value.toUrl().toEncoded();
1305
1306 default:
1307 return value.toByteArray();
1308 }
1309
1310 case QNetworkRequest::LastModifiedHeader:
1311 case QNetworkRequest::IfModifiedSinceHeader:
1312 switch (value.userType()) {
1313 // Generate RFC 1123/822 dates:
1314 case QMetaType::QDate:
1315 return QNetworkHeadersPrivate::toHttpDate(value.toDate().startOfDay(QTimeZone::UTC));
1316 case QMetaType::QDateTime:
1317 return QNetworkHeadersPrivate::toHttpDate(value.toDateTime());
1318
1319 default:
1320 return value.toByteArray();
1321 }
1322
1323 case QNetworkRequest::CookieHeader:
1324 return makeCookieHeader(value, QNetworkCookie::NameAndValueOnly, "; ");
1325
1326 case QNetworkRequest::SetCookieHeader:
1327 return makeCookieHeader(value, QNetworkCookie::Full, ", ");
1328
1329 default:
1330 Q_UNREACHABLE_RETURN({});
1331 }
1332}
1333
1334static int parseHeaderName(QByteArrayView headerName)
1335{
1336 if (headerName.isEmpty())
1337 return -1;
1338
1339 auto is = [headerName](QByteArrayView what) {
1340 return headerName.compare(what, Qt::CaseInsensitive) == 0;
1341 };
1342
1343 switch (QtMiscUtils::toAsciiLower(headerName.front())) {
1344 case 'c':
1345 if (is("content-type"))
1346 return QNetworkRequest::ContentTypeHeader;
1347 else if (is("content-length"))
1348 return QNetworkRequest::ContentLengthHeader;
1349 else if (is("cookie"))
1350 return QNetworkRequest::CookieHeader;
1351 else if (is("content-disposition"))
1352 return QNetworkRequest::ContentDispositionHeader;
1353 break;
1354
1355 case 'e':
1356 if (is("etag"))
1357 return QNetworkRequest::ETagHeader;
1358 break;
1359
1360 case 'i':
1361 if (is("if-modified-since"))
1362 return QNetworkRequest::IfModifiedSinceHeader;
1363 if (is("if-match"))
1364 return QNetworkRequest::IfMatchHeader;
1365 if (is("if-none-match"))
1366 return QNetworkRequest::IfNoneMatchHeader;
1367 break;
1368
1369 case 'l':
1370 if (is("location"))
1371 return QNetworkRequest::LocationHeader;
1372 else if (is("last-modified"))
1373 return QNetworkRequest::LastModifiedHeader;
1374 break;
1375
1376 case 's':
1377 if (is("set-cookie"))
1378 return QNetworkRequest::SetCookieHeader;
1379 else if (is("server"))
1380 return QNetworkRequest::ServerHeader;
1381 break;
1382
1383 case 'u':
1384 if (is("user-agent"))
1385 return QNetworkRequest::UserAgentHeader;
1386 break;
1387 }
1388
1389 return -1; // nothing found
1390}
1391
1392static QVariant parseHttpDate(QByteArrayView raw)
1393{
1394 QDateTime dt = QNetworkHeadersPrivate::fromHttpDate(raw);
1395 if (dt.isValid())
1396 return dt;
1397 return QVariant(); // transform an invalid QDateTime into a null QVariant
1398}
1399
1400static QList<QNetworkCookie> parseCookieHeader(QByteArrayView raw)
1401{
1402 QList<QNetworkCookie> result;
1403 for (auto cookie : QLatin1StringView(raw).tokenize(';'_L1)) {
1404 QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookie.trimmed());
1405 if (parsed.size() != 1)
1406 return {}; // invalid Cookie: header
1407
1408 result += parsed;
1409 }
1410
1411 return result;
1412}
1413
1414static QVariant parseETag(QByteArrayView raw)
1415{
1416 const QByteArrayView trimmed = raw.trimmed();
1417 if (!trimmed.startsWith('"') && !trimmed.startsWith(R"(W/")"))
1418 return QVariant();
1419
1420 if (!trimmed.endsWith('"'))
1421 return QVariant();
1422
1423 return QString::fromLatin1(trimmed);
1424}
1425
1426template<typename T>
1427static QStringList parseMatchImpl(QByteArrayView raw, T op)
1428{
1429 const QByteArrayView trimmedRaw = raw.trimmed();
1430 if (trimmedRaw == "*")
1431 return QStringList(QStringLiteral("*"));
1432
1433 QStringList tags;
1434 for (auto &element : QLatin1StringView(trimmedRaw).tokenize(','_L1)) {
1435 if (const auto trimmed = element.trimmed(); op(trimmed))
1436 tags += QString::fromLatin1(trimmed);
1437 }
1438 return tags;
1439}
1440
1441
1442static QStringList parseIfMatch(QByteArrayView raw)
1443{
1444 return parseMatchImpl(raw, [](QByteArrayView element) {
1445 return element.startsWith('"') && element.endsWith('"');
1446 });
1447}
1448
1449static QStringList parseIfNoneMatch(QByteArrayView raw)
1450{
1451 return parseMatchImpl(raw, [](QByteArrayView element) {
1452 return (element.startsWith('"') || element.startsWith(R"(W/")")) && element.endsWith('"');
1453 });
1454}
1455
1456
1457static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, QByteArrayView value)
1458{
1459 // header is always a valid value
1460 switch (header) {
1461 case QNetworkRequest::UserAgentHeader:
1462 case QNetworkRequest::ServerHeader:
1463 case QNetworkRequest::ContentTypeHeader:
1464 case QNetworkRequest::ContentDispositionHeader:
1465 // copy exactly, convert to QString
1466 return QString::fromLatin1(value);
1467
1468 case QNetworkRequest::ContentLengthHeader: {
1469 bool ok;
1470 qint64 result = QByteArrayView(value).trimmed().toLongLong(&ok);
1471 if (ok)
1472 return result;
1473 return QVariant();
1474 }
1475
1476 case QNetworkRequest::LocationHeader: {
1477 QUrl result = QUrl::fromEncoded(value, QUrl::StrictMode);
1478 if (result.isValid() && !result.scheme().isEmpty())
1479 return result;
1480 return QVariant();
1481 }
1482
1483 case QNetworkRequest::LastModifiedHeader:
1484 case QNetworkRequest::IfModifiedSinceHeader:
1485 return parseHttpDate(value);
1486
1487 case QNetworkRequest::ETagHeader:
1488 return parseETag(value);
1489
1490 case QNetworkRequest::IfMatchHeader:
1491 return parseIfMatch(value);
1492
1493 case QNetworkRequest::IfNoneMatchHeader:
1494 return parseIfNoneMatch(value);
1495
1496 case QNetworkRequest::CookieHeader:
1497 return QVariant::fromValue(parseCookieHeader(value));
1498
1499 case QNetworkRequest::SetCookieHeader:
1500 return QVariant::fromValue(QNetworkCookie::parseCookies(value));
1501
1502 default:
1503 Q_UNREACHABLE_RETURN({});
1504 }
1505}
1506
1507static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, QList<QByteArray> values)
1508{
1509 if (values.empty())
1510 return QVariant();
1511
1512 // header is always a valid value
1513 switch (header) {
1514 case QNetworkRequest::IfMatchHeader: {
1515 QStringList res;
1516 for (const auto &val : values)
1517 res << parseIfMatch(val);
1518 return res;
1519 }
1520 case QNetworkRequest::IfNoneMatchHeader: {
1521 QStringList res;
1522 for (const auto &val : values)
1523 res << parseIfNoneMatch(val);
1524 return res;
1525 }
1526 case QNetworkRequest::CookieHeader: {
1527 auto listOpt = QNetworkHeadersPrivate::toCookieList(values);
1528 return listOpt.has_value() ? QVariant::fromValue(listOpt.value()) : QVariant();
1529 }
1530 case QNetworkRequest::SetCookieHeader: {
1531 QList<QNetworkCookie> res;
1532 for (const auto &val : values)
1533 res << QNetworkCookie::parseCookies(val);
1534 return QVariant::fromValue(res);
1535 }
1536 default:
1537 return parseHeaderValue(header, values.first());
1538 }
1539 return QVariant();
1540}
1541
1542static bool isSetCookie(QByteArrayView name)
1543{
1544 return name.compare(QHttpHeaders::wellKnownHeaderName(QHttpHeaders::WellKnownHeader::SetCookie),
1545 Qt::CaseInsensitive) == 0;
1546}
1547
1548static bool isSetCookie(QHttpHeaders::WellKnownHeader name)
1549{
1550 return name == QHttpHeaders::WellKnownHeader::SetCookie;
1551}
1552
1553template<class HeaderName>
1554static void setFromRawHeader(QHttpHeaders &headers, HeaderName header,
1555 QByteArrayView value)
1556{
1557 headers.removeAll(header);
1558
1559 if (value.isNull())
1560 // only wanted to erase key
1561 return;
1562
1563 if (isSetCookie(header)) {
1564 for (auto cookie : QLatin1StringView(value).tokenize('\n'_L1))
1565 headers.append(QHttpHeaders::WellKnownHeader::SetCookie, cookie);
1566 } else {
1567 headers.append(header, value);
1568 }
1569}
1570
1572{
1573 if (rawHeaderCache.isCached)
1574 return rawHeaderCache.headersList;
1575
1576 rawHeaderCache.headersList = fromHttpToRaw(httpHeaders);
1577 rawHeaderCache.isCached = true;
1578 return rawHeaderCache.headersList;
1579}
1580
1582{
1583 if (httpHeaders.isEmpty())
1584 return {};
1585
1586 QList<QByteArray> result;
1587 result.reserve(httpHeaders.size());
1588 QDuplicateTracker<QByteArray> seen(httpHeaders.size());
1589
1590 for (qsizetype i = 0; i < httpHeaders.size(); i++) {
1591 const auto nameL1 = httpHeaders.nameAt(i);
1592 const auto name = QByteArray(nameL1.data(), nameL1.size());
1593 if (seen.hasSeen(name))
1594 continue;
1595
1596 result << name;
1597 }
1598
1599 return result;
1600}
1601
1602QByteArray QNetworkHeadersPrivate::rawHeader(QAnyStringView headerName) const
1603{
1604 QByteArrayView setCookieStr = QHttpHeaders::wellKnownHeaderName(
1605 QHttpHeaders::WellKnownHeader::SetCookie);
1606 if (QAnyStringView::compare(headerName, setCookieStr, Qt::CaseInsensitive) != 0)
1607 return httpHeaders.combinedValue(headerName);
1608
1609 QByteArray result;
1610 const char* separator = "";
1611 for (qsizetype i = 0; i < httpHeaders.size(); ++i) {
1612 if (QAnyStringView::compare(httpHeaders.nameAt(i), headerName, Qt::CaseInsensitive) == 0) {
1613 result.append(separator);
1614 result.append(httpHeaders.valueAt(i));
1615 separator = "\n";
1616 }
1617 }
1618 return result;
1619}
1620
1621void QNetworkHeadersPrivate::setRawHeader(const QByteArray &key, const QByteArray &value)
1622{
1623 if (key.isEmpty())
1624 // refuse to accept an empty raw header
1625 return;
1626
1627 setFromRawHeader(httpHeaders, key, value);
1628 parseAndSetHeader(key, value);
1629
1630 invalidateHeaderCache();
1631}
1632
1633void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders header,
1634 const QVariant &value)
1635{
1636 const auto wellKnownOpt = toWellKnownHeader(header);
1637 if (!wellKnownOpt) {
1638 // verifies that \a header is a known value
1639 qWarning("QNetworkRequest::setHeader: invalid header value KnownHeader(%d) received", header);
1640 return;
1641 }
1642
1643 if (value.isNull()) {
1644 httpHeaders.removeAll(wellKnownOpt.value());
1645 cookedHeaders.remove(header);
1646 } else {
1647 QByteArray rawValue = headerValue(header, value);
1648 if (rawValue.isEmpty()) {
1649 qWarning("QNetworkRequest::setHeader: QVariant of type %s cannot be used with header %s",
1650 value.typeName(),
1651 QHttpHeaders::wellKnownHeaderName(wellKnownOpt.value()).constData());
1652 return;
1653 }
1654
1655 setFromRawHeader(httpHeaders, wellKnownOpt.value(), rawValue);
1656 cookedHeaders.insert(header, value);
1657 }
1658
1659 invalidateHeaderCache();
1660}
1661
1663{
1664 return httpHeaders;
1665}
1666
1667void QNetworkHeadersPrivate::setHeaders(const QHttpHeaders &newHeaders)
1668{
1669 httpHeaders = newHeaders;
1670 setCookedFromHttp(httpHeaders);
1671 invalidateHeaderCache();
1672}
1673
1674void QNetworkHeadersPrivate::setHeaders(QHttpHeaders &&newHeaders)
1675{
1676 httpHeaders = std::move(newHeaders);
1677 setCookedFromHttp(httpHeaders);
1678 invalidateHeaderCache();
1679}
1680
1681void QNetworkHeadersPrivate::setHeader(QHttpHeaders::WellKnownHeader name, QByteArrayView value)
1682{
1683 httpHeaders.replaceOrAppend(name, value);
1684
1685 // set cooked header
1686 const auto knownHeaderOpt = toKnownHeader(name);
1687 if (knownHeaderOpt)
1688 parseAndSetHeader(knownHeaderOpt.value(), value);
1689
1690 invalidateHeaderCache();
1691}
1692
1694{
1695 httpHeaders.clear();
1696 cookedHeaders.clear();
1697 invalidateHeaderCache();
1698}
1699
1700void QNetworkHeadersPrivate::parseAndSetHeader(QByteArrayView key, QByteArrayView value)
1701{
1702 // is it a known header?
1703 const int parsedKeyAsInt = parseHeaderName(key);
1704 if (parsedKeyAsInt != -1) {
1705 const QNetworkRequest::KnownHeaders parsedKey
1706 = static_cast<QNetworkRequest::KnownHeaders>(parsedKeyAsInt);
1707 parseAndSetHeader(parsedKey, value);
1708 }
1709}
1710
1711void QNetworkHeadersPrivate::parseAndSetHeader(QNetworkRequest::KnownHeaders key,
1712 QByteArrayView value)
1713{
1714 if (value.isNull()) {
1715 cookedHeaders.remove(key);
1716 } else if (key == QNetworkRequest::ContentLengthHeader
1717 && cookedHeaders.contains(QNetworkRequest::ContentLengthHeader)) {
1718 // Only set the cooked header "Content-Length" once.
1719 // See bug QTBUG-15311
1720 } else {
1721 cookedHeaders.insert(key, parseHeaderValue(key, value));
1722 }
1723}
1724
1725// Fast month string to int conversion. This code
1726// assumes that the Month name is correct and that
1727// the string is at least three chars long.
1728static int name_to_month(const char* month_str)
1729{
1730 switch (month_str[0]) {
1731 case 'J':
1732 switch (month_str[1]) {
1733 case 'a':
1734 return 1;
1735 case 'u':
1736 switch (month_str[2] ) {
1737 case 'n':
1738 return 6;
1739 case 'l':
1740 return 7;
1741 }
1742 }
1743 break;
1744 case 'F':
1745 return 2;
1746 case 'M':
1747 switch (month_str[2] ) {
1748 case 'r':
1749 return 3;
1750 case 'y':
1751 return 5;
1752 }
1753 break;
1754 case 'A':
1755 switch (month_str[1]) {
1756 case 'p':
1757 return 4;
1758 case 'u':
1759 return 8;
1760 }
1761 break;
1762 case 'O':
1763 return 10;
1764 case 'S':
1765 return 9;
1766 case 'N':
1767 return 11;
1768 case 'D':
1769 return 12;
1770 }
1771
1772 return 0;
1773}
1774
1775QDateTime QNetworkHeadersPrivate::fromHttpDate(QByteArrayView value)
1776{
1777 // HTTP dates have three possible formats:
1778 // RFC 1123/822 - ddd, dd MMM yyyy hh:mm:ss "GMT"
1779 // RFC 850 - dddd, dd-MMM-yy hh:mm:ss "GMT"
1780 // ANSI C's asctime - ddd MMM d hh:mm:ss yyyy
1781 // We only handle them exactly. If they deviate, we bail out.
1782
1783 int pos = value.indexOf(',');
1784 QDateTime dt;
1785#if QT_CONFIG(datestring)
1786 if (pos == -1) {
1787 // no comma -> asctime(3) format
1788 dt = QDateTime::fromString(QString::fromLatin1(value), Qt::TextDate);
1789 } else {
1790 // Use sscanf over QLocal/QDateTimeParser for speed reasons. See the
1791 // Qt WebKit performance benchmarks to get an idea.
1792 if (pos == 3) {
1793 char month_name[4];
1794 int day, year, hour, minute, second;
1795#ifdef Q_CC_MSVC
1796 // Use secure version to avoid compiler warning
1797 if (sscanf_s(value.constData(), "%*3s, %d %3s %d %d:%d:%d 'GMT'", &day, month_name, 4, &year, &hour, &minute, &second) == 6)
1798#else
1799 // The POSIX secure mode is %ms (which allocates memory), too bleeding edge for now
1800 // In any case this is already safe as field width is specified.
1801 if (sscanf(value.constData(), "%*3s, %d %3s %d %d:%d:%d 'GMT'", &day, month_name, &year, &hour, &minute, &second) == 6)
1802#endif
1803 dt = QDateTime(QDate(year, name_to_month(month_name), day), QTime(hour, minute, second));
1804 } else {
1805 QLocale c = QLocale::c();
1806 // eat the weekday, the comma and the space following it
1807 QString sansWeekday = QString::fromLatin1(value.constData() + pos + 2);
1808 // must be RFC 850 date
1809 dt = c.toDateTime(sansWeekday, "dd-MMM-yy hh:mm:ss 'GMT'"_L1);
1810 }
1811 }
1812#endif // datestring
1813
1814 if (dt.isValid())
1815 dt.setTimeZone(QTimeZone::UTC);
1816 return dt;
1817}
1818
1819QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt)
1820{
1821 return QLocale::c().toString(dt.toUTC(), u"ddd, dd MMM yyyy hh:mm:ss 'GMT'").toLatin1();
1822}
1823
1825 const QHttpHeaders &headers)
1826{
1827 if (headers.isEmpty())
1828 return {};
1829
1831 QHash<QByteArray, qsizetype> nameToIndex;
1832 list.reserve(headers.size());
1833 nameToIndex.reserve(headers.size());
1834
1835 for (qsizetype i = 0; i < headers.size(); ++i) {
1836 const auto nameL1 = headers.nameAt(i);
1837 const auto value = headers.valueAt(i);
1838
1839 const bool isSetCookie = nameL1 == QHttpHeaders::wellKnownHeaderName(
1840 QHttpHeaders::WellKnownHeader::SetCookie);
1841
1842 const auto name = QByteArray(nameL1.data(), nameL1.size());
1843 if (auto it = nameToIndex.find(name); it != nameToIndex.end()) {
1844 list[it.value()].second += isSetCookie ? "\n" : ", ";
1845 list[it.value()].second += value;
1846 } else {
1847 nameToIndex[name] = list.size();
1848 list.emplaceBack(name, value.toByteArray());
1849 }
1850 }
1851
1852 return list;
1853}
1854
1855QHttpHeaders QNetworkHeadersPrivate::fromRawToHttp(const RawHeadersList &raw)
1856{
1857 if (raw.empty())
1858 return {};
1859
1860 QHttpHeaders headers;
1861 headers.reserve(raw.size());
1862
1863 for (const auto &[key, value] : raw) {
1864 const bool isSetCookie = key.compare(QHttpHeaders::wellKnownHeaderName(
1865 QHttpHeaders::WellKnownHeader::SetCookie),
1866 Qt::CaseInsensitive) == 0;
1867 if (isSetCookie) {
1868 for (auto header : QLatin1StringView(value).tokenize('\n'_L1))
1869 headers.append(key, header);
1870 } else {
1871 headers.append(key, value);
1872 }
1873 }
1874
1875 return headers;
1876}
1877
1878std::optional<qint64> QNetworkHeadersPrivate::toInt(QByteArrayView value)
1879{
1880 if (value.empty())
1881 return std::nullopt;
1882
1883 bool ok;
1884 qint64 res = value.toLongLong(&ok);
1885 if (ok)
1886 return res;
1887 return std::nullopt;
1888}
1889
1890std::optional<QNetworkHeadersPrivate::NetworkCookieList> QNetworkHeadersPrivate::toSetCookieList(
1891 const QList<QByteArray> &values)
1892{
1893 if (values.empty())
1894 return std::nullopt;
1895
1896 QList<QNetworkCookie> cookies;
1897 for (const auto &s : values)
1898 cookies += QNetworkCookie::parseCookies(s);
1899
1900 if (cookies.empty())
1901 return std::nullopt;
1902 return cookies;
1903}
1904
1905QByteArray QNetworkHeadersPrivate::fromCookieList(const QList<QNetworkCookie> &cookies)
1906{
1907 return makeCookieHeader(cookies, QNetworkCookie::NameAndValueOnly, "; ");
1908}
1909
1910std::optional<QNetworkHeadersPrivate::NetworkCookieList> QNetworkHeadersPrivate::toCookieList(
1911 const QList<QByteArray> &values)
1912{
1913 if (values.empty())
1914 return std::nullopt;
1915
1916 QList<QNetworkCookie> cookies;
1917 for (const auto &s : values)
1918 cookies += parseCookieHeader(s);
1919
1920 if (cookies.empty())
1921 return std::nullopt;
1922 return cookies;
1923}
1924
1925void QNetworkHeadersPrivate::invalidateHeaderCache()
1926{
1927 rawHeaderCache.headersList.clear();
1928 rawHeaderCache.isCached = false;
1929}
1930
1931void QNetworkHeadersPrivate::setCookedFromHttp(const QHttpHeaders &newHeaders)
1932{
1933 cookedHeaders.clear();
1934
1935 QMap<QNetworkRequest::KnownHeaders, QList<QByteArray>> multipleHeadersMap;
1936 for (int i = 0; i < newHeaders.size(); ++i) {
1937 const auto name = newHeaders.nameAt(i);
1938 const auto value = newHeaders.valueAt(i);
1939
1940 const int parsedKeyAsInt = parseHeaderName(name);
1941 if (parsedKeyAsInt == -1)
1942 continue;
1943
1944 const QNetworkRequest::KnownHeaders parsedKey
1945 = static_cast<QNetworkRequest::KnownHeaders>(parsedKeyAsInt);
1946
1947 auto &list = multipleHeadersMap[parsedKey];
1948 list.append(value.toByteArray());
1949 }
1950
1951 for (auto i = multipleHeadersMap.cbegin(), end = multipleHeadersMap.cend(); i != end; ++i)
1952 cookedHeaders.insert(i.key(), parseHeaderValue(i.key(), i.value()));
1953}
1954
1955QT_END_NAMESPACE
1956
1957#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[]