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

source code of qtbase/src/network/access/qnetworkrequest.cpp