1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 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 
60 QT_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 
428 /*!
429     \enum QNetworkRequest::TransferTimeoutConstant
430     \since 5.15
431 
432     A constant that can be used for enabling transfer
433     timeouts with a preset value.
434 
435     \value DefaultTransferTimeoutConstant     The transfer timeout in milliseconds.
436                                               Used if setTimeout() is called
437                                               without an argument.
438  */
439 
440 class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate
441 {
442 public:
443     static const int maxRedirectCount = 50;
QNetworkRequestPrivate()444     inline QNetworkRequestPrivate()
445         : priority(QNetworkRequest::NormalPriority)
446 #ifndef QT_NO_SSL
447         , sslConfiguration(nullptr)
448 #endif
449         , maxRedirectsAllowed(maxRedirectCount)
450         , transferTimeout(0)
451     { qRegisterMetaType<QNetworkRequest>(); }
~QNetworkRequestPrivate()452     ~QNetworkRequestPrivate()
453     {
454 #ifndef QT_NO_SSL
455         delete sslConfiguration;
456 #endif
457     }
458 
459 
QNetworkRequestPrivate(const QNetworkRequestPrivate & other)460     QNetworkRequestPrivate(const QNetworkRequestPrivate &other)
461         : QSharedData(other), QNetworkHeadersPrivate(other)
462     {
463         url = other.url;
464         priority = other.priority;
465         maxRedirectsAllowed = other.maxRedirectsAllowed;
466 #ifndef QT_NO_SSL
467         sslConfiguration = nullptr;
468         if (other.sslConfiguration)
469             sslConfiguration = new QSslConfiguration(*other.sslConfiguration);
470 #endif
471         peerVerifyName = other.peerVerifyName;
472 #if QT_CONFIG(http)
473         h2Configuration = other.h2Configuration;
474 #endif
475         transferTimeout = other.transferTimeout;
476     }
477 
operator ==(const QNetworkRequestPrivate & other) const478     inline bool operator==(const QNetworkRequestPrivate &other) const
479     {
480         return url == other.url &&
481             priority == other.priority &&
482             rawHeaders == other.rawHeaders &&
483             attributes == other.attributes &&
484             maxRedirectsAllowed == other.maxRedirectsAllowed &&
485             peerVerifyName == other.peerVerifyName
486 #if QT_CONFIG(http)
487             && h2Configuration == other.h2Configuration
488 #endif
489             && transferTimeout == other.transferTimeout
490             ;
491         // don't compare cookedHeaders
492     }
493 
494     QUrl url;
495     QNetworkRequest::Priority priority;
496 #ifndef QT_NO_SSL
497     mutable QSslConfiguration *sslConfiguration;
498 #endif
499     int maxRedirectsAllowed;
500     QString peerVerifyName;
501 #if QT_CONFIG(http)
502     QHttp2Configuration h2Configuration;
503 #endif
504     int transferTimeout;
505 };
506 
507 /*!
508     Constructs a QNetworkRequest object with no URL to be requested.
509     Use setUrl() to set one.
510 
511     \sa url(), setUrl()
512 */
QNetworkRequest()513 QNetworkRequest::QNetworkRequest()
514     : d(new QNetworkRequestPrivate)
515 {
516 #if QT_CONFIG(http)
517     // Initial values proposed by RFC 7540 are quite draconian,
518     // so unless an application will set its own parameters, we
519     // make stream window size larger and increase (via WINDOW_UPDATE)
520     // the session window size. These are our 'defaults':
521     d->h2Configuration.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize);
522     d->h2Configuration.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize);
523     d->h2Configuration.setServerPushEnabled(false);
524 #endif // QT_CONFIG(http)
525 }
526 
527 /*!
528     Constructs a QNetworkRequest object with \a url as the URL to be
529     requested.
530 
531     \sa url(), setUrl()
532 */
QNetworkRequest(const QUrl & url)533 QNetworkRequest::QNetworkRequest(const QUrl &url)
534     : QNetworkRequest()
535 {
536     d->url = url;
537 }
538 
539 /*!
540     Creates a copy of \a other.
541 */
QNetworkRequest(const QNetworkRequest & other)542 QNetworkRequest::QNetworkRequest(const QNetworkRequest &other)
543     : d(other.d)
544 {
545 }
546 
547 /*!
548     Disposes of the QNetworkRequest object.
549 */
~QNetworkRequest()550 QNetworkRequest::~QNetworkRequest()
551 {
552     // QSharedDataPointer auto deletes
553     d = nullptr;
554 }
555 
556 /*!
557     Returns \c true if this object is the same as \a other (i.e., if they
558     have the same URL, same headers and same meta-data settings).
559 
560     \sa operator!=()
561 */
operator ==(const QNetworkRequest & other) const562 bool QNetworkRequest::operator==(const QNetworkRequest &other) const
563 {
564     return d == other.d || *d == *other.d;
565 }
566 
567 /*!
568     \fn bool QNetworkRequest::operator!=(const QNetworkRequest &other) const
569 
570     Returns \c false if this object is not the same as \a other.
571 
572     \sa operator==()
573 */
574 
575 /*!
576     Creates a copy of \a other
577 */
operator =(const QNetworkRequest & other)578 QNetworkRequest &QNetworkRequest::operator=(const QNetworkRequest &other)
579 {
580     d = other.d;
581     return *this;
582 }
583 
584 /*!
585     \fn void QNetworkRequest::swap(QNetworkRequest &other)
586     \since 5.0
587 
588     Swaps this network request with \a other. This function is very
589     fast and never fails.
590 */
591 
592 /*!
593     Returns the URL this network request is referring to.
594 
595     \sa setUrl()
596 */
url() const597 QUrl QNetworkRequest::url() const
598 {
599     return d->url;
600 }
601 
602 /*!
603     Sets the URL this network request is referring to be \a url.
604 
605     \sa url()
606 */
setUrl(const QUrl & url)607 void QNetworkRequest::setUrl(const QUrl &url)
608 {
609     d->url = url;
610 }
611 
612 /*!
613     Returns the value of the known network header \a header if it is
614     present in this request. If it is not present, returns QVariant()
615     (i.e., an invalid variant).
616 
617     \sa KnownHeaders, rawHeader(), setHeader()
618 */
header(KnownHeaders header) const619 QVariant QNetworkRequest::header(KnownHeaders header) const
620 {
621     return d->cookedHeaders.value(header);
622 }
623 
624 /*!
625     Sets the value of the known header \a header to be \a value,
626     overriding any previously set headers. This operation also sets
627     the equivalent raw HTTP header.
628 
629     \sa KnownHeaders, setRawHeader(), header()
630 */
setHeader(KnownHeaders header,const QVariant & value)631 void QNetworkRequest::setHeader(KnownHeaders header, const QVariant &value)
632 {
633     d->setCookedHeader(header, value);
634 }
635 
636 /*!
637     Returns \c true if the raw header \a headerName is present in this
638     network request.
639 
640     \sa rawHeader(), setRawHeader()
641 */
hasRawHeader(const QByteArray & headerName) const642 bool QNetworkRequest::hasRawHeader(const QByteArray &headerName) const
643 {
644     return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
645 }
646 
647 /*!
648     Returns the raw form of header \a headerName. If no such header is
649     present, an empty QByteArray is returned, which may be
650     indistinguishable from a header that is present but has no content
651     (use hasRawHeader() to find out if the header exists or not).
652 
653     Raw headers can be set with setRawHeader() or with setHeader().
654 
655     \sa header(), setRawHeader()
656 */
rawHeader(const QByteArray & headerName) const657 QByteArray QNetworkRequest::rawHeader(const QByteArray &headerName) const
658 {
659     QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
660         d->findRawHeader(headerName);
661     if (it != d->rawHeaders.constEnd())
662         return it->second;
663     return QByteArray();
664 }
665 
666 /*!
667     Returns a list of all raw headers that are set in this network
668     request. The list is in the order that the headers were set.
669 
670     \sa hasRawHeader(), rawHeader()
671 */
rawHeaderList() const672 QList<QByteArray> QNetworkRequest::rawHeaderList() const
673 {
674     return d->rawHeadersKeys();
675 }
676 
677 /*!
678     Sets the header \a headerName to be of value \a headerValue. If \a
679     headerName corresponds to a known header (see
680     QNetworkRequest::KnownHeaders), the raw format will be parsed and
681     the corresponding "cooked" header will be set as well.
682 
683     For example:
684     \snippet code/src_network_access_qnetworkrequest.cpp 0
685 
686     will also set the known header LastModifiedHeader to be the
687     QDateTime object of the parsed date.
688 
689     \note Setting the same header twice overrides the previous
690     setting. To accomplish the behaviour of multiple HTTP headers of
691     the same name, you should concatenate the two values, separating
692     them with a comma (",") and set one single raw header.
693 
694     \sa KnownHeaders, setHeader(), hasRawHeader(), rawHeader()
695 */
setRawHeader(const QByteArray & headerName,const QByteArray & headerValue)696 void QNetworkRequest::setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
697 {
698     d->setRawHeader(headerName, headerValue);
699 }
700 
701 /*!
702     Returns the attribute associated with the code \a code. If the
703     attribute has not been set, it returns \a defaultValue.
704 
705     \note This function does not apply the defaults listed in
706     QNetworkRequest::Attribute.
707 
708     \sa setAttribute(), QNetworkRequest::Attribute
709 */
attribute(Attribute code,const QVariant & defaultValue) const710 QVariant QNetworkRequest::attribute(Attribute code, const QVariant &defaultValue) const
711 {
712     return d->attributes.value(code, defaultValue);
713 }
714 
715 /*!
716     Sets the attribute associated with code \a code to be value \a
717     value. If the attribute is already set, the previous value is
718     discarded. In special, if \a value is an invalid QVariant, the
719     attribute is unset.
720 
721     \sa attribute(), QNetworkRequest::Attribute
722 */
setAttribute(Attribute code,const QVariant & value)723 void QNetworkRequest::setAttribute(Attribute code, const QVariant &value)
724 {
725     if (value.isValid())
726         d->attributes.insert(code, value);
727     else
728         d->attributes.remove(code);
729 }
730 
731 #ifndef QT_NO_SSL
732 /*!
733     Returns this network request's SSL configuration. By default this is the same
734     as QSslConfiguration::defaultConfiguration().
735 
736     \sa setSslConfiguration(), QSslConfiguration::defaultConfiguration()
737 */
sslConfiguration() const738 QSslConfiguration QNetworkRequest::sslConfiguration() const
739 {
740     if (!d->sslConfiguration)
741         d->sslConfiguration = new QSslConfiguration(QSslConfiguration::defaultConfiguration());
742     return *d->sslConfiguration;
743 }
744 
745 /*!
746     Sets this network request's SSL configuration to be \a config. The
747     settings that apply are the private key, the local certificate,
748     the SSL protocol (SSLv2, SSLv3, TLSv1.0 where applicable), the CA
749     certificates and the ciphers that the SSL backend is allowed to
750     use.
751 
752     \sa sslConfiguration(), QSslConfiguration::defaultConfiguration()
753 */
setSslConfiguration(const QSslConfiguration & config)754 void QNetworkRequest::setSslConfiguration(const QSslConfiguration &config)
755 {
756     if (!d->sslConfiguration)
757         d->sslConfiguration = new QSslConfiguration(config);
758     else
759         *d->sslConfiguration = config;
760 }
761 #endif
762 
763 /*!
764     \since 4.6
765 
766     Allows setting a reference to the \a object initiating
767     the request.
768 
769     For example Qt WebKit sets the originating object to the
770     QWebFrame that initiated the request.
771 
772     \sa originatingObject()
773 */
setOriginatingObject(QObject * object)774 void QNetworkRequest::setOriginatingObject(QObject *object)
775 {
776     d->originatingObject = object;
777 }
778 
779 /*!
780     \since 4.6
781 
782     Returns a reference to the object that initiated this
783     network request; returns \nullptr if not set or the object has
784     been destroyed.
785 
786     \sa setOriginatingObject()
787 */
originatingObject() const788 QObject *QNetworkRequest::originatingObject() const
789 {
790     return d->originatingObject.data();
791 }
792 
793 /*!
794     \since 4.7
795 
796     Return the priority of this request.
797 
798     \sa setPriority()
799 */
priority() const800 QNetworkRequest::Priority QNetworkRequest::priority() const
801 {
802     return d->priority;
803 }
804 
805 /*! \enum QNetworkRequest::Priority
806 
807   \since 4.7
808 
809   This enum lists the possible network request priorities.
810 
811   \value HighPriority   High priority
812   \value NormalPriority Normal priority
813   \value LowPriority    Low priority
814  */
815 
816 /*!
817     \since 4.7
818 
819     Set the priority of this request to \a priority.
820 
821     \note The \a priority is only a hint to the network access
822     manager.  It can use it or not. Currently it is used for HTTP to
823     decide which request should be sent first to a server.
824 
825     \sa priority()
826 */
setPriority(Priority priority)827 void QNetworkRequest::setPriority(Priority priority)
828 {
829     d->priority = priority;
830 }
831 
832 /*!
833     \since 5.6
834 
835     Returns the maximum number of redirects allowed to be followed for this
836     request.
837 
838     \sa setMaximumRedirectsAllowed()
839 */
maximumRedirectsAllowed() const840 int QNetworkRequest::maximumRedirectsAllowed() const
841 {
842     return d->maxRedirectsAllowed;
843 }
844 
845 /*!
846     \since 5.6
847 
848     Sets the maximum number of redirects allowed to be followed for this
849     request to \a maxRedirectsAllowed.
850 
851     \sa maximumRedirectsAllowed()
852 */
setMaximumRedirectsAllowed(int maxRedirectsAllowed)853 void QNetworkRequest::setMaximumRedirectsAllowed(int maxRedirectsAllowed)
854 {
855     d->maxRedirectsAllowed = maxRedirectsAllowed;
856 }
857 
858 /*!
859     \since 5.13
860 
861     Returns the host name set for the certificate validation, as set by
862     setPeerVerifyName. By default this returns a null string.
863 
864     \sa setPeerVerifyName
865 */
peerVerifyName() const866 QString QNetworkRequest::peerVerifyName() const
867 {
868     return d->peerVerifyName;
869 }
870 
871 /*!
872     \since 5.13
873 
874     Sets \a peerName as host name for the certificate validation, instead of the one used for the
875     TCP connection.
876 
877     \sa peerVerifyName
878 */
setPeerVerifyName(const QString & peerName)879 void QNetworkRequest::setPeerVerifyName(const QString &peerName)
880 {
881     d->peerVerifyName = peerName;
882 }
883 
884 #if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
885 /*!
886     \since 5.14
887 
888     Returns the current parameters that QNetworkAccessManager is
889     using for this request and its underlying HTTP/2 connection.
890     This is either a configuration previously set by an application
891     or a default configuration.
892 
893     The default values that QNetworkAccessManager is using are:
894 
895     \list
896       \li Window size for connection-level flowcontrol is 2147483647 octets
897       \li Window size for stream-level flowcontrol is 21474836 octets
898       \li Max frame size is 16384
899     \endlist
900 
901     By default, server push is disabled, Huffman compression and
902     string indexing are enabled.
903 
904     \sa setHttp2Configuration
905 */
http2Configuration() const906 QHttp2Configuration QNetworkRequest::http2Configuration() const
907 {
908     return d->h2Configuration;
909 }
910 
911 /*!
912     \since 5.14
913 
914     Sets request's HTTP/2 parameters from \a configuration.
915 
916     \note The configuration must be set prior to making a request.
917     \note HTTP/2 multiplexes several streams in a single HTTP/2
918     connection. This implies that QNetworkAccessManager will use
919     the configuration found in the first request from  a series
920     of requests sent to the same host.
921 
922     \sa http2Configuration, QNetworkAccessManager, QHttp2Configuration
923 */
setHttp2Configuration(const QHttp2Configuration & configuration)924 void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configuration)
925 {
926     d->h2Configuration = configuration;
927 }
928 #endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC)
929 #if QT_CONFIG(http) || defined(Q_CLANG_QDOC) || defined (Q_OS_WASM)
930 /*!
931     \since 5.15
932 
933     Returns the timeout used for transfers, in milliseconds.
934 
935     This timeout is zero if setTransferTimeout hasn't been
936     called, which means that the timeout is not used.
937 
938     \sa setTransferTimeout
939 */
transferTimeout() const940 int QNetworkRequest::transferTimeout() const
941 {
942     return d->transferTimeout;
943 }
944 
945 /*!
946     \since 5.15
947 
948     Sets \a timeout as the transfer timeout in milliseconds.
949 
950     Transfers are aborted if no bytes are transferred before
951     the timeout expires. Zero means no timer is set. If no
952     argument is provided, the timeout is
953     QNetworkRequest::DefaultTransferTimeoutConstant. If this function
954     is not called, the timeout is disabled and has the
955     value zero.
956 
957     \sa transferTimeout
958 */
setTransferTimeout(int timeout)959 void QNetworkRequest::setTransferTimeout(int timeout)
960 {
961     d->transferTimeout = timeout;
962 }
963 #endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC) || defined (Q_OS_WASM)
964 
headerName(QNetworkRequest::KnownHeaders header)965 static QByteArray headerName(QNetworkRequest::KnownHeaders header)
966 {
967     switch (header) {
968     case QNetworkRequest::ContentTypeHeader:
969         return "Content-Type";
970 
971     case QNetworkRequest::ContentLengthHeader:
972         return "Content-Length";
973 
974     case QNetworkRequest::LocationHeader:
975         return "Location";
976 
977     case QNetworkRequest::LastModifiedHeader:
978         return "Last-Modified";
979 
980     case QNetworkRequest::IfModifiedSinceHeader:
981         return "If-Modified-Since";
982 
983     case QNetworkRequest::ETagHeader:
984         return "ETag";
985 
986     case QNetworkRequest::IfMatchHeader:
987         return "If-Match";
988 
989     case QNetworkRequest::IfNoneMatchHeader:
990         return "If-None-Match";
991 
992     case QNetworkRequest::CookieHeader:
993         return "Cookie";
994 
995     case QNetworkRequest::SetCookieHeader:
996         return "Set-Cookie";
997 
998     case QNetworkRequest::ContentDispositionHeader:
999         return "Content-Disposition";
1000 
1001     case QNetworkRequest::UserAgentHeader:
1002         return "User-Agent";
1003 
1004     case QNetworkRequest::ServerHeader:
1005         return "Server";
1006 
1007     // no default:
1008     // if new values are added, this will generate a compiler warning
1009     }
1010 
1011     return QByteArray();
1012 }
1013 
headerValue(QNetworkRequest::KnownHeaders header,const QVariant & value)1014 static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVariant &value)
1015 {
1016     switch (header) {
1017     case QNetworkRequest::ContentTypeHeader:
1018     case QNetworkRequest::ContentLengthHeader:
1019     case QNetworkRequest::ContentDispositionHeader:
1020     case QNetworkRequest::UserAgentHeader:
1021     case QNetworkRequest::ServerHeader:
1022     case QNetworkRequest::ETagHeader:
1023     case QNetworkRequest::IfMatchHeader:
1024     case QNetworkRequest::IfNoneMatchHeader:
1025         return value.toByteArray();
1026 
1027     case QNetworkRequest::LocationHeader:
1028         switch (value.userType()) {
1029         case QMetaType::QUrl:
1030             return value.toUrl().toEncoded();
1031 
1032         default:
1033             return value.toByteArray();
1034         }
1035 
1036     case QNetworkRequest::LastModifiedHeader:
1037     case QNetworkRequest::IfModifiedSinceHeader:
1038         switch (value.userType()) {
1039         case QMetaType::QDate:
1040         case QMetaType::QDateTime:
1041             // generate RFC 1123/822 dates:
1042             return QNetworkHeadersPrivate::toHttpDate(value.toDateTime());
1043 
1044         default:
1045             return value.toByteArray();
1046         }
1047 
1048     case QNetworkRequest::CookieHeader: {
1049         QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
1050         if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
1051             cookies << qvariant_cast<QNetworkCookie>(value);
1052 
1053         QByteArray result;
1054         bool first = true;
1055         for (const QNetworkCookie &cookie : qAsConst(cookies)) {
1056             if (!first)
1057                 result += "; ";
1058             first = false;
1059             result += cookie.toRawForm(QNetworkCookie::NameAndValueOnly);
1060         }
1061         return result;
1062     }
1063 
1064     case QNetworkRequest::SetCookieHeader: {
1065         QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
1066         if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
1067             cookies << qvariant_cast<QNetworkCookie>(value);
1068 
1069         QByteArray result;
1070         bool first = true;
1071         for (const QNetworkCookie &cookie : qAsConst(cookies)) {
1072             if (!first)
1073                 result += ", ";
1074             first = false;
1075             result += cookie.toRawForm(QNetworkCookie::Full);
1076         }
1077         return result;
1078     }
1079     }
1080 
1081     return QByteArray();
1082 }
1083 
parseHeaderName(const QByteArray & headerName)1084 static int parseHeaderName(const QByteArray &headerName)
1085 {
1086     if (headerName.isEmpty())
1087         return -1;
1088 
1089     switch (tolower(headerName.at(0))) {
1090     case 'c':
1091         if (headerName.compare("content-type", Qt::CaseInsensitive) == 0)
1092             return QNetworkRequest::ContentTypeHeader;
1093         else if (headerName.compare("content-length", Qt::CaseInsensitive) == 0)
1094             return QNetworkRequest::ContentLengthHeader;
1095         else if (headerName.compare("cookie", Qt::CaseInsensitive) == 0)
1096             return QNetworkRequest::CookieHeader;
1097         else if (qstricmp(headerName.constData(), "content-disposition") == 0)
1098             return QNetworkRequest::ContentDispositionHeader;
1099         break;
1100 
1101     case 'e':
1102         if (qstricmp(headerName.constData(), "etag") == 0)
1103             return QNetworkRequest::ETagHeader;
1104         break;
1105 
1106     case 'i':
1107         if (qstricmp(headerName.constData(), "if-modified-since") == 0)
1108             return QNetworkRequest::IfModifiedSinceHeader;
1109         if (qstricmp(headerName.constData(), "if-match") == 0)
1110             return QNetworkRequest::IfMatchHeader;
1111         if (qstricmp(headerName.constData(), "if-none-match") == 0)
1112             return QNetworkRequest::IfNoneMatchHeader;
1113         break;
1114 
1115     case 'l':
1116         if (headerName.compare("location", Qt::CaseInsensitive) == 0)
1117             return QNetworkRequest::LocationHeader;
1118         else if (headerName.compare("last-modified", Qt::CaseInsensitive) == 0)
1119             return QNetworkRequest::LastModifiedHeader;
1120         break;
1121 
1122     case 's':
1123         if (headerName.compare("set-cookie", Qt::CaseInsensitive) == 0)
1124             return QNetworkRequest::SetCookieHeader;
1125         else if (headerName.compare("server", Qt::CaseInsensitive) == 0)
1126             return QNetworkRequest::ServerHeader;
1127         break;
1128 
1129     case 'u':
1130         if (headerName.compare("user-agent", Qt::CaseInsensitive) == 0)
1131             return QNetworkRequest::UserAgentHeader;
1132         break;
1133     }
1134 
1135     return -1; // nothing found
1136 }
1137 
parseHttpDate(const QByteArray & raw)1138 static QVariant parseHttpDate(const QByteArray &raw)
1139 {
1140     QDateTime dt = QNetworkHeadersPrivate::fromHttpDate(raw);
1141     if (dt.isValid())
1142         return dt;
1143     return QVariant();          // transform an invalid QDateTime into a null QVariant
1144 }
1145 
parseCookieHeader(const QByteArray & raw)1146 static QVariant parseCookieHeader(const QByteArray &raw)
1147 {
1148     QList<QNetworkCookie> result;
1149     const QList<QByteArray> cookieList = raw.split(';');
1150     for (const QByteArray &cookie : cookieList) {
1151         QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookie.trimmed());
1152         if (parsed.count() != 1)
1153             return QVariant();  // invalid Cookie: header
1154 
1155         result += parsed;
1156     }
1157 
1158     return QVariant::fromValue(result);
1159 }
1160 
parseETag(const QByteArray & raw)1161 static QVariant parseETag(const QByteArray &raw)
1162 {
1163     const QByteArray trimmed = raw.trimmed();
1164     if (!trimmed.startsWith('"') && !trimmed.startsWith(R"(W/")"))
1165         return QVariant();
1166 
1167     if (!trimmed.endsWith('"'))
1168         return QVariant();
1169 
1170     return QString::fromLatin1(trimmed);
1171 }
1172 
1173 static QVariant parseIfMatch(const QByteArray &raw)
1174 {
1175     const QByteArray trimmedRaw = raw.trimmed();
1176     if (trimmedRaw == "*")
1177         return QStringList(QStringLiteral("*"));
1178 
1179     QStringList tags;
1180     const QList<QByteArray> split = trimmedRaw.split(',');
1181     for (const QByteArray &element : split) {
1182         const QByteArray trimmed = element.trimmed();
1183         if (!trimmed.startsWith('"'))
1184             continue;
1185 
1186         if (!trimmed.endsWith('"'))
1187             continue;
1188 
1189         tags += QString::fromLatin1(trimmed);
1190     }
1191     return tags;
1192 }
1193 
1194 static QVariant parseIfNoneMatch(const QByteArray &raw)
1195 {
1196     const QByteArray trimmedRaw = raw.trimmed();
1197     if (trimmedRaw == "*")
1198         return QStringList(QStringLiteral("*"));
1199 
1200     QStringList tags;
1201     const QList<QByteArray> split = trimmedRaw.split(',');
1202     for (const QByteArray &element : split) {
1203         const QByteArray trimmed = element.trimmed();
1204         if (!trimmed.startsWith('"') && !trimmed.startsWith(R"(W/")"))
1205             continue;
1206 
1207         if (!trimmed.endsWith('"'))
1208             continue;
1209 
1210         tags += QString::fromLatin1(trimmed);
1211     }
1212     return tags;
1213 }
1214 
1215 
parseHeaderValue(QNetworkRequest::KnownHeaders header,const QByteArray & value)1216 static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QByteArray &value)
1217 {
1218     // header is always a valid value
1219     switch (header) {
1220     case QNetworkRequest::UserAgentHeader:
1221     case QNetworkRequest::ServerHeader:
1222     case QNetworkRequest::ContentTypeHeader:
1223     case QNetworkRequest::ContentDispositionHeader:
1224         // copy exactly, convert to QString
1225         return QString::fromLatin1(value);
1226 
1227     case QNetworkRequest::ContentLengthHeader: {
1228         bool ok;
1229         qint64 result = value.trimmed().toLongLong(&ok);
1230         if (ok)
1231             return result;
1232         return QVariant();
1233     }
1234 
1235     case QNetworkRequest::LocationHeader: {
1236         QUrl result = QUrl::fromEncoded(value, QUrl::StrictMode);
1237         if (result.isValid() && !result.scheme().isEmpty())
1238             return result;
1239         return QVariant();
1240     }
1241 
1242     case QNetworkRequest::LastModifiedHeader:
1243     case QNetworkRequest::IfModifiedSinceHeader:
1244         return parseHttpDate(value);
1245 
1246     case QNetworkRequest::ETagHeader:
1247         return parseETag(value);
1248 
1249     case QNetworkRequest::IfMatchHeader:
1250         return parseIfMatch(value);
1251 
1252     case QNetworkRequest::IfNoneMatchHeader:
1253         return parseIfNoneMatch(value);
1254 
1255     case QNetworkRequest::CookieHeader:
1256         return parseCookieHeader(value);
1257 
1258     case QNetworkRequest::SetCookieHeader:
1259         return QVariant::fromValue(QNetworkCookie::parseCookies(value));
1260 
1261     default:
1262         Q_ASSERT(0);
1263     }
1264     return QVariant();
1265 }
1266 
1267 QNetworkHeadersPrivate::RawHeadersList::ConstIterator
findRawHeader(const QByteArray & key) const1268 QNetworkHeadersPrivate::findRawHeader(const QByteArray &key) const
1269 {
1270     RawHeadersList::ConstIterator it = rawHeaders.constBegin();
1271     RawHeadersList::ConstIterator end = rawHeaders.constEnd();
1272     for ( ; it != end; ++it)
1273         if (it->first.compare(key, Qt::CaseInsensitive) == 0)
1274             return it;
1275 
1276     return end;                 // not found
1277 }
1278 
allRawHeaders() const1279 QNetworkHeadersPrivate::RawHeadersList QNetworkHeadersPrivate::allRawHeaders() const
1280 {
1281     return rawHeaders;
1282 }
1283 
rawHeadersKeys() const1284 QList<QByteArray> QNetworkHeadersPrivate::rawHeadersKeys() const
1285 {
1286     QList<QByteArray> result;
1287     result.reserve(rawHeaders.size());
1288     RawHeadersList::ConstIterator it = rawHeaders.constBegin(),
1289                                  end = rawHeaders.constEnd();
1290     for ( ; it != end; ++it)
1291         result << it->first;
1292 
1293     return result;
1294 }
1295 
setRawHeader(const QByteArray & key,const QByteArray & value)1296 void QNetworkHeadersPrivate::setRawHeader(const QByteArray &key, const QByteArray &value)
1297 {
1298     if (key.isEmpty())
1299         // refuse to accept an empty raw header
1300         return;
1301 
1302     setRawHeaderInternal(key, value);
1303     parseAndSetHeader(key, value);
1304 }
1305 
1306 /*!
1307     \internal
1308     Sets the internal raw headers list to match \a list. The cooked headers
1309     will also be updated.
1310 
1311     If \a list contains duplicates, they will be stored, but only the first one
1312     is usually accessed.
1313 */
setAllRawHeaders(const RawHeadersList & list)1314 void QNetworkHeadersPrivate::setAllRawHeaders(const RawHeadersList &list)
1315 {
1316     cookedHeaders.clear();
1317     rawHeaders = list;
1318 
1319     RawHeadersList::ConstIterator it = rawHeaders.constBegin();
1320     RawHeadersList::ConstIterator end = rawHeaders.constEnd();
1321     for ( ; it != end; ++it)
1322         parseAndSetHeader(it->first, it->second);
1323 }
1324 
setCookedHeader(QNetworkRequest::KnownHeaders header,const QVariant & value)1325 void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders header,
1326                                              const QVariant &value)
1327 {
1328     QByteArray name = headerName(header);
1329     if (name.isEmpty()) {
1330         // headerName verifies that \a header is a known value
1331         qWarning("QNetworkRequest::setHeader: invalid header value KnownHeader(%d) received", header);
1332         return;
1333     }
1334 
1335     if (value.isNull()) {
1336         setRawHeaderInternal(name, QByteArray());
1337         cookedHeaders.remove(header);
1338     } else {
1339         QByteArray rawValue = headerValue(header, value);
1340         if (rawValue.isEmpty()) {
1341             qWarning("QNetworkRequest::setHeader: QVariant of type %s cannot be used with header %s",
1342                      value.typeName(), name.constData());
1343             return;
1344         }
1345 
1346         setRawHeaderInternal(name, rawValue);
1347         cookedHeaders.insert(header, value);
1348     }
1349 }
1350 
setRawHeaderInternal(const QByteArray & key,const QByteArray & value)1351 void QNetworkHeadersPrivate::setRawHeaderInternal(const QByteArray &key, const QByteArray &value)
1352 {
1353     auto firstEqualsKey = [&key](const RawHeaderPair &header) {
1354         return header.first.compare(key, Qt::CaseInsensitive) == 0;
1355     };
1356     rawHeaders.erase(std::remove_if(rawHeaders.begin(), rawHeaders.end(),
1357                                     firstEqualsKey),
1358                      rawHeaders.end());
1359 
1360     if (value.isNull())
1361         return;                 // only wanted to erase key
1362 
1363     RawHeaderPair pair;
1364     pair.first = key;
1365     pair.second = value;
1366     rawHeaders.append(pair);
1367 }
1368 
parseAndSetHeader(const QByteArray & key,const QByteArray & value)1369 void QNetworkHeadersPrivate::parseAndSetHeader(const QByteArray &key, const QByteArray &value)
1370 {
1371     // is it a known header?
1372     const int parsedKeyAsInt = parseHeaderName(key);
1373     if (parsedKeyAsInt != -1) {
1374         const QNetworkRequest::KnownHeaders parsedKey
1375                 = static_cast<QNetworkRequest::KnownHeaders>(parsedKeyAsInt);
1376         if (value.isNull()) {
1377             cookedHeaders.remove(parsedKey);
1378         } else if (parsedKey == QNetworkRequest::ContentLengthHeader
1379                  && cookedHeaders.contains(QNetworkRequest::ContentLengthHeader)) {
1380             // Only set the cooked header "Content-Length" once.
1381             // See bug QTBUG-15311
1382         } else {
1383             cookedHeaders.insert(parsedKey, parseHeaderValue(parsedKey, value));
1384         }
1385 
1386     }
1387 }
1388 
1389 // Fast month string to int conversion. This code
1390 // assumes that the Month name is correct and that
1391 // the string is at least three chars long.
name_to_month(const char * month_str)1392 static int name_to_month(const char* month_str)
1393 {
1394     switch (month_str[0]) {
1395     case 'J':
1396         switch (month_str[1]) {
1397         case 'a':
1398             return 1;
1399         case 'u':
1400             switch (month_str[2] ) {
1401             case 'n':
1402                 return 6;
1403             case 'l':
1404                 return 7;
1405             }
1406         }
1407         break;
1408     case 'F':
1409         return 2;
1410     case 'M':
1411         switch (month_str[2] ) {
1412         case 'r':
1413             return 3;
1414         case 'y':
1415             return 5;
1416         }
1417         break;
1418     case 'A':
1419         switch (month_str[1]) {
1420         case 'p':
1421             return 4;
1422         case 'u':
1423             return 8;
1424         }
1425         break;
1426     case 'O':
1427         return 10;
1428     case 'S':
1429         return 9;
1430     case 'N':
1431         return 11;
1432     case 'D':
1433         return 12;
1434     }
1435 
1436     return 0;
1437 }
1438 
fromHttpDate(const QByteArray & value)1439 QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value)
1440 {
1441     // HTTP dates have three possible formats:
1442     //  RFC 1123/822      -   ddd, dd MMM yyyy hh:mm:ss "GMT"
1443     //  RFC 850           -   dddd, dd-MMM-yy hh:mm:ss "GMT"
1444     //  ANSI C's asctime  -   ddd MMM d hh:mm:ss yyyy
1445     // We only handle them exactly. If they deviate, we bail out.
1446 
1447     int pos = value.indexOf(',');
1448     QDateTime dt;
1449 #if QT_CONFIG(datestring)
1450     if (pos == -1) {
1451         // no comma -> asctime(3) format
1452         dt = QDateTime::fromString(QString::fromLatin1(value), Qt::TextDate);
1453     } else {
1454         // Use sscanf over QLocal/QDateTimeParser for speed reasons. See the
1455         // Qt WebKit performance benchmarks to get an idea.
1456         if (pos == 3) {
1457             char month_name[4];
1458             int day, year, hour, minute, second;
1459 #ifdef Q_CC_MSVC
1460             // Use secure version to avoid compiler warning
1461             if (sscanf_s(value.constData(), "%*3s, %d %3s %d %d:%d:%d 'GMT'", &day, month_name, 4, &year, &hour, &minute, &second) == 6)
1462 #else
1463             // The POSIX secure mode is %ms (which allocates memory), too bleeding edge for now
1464             // In any case this is already safe as field width is specified.
1465             if (sscanf(value.constData(), "%*3s, %d %3s %d %d:%d:%d 'GMT'", &day, month_name, &year, &hour, &minute, &second) == 6)
1466 #endif
1467                 dt = QDateTime(QDate(year, name_to_month(month_name), day), QTime(hour, minute, second));
1468         } else {
1469             QLocale c = QLocale::c();
1470             // eat the weekday, the comma and the space following it
1471             QString sansWeekday = QString::fromLatin1(value.constData() + pos + 2);
1472             // must be RFC 850 date
1473             dt = c.toDateTime(sansWeekday, QLatin1String("dd-MMM-yy hh:mm:ss 'GMT'"));
1474         }
1475     }
1476 #endif // datestring
1477 
1478     if (dt.isValid())
1479         dt.setTimeSpec(Qt::UTC);
1480     return dt;
1481 }
1482 
toHttpDate(const QDateTime & dt)1483 QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt)
1484 {
1485     return QLocale::c().toString(dt, u"ddd, dd MMM yyyy hh:mm:ss 'GMT'")
1486         .toLatin1();
1487 }
1488 
1489 QT_END_NAMESPACE
1490