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

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