src/network/access/qnetworkrequest.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    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 QT_BEGIN_NAMESPACE
       
    52 
       
    53 /*!
       
    54     \class QNetworkRequest
       
    55     \brief The QNetworkRequest class holds a request to be sent with QNetworkAccessManager.
       
    56     \since 4.4
       
    57 
       
    58     \ingroup network
       
    59     \inmodule QtNetwork
       
    60 
       
    61     QNetworkRequest is part of the Network Access API and is the class
       
    62     holding the information necessary to send a request over the
       
    63     network. It contains a URL and some ancillary information that can
       
    64     be used to modify the request.
       
    65 
       
    66     \sa QNetworkReply, QNetworkAccessManager
       
    67 */
       
    68 
       
    69 /*!
       
    70     \enum QNetworkRequest::KnownHeaders
       
    71 
       
    72     List of known header types that QNetworkRequest parses. Each known
       
    73     header is also represented in raw form with its full HTTP name.
       
    74 
       
    75     \value ContentTypeHeader    corresponds to the HTTP Content-Type
       
    76     header and contains a string containing the media (MIME) type and
       
    77     any auxiliary data (for instance, charset)
       
    78 
       
    79     \value ContentLengthHeader  corresponds to the HTTP Content-Length
       
    80     header and contains the length in bytes of the data transmitted.
       
    81 
       
    82     \value LocationHeader       corresponds to the HTTP Location
       
    83     header and contains a URL representing the actual location of the
       
    84     data, including the destination URL in case of redirections.
       
    85 
       
    86     \value LastModifiedHeader   corresponds to the HTTP Last-Modified
       
    87     header and contains a QDateTime representing the last modification
       
    88     date of the contents
       
    89 
       
    90     \value CookieHeader         corresponds to the HTTP Cookie header
       
    91     and contains a QList<QNetworkCookie> representing the cookies to
       
    92     be sent back to the server
       
    93 
       
    94     \value SetCookieHeader      corresponds to the HTTP Set-Cookie
       
    95     header and contains a QList<QNetworkCookie> representing the
       
    96     cookies sent by the server to be stored locally
       
    97 
       
    98     \sa header(), setHeader(), rawHeader(), setRawHeader()
       
    99 */
       
   100 
       
   101 /*!
       
   102     \enum QNetworkRequest::Attribute
       
   103 
       
   104     Attribute codes for the QNetworkRequest and QNetworkReply.
       
   105 
       
   106     Attributes are extra meta-data that are used to control the
       
   107     behavior of the request and to pass further information from the
       
   108     reply back to the application. Attributes are also extensible,
       
   109     allowing custom implementations to pass custom values.
       
   110 
       
   111     The following table explains what the default attribute codes are,
       
   112     the QVariant types associated, the default value if said attribute
       
   113     is missing and whether it's used in requests or replies.
       
   114 
       
   115     \value HttpStatusCodeAttribute
       
   116         Replies only, type: QVariant::Int (no default)
       
   117         Indicates the HTTP status code received from the HTTP server
       
   118         (like 200, 304, 404, 401, etc.). If the connection was not
       
   119         HTTP-based, this attribute will not be present.
       
   120 
       
   121     \value HttpReasonPhraseAttribute
       
   122         Replies only, type: QVariant::ByteArray (no default)
       
   123         Indicates the HTTP reason phrase as received from the HTTP
       
   124         server (like "Ok", "Found", "Not Found", "Access Denied",
       
   125         etc.) This is the human-readable representation of the status
       
   126         code (see above). If the connection was not HTTP-based, this
       
   127         attribute will not be present.
       
   128 
       
   129     \value RedirectionTargetAttribute
       
   130         Replies only, type: QVariant::Url (no default)
       
   131         If present, it indicates that the server is redirecting the
       
   132         request to a different URL. The Network Access API does not by
       
   133         default follow redirections: it's up to the application to
       
   134         determine if the requested redirection should be allowed,
       
   135         according to its security policies.
       
   136 
       
   137     \value ConnectionEncryptedAttribute
       
   138         Replies only, type: QVariant::Bool (default: false)
       
   139         Indicates whether the data was obtained through an encrypted
       
   140         (secure) connection.
       
   141 
       
   142     \value CacheLoadControlAttribute
       
   143         Requests only, type: QVariant::Int (default: QNetworkRequest::PreferNetwork)
       
   144         Controls how the cache should be accessed. The possible values
       
   145         are those of QNetworkRequest::CacheLoadControl. Note that the
       
   146         default QNetworkAccessManager implementation does not support
       
   147         caching. However, this attribute may be used by certain
       
   148         backends to modify their requests (for example, for caching proxies).
       
   149 
       
   150     \value CacheSaveControlAttribute
       
   151         Requests only, type: QVariant::Bool (default: true)
       
   152         Controls if the data obtained should be saved to cache for
       
   153         future uses. If the value is false, the data obtained will not
       
   154         be automatically cached. If true, data may be cached, provided
       
   155         it is cacheable (what is cacheable depends on the protocol
       
   156         being used).
       
   157 
       
   158     \value SourceIsFromCacheAttribute
       
   159         Replies only, type: QVariant::Bool (default: false)
       
   160         Indicates whether the data was obtained from cache
       
   161         or not.
       
   162 
       
   163     \value DoNotBufferUploadDataAttribute
       
   164         Requests only, type: QVariant::Bool (default: false)
       
   165         Indicates whether the QNetworkAccessManager code is
       
   166         allowed to buffer the upload data, e.g. when doing a HTTP POST.
       
   167         When using this flag with sequential upload data, the ContentLengthHeader
       
   168         header must be set.
       
   169 
       
   170      \value HttpPipeliningAllowedAttribute
       
   171         Requests only, type: QVariant::Bool (default: false)
       
   172         Indicates whether the QNetworkAccessManager code is
       
   173         allowed to use HTTP pipelining with this request.
       
   174 
       
   175      \value HttpPipeliningWasUsedAttribute
       
   176         Replies only, type: QVariant::Bool
       
   177         Indicates whether the HTTP pipelining was used for receiving
       
   178         this reply.
       
   179 
       
   180     \value User
       
   181         Special type. Additional information can be passed in
       
   182         QVariants with types ranging from User to UserMax. The default
       
   183         implementation of Network Access will ignore any request
       
   184         attributes in this range and it will not produce any
       
   185         attributes in this range in replies. The range is reserved for
       
   186         extensions of QNetworkAccessManager.
       
   187 
       
   188     \value UserMax
       
   189         Special type. See User.
       
   190 */
       
   191 
       
   192 /*!
       
   193     \enum QNetworkRequest::CacheLoadControl
       
   194 
       
   195     Controls the caching mechanism of QNetworkAccessManager.
       
   196 
       
   197     \value AlwaysNetwork        always load from network and do not
       
   198     check if the cache has a valid entry (similar to the
       
   199     "Reload" feature in browsers)
       
   200 
       
   201     \value PreferNetwork        default value; load from the network
       
   202     if the cached entry is older than the network entry
       
   203 
       
   204     \value PreferCache          load from cache if available,
       
   205     otherwise load from network. Note that this can return possibly
       
   206     stale (but not expired) items from cache.
       
   207 
       
   208     \value AlwaysCache          only load from cache, indicating error
       
   209     if the item was not cached (i.e., off-line mode)
       
   210 */
       
   211 
       
   212 class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate
       
   213 {
       
   214 public:
       
   215     inline QNetworkRequestPrivate()
       
   216 #ifndef QT_NO_OPENSSL
       
   217         : sslConfiguration(0)
       
   218 #endif
       
   219     { qRegisterMetaType<QNetworkRequest>(); }
       
   220     ~QNetworkRequestPrivate()
       
   221     {
       
   222 #ifndef QT_NO_OPENSSL
       
   223         delete sslConfiguration;
       
   224 #endif
       
   225     }
       
   226 
       
   227 
       
   228     QNetworkRequestPrivate(const QNetworkRequestPrivate &other)
       
   229         : QSharedData(other), QNetworkHeadersPrivate(other)
       
   230     {
       
   231         url = other.url;
       
   232 
       
   233 #ifndef QT_NO_OPENSSL
       
   234         sslConfiguration = 0;
       
   235         if (other.sslConfiguration)
       
   236             sslConfiguration = new QSslConfiguration(*other.sslConfiguration);
       
   237 #endif
       
   238     }
       
   239 
       
   240     inline bool operator==(const QNetworkRequestPrivate &other) const
       
   241     {
       
   242         return url == other.url &&
       
   243             rawHeaders == other.rawHeaders &&
       
   244             attributes == other.attributes;
       
   245         // don't compare cookedHeaders
       
   246     }
       
   247 
       
   248     QUrl url;
       
   249 #ifndef QT_NO_OPENSSL
       
   250     mutable QSslConfiguration *sslConfiguration;
       
   251 #endif
       
   252 };
       
   253 
       
   254 /*!
       
   255     Constructs a QNetworkRequest object with \a url as the URL to be
       
   256     requested.
       
   257 
       
   258     \sa url(), setUrl()
       
   259 */
       
   260 QNetworkRequest::QNetworkRequest(const QUrl &url)
       
   261     : d(new QNetworkRequestPrivate)
       
   262 {
       
   263     d->url = url;
       
   264 }
       
   265 
       
   266 /*!
       
   267     Creates a copy of \a other.
       
   268 */
       
   269 QNetworkRequest::QNetworkRequest(const QNetworkRequest &other)
       
   270     : d(other.d)
       
   271 {
       
   272 }
       
   273 
       
   274 /*!
       
   275     Disposes of the QNetworkRequest object.
       
   276 */
       
   277 QNetworkRequest::~QNetworkRequest()
       
   278 {
       
   279     // QSharedDataPointer auto deletes
       
   280     d = 0;
       
   281 }
       
   282 
       
   283 /*!
       
   284     Returns true if this object is the same as \a other (i.e., if they
       
   285     have the same URL, same headers and same meta-data settings).
       
   286 
       
   287     \sa operator!=()
       
   288 */
       
   289 bool QNetworkRequest::operator==(const QNetworkRequest &other) const
       
   290 {
       
   291     return d == other.d || *d == *other.d;
       
   292 }
       
   293 
       
   294 /*!
       
   295     \fn bool QNetworkRequest::operator!=(const QNetworkRequest &other) const
       
   296 
       
   297     Returns false if this object is not the same as \a other.
       
   298 
       
   299     \sa operator==()
       
   300 */
       
   301 
       
   302 /*!
       
   303     Creates a copy of \a other
       
   304 */
       
   305 QNetworkRequest &QNetworkRequest::operator=(const QNetworkRequest &other)
       
   306 {
       
   307     d = other.d;
       
   308     return *this;
       
   309 }
       
   310 
       
   311 /*!
       
   312     Returns the URL this network request is referring to.
       
   313 
       
   314     \sa setUrl()
       
   315 */
       
   316 QUrl QNetworkRequest::url() const
       
   317 {
       
   318     return d->url;
       
   319 }
       
   320 
       
   321 /*!
       
   322     Sets the URL this network request is referring to to be \a url.
       
   323 
       
   324     \sa url()
       
   325 */
       
   326 void QNetworkRequest::setUrl(const QUrl &url)
       
   327 {
       
   328     d->url = url;
       
   329 }
       
   330 
       
   331 /*!
       
   332     Returns the value of the known network header \a header if it is
       
   333     present in this request. If it is not present, returns QVariant()
       
   334     (i.e., an invalid variant).
       
   335 
       
   336     \sa KnownHeaders, rawHeader(), setHeader()
       
   337 */
       
   338 QVariant QNetworkRequest::header(KnownHeaders header) const
       
   339 {
       
   340     return d->cookedHeaders.value(header);
       
   341 }
       
   342 
       
   343 /*!
       
   344     Sets the value of the known header \a header to be \a value,
       
   345     overriding any previously set headers. This operation also sets
       
   346     the equivalent raw HTTP header.
       
   347 
       
   348     \sa KnownHeaders, setRawHeader(), header()
       
   349 */
       
   350 void QNetworkRequest::setHeader(KnownHeaders header, const QVariant &value)
       
   351 {
       
   352     d->setCookedHeader(header, value);
       
   353 }
       
   354 
       
   355 /*!
       
   356     Returns true if the raw header \a headerName is present in this
       
   357     network request.
       
   358 
       
   359     \sa rawHeader(), setRawHeader()
       
   360 */
       
   361 bool QNetworkRequest::hasRawHeader(const QByteArray &headerName) const
       
   362 {
       
   363     return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
       
   364 }
       
   365 
       
   366 /*!
       
   367     Returns the raw form of header \a headerName. If no such header is
       
   368     present, an empty QByteArray is returned, which may be
       
   369     indistinguishable from a header that is present but has no content
       
   370     (use hasRawHeader() to find out if the header exists or not).
       
   371 
       
   372     Raw headers can be set with setRawHeader() or with setHeader().
       
   373 
       
   374     \sa header(), setRawHeader()
       
   375 */
       
   376 QByteArray QNetworkRequest::rawHeader(const QByteArray &headerName) const
       
   377 {
       
   378     QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
       
   379         d->findRawHeader(headerName);
       
   380     if (it != d->rawHeaders.constEnd())
       
   381         return it->second;
       
   382     return QByteArray();
       
   383 }
       
   384 
       
   385 /*!
       
   386     Returns a list of all raw headers that are set in this network
       
   387     request. The list is in the order that the headers were set.
       
   388 
       
   389     \sa hasRawHeader(), rawHeader()
       
   390 */
       
   391 QList<QByteArray> QNetworkRequest::rawHeaderList() const
       
   392 {
       
   393     return d->rawHeadersKeys();
       
   394 }
       
   395 
       
   396 /*!
       
   397     Sets the header \a headerName to be of value \a headerValue. If \a
       
   398     headerName corresponds to a known header (see
       
   399     QNetworkRequest::KnownHeaders), the raw format will be parsed and
       
   400     the corresponding "cooked" header will be set as well.
       
   401 
       
   402     For example:
       
   403     \snippet doc/src/snippets/code/src_network_access_qnetworkrequest.cpp 0
       
   404 
       
   405     will also set the known header LastModifiedHeader to be the
       
   406     QDateTime object of the parsed date.
       
   407 
       
   408     Note: setting the same header twice overrides the previous
       
   409     setting. To accomplish the behaviour of multiple HTTP headers of
       
   410     the same name, you should concatenate the two values, separating
       
   411     them with a comma (",") and set one single raw header.
       
   412 
       
   413     \sa KnownHeaders, setHeader(), hasRawHeader(), rawHeader()
       
   414 */
       
   415 void QNetworkRequest::setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
       
   416 {
       
   417     d->setRawHeader(headerName, headerValue);
       
   418 }
       
   419 
       
   420 /*!
       
   421     Returns the attribute associated with the code \a code. If the
       
   422     attribute has not been set, it returns \a defaultValue.
       
   423 
       
   424     Note: this function does not apply the defaults listed in
       
   425     QNetworkRequest::Attribute.
       
   426 
       
   427     \sa setAttribute(), QNetworkRequest::Attribute
       
   428 */
       
   429 QVariant QNetworkRequest::attribute(Attribute code, const QVariant &defaultValue) const
       
   430 {
       
   431     return d->attributes.value(code, defaultValue);
       
   432 }
       
   433 
       
   434 /*!
       
   435     Sets the attribute associated with code \a code to be value \a
       
   436     value. If the attribute is already set, the previous value is
       
   437     discarded. In special, if \a value is an invalid QVariant, the
       
   438     attribute is unset.
       
   439 
       
   440     \sa attribute(), QNetworkRequest::Attribute
       
   441 */
       
   442 void QNetworkRequest::setAttribute(Attribute code, const QVariant &value)
       
   443 {
       
   444     if (value.isValid())
       
   445         d->attributes.insert(code, value);
       
   446     else
       
   447         d->attributes.remove(code);
       
   448 }
       
   449 
       
   450 #ifndef QT_NO_OPENSSL
       
   451 /*!
       
   452     Returns this network request's SSL configuration. By default, no
       
   453     SSL settings are specified.
       
   454 
       
   455     \sa setSslConfiguration()
       
   456 */
       
   457 QSslConfiguration QNetworkRequest::sslConfiguration() const
       
   458 {
       
   459     if (!d->sslConfiguration)
       
   460         d->sslConfiguration = new QSslConfiguration;
       
   461     return *d->sslConfiguration;
       
   462 }
       
   463 
       
   464 /*!
       
   465     Sets this network request's SSL configuration to be \a config. The
       
   466     settings that apply are the private key, the local certificate,
       
   467     the SSL protocol (SSLv2, SSLv3, TLSv1 where applicable) and the
       
   468     ciphers that the SSL backend is allowed to use.
       
   469 
       
   470     By default, no SSL configuration is set, which allows the backends
       
   471     to choose freely what configuration is best for them.
       
   472 
       
   473     \sa sslConfiguration(), QSslConfiguration::defaultConfiguration()
       
   474 */
       
   475 void QNetworkRequest::setSslConfiguration(const QSslConfiguration &config)
       
   476 {
       
   477     if (!d->sslConfiguration)
       
   478         d->sslConfiguration = new QSslConfiguration(config);
       
   479     else
       
   480         *d->sslConfiguration = config;
       
   481 }
       
   482 #endif
       
   483 
       
   484 /*!
       
   485     \since 4.6
       
   486 
       
   487     Allows setting a reference to the \a object initiating
       
   488     the request.
       
   489 
       
   490     For example QtWebKit sets the originating object to the
       
   491     QWebFrame that initiated the request.
       
   492 
       
   493     \sa originatingObject()
       
   494 */
       
   495 void QNetworkRequest::setOriginatingObject(QObject *object)
       
   496 {
       
   497     d->originatingObject = object;
       
   498 }
       
   499 
       
   500 /*!
       
   501     \since 4.6
       
   502 
       
   503     Returns a reference to the object that initiated this
       
   504     network request; returns 0 if not set or the object has
       
   505     been destroyed.
       
   506 
       
   507     \sa setOriginatingObject()
       
   508 */
       
   509 QObject *QNetworkRequest::originatingObject() const
       
   510 {
       
   511     return d->originatingObject.data();
       
   512 }
       
   513 
       
   514 static QByteArray headerName(QNetworkRequest::KnownHeaders header)
       
   515 {
       
   516     switch (header) {
       
   517     case QNetworkRequest::ContentTypeHeader:
       
   518         return "Content-Type";
       
   519 
       
   520     case QNetworkRequest::ContentLengthHeader:
       
   521         return "Content-Length";
       
   522 
       
   523     case QNetworkRequest::LocationHeader:
       
   524         return "Location";
       
   525 
       
   526     case QNetworkRequest::LastModifiedHeader:
       
   527         return "Last-Modified";
       
   528 
       
   529     case QNetworkRequest::CookieHeader:
       
   530         return "Cookie";
       
   531 
       
   532     case QNetworkRequest::SetCookieHeader:
       
   533         return "Set-Cookie";
       
   534 
       
   535     // no default:
       
   536     // if new values are added, this will generate a compiler warning
       
   537     }
       
   538 
       
   539     return QByteArray();
       
   540 }
       
   541 
       
   542 static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVariant &value)
       
   543 {
       
   544     switch (header) {
       
   545     case QNetworkRequest::ContentTypeHeader:
       
   546     case QNetworkRequest::ContentLengthHeader:
       
   547         return value.toByteArray();
       
   548 
       
   549     case QNetworkRequest::LocationHeader:
       
   550         switch (value.type()) {
       
   551         case QVariant::Url:
       
   552             return value.toUrl().toEncoded();
       
   553 
       
   554         default:
       
   555             return value.toByteArray();
       
   556         }
       
   557 
       
   558     case QNetworkRequest::LastModifiedHeader:
       
   559         switch (value.type()) {
       
   560         case QVariant::Date:
       
   561         case QVariant::DateTime:
       
   562             // generate RFC 1123/822 dates:
       
   563             return QNetworkHeadersPrivate::toHttpDate(value.toDateTime());
       
   564 
       
   565         default:
       
   566             return value.toByteArray();
       
   567         }
       
   568 
       
   569     case QNetworkRequest::CookieHeader: {
       
   570         QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
       
   571         if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
       
   572             cookies << qvariant_cast<QNetworkCookie>(value);
       
   573 
       
   574         QByteArray result;
       
   575         bool first = true;
       
   576         foreach (const QNetworkCookie &cookie, cookies) {
       
   577             if (!first)
       
   578                 result += "; ";
       
   579             first = false;
       
   580             result += cookie.toRawForm(QNetworkCookie::NameAndValueOnly);
       
   581         }
       
   582         return result;
       
   583     }
       
   584 
       
   585     case QNetworkRequest::SetCookieHeader: {
       
   586         QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
       
   587         if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
       
   588             cookies << qvariant_cast<QNetworkCookie>(value);
       
   589 
       
   590         QByteArray result;
       
   591         bool first = true;
       
   592         foreach (const QNetworkCookie &cookie, cookies) {
       
   593             if (!first)
       
   594                 result += ", ";
       
   595             first = false;
       
   596             result += cookie.toRawForm(QNetworkCookie::Full);
       
   597         }
       
   598         return result;
       
   599     }
       
   600     }
       
   601 
       
   602     return QByteArray();
       
   603 }
       
   604 
       
   605 static QNetworkRequest::KnownHeaders parseHeaderName(const QByteArray &headerName)
       
   606 {
       
   607     // headerName is not empty here
       
   608 
       
   609     QByteArray lower = headerName.toLower();
       
   610     switch (lower.at(0)) {
       
   611     case 'c':
       
   612         if (lower == "content-type")
       
   613             return QNetworkRequest::ContentTypeHeader;
       
   614         else if (lower == "content-length")
       
   615             return QNetworkRequest::ContentLengthHeader;
       
   616         else if (lower == "cookie")
       
   617             return QNetworkRequest::CookieHeader;
       
   618         break;
       
   619 
       
   620     case 'l':
       
   621         if (lower == "location")
       
   622             return QNetworkRequest::LocationHeader;
       
   623         else if (lower == "last-modified")
       
   624             return QNetworkRequest::LastModifiedHeader;
       
   625         break;
       
   626 
       
   627     case 's':
       
   628         if (lower == "set-cookie")
       
   629             return QNetworkRequest::SetCookieHeader;
       
   630         break;
       
   631     }
       
   632 
       
   633     return QNetworkRequest::KnownHeaders(-1); // nothing found
       
   634 }
       
   635 
       
   636 static QVariant parseHttpDate(const QByteArray &raw)
       
   637 {
       
   638     QDateTime dt = QNetworkHeadersPrivate::fromHttpDate(raw);
       
   639     if (dt.isValid())
       
   640         return dt;
       
   641     return QVariant();          // transform an invalid QDateTime into a null QVariant
       
   642 }
       
   643 
       
   644 static QVariant parseCookieHeader(const QByteArray &raw)
       
   645 {
       
   646     QList<QNetworkCookie> result;
       
   647     QList<QByteArray> cookieList = raw.split(';');
       
   648     foreach (QByteArray cookie, cookieList) {
       
   649         QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookie.trimmed());
       
   650         if (parsed.count() != 1)
       
   651             return QVariant();  // invalid Cookie: header
       
   652 
       
   653         result += parsed;
       
   654     }
       
   655 
       
   656     return qVariantFromValue(result);
       
   657 }
       
   658 
       
   659 static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QByteArray &value)
       
   660 {
       
   661     // header is always a valid value
       
   662     switch (header) {
       
   663     case QNetworkRequest::ContentTypeHeader:
       
   664         // copy exactly, convert to QString
       
   665         return QString::fromLatin1(value);
       
   666 
       
   667     case QNetworkRequest::ContentLengthHeader: {
       
   668         bool ok;
       
   669         qint64 result = value.trimmed().toLongLong(&ok);
       
   670         if (ok)
       
   671             return result;
       
   672         return QVariant();
       
   673     }
       
   674 
       
   675     case QNetworkRequest::LocationHeader: {
       
   676         QUrl result = QUrl::fromEncoded(value, QUrl::StrictMode);
       
   677         if (result.isValid() && !result.scheme().isEmpty())
       
   678             return result;
       
   679         return QVariant();
       
   680     }
       
   681 
       
   682     case QNetworkRequest::LastModifiedHeader:
       
   683         return parseHttpDate(value);
       
   684 
       
   685     case QNetworkRequest::CookieHeader:
       
   686         return parseCookieHeader(value);
       
   687 
       
   688     case QNetworkRequest::SetCookieHeader:
       
   689         return qVariantFromValue(QNetworkCookie::parseCookies(value));
       
   690 
       
   691     default:
       
   692         Q_ASSERT(0);
       
   693     }
       
   694     return QVariant();
       
   695 }
       
   696 
       
   697 QNetworkHeadersPrivate::RawHeadersList::ConstIterator
       
   698 QNetworkHeadersPrivate::findRawHeader(const QByteArray &key) const
       
   699 {
       
   700     QByteArray lowerKey = key.toLower();
       
   701     RawHeadersList::ConstIterator it = rawHeaders.constBegin();
       
   702     RawHeadersList::ConstIterator end = rawHeaders.constEnd();
       
   703     for ( ; it != end; ++it)
       
   704         if (it->first.toLower() == lowerKey)
       
   705             return it;
       
   706 
       
   707     return end;                 // not found
       
   708 }
       
   709 
       
   710 QList<QByteArray> QNetworkHeadersPrivate::rawHeadersKeys() const
       
   711 {
       
   712     QList<QByteArray> result;
       
   713     RawHeadersList::ConstIterator it = rawHeaders.constBegin(),
       
   714                                  end = rawHeaders.constEnd();
       
   715     for ( ; it != end; ++it)
       
   716         result << it->first;
       
   717 
       
   718     return result;
       
   719 }
       
   720 
       
   721 void QNetworkHeadersPrivate::setRawHeader(const QByteArray &key, const QByteArray &value)
       
   722 {
       
   723     if (key.isEmpty())
       
   724         // refuse to accept an empty raw header
       
   725         return;
       
   726 
       
   727     setRawHeaderInternal(key, value);
       
   728     parseAndSetHeader(key, value);
       
   729 }
       
   730 
       
   731 /*!
       
   732     \internal
       
   733     Sets the internal raw headers list to match \a list. The cooked headers
       
   734     will also be updated.
       
   735 
       
   736     If \a list contains duplicates, they will be stored, but only the first one
       
   737     is usually accessed.
       
   738 */
       
   739 void QNetworkHeadersPrivate::setAllRawHeaders(const RawHeadersList &list)
       
   740 {
       
   741     cookedHeaders.clear();
       
   742     rawHeaders = list;
       
   743 
       
   744     RawHeadersList::ConstIterator it = rawHeaders.constBegin();
       
   745     RawHeadersList::ConstIterator end = rawHeaders.constEnd();
       
   746     for ( ; it != end; ++it)
       
   747         parseAndSetHeader(it->first, it->second);
       
   748 }
       
   749 
       
   750 void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders header,
       
   751                                              const QVariant &value)
       
   752 {
       
   753     QByteArray name = headerName(header);
       
   754     if (name.isEmpty()) {
       
   755         // headerName verifies that \a header is a known value
       
   756         qWarning("QNetworkRequest::setHeader: invalid header value KnownHeader(%d) received", header);
       
   757         return;
       
   758     }
       
   759 
       
   760     if (value.isNull()) {
       
   761         setRawHeaderInternal(name, QByteArray());
       
   762         cookedHeaders.remove(header);
       
   763     } else {
       
   764         QByteArray rawValue = headerValue(header, value);
       
   765         if (rawValue.isEmpty()) {
       
   766             qWarning("QNetworkRequest::setHeader: QVariant of type %s cannot be used with header %s",
       
   767                      value.typeName(), name.constData());
       
   768             return;
       
   769         }
       
   770 
       
   771         setRawHeaderInternal(name, rawValue);
       
   772         cookedHeaders.insert(header, value);
       
   773     }
       
   774 }
       
   775 
       
   776 void QNetworkHeadersPrivate::setRawHeaderInternal(const QByteArray &key, const QByteArray &value)
       
   777 {
       
   778     QByteArray lowerKey = key.toLower();
       
   779     RawHeadersList::Iterator it = rawHeaders.begin();
       
   780     while (it != rawHeaders.end()) {
       
   781         if (it->first.toLower() == lowerKey)
       
   782             it = rawHeaders.erase(it);
       
   783         else
       
   784             ++it;
       
   785     }
       
   786 
       
   787     if (value.isNull())
       
   788         return;                 // only wanted to erase key
       
   789 
       
   790     RawHeaderPair pair;
       
   791     pair.first = key;
       
   792     pair.second = value;
       
   793     rawHeaders.append(pair);
       
   794 }
       
   795 
       
   796 void QNetworkHeadersPrivate::parseAndSetHeader(const QByteArray &key, const QByteArray &value)
       
   797 {
       
   798     // is it a known header?
       
   799     QNetworkRequest::KnownHeaders parsedKey = parseHeaderName(key);
       
   800     if (parsedKey != QNetworkRequest::KnownHeaders(-1)) {
       
   801         if (value.isNull())
       
   802             cookedHeaders.remove(parsedKey);
       
   803         else
       
   804             cookedHeaders.insert(parsedKey, parseHeaderValue(parsedKey, value));
       
   805     }
       
   806 }
       
   807 
       
   808 QDateTime QNetworkHeadersPrivate::fromHttpDate(const QByteArray &value)
       
   809 {
       
   810     // HTTP dates have three possible formats:
       
   811     //  RFC 1123/822      -   ddd, dd MMM yyyy hh:mm:ss "GMT"
       
   812     //  RFC 850           -   dddd, dd-MMM-yy hh:mm:ss "GMT"
       
   813     //  ANSI C's asctime  -   ddd MMM d hh:mm:ss yyyy
       
   814     // We only handle them exactly. If they deviate, we bail out.
       
   815 
       
   816     int pos = value.indexOf(',');
       
   817     QDateTime dt;
       
   818 #ifndef QT_NO_DATESTRING
       
   819     if (pos == -1) {
       
   820         // no comma -> asctime(3) format
       
   821         dt = QDateTime::fromString(QString::fromLatin1(value), Qt::TextDate);
       
   822     } else {
       
   823         // eat the weekday, the comma and the space following it
       
   824         QString sansWeekday = QString::fromLatin1(value.constData() + pos + 2);
       
   825 
       
   826         QLocale c = QLocale::c();
       
   827         if (pos == 3)
       
   828             // must be RFC 1123 date
       
   829             dt = c.toDateTime(sansWeekday, QLatin1String("dd MMM yyyy hh:mm:ss 'GMT"));
       
   830         else
       
   831             // must be RFC 850 date
       
   832             dt = c.toDateTime(sansWeekday, QLatin1String("dd-MMM-yy hh:mm:ss 'GMT'"));
       
   833     }
       
   834 #endif // QT_NO_DATESTRING
       
   835 
       
   836     if (dt.isValid())
       
   837         dt.setTimeSpec(Qt::UTC);
       
   838     return dt;
       
   839 }
       
   840 
       
   841 QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt)
       
   842 {
       
   843     return QLocale::c().toString(dt, QLatin1String("ddd, dd MMM yyyy hh:mm:ss 'GMT'"))
       
   844         .toLatin1();
       
   845 }
       
   846 
       
   847 QT_END_NAMESPACE