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