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