util/src/network/access/qnetworkaccessmanager.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 "qnetworkaccessmanager.h"
       
    43 #include "qnetworkaccessmanager_p.h"
       
    44 #include "qnetworkrequest.h"
       
    45 #include "qnetworkreply.h"
       
    46 #include "qnetworkreply_p.h"
       
    47 #include "qnetworkcookie.h"
       
    48 #include "qabstractnetworkcache.h"
       
    49 
       
    50 #include "qnetworkaccesshttpbackend_p.h"
       
    51 #include "qnetworkaccessftpbackend_p.h"
       
    52 #include "qnetworkaccessfilebackend_p.h"
       
    53 #include "qnetworkaccessdatabackend_p.h"
       
    54 #include "qnetworkaccessdebugpipebackend_p.h"
       
    55 #include "qfilenetworkreply_p.h"
       
    56 
       
    57 #include "QtCore/qbuffer.h"
       
    58 #include "QtCore/qurl.h"
       
    59 #include "QtCore/qvector.h"
       
    60 #include "QtNetwork/qauthenticator.h"
       
    61 #include "QtNetwork/qsslconfiguration.h"
       
    62 
       
    63 QT_BEGIN_NAMESPACE
       
    64 
       
    65 #ifndef QT_NO_HTTP
       
    66 Q_GLOBAL_STATIC(QNetworkAccessHttpBackendFactory, httpBackend)
       
    67 #endif // QT_NO_HTTP
       
    68 Q_GLOBAL_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
       
    69 Q_GLOBAL_STATIC(QNetworkAccessDataBackendFactory, dataBackend)
       
    70 #ifndef QT_NO_FTP
       
    71 Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
       
    72 #endif // QT_NO_FTP
       
    73 
       
    74 #ifdef QT_BUILD_INTERNAL
       
    75 Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
       
    76 #endif
       
    77 
       
    78 static void ensureInitialized()
       
    79 {
       
    80 #ifndef QT_NO_HTTP
       
    81     (void) httpBackend();
       
    82 #endif // QT_NO_HTTP
       
    83     (void) dataBackend();
       
    84 #ifndef QT_NO_FTP
       
    85     (void) ftpBackend();
       
    86 #endif
       
    87 
       
    88 #ifdef QT_BUILD_INTERNAL
       
    89     (void) debugpipeBackend();
       
    90 #endif
       
    91 
       
    92     // leave this one last since it will query the special QAbstractFileEngines
       
    93     (void) fileBackend();
       
    94 }
       
    95 
       
    96 /*!
       
    97     \class QNetworkAccessManager
       
    98     \brief The QNetworkAccessManager class allows the application to
       
    99     send network requests and receive replies
       
   100     \since 4.4
       
   101 
       
   102     \ingroup network
       
   103     \inmodule QtNetwork
       
   104     \reentrant
       
   105 
       
   106     The Network Access API is constructed around one QNetworkAccessManager
       
   107     object, which holds the common configuration and settings for the requests
       
   108     it sends. It contains the proxy and cache configuration, as well as the
       
   109     signals related to such issues, and reply signals that can be used to
       
   110     monitor the progress of a network operation. One QNetworkAccessManager
       
   111     should be enough for the whole Qt application.
       
   112 
       
   113     Once a QNetworkAccessManager object has been created, the application can
       
   114     use it to send requests over the network. A group of standard functions
       
   115     are supplied that take a request and optional data, and each return a
       
   116     QNetworkReply object. The returned object is used to obtain any data
       
   117     returned in response to the corresponding request.
       
   118 
       
   119     A simple download off the network could be accomplished with:
       
   120     \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 0
       
   121 
       
   122     QNetworkAccessManager has an asynchronous API.
       
   123     When the \tt replyFinished slot above is called, the parameter it
       
   124     takes is the QNetworkReply object containing the downloaded data
       
   125     as well as meta-data (headers, etc.).
       
   126 
       
   127     \note After the request has finished, it is the responsibility of the user
       
   128     to delete the QNetworkReply object at an appropriate time. Do not directly
       
   129     delete it inside the slot connected to finished(). You can use the
       
   130     deleteLater() function.
       
   131 
       
   132     \note QNetworkAccessManager queues the requests it receives. The number
       
   133     of requests executed in parallel is dependent on the protocol.
       
   134     Currently, for the HTTP protocol on desktop platforms, 6 requests are
       
   135     executed in parallel for one host/port combination.
       
   136 
       
   137     A more involved example, assuming the manager is already existent,
       
   138     can be:
       
   139     \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 1
       
   140 
       
   141     \sa QNetworkRequest, QNetworkReply, QNetworkProxy
       
   142 */
       
   143 
       
   144 /*!
       
   145     \enum QNetworkAccessManager::Operation
       
   146 
       
   147     Indicates the operation this reply is processing.
       
   148 
       
   149     \value HeadOperation        retrieve headers operation (created
       
   150     with head())
       
   151 
       
   152     \value GetOperation         retrieve headers and download contents
       
   153     (created with get())
       
   154 
       
   155     \value PutOperation         upload contents operation (created
       
   156     with put())
       
   157 
       
   158     \value PostOperation        send the contents of an HTML form for
       
   159     processing via HTTP POST (created with post())
       
   160 
       
   161     \value DeleteOperation      delete contents operation (created with
       
   162     deleteResource())
       
   163 
       
   164     \omitvalue UnknownOperation
       
   165 
       
   166     \sa QNetworkReply::operation()
       
   167 */
       
   168 
       
   169 /*!
       
   170     \fn void QNetworkAccessManager::proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator)
       
   171 
       
   172     This signal is emitted whenever a proxy requests authentication
       
   173     and QNetworkAccessManager cannot find a valid, cached
       
   174     credential. The slot connected to this signal should fill in the
       
   175     credentials for the proxy \a proxy in the \a authenticator object.
       
   176 
       
   177     QNetworkAccessManager will cache the credentials internally. The
       
   178     next time the proxy requests authentication, QNetworkAccessManager
       
   179     will automatically send the same credential without emitting the
       
   180     proxyAuthenticationRequired signal again.
       
   181 
       
   182     If the proxy rejects the credentials, QNetworkAccessManager will
       
   183     emit the signal again.
       
   184 
       
   185     \sa proxy(), setProxy(), authenticationRequired()
       
   186 */
       
   187 
       
   188 /*!
       
   189     \fn void QNetworkAccessManager::authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)
       
   190 
       
   191     This signal is emitted whenever a final server requests
       
   192     authentication before it delivers the requested contents. The slot
       
   193     connected to this signal should fill the credentials for the
       
   194     contents (which can be determined by inspecting the \a reply
       
   195     object) in the \a authenticator object.
       
   196 
       
   197     QNetworkAccessManager will cache the credentials internally and
       
   198     will send the same values if the server requires authentication
       
   199     again, without emitting the authenticationRequired() signal. If it
       
   200     rejects the credentials, this signal will be emitted again.
       
   201 
       
   202     \sa proxyAuthenticationRequired()
       
   203 */
       
   204 
       
   205 /*!
       
   206     \fn void QNetworkAccessManager::finished(QNetworkReply *reply)
       
   207 
       
   208     This signal is emitted whenever a pending network reply is
       
   209     finished. The \a reply parameter will contain a pointer to the
       
   210     reply that has just finished. This signal is emitted in tandem
       
   211     with the QNetworkReply::finished() signal.
       
   212 
       
   213     See QNetworkReply::finished() for information on the status that
       
   214     the object will be in.
       
   215 
       
   216     \note Do not delete the \a reply object in the slot connected to this
       
   217     signal. Use deleteLater().
       
   218 
       
   219     \sa QNetworkReply::finished(), QNetworkReply::error()
       
   220 */
       
   221 
       
   222 /*!
       
   223     \fn void QNetworkAccessManager::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
       
   224 
       
   225     This signal is emitted if the SSL/TLS session encountered errors
       
   226     during the set up, including certificate verification errors. The
       
   227     \a errors parameter contains the list of errors and \a reply is
       
   228     the QNetworkReply that is encountering these errors.
       
   229 
       
   230     To indicate that the errors are not fatal and that the connection
       
   231     should proceed, the QNetworkReply::ignoreSslErrors() function should be called
       
   232     from the slot connected to this signal. If it is not called, the
       
   233     SSL session will be torn down before any data is exchanged
       
   234     (including the URL).
       
   235 
       
   236     This signal can be used to display an error message to the user
       
   237     indicating that security may be compromised and display the
       
   238     SSL settings (see sslConfiguration() to obtain it). If the user
       
   239     decides to proceed after analyzing the remote certificate, the
       
   240     slot should call ignoreSslErrors().
       
   241 
       
   242     \sa QSslSocket::sslErrors(), QNetworkReply::sslErrors(),
       
   243     QNetworkReply::sslConfiguration(), QNetworkReply::ignoreSslErrors()
       
   244 */
       
   245 
       
   246 class QNetworkAuthenticationCredential
       
   247 {
       
   248 public:
       
   249     QString domain;
       
   250     QString user;
       
   251     QString password;
       
   252 };
       
   253 Q_DECLARE_TYPEINFO(QNetworkAuthenticationCredential, Q_MOVABLE_TYPE);
       
   254 inline bool operator<(const QNetworkAuthenticationCredential &t1, const QString &t2)
       
   255 { return t1.domain < t2; }
       
   256 
       
   257 class QNetworkAuthenticationCache: private QVector<QNetworkAuthenticationCredential>,
       
   258                                    public QNetworkAccessCache::CacheableObject
       
   259 {
       
   260 public:
       
   261     QNetworkAuthenticationCache()
       
   262     {
       
   263         setExpires(false);
       
   264         setShareable(true);
       
   265         reserve(1);
       
   266     }
       
   267 
       
   268     QNetworkAuthenticationCredential *findClosestMatch(const QString &domain)
       
   269     {
       
   270         iterator it = qLowerBound(begin(), end(), domain);
       
   271         if (it == end() && !isEmpty())
       
   272             --it;
       
   273         if (it == end() || !domain.startsWith(it->domain))
       
   274             return 0;
       
   275         return &*it;
       
   276     }
       
   277 
       
   278     void insert(const QString &domain, const QString &user, const QString &password)
       
   279     {
       
   280         QNetworkAuthenticationCredential *closestMatch = findClosestMatch(domain);
       
   281         if (closestMatch && closestMatch->domain == domain) {
       
   282             // we're overriding the current credentials
       
   283             closestMatch->user = user;
       
   284             closestMatch->password = password;
       
   285         } else {
       
   286             QNetworkAuthenticationCredential newCredential;
       
   287             newCredential.domain = domain;
       
   288             newCredential.user = user;
       
   289             newCredential.password = password;
       
   290 
       
   291             if (closestMatch)
       
   292                 QVector<QNetworkAuthenticationCredential>::insert(++closestMatch, newCredential);
       
   293             else
       
   294                 QVector<QNetworkAuthenticationCredential>::insert(end(), newCredential);
       
   295         }
       
   296     }
       
   297 
       
   298     virtual void dispose() { delete this; }
       
   299 };
       
   300 
       
   301 #ifndef QT_NO_NETWORKPROXY
       
   302 static QByteArray proxyAuthenticationKey(const QNetworkProxy &proxy, const QString &realm)
       
   303 {
       
   304     QUrl key;
       
   305 
       
   306     switch (proxy.type()) {
       
   307     case QNetworkProxy::Socks5Proxy:
       
   308         key.setScheme(QLatin1String("proxy-socks5"));
       
   309         break;
       
   310 
       
   311     case QNetworkProxy::HttpProxy:
       
   312     case QNetworkProxy::HttpCachingProxy:
       
   313         key.setScheme(QLatin1String("proxy-http"));
       
   314         break;
       
   315 
       
   316     case QNetworkProxy::FtpCachingProxy:
       
   317         key.setScheme(QLatin1String("proxy-ftp"));
       
   318         break;
       
   319 
       
   320     case QNetworkProxy::DefaultProxy:
       
   321     case QNetworkProxy::NoProxy:
       
   322         // shouldn't happen
       
   323         return QByteArray();
       
   324 
       
   325         // no default:
       
   326         // let there be errors if a new proxy type is added in the future
       
   327     }
       
   328 
       
   329     if (key.scheme().isEmpty())
       
   330         // proxy type not handled
       
   331         return QByteArray();
       
   332 
       
   333     key.setUserName(proxy.user());
       
   334     key.setHost(proxy.hostName());
       
   335     key.setPort(proxy.port());
       
   336     key.setFragment(realm);
       
   337     return "auth:" + key.toEncoded();
       
   338 }
       
   339 #endif
       
   340 
       
   341 static inline QByteArray authenticationKey(const QUrl &url, const QString &realm)
       
   342 {
       
   343     QUrl copy = url;
       
   344     copy.setFragment(realm);
       
   345     return "auth:" + copy.toEncoded(QUrl::RemovePassword | QUrl::RemovePath | QUrl::RemoveQuery);
       
   346 }
       
   347 
       
   348 /*!
       
   349     Constructs a QNetworkAccessManager object that is the center of
       
   350     the Network Access API and sets \a parent as the parent object.
       
   351 */
       
   352 QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
       
   353     : QObject(*new QNetworkAccessManagerPrivate, parent)
       
   354 {
       
   355     ensureInitialized();
       
   356 }
       
   357 
       
   358 /*!
       
   359     Destroys the QNetworkAccessManager object and frees up any
       
   360     resources. Note that QNetworkReply objects that are returned from
       
   361     this class have this object set as their parents, which means that
       
   362     they will be deleted along with it if you don't call
       
   363     QObject::setParent() on them.
       
   364 */
       
   365 QNetworkAccessManager::~QNetworkAccessManager()
       
   366 {
       
   367 #ifndef QT_NO_NETWORKPROXY
       
   368     delete d_func()->proxyFactory;
       
   369 #endif
       
   370 }
       
   371 
       
   372 #ifndef QT_NO_NETWORKPROXY
       
   373 /*!
       
   374     Returns the QNetworkProxy that the requests sent using this
       
   375     QNetworkAccessManager object will use. The default value for the
       
   376     proxy is QNetworkProxy::DefaultProxy.
       
   377 
       
   378     \sa setProxy(), setProxyFactory(), proxyAuthenticationRequired()
       
   379 */
       
   380 QNetworkProxy QNetworkAccessManager::proxy() const
       
   381 {
       
   382     return d_func()->proxy;
       
   383 }
       
   384 
       
   385 /*!
       
   386     Sets the proxy to be used in future requests to be \a proxy. This
       
   387     does not affect requests that have already been sent. The
       
   388     proxyAuthenticationRequired() signal will be emitted if the proxy
       
   389     requests authentication.
       
   390 
       
   391     A proxy set with this function will be used for all requests
       
   392     issued by QNetworkAccessManager. In some cases, it might be
       
   393     necessary to select different proxies depending on the type of
       
   394     request being sent or the destination host. If that's the case,
       
   395     you should consider using setProxyFactory().
       
   396 
       
   397     \sa proxy(), proxyAuthenticationRequired()
       
   398 */
       
   399 void QNetworkAccessManager::setProxy(const QNetworkProxy &proxy)
       
   400 {
       
   401     Q_D(QNetworkAccessManager);
       
   402     delete d->proxyFactory;
       
   403     d->proxy = proxy;
       
   404     d->proxyFactory = 0;
       
   405 }
       
   406 
       
   407 /*!
       
   408     \fn QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
       
   409     \since 4.5
       
   410 
       
   411     Returns the proxy factory that this QNetworkAccessManager object
       
   412     is using to determine the proxies to be used for requests.
       
   413 
       
   414     Note that the pointer returned by this function is managed by
       
   415     QNetworkAccessManager and could be deleted at any time.
       
   416 
       
   417     \sa setProxyFactory(), proxy()
       
   418 */
       
   419 QNetworkProxyFactory *QNetworkAccessManager::proxyFactory() const
       
   420 {
       
   421     return d_func()->proxyFactory;
       
   422 }
       
   423 
       
   424 /*!
       
   425     \since 4.5
       
   426 
       
   427     Sets the proxy factory for this class to be \a factory. A proxy
       
   428     factory is used to determine a more specific list of proxies to be
       
   429     used for a given request, instead of trying to use the same proxy
       
   430     value for all requests.
       
   431 
       
   432     All queries sent by QNetworkAccessManager will have type
       
   433     QNetworkProxyQuery::UrlRequest.
       
   434 
       
   435     For example, a proxy factory could apply the following rules:
       
   436     \list
       
   437       \o if the target address is in the local network (for example,
       
   438          if the hostname contains no dots or if it's an IP address in
       
   439          the organization's range), return QNetworkProxy::NoProxy
       
   440       \o if the request is FTP, return an FTP proxy
       
   441       \o if the request is HTTP or HTTPS, then return an HTTP proxy
       
   442       \o otherwise, return a SOCKSv5 proxy server
       
   443     \endlist
       
   444 
       
   445     The lifetime of the object \a factory will be managed by
       
   446     QNetworkAccessManager. It will delete the object when necessary.
       
   447 
       
   448     \note If a specific proxy is set with setProxy(), the factory will not
       
   449     be used.
       
   450 
       
   451     \sa proxyFactory(), setProxy(), QNetworkProxyQuery
       
   452 */
       
   453 void QNetworkAccessManager::setProxyFactory(QNetworkProxyFactory *factory)
       
   454 {
       
   455     Q_D(QNetworkAccessManager);
       
   456     delete d->proxyFactory;
       
   457     d->proxyFactory = factory;
       
   458     d->proxy = QNetworkProxy();
       
   459 }
       
   460 #endif
       
   461 
       
   462 /*!
       
   463     \since 4.5
       
   464 
       
   465     Returns the cache that is used to store data obtained from the network.
       
   466 
       
   467     \sa setCache()
       
   468 */
       
   469 QAbstractNetworkCache *QNetworkAccessManager::cache() const
       
   470 {
       
   471     Q_D(const QNetworkAccessManager);
       
   472     return d->networkCache;
       
   473 }
       
   474 
       
   475 /*!
       
   476     \since 4.5
       
   477 
       
   478     Sets the manager's network cache to be the \a cache specified. The cache
       
   479     is used for all requests dispatched by the manager.
       
   480 
       
   481     Use this function to set the network cache object to a class that implements
       
   482     additional features, like saving the cookies to permanent storage.
       
   483 
       
   484     \note QNetworkAccessManager takes ownership of the \a cache object.
       
   485 
       
   486     QNetworkAccessManager by default does not have a set cache.
       
   487     Qt provides a simple disk cache, QNetworkDiskCache, which can be used.
       
   488 
       
   489     \sa cache(), QNetworkRequest::CacheLoadControl
       
   490 */
       
   491 void QNetworkAccessManager::setCache(QAbstractNetworkCache *cache)
       
   492 {
       
   493     Q_D(QNetworkAccessManager);
       
   494     if (d->networkCache != cache) {
       
   495         delete d->networkCache;
       
   496         d->networkCache = cache;
       
   497         if (d->networkCache)
       
   498             d->networkCache->setParent(this);
       
   499     }
       
   500 }
       
   501 
       
   502 /*!
       
   503     Returns the QNetworkCookieJar that is used to store cookies
       
   504     obtained from the network as well as cookies that are about to be
       
   505     sent.
       
   506 
       
   507     \sa setCookieJar()
       
   508 */
       
   509 QNetworkCookieJar *QNetworkAccessManager::cookieJar() const
       
   510 {
       
   511     Q_D(const QNetworkAccessManager);
       
   512     if (!d->cookieJar)
       
   513         d->createCookieJar();
       
   514     return d->cookieJar;
       
   515 }
       
   516 
       
   517 /*!
       
   518     Sets the manager's cookie jar to be the \a cookieJar specified.
       
   519     The cookie jar is used by all requests dispatched by the manager.
       
   520 
       
   521     Use this function to set the cookie jar object to a class that
       
   522     implements additional features, like saving the cookies to permanent
       
   523     storage.
       
   524 
       
   525     \note QNetworkAccessManager takes ownership of the \a cookieJar object.
       
   526 
       
   527     QNetworkAccessManager will set the parent of the \a cookieJar
       
   528     passed to itself, so that the cookie jar is deleted when this
       
   529     object is deleted as well. If you want to share cookie jars
       
   530     between different QNetworkAccessManager objects, you may want to
       
   531     set the cookie jar's parent to 0 after calling this function.
       
   532 
       
   533     QNetworkAccessManager by default does not implement any cookie
       
   534     policy of its own: it accepts all cookies sent by the server, as
       
   535     long as they are well formed and meet the minimum security
       
   536     requirements (cookie domain matches the request's and cookie path
       
   537     matches the request's). In order to implement your own security
       
   538     policy, override the QNetworkCookieJar::cookiesForUrl() and
       
   539     QNetworkCookieJar::setCookiesFromUrl() virtual functions. Those
       
   540     functions are called by QNetworkAccessManager when it detects a
       
   541     new cookie.
       
   542 
       
   543     \sa cookieJar(), QNetworkCookieJar::cookiesForUrl(), QNetworkCookieJar::setCookiesFromUrl()
       
   544 */
       
   545 void QNetworkAccessManager::setCookieJar(QNetworkCookieJar *cookieJar)
       
   546 {
       
   547     Q_D(QNetworkAccessManager);
       
   548     d->cookieJarCreated = true;
       
   549     if (d->cookieJar != cookieJar) {
       
   550         if (d->cookieJar && d->cookieJar->parent() == this)
       
   551             delete d->cookieJar;
       
   552         d->cookieJar = cookieJar;
       
   553         d->cookieJar->setParent(this);
       
   554     }
       
   555 }
       
   556 
       
   557 /*!
       
   558     Posts a request to obtain the network headers for \a request
       
   559     and returns a new QNetworkReply object which will contain such headers.
       
   560 
       
   561     The function is named after the HTTP request associated (HEAD).
       
   562 */
       
   563 QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request)
       
   564 {
       
   565     return d_func()->postProcess(createRequest(QNetworkAccessManager::HeadOperation, request));
       
   566 }
       
   567 
       
   568 /*!
       
   569     Posts a request to obtain the contents of the target \a request
       
   570     and returns a new QNetworkReply object opened for reading which emits the 
       
   571     \l{QIODevice::readyRead()}{readyRead()} signal whenever new data 
       
   572     arrives.
       
   573 
       
   574     The contents as well as associated headers will be downloaded.
       
   575 
       
   576     \sa post(), put(), deleteResource()
       
   577 */
       
   578 QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
       
   579 {
       
   580     return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
       
   581 }
       
   582 
       
   583 /*!
       
   584     Sends an HTTP POST request to the destination specified by \a request
       
   585     and returns a new QNetworkReply object opened for reading that will 
       
   586     contain the reply sent by the server. The contents of  the \a data 
       
   587     device will be uploaded to the server.
       
   588 
       
   589     \a data must be open for reading and must remain valid until the 
       
   590     finished() signal is emitted for this reply.
       
   591 
       
   592     \note Sending a POST request on protocols other than HTTP and
       
   593     HTTPS is undefined and will probably fail.
       
   594 
       
   595     \sa get(), put(), deleteResource()
       
   596 */
       
   597 QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
       
   598 {
       
   599     return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation, request, data));
       
   600 }
       
   601 
       
   602 /*!
       
   603     \overload
       
   604 
       
   605     Sends the contents of the \a data byte array to the destination 
       
   606     specified by \a request.
       
   607 */
       
   608 QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data)
       
   609 {
       
   610     QBuffer *buffer = new QBuffer;
       
   611     buffer->setData(data);
       
   612     buffer->open(QIODevice::ReadOnly);
       
   613 
       
   614     QNetworkReply *reply = post(request, buffer);
       
   615     buffer->setParent(reply);
       
   616     return reply;
       
   617 }
       
   618 
       
   619 /*!
       
   620     Uploads the contents of \a data to the destination \a request and
       
   621     returnes a new QNetworkReply object that will be open for reply.
       
   622 
       
   623     \a data must be opened for reading when this function is called
       
   624     and must remain valid until the finished() signal is emitted for
       
   625     this reply.
       
   626 
       
   627     Whether anything will be available for reading from the returned
       
   628     object is protocol dependent. For HTTP, the server may send a 
       
   629     small HTML page indicating the upload was successful (or not). 
       
   630     Other protocols will probably have content in their replies.
       
   631 
       
   632     \note For HTTP, this request will send a PUT request, which most servers
       
   633     do not allow. Form upload mechanisms, including that of uploading
       
   634     files through HTML forms, use the POST mechanism.
       
   635 
       
   636     \sa get(), post()
       
   637 */
       
   638 QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)
       
   639 {
       
   640     return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, data));
       
   641 }
       
   642 
       
   643 /*!
       
   644     \overload
       
   645     Sends the contents of the \a data byte array to the destination 
       
   646     specified by \a request.
       
   647 */
       
   648 QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const QByteArray &data)
       
   649 {
       
   650     QBuffer *buffer = new QBuffer;
       
   651     buffer->setData(data);
       
   652     buffer->open(QIODevice::ReadOnly);
       
   653 
       
   654     QNetworkReply *reply = put(request, buffer);
       
   655     buffer->setParent(reply);
       
   656     return reply;
       
   657 }
       
   658 
       
   659 /*!
       
   660     \since 4.6
       
   661 
       
   662     Sends a request to delete the resource identified by the URL of \a request.
       
   663 
       
   664     \note This feature is currently available for HTTP only, performing an 
       
   665     HTTP DELETE request.
       
   666 
       
   667     \sa get(), post(), put()
       
   668 */
       
   669 QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request)
       
   670 {
       
   671     return d_func()->postProcess(createRequest(QNetworkAccessManager::DeleteOperation, request));
       
   672 }
       
   673 
       
   674 /*!
       
   675     Returns a new QNetworkReply object to handle the operation \a op
       
   676     and request \a req. The device \a outgoingData is always 0 for Get and
       
   677     Head requests, but is the value passed to post() and put() in
       
   678     those operations (the QByteArray variants will pass a QBuffer
       
   679     object).
       
   680 
       
   681     The default implementation calls QNetworkCookieJar::cookiesForUrl()
       
   682     on the cookie jar set with setCookieJar() to obtain the cookies to
       
   683     be sent to the remote server.
       
   684 
       
   685     The returned object must be in an open state.
       
   686 */
       
   687 QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
       
   688                                                     const QNetworkRequest &req,
       
   689                                                     QIODevice *outgoingData)
       
   690 {
       
   691     Q_D(QNetworkAccessManager);
       
   692 
       
   693     // fast path for GET on file:// URLs
       
   694     // Also if the scheme is empty we consider it a file.
       
   695     // The QNetworkAccessFileBackend will right now only be used
       
   696     // for PUT or qrc://
       
   697     if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation)
       
   698          && (req.url().scheme() == QLatin1String("file")
       
   699              || req.url().scheme().isEmpty())) {
       
   700         return new QFileNetworkReply(this, req, op);
       
   701     }
       
   702 
       
   703     QNetworkRequest request = req;
       
   704     if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
       
   705         outgoingData && !outgoingData->isSequential()) {
       
   706         // request has no Content-Length
       
   707         // but the data that is outgoing is random-access
       
   708         request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
       
   709     }
       
   710     if (d->cookieJar) {
       
   711         QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
       
   712         if (!cookies.isEmpty())
       
   713             request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
       
   714     }
       
   715 
       
   716     // first step: create the reply
       
   717     QUrl url = request.url();
       
   718     QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
       
   719     QNetworkReplyImplPrivate *priv = reply->d_func();
       
   720     priv->manager = this;
       
   721 
       
   722     // second step: fetch cached credentials
       
   723     QNetworkAuthenticationCredential *cred = d->fetchCachedCredentials(url);
       
   724     if (cred) {
       
   725         url.setUserName(cred->user);
       
   726         url.setPassword(cred->password);
       
   727         priv->urlForLastAuthentication = url;
       
   728     }
       
   729 
       
   730     // third step: find a backend
       
   731     priv->backend = d->findBackend(op, request);
       
   732 
       
   733 #ifndef QT_NO_NETWORKPROXY
       
   734     QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url()));
       
   735     priv->proxyList = proxyList;
       
   736 #endif
       
   737     if (priv->backend) {
       
   738         priv->backend->setParent(reply);
       
   739         priv->backend->reply = priv;
       
   740     }
       
   741     // fourth step: setup the reply
       
   742     priv->setup(op, request, outgoingData);
       
   743 
       
   744 #ifndef QT_NO_OPENSSL
       
   745     reply->setSslConfiguration(request.sslConfiguration());
       
   746 #endif
       
   747     return reply;
       
   748 }
       
   749 
       
   750 void QNetworkAccessManagerPrivate::_q_replyFinished()
       
   751 {
       
   752     Q_Q(QNetworkAccessManager);
       
   753     QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
       
   754     if (reply)
       
   755         emit q->finished(reply);
       
   756 }
       
   757 
       
   758 void QNetworkAccessManagerPrivate::_q_replySslErrors(const QList<QSslError> &errors)
       
   759 {
       
   760 #ifndef QT_NO_OPENSSL
       
   761     Q_Q(QNetworkAccessManager);
       
   762     QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
       
   763     if (reply)
       
   764         emit q->sslErrors(reply, errors);
       
   765 #else
       
   766     Q_UNUSED(errors);
       
   767 #endif
       
   768 }
       
   769 
       
   770 QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
       
   771 {
       
   772     Q_Q(QNetworkAccessManager);
       
   773     QNetworkReplyPrivate::setManager(reply, q);
       
   774     q->connect(reply, SIGNAL(finished()), SLOT(_q_replyFinished()));
       
   775 #ifndef QT_NO_OPENSSL
       
   776     /* In case we're compiled without SSL support, we don't have this signal and we need to
       
   777      * avoid getting a connection error. */
       
   778     q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
       
   779 #endif
       
   780 
       
   781     return reply;
       
   782 }
       
   783 
       
   784 void QNetworkAccessManagerPrivate::createCookieJar() const
       
   785 {
       
   786     if (!cookieJarCreated) {
       
   787         // keep the ugly hack in here
       
   788         QNetworkAccessManagerPrivate *that = const_cast<QNetworkAccessManagerPrivate *>(this);
       
   789         that->cookieJar = new QNetworkCookieJar(that->q_func());
       
   790         that->cookieJarCreated = true;
       
   791     }
       
   792 }
       
   793 
       
   794 void QNetworkAccessManagerPrivate::authenticationRequired(QNetworkAccessBackend *backend,
       
   795                                                           QAuthenticator *authenticator)
       
   796 {
       
   797     Q_Q(QNetworkAccessManager);
       
   798 
       
   799     // FIXME: Add support for domains (i.e., the leading path)
       
   800     QUrl url = backend->reply->url;
       
   801 
       
   802     // don't try the cache for the same URL twice in a row
       
   803     // being called twice for the same URL means the authentication failed
       
   804     if (url != backend->reply->urlForLastAuthentication) {
       
   805         QNetworkAuthenticationCredential *cred = fetchCachedCredentials(url, authenticator);
       
   806         if (cred) {
       
   807             authenticator->setUser(cred->user);
       
   808             authenticator->setPassword(cred->password);
       
   809             backend->reply->urlForLastAuthentication = url;
       
   810             return;
       
   811         }
       
   812     }
       
   813 
       
   814     backend->reply->urlForLastAuthentication = url;
       
   815     emit q->authenticationRequired(backend->reply->q_func(), authenticator);
       
   816     addCredentials(url, authenticator);
       
   817 }
       
   818 
       
   819 #ifndef QT_NO_NETWORKPROXY
       
   820 void QNetworkAccessManagerPrivate::proxyAuthenticationRequired(QNetworkAccessBackend *backend,
       
   821                                                                const QNetworkProxy &proxy,
       
   822                                                                QAuthenticator *authenticator)
       
   823 {
       
   824     Q_Q(QNetworkAccessManager);
       
   825     // ### FIXME Tracking of successful authentications
       
   826     // This code is a bit broken right now for SOCKS authentication
       
   827     // first request: proxyAuthenticationRequired gets emitted, credentials gets saved
       
   828     // second request: (proxy != backend->reply->lastProxyAuthentication) does not evaluate to true,
       
   829     //      proxyAuthenticationRequired gets emitted again
       
   830     // possible solution: some tracking inside the authenticator
       
   831     //      or a new function proxyAuthenticationSucceeded(true|false)
       
   832     if (proxy != backend->reply->lastProxyAuthentication) {
       
   833         QNetworkAuthenticationCredential *cred = fetchCachedCredentials(proxy);
       
   834         if (cred) {
       
   835             authenticator->setUser(cred->user);
       
   836             authenticator->setPassword(cred->password);
       
   837             return;
       
   838         }
       
   839     }
       
   840 
       
   841     backend->reply->lastProxyAuthentication = proxy;
       
   842     emit q->proxyAuthenticationRequired(proxy, authenticator);
       
   843     addCredentials(proxy, authenticator);
       
   844 }
       
   845 
       
   846 void QNetworkAccessManagerPrivate::addCredentials(const QNetworkProxy &p,
       
   847                                                   const QAuthenticator *authenticator)
       
   848 {
       
   849     Q_ASSERT(authenticator);
       
   850     Q_ASSERT(p.type() != QNetworkProxy::DefaultProxy);
       
   851     Q_ASSERT(p.type() != QNetworkProxy::NoProxy);
       
   852 
       
   853     QString realm = authenticator->realm();
       
   854     QNetworkProxy proxy = p;
       
   855     proxy.setUser(authenticator->user());
       
   856     // Set two credentials: one with the username and one without
       
   857     do {
       
   858         // Set two credentials actually: one with and one without the realm
       
   859         do {
       
   860             QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
       
   861             if (cacheKey.isEmpty())
       
   862                 return;             // should not happen
       
   863 
       
   864             QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
       
   865             auth->insert(QString(), authenticator->user(), authenticator->password());
       
   866             objectCache.addEntry(cacheKey, auth); // replace the existing one, if there's any
       
   867 
       
   868             if (realm.isEmpty()) {
       
   869                 break;
       
   870             } else {
       
   871                 realm.clear();
       
   872             }
       
   873         } while (true);
       
   874 
       
   875         if (proxy.user().isEmpty())
       
   876             break;
       
   877         else
       
   878             proxy.setUser(QString());
       
   879     } while (true);
       
   880 }
       
   881 
       
   882 QNetworkAuthenticationCredential *
       
   883 QNetworkAccessManagerPrivate::fetchCachedCredentials(const QNetworkProxy &p,
       
   884                                                      const QAuthenticator *authenticator)
       
   885 {
       
   886     QNetworkProxy proxy = p;
       
   887     if (proxy.type() == QNetworkProxy::DefaultProxy) {
       
   888         proxy = QNetworkProxy::applicationProxy();
       
   889     }
       
   890     if (!proxy.password().isEmpty())
       
   891         return 0;               // no need to set credentials if it already has them
       
   892 
       
   893     QString realm;
       
   894     if (authenticator)
       
   895         realm = authenticator->realm();
       
   896 
       
   897     QByteArray cacheKey = proxyAuthenticationKey(proxy, realm);
       
   898     if (cacheKey.isEmpty())
       
   899         return 0;
       
   900     if (!objectCache.hasEntry(cacheKey))
       
   901         return 0;
       
   902 
       
   903     QNetworkAuthenticationCache *auth =
       
   904         static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
       
   905     QNetworkAuthenticationCredential *cred = auth->findClosestMatch(QString());
       
   906     objectCache.releaseEntry(cacheKey);
       
   907 
       
   908     // proxy cache credentials always have exactly one item
       
   909     Q_ASSERT_X(cred, "QNetworkAccessManager",
       
   910                "Internal inconsistency: found a cache key for a proxy, but it's empty");
       
   911     return cred;
       
   912 }
       
   913 
       
   914 QList<QNetworkProxy> QNetworkAccessManagerPrivate::queryProxy(const QNetworkProxyQuery &query)
       
   915 {
       
   916     QList<QNetworkProxy> proxies;
       
   917     if (proxyFactory) {
       
   918         proxies = proxyFactory->queryProxy(query);
       
   919         if (proxies.isEmpty()) {
       
   920             qWarning("QNetworkAccessManager: factory %p has returned an empty result set",
       
   921                      proxyFactory);
       
   922             proxies << QNetworkProxy::NoProxy;
       
   923         }
       
   924     } else if (proxy.type() == QNetworkProxy::DefaultProxy) {
       
   925         // no proxy set, query the application
       
   926         return QNetworkProxyFactory::proxyForQuery(query);
       
   927     } else {
       
   928         proxies << proxy;
       
   929     }
       
   930 
       
   931     return proxies;
       
   932 }
       
   933 #endif
       
   934 
       
   935 void QNetworkAccessManagerPrivate::addCredentials(const QUrl &url,
       
   936                                                   const QAuthenticator *authenticator)
       
   937 {
       
   938     Q_ASSERT(authenticator);
       
   939     QString domain = QString::fromLatin1("/"); // FIXME: make QAuthenticator return the domain
       
   940     QString realm = authenticator->realm();
       
   941 
       
   942     // Set two credentials actually: one with and one without the username in the URL
       
   943     QUrl copy = url;
       
   944     copy.setUserName(authenticator->user());
       
   945     do {
       
   946         QByteArray cacheKey = authenticationKey(copy, realm);
       
   947         if (objectCache.hasEntry(cacheKey)) {
       
   948             QNetworkAuthenticationCache *auth =
       
   949                 static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
       
   950             auth->insert(domain, authenticator->user(), authenticator->password());
       
   951             objectCache.releaseEntry(cacheKey);
       
   952         } else {
       
   953             QNetworkAuthenticationCache *auth = new QNetworkAuthenticationCache;
       
   954             auth->insert(domain, authenticator->user(), authenticator->password());
       
   955             objectCache.addEntry(cacheKey, auth);
       
   956         }
       
   957 
       
   958         if (copy.userName().isEmpty()) {
       
   959             break;
       
   960         } else {
       
   961             copy.setUserName(QString());
       
   962         }
       
   963     } while (true);
       
   964 }
       
   965 
       
   966 /*!
       
   967     Fetch the credential data from the credential cache.
       
   968 
       
   969     If auth is 0 (as it is when called from createRequest()), this will try to
       
   970     look up with an empty realm. That fails in most cases for HTTP (because the
       
   971     realm is seldom empty for HTTP challenges). In any case, QHttpNetworkConnection
       
   972     never sends the credentials on the first attempt: it needs to find out what
       
   973     authentication methods the server supports.
       
   974 
       
   975     For FTP, realm is always empty.
       
   976 */
       
   977 QNetworkAuthenticationCredential *
       
   978 QNetworkAccessManagerPrivate::fetchCachedCredentials(const QUrl &url,
       
   979                                                      const QAuthenticator *authentication)
       
   980 {
       
   981     if (!url.password().isEmpty())
       
   982         return 0;               // no need to set credentials if it already has them
       
   983 
       
   984     QString realm;
       
   985     if (authentication)
       
   986         realm = authentication->realm();
       
   987 
       
   988     QByteArray cacheKey = authenticationKey(url, realm);
       
   989     if (!objectCache.hasEntry(cacheKey))
       
   990         return 0;
       
   991 
       
   992     QNetworkAuthenticationCache *auth =
       
   993         static_cast<QNetworkAuthenticationCache *>(objectCache.requestEntryNow(cacheKey));
       
   994     QNetworkAuthenticationCredential *cred = auth->findClosestMatch(url.path());
       
   995     objectCache.releaseEntry(cacheKey);
       
   996     return cred;
       
   997 }
       
   998 
       
   999 void QNetworkAccessManagerPrivate::clearCache(QNetworkAccessManager *manager)
       
  1000 {
       
  1001     manager->d_func()->objectCache.clear();
       
  1002 }
       
  1003 
       
  1004 QNetworkAccessManagerPrivate::~QNetworkAccessManagerPrivate()
       
  1005 {
       
  1006 }
       
  1007 
       
  1008 QT_END_NAMESPACE
       
  1009 
       
  1010 #include "moc_qnetworkaccessmanager.cpp"