source: trunk/src/network/access/qnetworkrequest.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 31.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtNetwork module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qplatformdefs.h"
43#include "qnetworkrequest.h"
44#include "qnetworkcookie.h"
45#include "qnetworkrequest_p.h"
46#include "qsslconfiguration.h"
47#include "QtCore/qshareddata.h"
48#include "QtCore/qlocale.h"
49#include "QtCore/qdatetime.h"
50
51#include <ctype.h>
52#ifndef QT_NO_DATESTRING
53# include <stdio.h>
54#endif
55
56QT_BEGIN_NAMESPACE
57
58/*!
59 \class QNetworkRequest
60 \brief The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
61 \since 4.4
62
63 \ingroup network
64 \inmodule QtNetwork
65
66 QNetworkRequest is part of the Network Access API and is the class
67 holding the information necessary to send a request over the
68 network. It contains a URL and some ancillary information that can
69 be used to modify the request.
70
71 \sa QNetworkReply, QNetworkAccessManager
72*/
73
74/*!
75 \enum QNetworkRequest::KnownHeaders
76
77 List of known header types that QNetworkRequest parses. Each known
78 header is also represented in raw form with its full HTTP name.
79
80 \value ContentTypeHeader corresponds to the HTTP Content-Type
81 header and contains a string containing the media (MIME) type and
82 any auxiliary data (for instance, charset)
83
84 \value ContentLengthHeader corresponds to the HTTP Content-Length
85 header and contains the length in bytes of the data transmitted.
86
87 \value LocationHeader corresponds to the HTTP Location
88 header and contains a URL representing the actual location of the
89 data, including the destination URL in case of redirections.
90
91 \value LastModifiedHeader corresponds to the HTTP Last-Modified
92 header and contains a QDateTime representing the last modification
93 date of the contents
94
95 \value CookieHeader corresponds to the HTTP Cookie header
96 and contains a QList<QNetworkCookie> representing the cookies to
97 be sent back to the server
98
99 \value SetCookieHeader corresponds to the HTTP Set-Cookie
100 header and contains a QList<QNetworkCookie> representing the
101 cookies sent by the server to be stored locally
102
103 \sa header(), setHeader(), rawHeader(), setRawHeader()
104*/
105
106/*!
107 \enum QNetworkRequest::Attribute
108 \since 4.7
109
110 Attribute codes for the QNetworkRequest and QNetworkReply.
111
112 Attributes are extra meta-data that are used to control the
113 behavior of the request and to pass further information from the
114 reply back to the application. Attributes are also extensible,
115 allowing custom implementations to pass custom values.
116
117 The following table explains what the default attribute codes are,
118 the QVariant types associated, the default value if said attribute
119 is missing and whether it's used in requests or replies.
120
121 \value HttpStatusCodeAttribute
122 Replies only, type: QVariant::Int (no default)
123 Indicates the HTTP status code received from the HTTP server
124 (like 200, 304, 404, 401, etc.). If the connection was not
125 HTTP-based, this attribute will not be present.
126
127 \value HttpReasonPhraseAttribute
128 Replies only, type: QVariant::ByteArray (no default)
129 Indicates the HTTP reason phrase as received from the HTTP
130 server (like "Ok", "Found", "Not Found", "Access Denied",
131 etc.) This is the human-readable representation of the status
132 code (see above). If the connection was not HTTP-based, this
133 attribute will not be present.
134
135 \value RedirectionTargetAttribute
136 Replies only, type: QVariant::Url (no default)
137 If present, it indicates that the server is redirecting the
138 request to a different URL. The Network Access API does not by
139 default follow redirections: it's up to the application to
140 determine if the requested redirection should be allowed,
141 according to its security policies.
142 The returned URL might be relative. Use QUrl::resolved()
143 to create an absolute URL out of it.
144
145 \value ConnectionEncryptedAttribute
146 Replies only, type: QVariant::Bool (default: false)
147 Indicates whether the data was obtained through an encrypted
148 (secure) connection.
149
150 \value CacheLoadControlAttribute
151 Requests only, type: QVariant::Int (default: QNetworkRequest::PreferNetwork)
152 Controls how the cache should be accessed. The possible values
153 are those of QNetworkRequest::CacheLoadControl. Note that the
154 default QNetworkAccessManager implementation does not support
155 caching. However, this attribute may be used by certain
156 backends to modify their requests (for example, for caching proxies).
157
158 \value CacheSaveControlAttribute
159 Requests only, type: QVariant::Bool (default: true)
160 Controls if the data obtained should be saved to cache for
161 future uses. If the value is false, the data obtained will not
162 be automatically cached. If true, data may be cached, provided
163 it is cacheable (what is cacheable depends on the protocol
164 being used).
165
166 \value SourceIsFromCacheAttribute
167 Replies only, type: QVariant::Bool (default: false)
168 Indicates whether the data was obtained from cache
169 or not.
170
171 \value DoNotBufferUploadDataAttribute
172 Requests only, type: QVariant::Bool (default: false)
173 Indicates whether the QNetworkAccessManager code is
174 allowed to buffer the upload data, e.g. when doing a HTTP POST.
175 When using this flag with sequential upload data, the ContentLengthHeader
176 header must be set.
177
178 \value HttpPipeliningAllowedAttribute
179 Requests only, type: QVariant::Bool (default: false)
180 Indicates whether the QNetworkAccessManager code is
181 allowed to use HTTP pipelining with this request.
182
183 \value HttpPipeliningWasUsedAttribute
184 Replies only, type: QVariant::Bool
185 Indicates whether the HTTP pipelining was used for receiving
186 this reply.
187
188 \value CustomVerbAttribute
189 Requests only, type: QVariant::ByteArray
190 Holds the value for the custom HTTP verb to send (destined for usage
191 of other verbs than GET, POST, PUT and DELETE). This verb is set
192 when calling QNetworkAccessManager::sendCustomRequest().
193
194 \value CookieLoadControlAttribute
195 Requests only, type: QVariant::Int (default: QNetworkRequest::Automatic)
196 Indicates whether to send 'Cookie' headers in the request.
197 This attribute is set to false by QtWebKit when creating a cross-origin
198 XMLHttpRequest where withCredentials has not been set explicitly to true by the
199 Javascript that created the request.
200 See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag}{here} for more information.
201 (This value was introduced in 4.7.)
202
203 \value CookieSaveControlAttribute
204 Requests only, type: QVariant::Int (default: QNetworkRequest::Automatic)
205 Indicates whether to save 'Cookie' headers received from the server in reply
206 to the request.
207 This attribute is set to false by QtWebKit when creating a cross-origin
208 XMLHttpRequest where withCredentials has not been set explicitly to true by the
209 Javascript that created the request.
210 See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information.
211 (This value was introduced in 4.7.)
212
213 \value AuthenticationReuseAttribute
214 Requests only, type: QVariant::Int (default: QNetworkRequest::Automatic)
215 Indicates whether to use cached authorization credentials in the request,
216 if available. If this is set to QNetworkRequest::Manual and the authentication
217 mechanism is 'Basic' or 'Digest', Qt will not send an an 'Authorization' HTTP
218 header with any cached credentials it may have for the request's URL.
219 This attribute is set to QNetworkRequest::Manual by QtWebKit when creating a cross-origin
220 XMLHttpRequest where withCredentials has not been set explicitly to true by the
221 Javascript that created the request.
222 See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information.
223 (This value was introduced in 4.7.)
224
225 \omitvalue MaximumDownloadBufferSizeAttribute
226
227 \omitvalue DownloadBufferAttribute
228
229 \value User
230 Special type. Additional information can be passed in
231 QVariants with types ranging from User to UserMax. The default
232 implementation of Network Access will ignore any request
233 attributes in this range and it will not produce any
234 attributes in this range in replies. The range is reserved for
235 extensions of QNetworkAccessManager.
236
237 \value UserMax
238 Special type. See User.
239*/
240
241/*!
242 \enum QNetworkRequest::CacheLoadControl
243
244 Controls the caching mechanism of QNetworkAccessManager.
245
246 \value AlwaysNetwork always load from network and do not
247 check if the cache has a valid entry (similar to the
248 "Reload" feature in browsers)
249
250 \value PreferNetwork default value; load from the network
251 if the cached entry is older than the network entry
252
253 \value PreferCache load from cache if available,
254 otherwise load from network. Note that this can return possibly
255 stale (but not expired) items from cache.
256
257 \value AlwaysCache only load from cache, indicating error
258 if the item was not cached (i.e., off-line mode)
259*/
260
261/*!
262 \enum QNetworkRequest::LoadControl
263 \since 4.7
264
265 Indicates if an aspect of the request's loading mechanism has been
266 manually overridden, e.g. by QtWebKit.
267
268 \value Automatic default value: indicates default behaviour.
269
270 \value Manual indicates behaviour has been manually overridden.
271*/
272
273class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate
274{
275public:
276 inline QNetworkRequestPrivate()
277 : priority(QNetworkRequest::NormalPriority)
278#ifndef QT_NO_OPENSSL
279 , sslConfiguration(0)
280#endif
281 { qRegisterMetaType<QNetworkRequest>(); }
282 ~QNetworkRequestPrivate()
283 {
284#ifndef QT_NO_OPENSSL
285 delete sslConfiguration;
286#endif
287 }
288
289
290 QNetworkRequestPrivate(const QNetworkRequestPrivate &other)
291 : QSharedData(other), QNetworkHeadersPrivate(other)
292 {
293 url = other.url;
294 priority = other.priority;
295
296#ifndef QT_NO_OPENSSL
297 sslConfiguration = 0;
298 if (other.sslConfiguration)
299 sslConfiguration = new QSslConfiguration(*other.sslConfiguration);
300#endif
301 }
302
303 inline bool operator==(const QNetworkRequestPrivate &other) const
304 {
305 return url == other.url &&
306 priority == other.priority &&
307 rawHeaders == other.rawHeaders &&
308 attributes == other.attributes;
309 // don't compare cookedHeaders
310 }
311
312 QUrl url;
313 QNetworkRequest::Priority priority;
314#ifndef QT_NO_OPENSSL
315 mutable QSslConfiguration *sslConfiguration;
316#endif
317};
318
319/*!
320 Constructs a QNetworkRequest object with \a url as the URL to be
321 requested.
322
323 \sa url(), setUrl()
324*/
325QNetworkRequest::QNetworkRequest(const QUrl &url)
326 : d(new QNetworkRequestPrivate)
327{
328 d->url = url;
329}
330
331/*!
332 Creates a copy of \a other.
333*/
334QNetworkRequest::QNetworkRequest(const QNetworkRequest &other)
335 : d(other.d)
336{
337}
338
339/*!
340 Disposes of the QNetworkRequest object.
341*/
342QNetworkRequest::~QNetworkRequest()
343{
344 // QSharedDataPointer auto deletes
345 d = 0;
346}
347
348/*!
349 Returns true if this object is the same as \a other (i.e., if they
350 have the same URL, same headers and same meta-data settings).
351
352 \sa operator!=()
353*/
354bool QNetworkRequest::operator==(const QNetworkRequest &other) const
355{
356 return d == other.d || *d == *other.d;
357}
358
359/*!
360 \fn bool QNetworkRequest::operator!=(const QNetworkRequest &other) const
361
362 Returns false if this object is not the same as \a other.
363
364 \sa operator==()
365*/
366
367/*!
368 Creates a copy of \a other
369*/
370QNetworkRequest &QNetworkRequest::operator=(const QNetworkRequest &other)
371{
372 d = other.d;
373 return *this;
374}
375
376/*!
377 Returns the URL this network request is referring to.
378
379 \sa setUrl()
380*/
381QUrl QNetworkRequest::url() const
382{
383 return d->url;
384}
385
386/*!
387 Sets the URL this network request is referring to to be \a url.
388
389 \sa url()
390*/
391void QNetworkRequest::setUrl(const QUrl &url)
392{
393 d->url = url;
394}
395
396/*!
397 Returns the value of the known network header \a header if it is
398 present in this request. If it is not present, returns QVariant()
399 (i.e., an invalid variant).
400
401 \sa KnownHeaders, rawHeader(), setHeader()
402*/
403QVariant QNetworkRequest::header(KnownHeaders header) const
404{
405 return d->cookedHeaders.value(header);
406}
407
408/*!
409 Sets the value of the known header \a header to be \a value,
410 overriding any previously set headers. This operation also sets
411 the equivalent raw HTTP header.
412
413 \sa KnownHeaders, setRawHeader(), header()
414*/
415void QNetworkRequest::setHeader(KnownHeaders header, const QVariant &value)
416{
417 d->setCookedHeader(header, value);
418}
419
420/*!
421 Returns true if the raw header \a headerName is present in this
422 network request.
423
424 \sa rawHeader(), setRawHeader()
425*/
426bool QNetworkRequest::hasRawHeader(const QByteArray &headerName) const
427{
428 return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
429}
430
431/*!
432 Returns the raw form of header \a headerName. If no such header is
433 present, an empty QByteArray is returned, which may be
434 indistinguishable from a header that is present but has no content
435 (use hasRawHeader() to find out if the header exists or not).
436
437 Raw headers can be set with setRawHeader() or with setHeader().
438
439 \sa header(), setRawHeader()
440*/
441QByteArray QNetworkRequest::rawHeader(const QByteArray &headerName) const
442{
443 QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
444 d->findRawHeader(headerName);
445 if (it != d->rawHeaders.constEnd())
446 return it->second;
447 return QByteArray();
448}
449
450/*!
451 Returns a list of all raw headers that are set in this network
452 request. The list is in the order that the headers were set.
453
454 \sa hasRawHeader(), rawHeader()
455*/
456QList<QByteArray> QNetworkRequest::rawHeaderList() const
457{
458 return d->rawHeadersKeys();
459}
460
461/*!
462 Sets the header \a headerName to be of value \a headerValue. If \a
463 headerName corresponds to a known header (see
464 QNetworkRequest::KnownHeaders), the raw format will be parsed and
465 the corresponding "cooked" header will be set as well.
466
467 For example:
468 \snippet doc/src/snippets/code/src_network_access_qnetworkrequest.cpp 0
469
470 will also set the known header LastModifiedHeader to be the
471 QDateTime object of the parsed date.
472
473 Note: setting the same header twice overrides the previous
474 setting. To accomplish the behaviour of multiple HTTP headers of
475 the same name, you should concatenate the two values, separating
476 them with a comma (",") and set one single raw header.
477
478 \sa KnownHeaders, setHeader(), hasRawHeader(), rawHeader()
479*/
480void QNetworkRequest::setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
481{
482 d->setRawHeader(headerName, headerValue);
483}
484
485/*!
486 Returns the attribute associated with the code \a code. If the
487 attribute has not been set, it returns \a defaultValue.
488
489 Note: this function does not apply the defaults listed in
490 QNetworkRequest::Attribute.
491
492 \sa setAttribute(), QNetworkRequest::Attribute
493*/
494QVariant QNetworkRequest::attribute(Attribute code, const QVariant &defaultValue) const
495{
496 return d->attributes.value(code, defaultValue);
497}
498
499/*!
500 Sets the attribute associated with code \a code to be value \a
501 value. If the attribute is already set, the previous value is
502 discarded. In special, if \a value is an invalid QVariant, the
503 attribute is unset.
504
505 \sa attribute(), QNetworkRequest::Attribute
506*/
507void QNetworkRequest::setAttribute(Attribute code, const QVariant &value)
508{
509 if (value.isValid())
510 d->attributes.insert(code, value);
511 else
512 d->attributes.remove(code);
513}
514
515#ifndef QT_NO_OPENSSL
516/*!
517 Returns this network request's SSL configuration. By default, no
518 SSL settings are specified.
519
520 \sa setSslConfiguration()
521*/
522QSslConfiguration QNetworkRequest::sslConfiguration() const
523{
524 if (!d->sslConfiguration)
525 d->sslConfiguration = new QSslConfiguration;
526 return *d->sslConfiguration;
527}
528
529/*!
530 Sets this network request's SSL configuration to be \a config. The
531 settings that apply are the private key, the local certificate,
532 the SSL protocol (SSLv2, SSLv3, TLSv1 where applicable) and the
533 ciphers that the SSL backend is allowed to use.
534
535 By default, no SSL configuration is set, which allows the backends
536 to choose freely what configuration is best for them.
537
538 \sa sslConfiguration(), QSslConfiguration::defaultConfiguration()
539*/
540void QNetworkRequest::setSslConfiguration(const QSslConfiguration &config)
541{
542 if (!d->sslConfiguration)
543 d->sslConfiguration = new QSslConfiguration(config);
544 else
545 *d->sslConfiguration = config;
546}
547#endif
548
549/*!
550 \since 4.6
551
552 Allows setting a reference to the \a object initiating
553 the request.
554
555 For example QtWebKit sets the originating object to the
556 QWebFrame that initiated the request.
557
558 \sa originatingObject()
559*/
560void QNetworkRequest::setOriginatingObject(QObject *object)
561{
562 d->originatingObject = object;
563}
564
565/*!
566 \since 4.6
567
568 Returns a reference to the object that initiated this
569 network request; returns 0 if not set or the object has
570 been destroyed.
571
572 \sa setOriginatingObject()
573*/
574QObject *QNetworkRequest::originatingObject() const
575{
576 return d->originatingObject.data();
577}
578
579/*!
580 \since 4.7
581
582 Return the priority of this request.
583
584 \sa setPriority()
585*/
586QNetworkRequest::Priority QNetworkRequest::priority() const
587{
588 return d->priority;
589}
590
591/*! \enum QNetworkRequest::Priority
592
593 \since 4.7
594
595 This enum lists the possible network request priorities.
596
597 \value HighPriority High priority
598 \value NormalPriority Normal priority
599 \value LowPriority Low priority
600 */
601
602/*!
603 \since 4.7
604
605 Set the priority of this request to \a priority.
606
607 \note The \a priority is only a hint to the network access
608 manager. It can use it or not. Currently it is used for HTTP to
609 decide which request should be sent first to a server.
610
611 \sa priority()
612*/
613void QNetworkRequest::setPriority(Priority priority)
614{
615 d->priority = priority;
616}
617
618static QByteArray headerName(QNetworkRequest::KnownHeaders header)
619{
620 switch (header) {
621 case QNetworkRequest::ContentTypeHeader:
622 return "Content-Type";
623
624 case QNetworkRequest::ContentLengthHeader:
625 return "Content-Length";
626
627 case QNetworkRequest::LocationHeader:
628 return "Location";
629
630 case QNetworkRequest::LastModifiedHeader:
631 return "Last-Modified";
632
633 case QNetworkRequest::CookieHeader:
634 return "Cookie";
635
636 case QNetworkRequest::SetCookieHeader:
637 return "Set-Cookie";
638
639 // no default:
640 // if new values are added, this will generate a compiler warning
641 }
642
643 return QByteArray();
644}
645
646static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVariant &value)
647{
648 switch (header) {
649 case QNetworkRequest::ContentTypeHeader:
650 case QNetworkRequest::ContentLengthHeader:
651 return value.toByteArray();
652
653 case QNetworkRequest::LocationHeader:
654 switch (value.type()) {
655 case QVariant::Url:
656 return value.toUrl().toEncoded();
657
658 default:
659 return value.toByteArray();
660 }
661
662 case QNetworkRequest::LastModifiedHeader:
663 switch (value.type()) {
664 case QVariant::Date:
665 case QVariant::DateTime:
666 // generate RFC 1123/822 dates:
667 return QNetworkHeadersPrivate::toHttpDate(value.toDateTime());
668
669 default:
670 return value.toByteArray();
671 }
672
673 case QNetworkRequest::CookieHeader: {
674 QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
675 if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
676 cookies << qvariant_cast<QNetworkCookie>(value);
677
678 QByteArray result;
679 bool first = true;
680 foreach (const QNetworkCookie &cookie, cookies) {
681 if (!first)
682 result += "; ";
683 first = false;
684 result += cookie.toRawForm(QNetworkCookie::NameAndValueOnly);
685 }
686 return result;
687 }
688
689 case QNetworkRequest::SetCookieHeader: {
690 QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
691 if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
692 cookies << qvariant_cast<QNetworkCookie>(value);
693
694 QByteArray result;
695 bool first = true;
696 foreach (const QNetworkCookie &cookie, cookies) {
697 if (!first)
698 result += ", ";
699 first = false;
700 result += cookie.toRawForm(QNetworkCookie::Full);
701 }
702 return result;
703 }
704 }
705
706 return QByteArray();
707}
708
709static QNetworkRequest::KnownHeaders parseHeaderName(const QByteArray &headerName)
710{
711 // headerName is not empty here
712
713 switch (tolower(headerName.at(0))) {
714 case 'c':
715 if (qstricmp(headerName.constData(), "content-type") == 0)
716 return QNetworkRequest::ContentTypeHeader;
717 else if (qstricmp(headerName.constData(), "content-length") == 0)
718 return QNetworkRequest::ContentLengthHeader;
719 else if (qstricmp(headerName.constData(), "cookie") == 0)
720 return QNetworkRequest::CookieHeader;
721 break;
722
723 case 'l':
724 if (qstricmp(headerName.constData(), "location") == 0)
725 return QNetworkRequest::LocationHeader;
726 else if (qstricmp(headerName.constData(), "last-modified") == 0)
727 return QNetworkRequest::LastModifiedHeader;
728 break;
729
730 case 's':
731 if (qstricmp(headerName.constData(), "set-cookie") == 0)
732 return QNetworkRequest::SetCookieHeader;
733 break;
734 }
735
736 return QNetworkRequest::KnownHeaders(-1); // nothing found
737}
738
739static QVariant parseHttpDate(const QByteArray &raw)
740{
741 QDateTime dt = QNetworkHeadersPrivate::fromHttpDate(raw);
742 if (dt.isValid())
743 return dt;
744 return QVariant(); // transform an invalid QDateTime into a null QVariant
745}
746
747static QVariant parseCookieHeader(const QByteArray &raw)
748{
749 QList<QNetworkCookie> result;
750 QList<QByteArray> cookieList = raw.split(';');
751 foreach (const QByteArray &cookie, cookieList) {
752 QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookie.trimmed());
753 if (parsed.count() != 1)
754 return QVariant(); // invalid Cookie: header
755
756 result += parsed;
757 }
758
759 return qVariantFromValue(result);
760}
761
762static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QByteArray &value)
763{
764 // header is always a valid value
765 switch (header) {
766 case QNetworkRequest::ContentTypeHeader:
767 // copy exactly, convert to QString
768 return QString::fromLatin1(value);
769
770 case QNetworkRequest::ContentLengthHeader: {
771 bool ok;
772 qint64 result = value.trimmed().toLongLong(&ok);
773 if (ok)
774 return result;
775 return QVariant();
776 }
777
778 case QNetworkRequest::LocationHeader: {
779 QUrl result = QUrl::fromEncoded(value, QUrl::StrictMode);
780 if (result.isValid() && !result.scheme().isEmpty())
781 return result;
782 return QVariant();
783 }
784
785 case QNetworkRequest::LastModifiedHeader:
786 return parseHttpDate(value);
787
788 case QNetworkRequest::CookieHeader:
789 return parseCookieHeader(value);
790
791 case QNetworkRequest::SetCookieHeader:
792 return qVariantFromValue(QNetworkCookie::parseCookies(value));
793
794 default:
795 Q_ASSERT(0);
796 }
797 return QVariant();
798}
799
800QNetworkHeadersPrivate::RawHeadersList::ConstIterator
801QNetworkHeadersPrivate::findRawHeader(const QByteArray &key) const
802{
803 RawHeadersList::ConstIterator it = rawHeaders.constBegin();
804 RawHeadersList::ConstIterator end = rawHeaders.constEnd();
805 for ( ; it != end; ++it)
806 if (qstricmp(it->first.constData(), key.constData()) == 0)
807 return it;
808
809 return end; // not found
810}
811
812QList<QByteArray> QNetworkHeadersPrivate::rawHeadersKeys() const
813{
814 QList<QByteArray> result;
815 RawHeadersList::ConstIterator it = rawHeaders.constBegin(),
816 end = rawHeaders.constEnd();
817 for ( ; it != end; ++it)
818 result << it->first;
819
820 return result;
821}
822
823void QNetworkHeadersPrivate::setRawHeader(const QByteArray &key, const QByteArray &value)
824{
825 if (key.isEmpty())
826 // refuse to accept an empty raw header
827 return;
828
829 setRawHeaderInternal(key, value);
830 parseAndSetHeader(key, value);
831}
832
833/*!
834 \internal
835 Sets the internal raw headers list to match \a list. The cooked headers
836 will also be updated.
837
838 If \a list contains duplicates, they will be stored, but only the first one
839 is usually accessed.
840*/
841void QNetworkHeadersPrivate::setAllRawHeaders(const RawHeadersList &list)
842{
843 cookedHeaders.clear();
844 rawHeaders = list;
845
846 RawHeadersList::ConstIterator it = rawHeaders.constBegin();
847 RawHeadersList::ConstIterator end = rawHeaders.constEnd();
848 for ( ; it != end; ++it)
849 parseAndSetHeader(it->first, it->second);
850}
851
852void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders header,
853 const QVariant &value)
854{
855 QByteArray name = headerName(header);
856 if (name.isEmpty()) {
857 // headerName verifies that \a header is a known value
858 qWarning("QNetworkRequest::setHeader: invalid header value KnownHeader(%d) received", header);
859 return;
860 }
861
862 if (value.isNull()) {
863 setRawHeaderInternal(name, QByteArray());
864 cookedHeaders.remove(header);
865 } else {
866 QByteArray rawValue = headerValue(header, value);
867 if (rawValue.isEmpty()) {
868 qWarning("QNetworkRequest::setHeader: QVariant of type %s cannot be used with header %s",
869 value.typeName(), name.constData());
870 return;
871 }
872
873 setRawHeaderInternal(name, rawValue);
874 cookedHeaders.insert(header, value);
875 }
876}
877
878void QNetworkHeadersPrivate::setRawHeaderInternal(const QByteArray &key, const QByteArray &value)
879{
880 RawHeadersList::Iterator it = rawHeaders.begin();
881 while (it != rawHeaders.end()) {
882 if (qstricmp(it->first.constData(), key.constData()) == 0)
883 it = rawHeaders.erase(it);
884 else
885 ++it;
886 }
887
888 if (value.isNull())
889 return; // only wanted to erase key
890
891 RawHeaderPair pair;
892 pair.first = key;
893 pair.second = value;
894 rawHeaders.append(pair);
895}
896
897void QNetworkHeadersPrivate::parseAndSetHeader(const QByteArray &key, const QByteArray &value)
898{
899 // is it a known header?
900 QNetworkRequest::KnownHeaders parsedKey = parseHeaderName(key);
901 if (parsedKey != QNetworkRequest::KnownHeaders(-1)) {
902 if (value.isNull()) {
903 cookedHeaders.remove(parsedKey);
904 } else if (parsedKey == QNetworkRequest::ContentLengthHeader
905 && cookedHeaders.contains(QNetworkRequest::ContentLengthHeader)) {
906 // Only set the cooked header "Content-Length" once.
907 // See bug QTBUG-15311
908 } else {
909 cookedHeaders.insert(parsedKey, parseHeaderValue(parsedKey, value));
910 }
911
912 }
913}
914
915// Fast month string to int conversion. This code
916// assumes that the Month name is correct and that
917// the string is at least three chars long.
918static int name_to_month(const char* month_str)
919{
920 switch (month_str[0]) {
921 case 'J':
922 switch (month_str[1]) {
923 case 'a':
924 return 1;
925 break;
926 case 'u':
927 switch (month_str[2] ) {
928 case 'n':
929 return 6;
930 break;
931 case 'l':
932 return 7;
933 break;
934 }
935 }
936 break;
937 case 'F':
938 return 2;
939 break;
940 case 'M':
941 switch (month_str[2] ) {
942 case 'r':
943 return 3;
944 break;
945 case 'y':
946 return 5;
947 break;
948 }
949 break;
950 case 'A':
951 switch (month_str[1]) {
952 case 'p':
953 return 4;
954 break;
955 case 'u':
956 return 8;
957 break;
958 }
959 break;
960 case 'O':
961 return 10;
962 break;
963 case 'S':
964 return 9;
965 break;
966 case 'N':
967 return 11;
968 break;
969 case 'D':
970 return 12;
971 break;
972 }
973
974 return 0;
975}
976
977QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value)
978{
979 // HTTP dates have three possible formats:
980 // RFC 1123/822 - ddd, dd MMM yyyy hh:mm:ss "GMT"
981 // RFC 850 - dddd, dd-MMM-yy hh:mm:ss "GMT"
982 // ANSI C's asctime - ddd MMM d hh:mm:ss yyyy
983 // We only handle them exactly. If they deviate, we bail out.
984
985 int pos = value.indexOf(',');
986 QDateTime dt;
987#ifndef QT_NO_DATESTRING
988 if (pos == -1) {
989 // no comma -> asctime(3) format
990 dt = QDateTime::fromString(QString::fromLatin1(value), Qt::TextDate);
991 } else {
992 // Use sscanf over QLocal/QDateTimeParser for speed reasons. See the
993 // QtWebKit performance benchmarks to get an idea.
994 if (pos == 3) {
995 char month_name[4];
996 int day, year, hour, minute, second;
997 if (sscanf(value.constData(), "%*3s, %d %3s %d %d:%d:%d 'GMT'", &day, month_name, &year, &hour, &minute, &second) == 6)
998 dt = QDateTime(QDate(year, name_to_month(month_name), day), QTime(hour, minute, second));
999 } else {
1000 QLocale c = QLocale::c();
1001 // eat the weekday, the comma and the space following it
1002 QString sansWeekday = QString::fromLatin1(value.constData() + pos + 2);
1003 // must be RFC 850 date
1004 dt = c.toDateTime(sansWeekday, QLatin1String("dd-MMM-yy hh:mm:ss 'GMT'"));
1005 }
1006 }
1007#endif // QT_NO_DATESTRING
1008
1009 if (dt.isValid())
1010 dt.setTimeSpec(Qt::UTC);
1011 return dt;
1012}
1013
1014QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt)
1015{
1016 return QLocale::c().toString(dt, QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'"))
1017 .toLatin1();
1018}
1019
1020QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.