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