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