Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

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

Location:
trunk
Files:
57 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/network/access/access.pri

    r561 r846  
    11# Qt network access module
    22
    3 HEADERS += access/qftp.h \
    4            access/qhttp.h \
    5            access/qhttpnetworkheader_p.h \
    6            access/qhttpnetworkrequest_p.h \
    7            access/qhttpnetworkreply_p.h \
    8            access/qhttpnetworkconnection_p.h \
    9            access/qhttpnetworkconnectionchannel_p.h \
    10            access/qfilenetworkreply_p.h \
    11            access/qnetworkaccessmanager.h \
    12            access/qnetworkaccessmanager_p.h \
    13            access/qnetworkaccesscache_p.h \
    14            access/qnetworkaccessbackend_p.h \
    15            access/qnetworkaccessdatabackend_p.h \
    16            access/qnetworkaccessdebugpipebackend_p.h \
    17            access/qnetworkaccesshttpbackend_p.h \
    18            access/qnetworkaccessfilebackend_p.h \
    19            access/qnetworkaccesscachebackend_p.h \
    20            access/qnetworkaccessftpbackend_p.h \
    21            access/qnetworkcookie.h \
    22            access/qnetworkcookie_p.h \
    23            access/qnetworkcookiejar.h \
    24            access/qnetworkcookiejar_p.h \
    25            access/qnetworkrequest.h \
    26            access/qnetworkrequest_p.h \
    27            access/qnetworkreply.h \
    28            access/qnetworkreply_p.h \
    29            access/qnetworkreplyimpl_p.h \
    30            access/qabstractnetworkcache_p.h \
    31            access/qabstractnetworkcache.h \
    32            access/qnetworkdiskcache_p.h \
    33            access/qnetworkdiskcache.h
     3HEADERS += \
     4    access/qftp.h \
     5    access/qhttp.h \
     6    access/qhttpnetworkheader_p.h \
     7    access/qhttpnetworkrequest_p.h \
     8    access/qhttpnetworkreply_p.h \
     9    access/qhttpnetworkconnection_p.h \
     10    access/qhttpnetworkconnectionchannel_p.h \
     11    access/qfilenetworkreply_p.h \
     12    access/qnetworkaccessmanager.h \
     13    access/qnetworkaccessmanager_p.h \
     14    access/qnetworkaccesscache_p.h \
     15    access/qnetworkaccessbackend_p.h \
     16    access/qnetworkaccessdatabackend_p.h \
     17    access/qnetworkaccessdebugpipebackend_p.h \
     18    access/qnetworkaccesshttpbackend_p.h \
     19    access/qnetworkaccessfilebackend_p.h \
     20    access/qnetworkaccesscachebackend_p.h \
     21    access/qnetworkaccessftpbackend_p.h \
     22    access/qnetworkcookie.h \
     23    access/qnetworkcookie_p.h \
     24    access/qnetworkcookiejar.h \
     25    access/qnetworkcookiejar_p.h \
     26    access/qnetworkcookiejartlds_p.h \
     27    access/qnetworkrequest.h \
     28    access/qnetworkrequest_p.h \
     29    access/qnetworkreply.h \
     30    access/qnetworkreply_p.h \
     31    access/qnetworkreplyimpl_p.h \
     32    access/qabstractnetworkcache_p.h \
     33    access/qabstractnetworkcache.h \
     34    access/qnetworkdiskcache_p.h \
     35    access/qnetworkdiskcache.h
    3436
    35 SOURCES += access/qftp.cpp \
    36            access/qhttp.cpp \
    37            access/qhttpnetworkheader.cpp \
    38            access/qhttpnetworkrequest.cpp \
    39            access/qhttpnetworkreply.cpp \
    40            access/qhttpnetworkconnection.cpp \
    41            access/qhttpnetworkconnectionchannel.cpp \
    42            access/qfilenetworkreply.cpp \
    43            access/qnetworkaccessmanager.cpp \
    44            access/qnetworkaccesscache.cpp \
    45            access/qnetworkaccessbackend.cpp \
    46            access/qnetworkaccessdatabackend.cpp \
    47            access/qnetworkaccessdebugpipebackend.cpp \
    48            access/qnetworkaccessfilebackend.cpp \
    49            access/qnetworkaccesscachebackend.cpp \
    50            access/qnetworkaccessftpbackend.cpp \
    51            access/qnetworkaccesshttpbackend.cpp \
    52            access/qnetworkcookie.cpp \
    53            access/qnetworkcookiejar.cpp \
    54            access/qnetworkrequest.cpp \
    55            access/qnetworkreply.cpp \
    56            access/qnetworkreplyimpl.cpp \
    57            access/qabstractnetworkcache.cpp \
    58            access/qnetworkdiskcache.cpp
     37SOURCES += \
     38    access/qftp.cpp \
     39    access/qhttp.cpp \
     40    access/qhttpnetworkheader.cpp \
     41    access/qhttpnetworkrequest.cpp \
     42    access/qhttpnetworkreply.cpp \
     43    access/qhttpnetworkconnection.cpp \
     44    access/qhttpnetworkconnectionchannel.cpp \
     45    access/qfilenetworkreply.cpp \
     46    access/qnetworkaccessmanager.cpp \
     47    access/qnetworkaccesscache.cpp \
     48    access/qnetworkaccessbackend.cpp \
     49    access/qnetworkaccessdatabackend.cpp \
     50    access/qnetworkaccessdebugpipebackend.cpp \
     51    access/qnetworkaccessfilebackend.cpp \
     52    access/qnetworkaccesscachebackend.cpp \
     53    access/qnetworkaccessftpbackend.cpp \
     54    access/qnetworkaccesshttpbackend.cpp \
     55    access/qnetworkcookie.cpp \
     56    access/qnetworkcookiejar.cpp \
     57    access/qnetworkrequest.cpp \
     58    access/qnetworkreply.cpp \
     59    access/qnetworkreplyimpl.cpp \
     60    access/qabstractnetworkcache.cpp \
     61    access/qnetworkdiskcache.cpp
    5962
    60 #zlib support
    61 contains(QT_CONFIG, zlib) {
    62    INCLUDEPATH += ../3rdparty/zlib
    63 } else:!contains(QT_CONFIG, no-zlib) {
    64    unix:LIBS_PRIVATE += -lz
    65 #  win32:LIBS += libz.lib
    66 }
     63include($$PWD/../../3rdparty/zlib_dependency.pri)
  • trunk/src/network/access/qabstractnetworkcache.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    313313    Writes \a metaData to the \a out stream.
    314314
    315     \sa {Format of the QDataStream operators}
     315    \sa {Serializing Qt Data Types}
    316316*/
    317317QDataStream &operator<<(QDataStream &out, const QNetworkCacheMetaData &metaData)
     
    351351    Reads a QNetworkCacheMetaData from the stream \a in into \a metaData.
    352352
    353     \sa {Format of the QDataStream operators}
     353    \sa {Serializing Qt Data Types}
    354354*/
    355355QDataStream &operator>>(QDataStream &in, QNetworkCacheMetaData &metaData)
  • trunk/src/network/access/qabstractnetworkcache.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qabstractnetworkcache_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qfilenetworkreply.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    9898    QString fileName = url.toLocalFile();
    9999    if (fileName.isEmpty()) {
    100         fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
     100        if (url.scheme() == QLatin1String("qrc"))
     101            fileName = QLatin1Char(':') + url.path();
     102        else
     103            fileName = url.toString(QUrl::RemoveAuthority | QUrl::RemoveFragment | QUrl::RemoveQuery);
    101104    }
    102105
  • trunk/src/network/access/qfilenetworkreply_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qftp.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    23122312
    23132313    if (pending.isEmpty()) {
    2314         qWarning() << "QFtpPrivate::_q_piError was called without pending command!";
     2314        qWarning("QFtpPrivate::_q_piError was called without pending command!");
    23152315        return;
    23162316    }
  • trunk/src/network/access/qftp.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qhttp.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    24432443            proxy.setType(QNetworkProxy::NoProxy);
    24442444        } else if (sslInUse) {
    2445             // Disallow use of cacheing proxy with HTTPS; instead fall back to
     2445            // Disallow use of caching proxy with HTTPS; instead fall back to
    24462446            // transparent HTTP CONNECT proxying.
    24472447            transparentProxyInUse = true;
  • trunk/src/network/access/qhttp.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qhttpnetworkconnection.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4040****************************************************************************/
    4141
     42#include <private/qabstractsocket_p.h>
    4243#include "qhttpnetworkconnection_p.h"
    4344#include "qhttpnetworkconnectionchannel_p.h"
     
    5758
    5859#ifndef QT_NO_OPENSSL
     60#    include <private/qsslsocket_p.h>
    5961#    include <QtNetwork/qsslkey.h>
    6062#    include <QtNetwork/qsslcipher.h>
     
    8082
    8183QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt)
    82 : hostName(hostName), port(port), encrypt(encrypt),
    83   channelCount(defaultChannelCount),
    84   pendingAuthSignal(false), pendingProxyAuthSignal(false)
     84: state(RunningState),
     85  hostName(hostName), port(port), encrypt(encrypt),
     86  channelCount(defaultChannelCount)
    8587#ifndef QT_NO_NETWORKPROXY
    8688  , networkProxy(QNetworkProxy::NoProxy)
     
    9193
    9294QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, quint16 port, bool encrypt)
    93 : hostName(hostName), port(port), encrypt(encrypt),
    94   channelCount(channelCount),
    95   pendingAuthSignal(false), pendingProxyAuthSignal(false)
     95: state(RunningState),
     96  hostName(hostName), port(port), encrypt(encrypt),
     97  channelCount(channelCount)
    9698#ifndef QT_NO_NETWORKPROXY
    9799  , networkProxy(QNetworkProxy::NoProxy)
     
    120122        channels[i].init();
    121123    }
     124}
     125
     126void QHttpNetworkConnectionPrivate::pauseConnection()
     127{
     128    state = PausedState;
     129
     130    // Disable all socket notifiers
     131    for (int i = 0; i < channelCount; i++) {
     132#ifndef QT_NO_OPENSSL
     133        if (encrypt)
     134            QSslSocketPrivate::pauseSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
     135        else
     136#endif
     137            QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket);
     138    }
     139}
     140
     141void QHttpNetworkConnectionPrivate::resumeConnection()
     142{
     143    state = RunningState;
     144    // Enable all socket notifiers
     145    for (int i = 0; i < channelCount; i++) {
     146#ifndef QT_NO_OPENSSL
     147        if (encrypt)
     148            QSslSocketPrivate::resumeSocketNotifiers(static_cast<QSslSocket*>(channels[i].socket));
     149        else
     150#endif
     151            QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket);
     152
     153        // Resume pending upload if needed
     154        if (channels[i].state == QHttpNetworkConnectionChannel::WritingState)
     155            QMetaObject::invokeMethod(&channels[i], "_q_uploadDataReadyRead", Qt::QueuedConnection);
     156    }
     157
     158    // queue _q_startNextRequest
     159    QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
    122160}
    123161
     
    258296    Q_ASSERT(auth);
    259297
     298    // NTLM is a multi phase authentication. Copying credentials between authenticators would mess things up.
     299    if (!isProxy && channels[fromChannel].authMethod == QAuthenticatorPrivate::Ntlm)
     300        return;
     301    if (isProxy && channels[fromChannel].proxyAuthMethod == QAuthenticatorPrivate::Ntlm)
     302        return;
     303
     304
    260305    // select another channel
    261306    QAuthenticator* otherAuth = 0;
     
    283328    Q_ASSERT(reply);
    284329
    285     Q_Q(QHttpNetworkConnection);
    286 
    287330    resend = false;
    288331    //create the response header to be used with QAuthenticatorPrivate.
    289     QHttpResponseHeader responseHeader;
    290332    QList<QPair<QByteArray, QByteArray> > fields = reply->header();
    291     QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
    292     while (it != fields.constEnd()) {
    293         responseHeader.addValue(QString::fromLatin1(it->first), QString::fromUtf8(it->second));
    294         it++;
    295     }
     333
    296334    //find out the type of authentication protocol requested.
    297335    QAuthenticatorPrivate::Method authMethod = reply->d_func()->authenticationMethod(isProxy);
     
    302340        if (isProxy) {
    303341            auth = &channels[i].proxyAuthenticator;
    304             channels[i].proxyAuthMehtod = authMethod;
     342            channels[i].proxyAuthMethod = authMethod;
    305343        } else {
    306344            auth = &channels[i].authenticator;
    307             channels[i].authMehtod = authMethod;
     345            channels[i].authMethod = authMethod;
    308346        }
    309347        //proceed with the authentication.
     
    311349            auth->detach();
    312350        QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*auth);
    313         priv->parseHttpResponse(responseHeader, isProxy);
     351        priv->parseHttpResponse(fields, isProxy);
    314352
    315353        if (priv->phase == QAuthenticatorPrivate::Done) {
    316             if ((isProxy && pendingProxyAuthSignal) ||(!isProxy && pendingAuthSignal)) {
    317                 // drop the request
    318                 reply->d_func()->eraseData();
    319                 channels[i].close();
    320                 channels[i].lastStatus = 0;
    321                 channels[i].state =  QHttpNetworkConnectionChannel::Wait4AuthState;
    322                 return false;
    323             }
    324             // cannot use this socket until the slot returns
    325             channels[i].state = QHttpNetworkConnectionChannel::WaitingState;
    326             socket->blockSignals(true);
     354            pauseConnection();
    327355            if (!isProxy) {
    328                 pendingAuthSignal = true;
    329                 emit q->authenticationRequired(reply->request(), auth, q);
    330                 pendingAuthSignal = false;
     356                emit reply->authenticationRequired(reply->request(), auth);
    331357#ifndef QT_NO_NETWORKPROXY
    332358            } else {
    333                 pendingProxyAuthSignal = true;
    334                 emit q->proxyAuthenticationRequired(networkProxy, auth, q);
    335                 pendingProxyAuthSignal = false;
     359                emit reply->proxyAuthenticationRequired(networkProxy, auth);
    336360#endif
    337361            }
    338             socket->blockSignals(false);
    339             // socket free to use
    340             channels[i].state = QHttpNetworkConnectionChannel::IdleState;
     362            resumeConnection();
     363
    341364            if (priv->phase != QAuthenticatorPrivate::Done) {
    342365                // send any pending requests
    343366                copyCredentials(i,  auth, isProxy);
    344                 QMetaObject::invokeMethod(q, "_q_restartAuthPendingRequests", Qt::QueuedConnection);
    345367            }
    346368        }
    347         // changing values in QAuthenticator will reset the 'phase'
    348         if (priv->phase == QAuthenticatorPrivate::Done) {
     369        // - Changing values in QAuthenticator will reset the 'phase'. Therefore if it is still "Done"
     370        //   then nothing was filled in by the user or the cache
     371        // - If withCredentials has been set to false (e.g. by QtWebKit for a cross-origin XMLHttpRequest) then
     372        //   we need to bail out if authentication is required.
     373        if (priv->phase == QAuthenticatorPrivate::Done || !reply->request().withCredentials()) {
     374            // Reset authenticator so the next request on that channel does not get messed up
     375            auth = 0;
     376            if (isProxy)
     377                channels[i].proxyAuthenticator = QAuthenticator();
     378            else
     379                channels[i].authenticator = QAuthenticator();
     380
    349381            // authentication is cancelled, send the current contents to the user.
    350382            emit channels[i].reply->headerChanged();
     
    355387                : QNetworkReply::AuthenticationRequiredError;
    356388            reply->d_func()->errorString = errorDetail(errorCode, socket);
    357             emit q->error(errorCode, reply->d_func()->errorString);
    358             emit channels[i].reply->finished();
     389            emit reply->finishedWithError(errorCode, reply->d_func()->errorString);
    359390            // ### at this point the reply could be deleted
    360391            socket->close();
    361             // remove pending request on the other channels
    362             for (int j = 0; j < channelCount; ++j) {
    363                 if (j != i && channels[j].state ==  QHttpNetworkConnectionChannel::Wait4AuthState)
    364                     channels[j].state = QHttpNetworkConnectionChannel::IdleState;
    365             }
    366392            return true;
    367393        }
     
    379405    int i = indexOf(socket);
    380406
    381     if (channels[i].authMehtod != QAuthenticatorPrivate::None) {
    382         if (!(channels[i].authMehtod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 401)) {
     407    // Send "Authorization" header, but not if it's NTLM and the socket is already authenticated.
     408    if (channels[i].authMethod != QAuthenticatorPrivate::None) {
     409        if (!(channels[i].authMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 401)) {
    383410            QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].authenticator);
    384411            if (priv && priv->method != QAuthenticatorPrivate::None) {
     
    388415        }
    389416    }
    390     if (channels[i].proxyAuthMehtod != QAuthenticatorPrivate::None) {
    391         if (!(channels[i].proxyAuthMehtod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) {
     417
     418    // Send "Proxy-Authorization" header, but not if it's NTLM and the socket is already authenticated.
     419    if (channels[i].proxyAuthMethod != QAuthenticatorPrivate::None) {
     420        if (!(channels[i].proxyAuthMethod == QAuthenticatorPrivate::Ntlm && channels[i].lastStatus != 407)) {
    392421            QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(channels[i].proxyAuthenticator);
    393422            if (priv && priv->method != QAuthenticatorPrivate::None) {
     
    652681        if (channels[i].reply == reply) {
    653682            channels[i].reply = 0;
     683            channels[i].request = QHttpNetworkRequest();
     684            channels[i].resendCurrent = false;
    654685
    655686            if (!reply->isFinished() && !channels[i].alreadyPipelinedRequests.isEmpty()) {
     
    720751void QHttpNetworkConnectionPrivate::_q_startNextRequest()
    721752{
     753    // If the QHttpNetworkConnection is currently paused then bail out immediately
     754    if (state == PausedState)
     755        return;
     756
    722757    //resend the necessary ones.
    723758    for (int i = 0; i < channelCount; ++i) {
     
    740775    // try to get a free AND connected socket
    741776    for (int i = 0; i < channelCount; ++i) {
    742         if (!channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
     777        if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) {
    743778            dequeueAndSendRequest(channels[i].socket);
    744779        }
     
    750785    // try to get a free unconnected socket
    751786    for (int i = 0; i < channelCount; ++i) {
    752         if (!channels[i].isSocketBusy()) {
     787        if (!channels[i].reply && !channels[i].isSocketBusy()) {
    753788            dequeueAndSendRequest(channels[i].socket);
    754789        }
     
    770805}
    771806
    772 void QHttpNetworkConnectionPrivate::_q_restartAuthPendingRequests()
    773 {
    774     // send the request using the idle socket
    775     for (int i = 0 ; i < channelCount; ++i) {
    776         if (channels[i].state ==  QHttpNetworkConnectionChannel::Wait4AuthState) {
    777             channels[i].state = QHttpNetworkConnectionChannel::IdleState;
    778             if (channels[i].reply)
    779                 channels[i].sendRequest();
    780         }
    781     }
    782 }
    783807
    784808void QHttpNetworkConnectionPrivate::readMoreLater(QHttpNetworkReply *reply)
     
    829853}
    830854
    831 void QHttpNetworkConnection::enableEncryption()
    832 {
    833     Q_D(QHttpNetworkConnection);
    834     d->encrypt = true;
    835 }
    836 
    837 bool QHttpNetworkConnection::isEncrypted() const
     855bool QHttpNetworkConnection::isSsl() const
    838856{
    839857    Q_D(const QHttpNetworkConnection);
     
    841859}
    842860
    843 void QHttpNetworkConnection::setProxyAuthentication(QAuthenticator *authenticator)
    844 {
    845     Q_D(QHttpNetworkConnection);
    846     for (int i = 0; i < d->channelCount; ++i)
    847         d->channels[i].proxyAuthenticator = *authenticator;
    848 }
    849 
    850 void QHttpNetworkConnection::setAuthentication(const QString &domain, QAuthenticator *authenticator)
    851 {
    852     Q_UNUSED(domain); // ### domain ?
    853     Q_D(QHttpNetworkConnection);
    854     for (int i = 0; i < d->channelCount; ++i)
    855         d->channels[i].authenticator = *authenticator;
     861QHttpNetworkConnectionChannel *QHttpNetworkConnection::channels() const
     862{
     863    return d_func()->channels;
    856864}
    857865
     
    948956void QHttpNetworkConnectionPrivate::emitProxyAuthenticationRequired(const QHttpNetworkConnectionChannel *chan, const QNetworkProxy &proxy, QAuthenticator* auth)
    949957{
    950     Q_Q(QHttpNetworkConnection);
    951     emit q->proxyAuthenticationRequired(proxy, auth, q);
     958    // Also pause the connection because socket notifiers may fire while an user
     959    // dialog is displaying
     960    pauseConnection();
     961    emit chan->reply->proxyAuthenticationRequired(proxy, auth);
     962    resumeConnection();
    952963    int i = indexOf(chan->socket);
    953964    copyCredentials(i, auth, true);
  • trunk/src/network/access/qhttpnetworkconnection_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    109109#endif
    110110
    111     //enable encryption
    112     void enableEncryption();
    113     bool isEncrypted() const;
    114 
    115     //authentication parameters
    116     void setProxyAuthentication(QAuthenticator *authenticator);
    117     void setAuthentication(const QString &domain, QAuthenticator *authenticator);
     111    bool isSsl() const;
     112
     113    QHttpNetworkConnectionChannel *channels() const;
    118114
    119115#ifndef QT_NO_OPENSSL
     
    121117    void ignoreSslErrors(int channel = -1);
    122118    void ignoreSslErrors(const QList<QSslError> &errors, int channel = -1);
    123 
    124 Q_SIGNALS:
    125     void sslErrors(const QList<QSslError> &errors);
    126 #endif
    127 
    128 Q_SIGNALS:
    129 #ifndef QT_NO_NETWORKPROXY
    130     //cannot be used with queued connection.
    131     void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator,
    132                                      const QHttpNetworkConnection *connection = 0);
    133 #endif
    134     void authenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *authenticator,
    135                                 const QHttpNetworkConnection *connection = 0);
    136     void error(QNetworkReply::NetworkError errorCode, const QString &detail = QString());
     119#endif
    137120
    138121private:
     
    140123    Q_DISABLE_COPY(QHttpNetworkConnection)
    141124    friend class QHttpNetworkReply;
     125    friend class QHttpNetworkReplyPrivate;
    142126    friend class QHttpNetworkConnectionChannel;
    143127
    144128    Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest())
    145     Q_PRIVATE_SLOT(d_func(), void _q_restartAuthPendingRequests())
    146129};
    147130
     
    159142    static const int defaultRePipelineLength;
    160143
     144    enum ConnectionState {
     145        RunningState = 0,
     146        PausedState = 1,
     147    };
     148
    161149    QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt);
    162150    QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, quint16 port, bool encrypt);
     
    164152    void init();
    165153
     154    void pauseConnection();
     155    void resumeConnection();
     156    ConnectionState state;
     157
    166158    enum { ChunkSize = 4096 };
    167159
     
    183175    // private slots
    184176    void _q_startNextRequest(); // send the next request from the queue
    185     void _q_restartAuthPendingRequests(); // send the currently blocked request
    186177
    187178    void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request);
     
    202193    QHttpNetworkConnectionChannel *channels; // parallel connections to the server
    203194
    204     bool pendingAuthSignal; // there is an incomplete authentication signal
    205     bool pendingProxyAuthSignal; // there is an incomplete proxy authentication signal
    206 
    207195    qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const;
    208196    qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const;
  • trunk/src/network/access/qhttpnetworkconnectionchannel.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6969    , pendingEncrypt(false)
    7070    , reconnectAttempts(2)
    71     , authMehtod(QAuthenticatorPrivate::None)
    72     , proxyAuthMehtod(QAuthenticatorPrivate::None)
     71    , authMethod(QAuthenticatorPrivate::None)
     72    , proxyAuthMethod(QAuthenticatorPrivate::None)
    7373#ifndef QT_NO_OPENSSL
    7474    , ignoreAllSslErrors(false)
     
    106106                     this, SLOT(_q_readyRead()),
    107107                     Qt::DirectConnection);
     108
     109    // The disconnected() and error() signals may already come
     110    // while calling connectToHost().
     111    // In case of a cached hostname or an IP this
     112    // will then emit a signal to the user of QNetworkReply
     113    // but cannot be caught because the user did not have a chance yet
     114    // to connect to QNetworkReply's signals.
     115    qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError");
    108116    QObject::connect(socket, SIGNAL(disconnected()),
    109117                     this, SLOT(_q_disconnected()),
    110                      Qt::DirectConnection);
     118                     Qt::QueuedConnection);
    111119    QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
    112120                     this, SLOT(_q_error(QAbstractSocket::SocketError)),
    113                      Qt::DirectConnection);
     121                     Qt::QueuedConnection);
     122
     123
    114124#ifndef QT_NO_NETWORKPROXY
    115125    QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
     
    171181        reply->d_func()->pipeliningUsed = false;
    172182
    173         pendingEncrypt = false;
    174183        // if the url contains authentication parameters, use the new ones
    175184        // both channels will use the new authentication parameters
    176         if (!request.url().userInfo().isEmpty()) {
     185        if (!request.url().userInfo().isEmpty() && request.withCredentials()) {
    177186            QUrl url = request.url();
    178187            QAuthenticator &auth = authenticator;
     
    181190                auth.setUser(url.userName());
    182191                auth.setPassword(url.password());
     192                emit reply->cacheCredentials(request, &auth);
    183193                connection->d_func()->copyCredentials(connection->d_func()->indexOf(socket), &auth, false);
    184194            }
     
    188198            request.setUrl(url);
    189199        }
    190         connection->d_func()->createAuthorization(socket, request);
     200        // Will only be false if QtWebKit is performing a cross-origin XMLHttpRequest
     201        // and withCredentials has not been set to true.
     202        if (request.withCredentials())
     203            connection->d_func()->createAuthorization(socket, request);
    191204#ifndef QT_NO_NETWORKPROXY
    192205        QByteArray header = QHttpNetworkRequestPrivate::header(request,
     
    297310    }
    298311    case QHttpNetworkConnectionChannel::ReadingState:
    299     case QHttpNetworkConnectionChannel::Wait4AuthState:
    300312        // ignore _q_bytesWritten in these states
    301313        // fall through
     
    400412        case QHttpNetworkReplyPrivate::ReadingDataState: {
    401413           QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
    402            if (replyPrivate->downstreamLimited && !replyPrivate->responseData.isEmpty() && replyPrivate->shouldEmitSignals()) {
     414           if (socket->state() == QAbstractSocket::ConnectedState &&
     415               replyPrivate->downstreamLimited && !replyPrivate->responseData.isEmpty() && replyPrivate->shouldEmitSignals()) {
     416               // (only do the following when still connected, not when we have already been disconnected and there is still data)
    403417               // We already have some HTTP body data. We don't read more from the socket until
    404418               // this is fetched by QHttpNetworkAccessHttpBackend. If we would read more,
     
    409423               return;
    410424           }
    411 
    412425            if (!replyPrivate->isChunked() && !replyPrivate->autoDecompress
    413426                && replyPrivate->bodyLength > 0) {
     
    645658    // Note that this may trigger a segfault at some other point. But then we can fix the underlying
    646659    // problem.
    647     if (!resendCurrent)
     660    if (!resendCurrent) {
     661        request = QHttpNetworkRequest();
    648662        reply = 0;
     663    }
    649664
    650665    // move next from pipeline to current request
     
    680695        QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
    681696    } else if (alreadyPipelinedRequests.isEmpty()) {
    682         QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
     697        if (qobject_cast<QHttpNetworkConnection*>(connection))
     698            QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
    683699    }
    684700}
     
    782798                : QNetworkReply::AuthenticationRequiredError;
    783799            reply->d_func()->errorString = connection->d_func()->errorDetail(errorCode, socket);
    784             emit connection->error(errorCode, reply->d_func()->errorString);
    785             emit reply->finished();
     800            emit reply->finishedWithError(errorCode, reply->d_func()->errorString);
    786801        }
    787802        break;
    788803    default:
    789         QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
     804        if (qobject_cast<QHttpNetworkConnection*>(connection))
     805            QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
    790806    }
    791807}
     
    835851    close();
    836852    resendCurrent = true;
    837     QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
     853    if (qobject_cast<QHttpNetworkConnection*>(connection))
     854        QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
    838855}
    839856
     
    928945    if (!socket)
    929946        return;
    930     bool send2Reply = false;
    931947    QNetworkReply::NetworkError errorCode = QNetworkReply::UnknownNetworkError;
    932948
     
    946962                return;
    947963            } else {
    948                 send2Reply = true;
    949964                errorCode = QNetworkReply::RemoteHostClosedError;
    950965            }
     
    959974            return;
    960975        }
    961         send2Reply = true;
    962976        errorCode = QNetworkReply::TimeoutError;
    963977        break;
     
    975989    QPointer<QHttpNetworkConnection> that = connection;
    976990    QString errorString = connection->d_func()->errorDetail(errorCode, socket, socket->errorString());
    977     if (send2Reply) {
    978         if (reply) {
    979             reply->d_func()->errorString = errorString;
    980             // this error matters only to this reply
    981             emit reply->finishedWithError(errorCode, errorString);
    982         }
    983         // send the next request
    984         QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
    985     } else {
    986         // the failure affects all requests.
    987         emit connection->error(errorCode, errorString);
    988     }
     991
     992    if (reply) {
     993        reply->d_func()->errorString = errorString;
     994        emit reply->finishedWithError(errorCode, errorString);
     995    }
     996    // send the next request
     997    QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
     998
    989999    if (that) //signal emission triggered event loop
    9901000        close();
     
    10091019        return; // ### error
    10101020    state = QHttpNetworkConnectionChannel::IdleState;
     1021    pendingEncrypt = false;
    10111022    sendRequest();
    10121023}
     
    10171028        return;
    10181029    //QNetworkReply::NetworkError errorCode = QNetworkReply::ProtocolFailure;
    1019     emit connection->sslErrors(errors);
     1030    // Also pause the connection because socket notifiers may fire while an user
     1031    // dialog is displaying
     1032    connection->d_func()->pauseConnection();
     1033    emit reply->sslErrors(errors);
     1034    connection->d_func()->resumeConnection();
    10201035}
    10211036
  • trunk/src/network/access/qhttpnetworkconnectionchannel_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    9696        WaitingState = 4,       // waiting for reply
    9797        ReadingState = 8,       // reading the reply
    98         Wait4AuthState = 0x10,  // blocked for send till the current authentication slot is done
    99         BusyState = (ConnectingState|WritingState|WaitingState|ReadingState|Wait4AuthState)
     98        BusyState = (ConnectingState|WritingState|WaitingState|ReadingState)
    10099    };
    101100    QAbstractSocket *socket;
     
    109108    bool pendingEncrypt; // for https (send after encrypted)
    110109    int reconnectAttempts; // maximum 2 reconnection attempts
    111     QAuthenticatorPrivate::Method authMehtod;
    112     QAuthenticatorPrivate::Method proxyAuthMehtod;
     110    QAuthenticatorPrivate::Method authMethod;
     111    QAuthenticatorPrivate::Method proxyAuthMethod;
    113112    QAuthenticator authenticator;
    114113    QAuthenticator proxyAuthenticator;
     
    160159    bool isSocketReading() const;
    161160
     161    friend class QNetworkAccessHttpBackend;
     162
    162163    protected slots:
    163164    void _q_receiveReply();
  • trunk/src/network/access/qhttpnetworkheader.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6161{
    6262    bool ok = false;
    63     QByteArray value = headerField("content-length");
     63    // We are not using the headerField() method here because servers might send us multiple content-length
     64    // headers which is crap (see QTBUG-15311). Therefore just take the first content-length header field.
     65    QByteArray value;
     66    QList<QPair<QByteArray, QByteArray> >::ConstIterator it = fields.constBegin(),
     67                                                        end = fields.constEnd();
     68    for ( ; it != end; ++it)
     69        if (qstricmp("content-length", it->first) == 0) {
     70            value = it->second;
     71            break;
     72        }
     73
    6474    qint64 length = value.toULongLong(&ok);
    6575    if (ok)
  • trunk/src/network/access/qhttpnetworkheader_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qhttpnetworkreply.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    189189}
    190190
     191QByteArray QHttpNetworkReply::readAll()
     192{
     193    Q_D(QHttpNetworkReply);
     194    return d->responseData.readAll();
     195}
     196
    191197void QHttpNetworkReply::setDownstreamLimited(bool dsl)
    192198{
     
    204210{
    205211    return d_func()->pipeliningUsed;
     212}
     213
     214QHttpNetworkConnection* QHttpNetworkReply::connection()
     215{
     216    return d_func()->connection;
    206217}
    207218
  • trunk/src/network/access/qhttpnetworkreply_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    127127    qint64 bytesAvailableNextBlock() const;
    128128    QByteArray readAny();
     129    QByteArray readAll();
    129130    void setDownstreamLimited(bool t);
    130131
     
    132133
    133134    bool isPipeliningUsed() const;
     135
     136    QHttpNetworkConnection* connection();
    134137
    135138#ifndef QT_NO_OPENSSL
     
    150153    void dataReadProgress(int done, int total);
    151154    void dataSendProgress(qint64 done, qint64 total);
    152 
     155    void cacheCredentials(const QHttpNetworkRequest &request, QAuthenticator *authenticator);
     156#ifndef QT_NO_NETWORKPROXY
     157    void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
     158#endif
     159    void authenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *authenticator);
    153160private:
    154161    Q_DECLARE_PRIVATE(QHttpNetworkReply)
  • trunk/src/network/access/qhttpnetworkrequest.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5050        QHttpNetworkRequest::Priority pri, const QUrl &newUrl)
    5151    : QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0),
    52       autoDecompress(false), pipeliningAllowed(false)
     52      autoDecompress(false), pipeliningAllowed(false), withCredentials(true)
    5353{
    5454}
     
    6262    autoDecompress = other.autoDecompress;
    6363    pipeliningAllowed = other.pipeliningAllowed;
     64    customVerb = other.customVerb;
     65    withCredentials = other.withCredentials;
    6466}
    6567
     
    7779QByteArray QHttpNetworkRequestPrivate::methodName() const
    7880{
    79     QByteArray ba;
    8081    switch (operation) {
     82    case QHttpNetworkRequest::Get:
     83        return "GET";
     84        break;
     85    case QHttpNetworkRequest::Head:
     86        return "HEAD";
     87        break;
     88    case QHttpNetworkRequest::Post:
     89        return "POST";
     90        break;
    8191    case QHttpNetworkRequest::Options:
    82         ba += "OPTIONS";
    83         break;
    84     case QHttpNetworkRequest::Get:
    85         ba += "GET";
    86         break;
    87     case QHttpNetworkRequest::Head:
    88         ba += "HEAD";
    89         break;
    90     case QHttpNetworkRequest::Post:
    91         ba += "POST";
     92        return "OPTIONS";
    9293        break;
    9394    case QHttpNetworkRequest::Put:
    94         ba += "PUT";
     95        return "PUT";
    9596        break;
    9697    case QHttpNetworkRequest::Delete:
    97         ba += "DELETE";
     98        return "DELETE";
    9899        break;
    99100    case QHttpNetworkRequest::Trace:
    100         ba += "TRACE";
     101        return "TRACE";
    101102        break;
    102103    case QHttpNetworkRequest::Connect:
    103         ba += "CONNECT";
     104        return "CONNECT";
     105        break;
     106    case QHttpNetworkRequest::Custom:
     107        return customVerb;
    104108        break;
    105109    default:
    106110        break;
    107111    }
    108     return ba;
     112    return QByteArray();
    109113}
    110114
     
    129133QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request, bool throughProxy)
    130134{
    131     QByteArray ba = request.d->methodName();
    132     QByteArray uri = request.d->uri(throughProxy);
    133     ba += ' ' + uri;
    134 
    135     QString majorVersion = QString::number(request.majorVersion());
    136     QString minorVersion = QString::number(request.minorVersion());
    137     ba += " HTTP/" + majorVersion.toLatin1() + '.' + minorVersion.toLatin1() + "\r\n";
    138 
    139135    QList<QPair<QByteArray, QByteArray> > fields = request.header();
     136    QByteArray ba;
     137    ba.reserve(40 + fields.length()*25); // very rough lower bound estimation
     138
     139    ba += request.d->methodName();
     140    ba += ' ';
     141    ba += request.d->uri(throughProxy);
     142
     143    ba += " HTTP/";
     144    ba += QByteArray::number(request.majorVersion());
     145    ba += '.';
     146    ba += QByteArray::number(request.minorVersion());
     147    ba += "\r\n";
     148
    140149    QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
    141     for (; it != fields.constEnd(); ++it)
    142         ba += it->first + ": " + it->second + "\r\n";
     150    QList<QPair<QByteArray, QByteArray> >::const_iterator endIt = fields.constEnd();
     151    for (; it != endIt; ++it) {
     152        ba += it->first;
     153        ba += ": ";
     154        ba += it->second;
     155        ba += "\r\n";
     156    }
    143157    if (request.d->operation == QHttpNetworkRequest::Post) {
    144158        // add content type, if not set in the request
     
    147161        if (!request.d->uploadByteDevice && request.d->url.hasQuery()) {
    148162            QByteArray query = request.d->url.encodedQuery();
    149             ba += "Content-Length: "+ QByteArray::number(query.size()) + "\r\n";
    150             ba += "\r\n";
     163            ba += "Content-Length: ";
     164            ba += QByteArray::number(query.size());
     165            ba += "\r\n\r\n";
    151166            ba += query;
    152167        } else {
     
    231246}
    232247
     248QByteArray QHttpNetworkRequest::customVerb() const
     249{
     250    return d->customVerb;
     251}
     252
     253void QHttpNetworkRequest::setCustomVerb(const QByteArray &customVerb)
     254{
     255    d->customVerb = customVerb;
     256}
     257
    233258QHttpNetworkRequest::Priority QHttpNetworkRequest::priority() const
    234259{
     
    251276}
    252277
     278bool QHttpNetworkRequest::withCredentials() const
     279{
     280    return d->withCredentials;
     281}
     282
     283void QHttpNetworkRequest::setWithCredentials(bool b)
     284{
     285    d->withCredentials = b;
     286}
     287
    253288void QHttpNetworkRequest::setUploadByteDevice(QNonContiguousByteDevice *bd)
    254289{
  • trunk/src/network/access/qhttpnetworkrequest_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7373        Delete,
    7474        Trace,
    75         Connect
     75        Connect,
     76        Custom
    7677    };
    7778
     
    104105    void setOperation(Operation operation);
    105106
     107    QByteArray customVerb() const;
     108    void setCustomVerb(const QByteArray &customOperation);
     109
    106110    Priority priority() const;
    107111    void setPriority(Priority priority);
     
    109113    bool isPipeliningAllowed() const;
    110114    void setPipeliningAllowed(bool b);
     115
     116    bool withCredentials() const;
     117    void setWithCredentials(bool b);
    111118
    112119    void setUploadByteDevice(QNonContiguousByteDevice *bd);
     
    134141
    135142    QHttpNetworkRequest::Operation operation;
     143    QByteArray customVerb;
    136144    QHttpNetworkRequest::Priority priority;
    137145    mutable QNonContiguousByteDevice* uploadByteDevice;
    138146    bool autoDecompress;
    139147    bool pipeliningAllowed;
     148    bool withCredentials;
    140149};
    141150
  • trunk/src/network/access/qnetworkaccessbackend.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4747#include "QtCore/qhash.h"
    4848#include "QtCore/qmutex.h"
     49#include "QtNetwork/qnetworksession.h"
    4950
    5051#include "qnetworkaccesscachebackend_p.h"
    5152#include "qabstractnetworkcache.h"
     53#include "qhostinfo.h"
    5254
    5355#include "private/qnoncontiguousbytedevice_p.h"
     
    8789                                                                 const QNetworkRequest &request)
    8890{
    89     QNetworkRequest::CacheLoadControl mode =
    90         static_cast<QNetworkRequest::CacheLoadControl>(
    91             request.attribute(QNetworkRequest::CacheLoadControlAttribute,
    92                               QNetworkRequest::PreferNetwork).toInt());
    93     if (mode == QNetworkRequest::AlwaysCache
    94         && (op == QNetworkAccessManager::GetOperation
    95         || op == QNetworkAccessManager::HeadOperation)) {
    96         QNetworkAccessBackend *backend = new QNetworkAccessCacheBackend;
    97         backend->manager = this;
    98         return backend;
    99     }
    100 
    10191    if (!factoryDataShutdown) {
    10292        QMutexLocker locker(&factoryData()->mutex);
     
    121111    if (reply->outgoingDataBuffer)
    122112        device = QNonContiguousByteDeviceFactory::create(reply->outgoingDataBuffer);
    123     else
     113    else if (reply->outgoingData) {
    124114        device = QNonContiguousByteDeviceFactory::create(reply->outgoingData);
     115    } else {
     116        return 0;
     117    }
    125118
    126119    bool bufferDisallowed =
     
    150143    : manager(0)
    151144    , reply(0)
     145    , synchronous(false)
    152146{
    153147}
     
    321315{
    322316    manager->authenticationRequired(this, authenticator);
     317}
     318
     319void QNetworkAccessBackend::cacheCredentials(QAuthenticator *authenticator)
     320{
     321    manager->cacheCredentials(this->reply->url, authenticator);
    323322}
    324323
     
    342341}
    343342
     343#ifndef QT_NO_BEARERMANAGEMENT
     344
     345/*!
     346    Starts the backend.  Returns true if the backend is started.  Returns false if the backend
     347    could not be started due to an unopened or roaming session.  The caller should recall this
     348    function once the session has been opened or the roaming process has finished.
     349*/
     350bool QNetworkAccessBackend::start()
     351{
     352    if (!manager->networkSession) {
     353        open();
     354        return true;
     355    }
     356
     357    // This is not ideal.
     358    const QString host = reply->url.host();
     359    if (host == QLatin1String("localhost") ||
     360        QHostAddress(host) == QHostAddress::LocalHost ||
     361        QHostAddress(host) == QHostAddress::LocalHostIPv6) {
     362        // Don't need an open session for localhost access.
     363        open();
     364        return true;
     365    }
     366
     367    if (manager->networkSession->isOpen() &&
     368        manager->networkSession->state() == QNetworkSession::Connected) {
     369        open();
     370        return true;
     371    }
     372
     373    return false;
     374}
     375#endif
     376
    344377QT_END_NAMESPACE
  • trunk/src/network/access/qnetworkaccessbackend_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    112112
    113113    virtual void open() = 0;
     114#ifndef QT_NO_BEARERMANAGEMENT
     115    virtual bool start();
     116#endif
    114117    virtual void closeDownstreamChannel() = 0;
    115     virtual bool waitForDownstreamReadyRead(int msecs) = 0;
    116118
    117119    // slot-like:
     
    156158    void setAttribute(QNetworkRequest::Attribute code, const QVariant &value);
    157159
     160    bool isSynchronous() { return synchronous; }
     161    void setSynchronous(bool sync) { synchronous = sync; }
     162
    158163    // return true if the QNonContiguousByteDevice of the upload
    159164    // data needs to support reset(). Currently needed for HTTP.
    160165    // This will possibly enable buffering of the upload data.
    161166    virtual bool needsResetableUploadData() { return false; }
     167
     168    // Returns true if backend is able to resume downloads.
     169    virtual bool canResume() const { return false; }
     170    virtual void setResumeOffset(quint64 offset) { Q_UNUSED(offset); }
     171
     172    virtual bool processRequestSynchronously() { return false; }
    162173
    163174protected:
     
    182193#endif
    183194    void authenticationRequired(QAuthenticator *auth);
     195    void cacheCredentials(QAuthenticator *auth);
    184196    void metaDataChanged();
    185197    void redirectionRequested(const QUrl &destination);
     
    191203    friend class QNetworkAccessManagerPrivate;
    192204    friend class QNetworkAccessBackendUploadIODevice;
     205    friend class QNetworkReplyImplPrivate;
    193206    QNetworkAccessManagerPrivate *manager;
    194207    QNetworkReplyImplPrivate *reply;
     208    bool synchronous;
    195209};
    196210
  • trunk/src/network/access/qnetworkaccesscache.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qnetworkaccesscache_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qnetworkaccesscachebackend.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    133133}
    134134
    135 bool QNetworkAccessCacheBackend::waitForDownstreamReadyRead(int)
    136 {
    137     Q_ASSERT_X(false, Q_FUNC_INFO , "This function show not have been called!");
    138     return false;
    139 }
    140 
    141 bool QNetworkAccessCacheBackend::waitForUpstreamBytesWritten(int)
    142 {
    143     Q_ASSERT_X(false, Q_FUNC_INFO, "This function show not have been called!");
    144     return false;
    145 }
    146 
    147135void QNetworkAccessCacheBackend::upstreamReadyRead()
    148136{
  • trunk/src/network/access/qnetworkaccesscachebackend_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7070    void closeDownstreamChannel();
    7171    void closeUpstreamChannel();
    72     bool waitForDownstreamReadyRead(int msecs);
    73     bool waitForUpstreamBytesWritten(int msecs);
    7472
    7573    void upstreamReadyRead();
  • trunk/src/network/access/qnetworkaccessdatabackend.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4444#include "qnetworkreply.h"
    4545#include "qurlinfo.h"
     46#include "private/qdataurl_p.h"
     47#include <qcoreapplication.h>
    4648
    4749QT_BEGIN_NAMESPACE
     
    7274        operation() != QNetworkAccessManager::HeadOperation) {
    7375        // data: doesn't support anything but GET
    74         QString msg = QObject::tr("Operation not supported on %1")
     76        const QString msg = QCoreApplication::translate("QNetworkAccessDataBackend",
     77                                                        "Operation not supported on %1")
    7578                      .arg(uri.toString());
    7679        error(QNetworkReply::ContentOperationNotPermittedError, msg);
     
    7982    }
    8083
    81     if (uri.host().isEmpty()) {
    82         setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("text/plain;charset=US-ASCII"));
     84    QPair<QString, QByteArray> decoded = qDecodeDataUrl(uri);
    8385
    84         // the following would have been the correct thing, but
    85         // reality often differs from the specification. People have
    86         // data: URIs with ? and #
    87         //QByteArray data = QByteArray::fromPercentEncoding(uri.encodedPath());
    88         QByteArray data = QByteArray::fromPercentEncoding(uri.toEncoded());
     86    if (! decoded.first.isNull()) {
     87        setHeader(QNetworkRequest::ContentTypeHeader, decoded.first);
     88        setHeader(QNetworkRequest::ContentLengthHeader, decoded.second.size());
     89        emit metaDataChanged();
    8990
    90         // remove the data: scheme
    91         data.remove(0, 5);
     91        QByteDataBuffer list;
     92        list.append(decoded.second);
     93        decoded.second.clear(); // important because of implicit sharing!
     94        writeDownstreamData(list);
    9295
    93         // parse it:
    94         int pos = data.indexOf(',');
    95         if (pos != -1) {
    96             QByteArray payload = data.mid(pos + 1);
    97             data.truncate(pos);
    98             data = data.trimmed();
    99 
    100             // find out if the payload is encoded in Base64
    101             if (data.endsWith(";base64")) {
    102                 payload = QByteArray::fromBase64(payload);
    103                 data.chop(7);
    104             }
    105 
    106             if (data.toLower().startsWith("charset")) {
    107                 int i = 7;      // strlen("charset")
    108                 while (data.at(i) == ' ')
    109                     ++i;
    110                 if (data.at(i) == '=')
    111                     data.prepend("text/plain;");
    112             }
    113 
    114             if (!data.isEmpty())
    115                 setHeader(QNetworkRequest::ContentTypeHeader, data.trimmed());
    116 
    117             setHeader(QNetworkRequest::ContentLengthHeader, payload.size());
    118             emit metaDataChanged();
    119 
    120             QByteDataBuffer list;
    121             list.append(payload);
    122             payload.clear(); // important because of implicit sharing!
    123             writeDownstreamData(list);
    124 
    125             finished();
    126             return;
    127         }
     96        finished();
     97        return;
    12898    }
    12999
    130100    // something wrong with this URI
    131     QString msg = QObject::tr("Invalid URI: %1").arg(uri.toString());
     101    const QString msg = QCoreApplication::translate("QNetworkAccessDataBackend",
     102                                                    "Invalid URI: %1").arg(uri.toString());
    132103    error(QNetworkReply::ProtocolFailure, msg);
    133104    finished();
     
    152123}
    153124
     125bool QNetworkAccessDataBackend::processRequestSynchronously()
     126{
     127#ifndef QT_NO_BEARERMANAGEMENT
     128    start();
     129#else
     130    open();
     131#endif
     132    return true;
     133}
     134
    154135QT_END_NAMESPACE
  • trunk/src/network/access/qnetworkaccessdatabackend_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6969    virtual bool waitForDownstreamReadyRead(int msecs);
    7070    virtual bool waitForUpstreamBytesWritten(int msecs);
     71
     72    virtual bool processRequestSynchronously();
    7173};
    7274
  • trunk/src/network/access/qnetworkaccessdebugpipebackend.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    253253    }
    254254
    255     error(code, QObject::tr("Socket error on %1: %2")
     255    error(code, QNetworkAccessDebugPipeBackend::tr("Socket error on %1: %2")
    256256          .arg(url().toString(), socket.errorString()));
    257257    finished();
     
    268268    } else {
    269269        // abnormal close
    270         QString msg = QObject::tr("Remote host closed the connection prematurely on %1")
     270        QString msg = QNetworkAccessDebugPipeBackend::tr("Remote host closed the connection prematurely on %1")
    271271                             .arg(url().toString());
    272272        error(QNetworkReply::RemoteHostClosedError, msg);
     
    279279}
    280280
    281 bool QNetworkAccessDebugPipeBackend::waitForDownstreamReadyRead(int ms)
    282 {
    283     Q_UNUSED(ms);
    284     qCritical("QNetworkAccess: Debug pipe backend does not support waitForReadyRead()");
    285     return false;
    286 }
    287281
    288282#endif
  • trunk/src/network/access/qnetworkaccessdebugpipebackend_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7272    virtual void open();
    7373    virtual void closeDownstreamChannel();
    74     virtual bool waitForDownstreamReadyRead(int msecs);
    7574
    7675    virtual void downstreamReadyWrite();
  • trunk/src/network/access/qnetworkaccessfilebackend.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    204204}
    205205
    206 bool QNetworkAccessFileBackend::waitForDownstreamReadyRead(int)
    207 {
    208     Q_ASSERT(operation() == QNetworkAccessManager::GetOperation);
    209     return readMoreFromFile();
    210 }
    211 
    212206void QNetworkAccessFileBackend::downstreamReadyWrite()
    213207{
  • trunk/src/network/access/qnetworkaccessfilebackend_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7070    virtual void open();
    7171    virtual void closeDownstreamChannel();
    72     virtual bool waitForDownstreamReadyRead(int msecs);
    7372
    7473    virtual void downstreamReadyWrite();
  • trunk/src/network/access/qnetworkaccessftpbackend.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    181181        exit(3);
    182182#endif
    183 }
    184 
    185 bool QNetworkAccessFtpBackend::waitForDownstreamReadyRead(int ms)
    186 {
    187     if (!ftp)
    188         return false;
    189 
    190     if (ftp->bytesAvailable()) {
    191         ftpReadyRead();
    192         return true;
    193     }
    194 
    195     if (ms == 0)
    196         return false;
    197 
    198     qCritical("QNetworkAccess: FTP backend does not support waitForReadyRead()");
    199     return false;
    200183}
    201184
  • trunk/src/network/access/qnetworkaccessftpbackend_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    8888    virtual void open();
    8989    virtual void closeDownstreamChannel();
    90     virtual bool waitForDownstreamReadyRead(int msecs);
    9190
    9291    virtual void downstreamReadyWrite();
  • trunk/src/network/access/qnetworkaccesshttpbackend.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5151#include "qnetworkcookie_p.h"
    5252#include "QtCore/qdatetime.h"
     53#include "QtCore/qelapsedtimer.h"
    5354#include "QtNetwork/qsslconfiguration.h"
    5455
     
    214215    case QNetworkAccessManager::PutOperation:
    215216    case QNetworkAccessManager::DeleteOperation:
     217    case QNetworkAccessManager::CustomOperation:
    216218        break;
    217219
     
    297299    , pendingSslConfiguration(0), pendingIgnoreAllSslErrors(false)
    298300#endif
     301    , resumeOffset(0)
    299302{
    300303}
     
    317320        // Get the object cache that stores our QHttpNetworkConnection objects
    318321        QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getObjectCache(this);
    319         cache->releaseEntry(cacheKey);
     322
     323        // synchronous calls are not put into the cache, so for them the key is empty
     324        if (!cacheKey.isEmpty())
     325            cache->releaseEntry(cacheKey);
    320326    }
    321327
     
    335341    // call parent
    336342    QNetworkAccessBackend::finished();
    337 }
    338 
    339 void QNetworkAccessHttpBackend::setupConnection()
    340 {
    341 #ifndef QT_NO_NETWORKPROXY
    342     connect(http, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
    343             SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
    344 #endif
    345     connect(http, SIGNAL(authenticationRequired(QHttpNetworkRequest,QAuthenticator*)),
    346             SLOT(httpAuthenticationRequired(QHttpNetworkRequest,QAuthenticator*)));
    347     connect(http, SIGNAL(error(QNetworkReply::NetworkError,QString)),
    348             SLOT(httpError(QNetworkReply::NetworkError,QString)));
    349 #ifndef QT_NO_OPENSSL
    350     connect(http, SIGNAL(sslErrors(QList<QSslError>)),
    351             SLOT(sslErrors(QList<QSslError>)));
    352 #endif
    353343}
    354344
     
    481471}
    482472
     473static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& prio)
     474{
     475    switch (prio) {
     476    case QNetworkRequest::LowPriority:
     477        return QHttpNetworkRequest::LowPriority;
     478    case QNetworkRequest::HighPriority:
     479        return QHttpNetworkRequest::HighPriority;
     480    case QNetworkRequest::NormalPriority:
     481    default:
     482        return QHttpNetworkRequest::NormalPriority;
     483    }
     484}
     485
    483486void QNetworkAccessHttpBackend::postRequest()
    484487{
    485488    bool loadedFromCache = false;
    486489    QHttpNetworkRequest httpRequest;
     490    httpRequest.setPriority(convert(request().priority()));
    487491    switch (operation()) {
    488492    case QNetworkAccessManager::GetOperation:
     
    513517        break;
    514518
     519    case QNetworkAccessManager::CustomOperation:
     520        invalidateCache(); // for safety reasons, we don't know what the operation does
     521        httpRequest.setOperation(QHttpNetworkRequest::Custom);
     522        httpRequest.setUploadByteDevice(createUploadByteDevice());
     523        httpRequest.setCustomVerb(request().attribute(
     524                QNetworkRequest::CustomVerbAttribute).toByteArray());
     525        break;
     526
    515527    default:
    516528        break;                  // can't happen
     
    520532
    521533    QList<QByteArray> headers = request().rawHeaderList();
     534    if (resumeOffset != 0) {
     535        if (headers.contains("Range")) {
     536            // Need to adjust resume offset for user specified range
     537
     538            headers.removeOne("Range");
     539
     540            // We've already verified that requestRange starts with "bytes=", see canResume.
     541            QByteArray requestRange = request().rawHeader("Range").mid(6);
     542
     543            int index = requestRange.indexOf('-');
     544
     545            quint64 requestStartOffset = requestRange.left(index).toULongLong();
     546            quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong();
     547
     548            requestRange = "bytes=" + QByteArray::number(resumeOffset + requestStartOffset) +
     549                           '-' + QByteArray::number(requestEndOffset);
     550
     551            httpRequest.setHeaderField("Range", requestRange);
     552        } else {
     553            httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-');
     554        }
     555    }
    522556    foreach (const QByteArray &header, headers)
    523557        httpRequest.setHeaderField(header, request().rawHeader(header));
     
    532566    if (request().attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool() == true)
    533567        httpRequest.setPipeliningAllowed(true);
     568
     569    if (static_cast<QNetworkRequest::LoadControl>
     570        (request().attribute(QNetworkRequest::AuthenticationReuseAttribute,
     571                             QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual)
     572        httpRequest.setWithCredentials(false);
    534573
    535574    httpReply = http->sendRequest(httpRequest);
     
    541580        httpReply->ignoreSslErrors();
    542581    httpReply->ignoreSslErrors(pendingIgnoreSslErrorsList);
     582    connect(httpReply, SIGNAL(sslErrors(QList<QSslError>)),
     583            SLOT(sslErrors(QList<QSslError>)));
    543584#endif
    544585
     
    548589            SLOT(httpError(QNetworkReply::NetworkError,QString)));
    549590    connect(httpReply, SIGNAL(headerChanged()), SLOT(replyHeaderChanged()));
     591    connect(httpReply, SIGNAL(cacheCredentials(QHttpNetworkRequest,QAuthenticator*)),
     592            SLOT(httpCacheCredentials(QHttpNetworkRequest,QAuthenticator*)));
     593#ifndef QT_NO_NETWORKPROXY
     594    connect(httpReply, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
     595            SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
     596#endif
     597    connect(httpReply, SIGNAL(authenticationRequired(const QHttpNetworkRequest,QAuthenticator*)),
     598                SLOT(httpAuthenticationRequired(const QHttpNetworkRequest,QAuthenticator*)));
    550599}
    551600
     
    595644        cacheProxy.type() == QNetworkProxy::DefaultProxy) {
    596645        // unsuitable proxies
    597         QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
    598                                   Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError),
    599                                   Q_ARG(QString, tr("No suitable proxy found")));
    600         QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
    601         return;
    602     }
    603 #endif
    604 
    605     // check if we have an open connection to this host
    606     cacheKey = makeCacheKey(this, theProxy);
    607     QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getObjectCache(this);
    608     // the http object is actually a QHttpNetworkConnection
    609     http = static_cast<QNetworkAccessCachedHttpConnection *>(cache->requestEntryNow(cacheKey));
    610     if (http == 0) {
    611         // no entry in cache; create an object
    612         // the http object is actually a QHttpNetworkConnection
    613         http = new QNetworkAccessCachedHttpConnection(url.host(), url.port(), encrypt);
    614 
     646        if (isSynchronous()) {
     647            error(QNetworkReply::ProxyNotFoundError, tr("No suitable proxy found"));
     648            finished();
     649        } else {
     650            QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
     651                                      Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProxyNotFoundError),
     652                                      Q_ARG(QString, tr("No suitable proxy found")));
     653            QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
     654        }
     655            return;
     656    }
     657#endif
     658
     659    if (isSynchronous()) {
     660        // for synchronous requests, we just create a new connection
     661        http = new QHttpNetworkConnection(1, url.host(), url.port(), encrypt, this);
    615662#ifndef QT_NO_NETWORKPROXY
    616663        http->setTransparentProxy(transparentProxy);
    617664        http->setCacheProxy(cacheProxy);
    618665#endif
    619 
    620         // cache the QHttpNetworkConnection corresponding to this cache key
    621         cache->addEntry(cacheKey, http);
    622     }
    623 
    624     setupConnection();
    625     postRequest();
     666        postRequest();
     667        processRequestSynchronously();
     668    } else {
     669        // check if we have an open connection to this host
     670        cacheKey = makeCacheKey(this, theProxy);
     671        QNetworkAccessCache *cache = QNetworkAccessManagerPrivate::getObjectCache(this);
     672        // the http object is actually a QHttpNetworkConnection
     673        http = static_cast<QNetworkAccessCachedHttpConnection *>(cache->requestEntryNow(cacheKey));
     674        if (http == 0) {
     675            // no entry in cache; create an object
     676            // the http object is actually a QHttpNetworkConnection
     677            http = new QNetworkAccessCachedHttpConnection(url.host(), url.port(), encrypt);
     678
     679#ifndef QT_NO_NETWORKPROXY
     680            http->setTransparentProxy(transparentProxy);
     681            http->setCacheProxy(cacheProxy);
     682#endif
     683
     684            // cache the QHttpNetworkConnection corresponding to this cache key
     685            cache->addEntry(cacheKey, static_cast<QNetworkAccessCachedHttpConnection *>(http.data()));
     686        }
     687        postRequest();
     688    }
    626689}
    627690
     
    630693    // this indicates that the user closed the stream while the reply isn't finished yet
    631694}
    632 
    633 bool QNetworkAccessHttpBackend::waitForDownstreamReadyRead(int msecs)
    634 {
    635     Q_ASSERT(http);
    636 
    637     if (httpReply->bytesAvailable()) {
    638         readFromHttp();
    639         return true;
    640     }
    641 
    642     if (msecs == 0) {
    643         // no bytes available in the socket and no waiting
    644         return false;
    645     }
    646 
    647     // ### FIXME
    648     qCritical("QNetworkAccess: HTTP backend does not support waitForReadyRead()");
    649     return false;
    650 }
    651 
    652695
    653696void QNetworkAccessHttpBackend::downstreamReadyWrite()
     
    816859}
    817860
     861void QNetworkAccessHttpBackend::httpCacheCredentials(const QHttpNetworkRequest &,
     862                                                 QAuthenticator *auth)
     863{
     864    cacheCredentials(auth);
     865}
     866
    818867void QNetworkAccessHttpBackend::httpError(QNetworkReply::NetworkError errorCode,
    819868                                          const QString &errorString)
     
    821870#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG)
    822871    qDebug() << "http error!" << errorCode << errorString;
    823 #endif
    824 #if 0
    825     static const QNetworkReply::NetworkError conversionTable[] = {
    826         QNetworkReply::ConnectionRefusedError,
    827         QNetworkReply::RemoteHostClosedError,
    828         QNetworkReply::HostNotFoundError,
    829         QNetworkReply::UnknownNetworkError, // SocketAccessError
    830         QNetworkReply::UnknownNetworkError, // SocketResourceError
    831         QNetworkReply::TimeoutError,        // SocketTimeoutError
    832         QNetworkReply::UnknownNetworkError, // DatagramTooLargeError
    833         QNetworkReply::UnknownNetworkError, // NetworkError
    834         QNetworkReply::UnknownNetworkError, // AddressInUseError
    835         QNetworkReply::UnknownNetworkError, // SocketAddressNotAvailableError
    836         QNetworkReply::UnknownNetworkError, // UnsupportedSocketOperationError
    837         QNetworkReply::UnknownNetworkError, // UnfinishedSocketOperationError
    838         QNetworkReply::ProxyAuthenticationRequiredError
    839     };
    840     QNetworkReply::NetworkError code;
    841     if (int(errorCode) >= 0 &&
    842         uint(errorCode) < (sizeof conversionTable / sizeof conversionTable[0]))
    843         code = conversionTable[errorCode];
    844     else
    845         code = QNetworkReply::UnknownNetworkError;
    846872#endif
    847873    error(errorCode, errorString);
     
    886912    checkForRedirect(status);
    887913
    888     emit metaDataChanged();
    889 
    890     // invoke this asynchronously, else Arora/QtDemoBrowser don't like cached downloads
    891     // see task 250221 / 251801
     914    // This needs to be emitted in the event loop because it can be reached at
     915    // the direct code path of qnam.get(...) before the user has a chance
     916    // to connect any signals.
     917    QMetaObject::invokeMethod(this, "metaDataChanged", Qt::QueuedConnection);
    892918    qRegisterMetaType<QIODevice*>("QIODevice*");
    893919    QMetaObject::invokeMethod(this, "writeDownstreamData", Qt::QueuedConnection, Q_ARG(QIODevice*, contents));
     
    10941120}
    10951121
     1122bool QNetworkAccessHttpBackend::canResume() const
     1123{
     1124    // Only GET operation supports resuming.
     1125    if (operation() != QNetworkAccessManager::GetOperation)
     1126        return false;
     1127
     1128    // Can only resume if server/resource supports Range header.
     1129    if (httpReply->headerField("Accept-Ranges", "none") == "none")
     1130        return false;
     1131
     1132    // We only support resuming for byte ranges.
     1133    if (request().hasRawHeader("Range")) {
     1134        QByteArray range = request().rawHeader("Range");
     1135        if (!range.startsWith("bytes="))
     1136            return false;
     1137    }
     1138
     1139    return true;
     1140}
     1141
     1142void QNetworkAccessHttpBackend::setResumeOffset(quint64 offset)
     1143{
     1144    resumeOffset = offset;
     1145}
     1146
     1147bool QNetworkAccessHttpBackend::processRequestSynchronously()
     1148{
     1149    QHttpNetworkConnectionChannel *channel = &http->channels()[0];
     1150
     1151    // Disconnect all socket signals. They will only confuse us when using waitFor*
     1152    QObject::disconnect(channel->socket, 0, 0, 0);
     1153
     1154    qint64 timeout = 20*1000; // 20 sec
     1155    QElapsedTimer timeoutTimer;
     1156
     1157    bool waitResult = channel->socket->waitForConnected(timeout);
     1158    timeoutTimer.start();
     1159
     1160    if (!waitResult || channel->socket->state() != QAbstractSocket::ConnectedState) {
     1161        error(QNetworkReply::UnknownNetworkError, QLatin1String("could not connect"));
     1162        return false;
     1163    }
     1164    channel->_q_connected(); // this will send the request (via sendRequest())
     1165
     1166#ifndef QT_NO_OPENSSL
     1167    if (http->isSsl()) {
     1168        qint64 remainingTimeEncrypted = timeout - timeoutTimer.elapsed();
     1169        if (!static_cast<QSslSocket *>(channel->socket)->waitForEncrypted(remainingTimeEncrypted)) {
     1170            error(QNetworkReply::SslHandshakeFailedError,
     1171                  QLatin1String("could not encrypt or timeout while encrypting"));
     1172            return false;
     1173        }
     1174        channel->_q_encrypted();
     1175    }
     1176#endif
     1177
     1178    // if we get a 401 or 407, we might need to send the request twice, see below
     1179    bool authenticating = false;
     1180
     1181    do {
     1182        channel->sendRequest();
     1183
     1184        qint64 remainingTimeBytesWritten;
     1185        while(channel->socket->bytesToWrite() > 0 ||
     1186              channel->state == QHttpNetworkConnectionChannel::WritingState) {
     1187            remainingTimeBytesWritten = timeout - timeoutTimer.elapsed();
     1188            channel->sendRequest(); // triggers channel->socket->write()
     1189            if (!channel->socket->waitForBytesWritten(remainingTimeBytesWritten)) {
     1190                error(QNetworkReply::TimeoutError,
     1191                      QLatin1String("could not write bytes to socket or timeout while writing"));
     1192                return false;
     1193            }
     1194        }
     1195
     1196        qint64 remainingTimeBytesRead = timeout - timeoutTimer.elapsed();
     1197        // Loop for at most remainingTime until either the socket disconnects
     1198        // or the reply is finished
     1199        do {
     1200            waitResult = channel->socket->waitForReadyRead(remainingTimeBytesRead);
     1201            remainingTimeBytesRead = timeout - timeoutTimer.elapsed();
     1202            if (!waitResult || remainingTimeBytesRead <= 0
     1203                || channel->socket->state() != QAbstractSocket::ConnectedState) {
     1204                error(QNetworkReply::TimeoutError,
     1205                      QLatin1String("could not read from socket or timeout while reading"));
     1206                return false;
     1207            }
     1208
     1209            if (channel->socket->bytesAvailable())
     1210                channel->_q_readyRead();
     1211
     1212            if (!httpReply)
     1213                return false; // we got a 401 or 407 and cannot handle it (it might happen that
     1214                              // disconnectFromHttp() was called, in that case the reply is zero)
     1215            // ### I am quite sure this does not work for NTLM
     1216            // ### how about uploading to an auth / proxyAuth site?
     1217
     1218            authenticating = (httpReply->statusCode() == 401 || httpReply->statusCode() == 407);
     1219
     1220            if (httpReply->isFinished())
     1221                break;
     1222        } while (remainingTimeBytesRead > 0);
     1223    } while (authenticating);
     1224
     1225    return true;
     1226}
     1227
    10961228QT_END_NAMESPACE
    10971229
  • trunk/src/network/access/qnetworkaccesshttpbackend_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    8080    virtual void open();
    8181    virtual void closeDownstreamChannel();
    82     virtual bool waitForDownstreamReadyRead(int msecs);
    8382
    8483    virtual void downstreamReadyWrite();
     
    9897    bool needsResetableUploadData() { return true; }
    9998
     99    bool canResume() const;
     100    void setResumeOffset(quint64 offset);
     101
     102    virtual bool processRequestSynchronously();
     103
    100104private slots:
    101105    void replyReadyRead();
     
    103107    void replyHeaderChanged();
    104108    void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth);
     109    void httpCacheCredentials(const QHttpNetworkRequest &request, QAuthenticator *auth);
    105110    void httpError(QNetworkReply::NetworkError error, const QString &errorString);
    106111    bool sendCacheContents(const QNetworkCacheMetaData &metaData);
     
    109114private:
    110115    QHttpNetworkReply *httpReply;
    111     QPointer<QNetworkAccessCachedHttpConnection> http;
     116    QPointer<QHttpNetworkConnection> http;
    112117    QByteArray cacheKey;
    113118    QNetworkAccessBackendUploadIODevice *uploadDevice;
     
    119124#endif
    120125
     126    quint64 resumeOffset;
     127
    121128    void disconnectFromHttp();
    122     void setupConnection();
    123129    void validateCache(QHttpNetworkRequest &httpRequest, bool &loadedFromCache);
    124130    void invalidateCache();
  • trunk/src/network/access/qnetworkaccessmanager.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4848#include "qabstractnetworkcache.h"
    4949
     50#include "QtNetwork/qnetworksession.h"
     51#include "QtNetwork/private/qsharednetworksession_p.h"
     52
    5053#include "qnetworkaccesshttpbackend_p.h"
    5154#include "qnetworkaccessftpbackend_p.h"
     
    5356#include "qnetworkaccessdatabackend_p.h"
    5457#include "qnetworkaccessdebugpipebackend_p.h"
     58#include "qnetworkaccesscachebackend_p.h"
    5559#include "qfilenetworkreply_p.h"
    5660
     
    6064#include "QtNetwork/qauthenticator.h"
    6165#include "QtNetwork/qsslconfiguration.h"
     66#include "QtNetwork/qnetworkconfigmanager.h"
    6267
    6368QT_BEGIN_NAMESPACE
     
    139144    \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 1
    140145
     146    \section1 Network and Roaming support
     147
     148    With the addition of the \l {Bearer Management} API to Qt 4.7
     149    QNetworkAccessManager gained the ability to manage network connections.
     150    QNetworkAccessManager can start the network interface if the device is
     151    offline and terminates the interface if the current process is the last
     152    one to use the uplink. Note that some platform utilize grace periods from
     153    when the last application stops using a uplink until the system actually
     154    terminates the connectivity link. Roaming is equally transparent. Any
     155    queued/pending network requests are automatically transferred to new
     156    access point.
     157
     158    Clients wanting to utilize this feature should not require any changes. In fact
     159    it is likely that existing platform specific connection code can simply be
     160    removed from the application.
     161
     162    \note The network and roaming support in QNetworkAccessManager is conditional
     163    upon the platform supporting connection management. The
     164    \l QNetworkConfigurationManager::NetworkSessionRequired can be used to
     165    detect whether QNetworkAccessManager utilizes this feature. Currently only
     166    Meego/Harmattan and Symbian platforms provide connection management support.
     167
     168    \note This feature cannot be used in combination with the Bearer Management
     169    API as provided by QtMobility. Applications have to migrate to the Qt version
     170    of Bearer Management.
     171
    141172    \section1 Symbian Platform Security Requirements
    142173
     
    172203    deleteResource())
    173204
     205    \value CustomOperation      custom operation (created with
     206    sendCustomRequest())    \since 4.7
     207
    174208    \omitvalue UnknownOperation
    175209
    176210    \sa QNetworkReply::operation()
     211*/
     212
     213/*!
     214    \enum QNetworkAccessManager::NetworkAccessibility
     215
     216    Indicates whether the network is accessible via this network access manager.
     217
     218    \value UnknownAccessibility     The network accessibility cannot be determined.
     219    \value NotAccessible            The network is not currently accessible, either because there
     220                                    is currently no network coverage or network access has been
     221                                    explicitly disabled by a call to setNetworkAccessible().
     222    \value Accessible               The network is accessible.
     223
     224    \sa networkAccessible
     225*/
     226
     227/*!
     228    \property QNetworkAccessManager::networkAccessible
     229    \brief whether the network is currently accessible via this network access manager.
     230
     231    \since 4.7
     232
     233    If the network is \l {NotAccessible}{not accessible} the network access manager will not
     234    process any new network requests, all such requests will fail with an error.  Requests with
     235    URLs with the file:// scheme will still be processed.
     236
     237    By default the value of this property reflects the physical state of the device.  Applications
     238    may override it to disable all network requests via this network access manager by calling
     239
     240    \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 4
     241
     242    Network requests can be reenabled again by calling
     243
     244    \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 5
     245
     246    \note Calling setNetworkAccessible() does not change the network state.
     247*/
     248
     249/*!
     250    \fn void QNetworkAccessManager::networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible)
     251
     252    This signal is emitted when the value of the \l networkAccessible property changes.
     253    \a accessible is the new network accessibility.
     254*/
     255
     256/*!
     257    \fn void QNetworkAccessManager::networkSessionConnected()
     258
     259    \since 4.7
     260
     261    \internal
     262
     263    This signal is emitted when the status of the network session changes into a usable (Connected)
     264    state. It is used to signal to QNetworkReplys to start or migrate their network operation once
     265    the network session has been opened or finished roaming.
    177266*/
    178267
     
    378467    delete d_func()->proxyFactory;
    379468#endif
     469
     470    // Delete the QNetworkReply children first.
     471    // Else a QAbstractNetworkCache might get deleted in ~QObject
     472    // before a QNetworkReply that accesses the QAbstractNetworkCache
     473    // object in its destructor.
     474    qDeleteAll(findChildren<QNetworkReply *>());
     475    // The other children will be deleted in this ~QObject
     476    // FIXME instead of this "hack" make the QNetworkReplyImpl
     477    // properly watch the cache deletion, e.g. via a QWeakPointer.
    380478}
    381479
     
    535633    \note QNetworkAccessManager takes ownership of the \a cookieJar object.
    536634
    537     QNetworkAccessManager will set the parent of the \a cookieJar
    538     passed to itself, so that the cookie jar is deleted when this
     635    If \a cookieJar is in the same thread as this QNetworkAccessManager,
     636    it will set the parent of the \a cookieJar
     637    so that the cookie jar is deleted when this
    539638    object is deleted as well. If you want to share cookie jars
    540639    between different QNetworkAccessManager objects, you may want to
     
    561660            delete d->cookieJar;
    562661        d->cookieJar = cookieJar;
    563         d->cookieJar->setParent(this);
     662        if (thread() == cookieJar->thread())
     663            d->cookieJar->setParent(this);
    564664    }
    565665}
     
    584684    The contents as well as associated headers will be downloaded.
    585685
    586     \sa post(), put(), deleteResource()
     686    \sa post(), put(), deleteResource(), sendCustomRequest()
    587687*/
    588688QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
     
    603703    HTTPS is undefined and will probably fail.
    604704
    605     \sa get(), put(), deleteResource()
     705    \sa get(), put(), deleteResource(), sendCustomRequest()
    606706*/
    607707QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
     
    644744    files through HTML forms, use the POST mechanism.
    645745
    646     \sa get(), post()
     746    \sa get(), post(), deleteResource(), sendCustomRequest()
    647747*/
    648748QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, QIODevice *data)
     
    675775    HTTP DELETE request.
    676776
    677     \sa get(), post(), put()
     777    \sa get(), post(), put(), sendCustomRequest()
    678778*/
    679779QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request)
    680780{
    681781    return d_func()->postProcess(createRequest(QNetworkAccessManager::DeleteOperation, request));
     782}
     783
     784#ifndef QT_NO_BEARERMANAGEMENT
     785
     786/*!
     787    \since 4.7
     788
     789    Sets the network configuration that will be used when creating the
     790    \l {QNetworkSession}{network session} to \a config.
     791
     792    The network configuration is used to create and open a network session before any request that
     793    requires network access is process.  If no network configuration is explicitly set via this
     794    function the network configuration returned by
     795    QNetworkConfigurationManager::defaultConfiguration() will be used.
     796
     797    To restore the default network configuration set the network configuration to the value
     798    returned from QNetworkConfigurationManager::defaultConfiguration().
     799
     800    \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 2
     801
     802    If an invalid network configuration is set, a network session will not be created.  In this
     803    case network requests will be processed regardless, but may fail.  For example:
     804
     805    \snippet doc/src/snippets/code/src_network_access_qnetworkaccessmanager.cpp 3
     806
     807    \sa configuration(), QNetworkSession
     808*/
     809void QNetworkAccessManager::setConfiguration(const QNetworkConfiguration &config)
     810{
     811    d_func()->createSession(config);
     812}
     813
     814/*!
     815    \since 4.7
     816
     817    Returns the network configuration that will be used to create the
     818    \l {QNetworkSession}{network session} which will be used when processing network requests.
     819
     820    \sa setConfiguration(), activeConfiguration()
     821*/
     822QNetworkConfiguration QNetworkAccessManager::configuration() const
     823{
     824    Q_D(const QNetworkAccessManager);
     825
     826    if (d->networkSession)
     827        return d->networkSession->configuration();
     828    else
     829        return QNetworkConfiguration();
     830}
     831
     832/*!
     833    \since 4.7
     834
     835    Returns the current active network configuration.
     836
     837    If the network configuration returned by configuration() is of type
     838    QNetworkConfiguration::ServiceNetwork this function will return the current active child
     839    network configuration of that configuration.  Otherwise returns the same network configuration
     840    as configuration().
     841
     842    Use this function to return the actual network configuration currently in use by the network
     843    session.
     844
     845    \sa configuration()
     846*/
     847QNetworkConfiguration QNetworkAccessManager::activeConfiguration() const
     848{
     849    Q_D(const QNetworkAccessManager);
     850
     851    if (d->networkSession) {
     852        QNetworkConfigurationManager manager;
     853
     854        return manager.configurationFromIdentifier(
     855            d->networkSession->sessionProperty(QLatin1String("ActiveConfiguration")).toString());
     856    } else {
     857        return QNetworkConfiguration();
     858    }
     859}
     860
     861/*!
     862    \since 4.7
     863
     864    Overrides the reported network accessibility.  If \a accessible is NotAccessible the reported
     865    network accessiblity will always be NotAccessible.  Otherwise the reported network
     866    accessibility will reflect the actual device state.
     867*/
     868void QNetworkAccessManager::setNetworkAccessible(QNetworkAccessManager::NetworkAccessibility accessible)
     869{
     870    Q_D(QNetworkAccessManager);
     871
     872    if (d->networkAccessible != accessible) {
     873        NetworkAccessibility previous = networkAccessible();
     874        d->networkAccessible = accessible;
     875        NetworkAccessibility current = networkAccessible();
     876        if (previous != current)
     877            emit networkAccessibleChanged(current);
     878    }
     879}
     880
     881/*!
     882    \since 4.7
     883
     884    Returns the current network accessibility.
     885*/
     886QNetworkAccessManager::NetworkAccessibility QNetworkAccessManager::networkAccessible() const
     887{
     888    Q_D(const QNetworkAccessManager);
     889
     890    if (d->networkSession) {
     891        // d->online holds online/offline state of this network session.
     892        if (d->online)
     893            return d->networkAccessible;
     894        else
     895            return NotAccessible;
     896    } else {
     897        // Network accessibility is either disabled or unknown.
     898        return (d->networkAccessible == NotAccessible) ? NotAccessible : UnknownAccessibility;
     899    }
     900}
     901
     902#endif // QT_NO_BEARERMANAGEMENT
     903
     904/*!
     905    \since 4.7
     906
     907    Sends a custom request to the server identified by the URL of \a request.
     908
     909    It is the user's responsibility to send a \a verb to the server that is valid
     910    according to the HTTP specification.
     911
     912    This method provides means to send verbs other than the common ones provided
     913    via get() or post() etc., for instance sending an HTTP OPTIONS command.
     914
     915    If \a data is not empty, the contents of the \a data
     916    device will be uploaded to the server; in that case, data must be open for
     917    reading and must remain valid until the finished() signal is emitted for this reply.
     918
     919    \note This feature is currently available for HTTP only.
     920
     921    \sa get(), post(), put(), deleteResource()
     922*/
     923QNetworkReply *QNetworkAccessManager::sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data)
     924{
     925    QNetworkRequest newRequest(request);
     926    newRequest.setAttribute(QNetworkRequest::CustomVerbAttribute, verb);
     927    return d_func()->postProcess(createRequest(QNetworkAccessManager::CustomOperation, newRequest, data));
    682928}
    683929
     
    701947    Q_D(QNetworkAccessManager);
    702948
     949    // 4.7 only hotfix fast path for data:// URLs
     950    // In 4.8 this is solved with QNetworkReplyDataImpl and will work there
     951    // This hotfix is done for not needing a QNetworkSession for data://
     952    if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation)
     953             && (req.url().scheme() == QLatin1String("data"))) {
     954        QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
     955        QNetworkReplyImplPrivate *priv = reply->d_func();
     956        priv->manager = this;
     957        priv->backend = new QNetworkAccessDataBackend();
     958        priv->backend->manager = this->d_func();
     959        priv->backend->setParent(reply);
     960        priv->backend->reply = priv;
     961        priv->setup(op, req, outgoingData);
     962        return reply;
     963    }
     964
    703965    // fast path for GET on file:// URLs
    704966    // Also if the scheme is empty we consider it a file.
    705     // The QNetworkAccessFileBackend will right now only be used
    706     // for PUT or qrc://
     967    // The QNetworkAccessFileBackend will right now only be used for PUT
    707968    if ((op == QNetworkAccessManager::GetOperation || op == QNetworkAccessManager::HeadOperation)
    708969         && (req.url().scheme() == QLatin1String("file")
     970             || req.url().scheme() == QLatin1String("qrc")
    709971             || req.url().scheme().isEmpty())) {
    710972        return new QFileNetworkReply(this, req, op);
    711973    }
     974
     975    // A request with QNetworkRequest::AlwaysCache does not need any bearer management
     976    QNetworkRequest::CacheLoadControl mode =
     977        static_cast<QNetworkRequest::CacheLoadControl>(
     978            req.attribute(QNetworkRequest::CacheLoadControlAttribute,
     979                              QNetworkRequest::PreferNetwork).toInt());
     980    if (mode == QNetworkRequest::AlwaysCache
     981        && (op == QNetworkAccessManager::GetOperation
     982        || op == QNetworkAccessManager::HeadOperation)) {
     983        // FIXME Implement a QNetworkReplyCacheImpl instead, see QTBUG-15106
     984        QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
     985        QNetworkReplyImplPrivate *priv = reply->d_func();
     986        priv->manager = this;
     987        priv->backend = new QNetworkAccessCacheBackend();
     988        priv->backend->manager = this->d_func();
     989        priv->backend->setParent(reply);
     990        priv->backend->reply = priv;
     991        priv->setup(op, req, outgoingData);
     992        return reply;
     993    }
     994
     995#ifndef QT_NO_BEARERMANAGEMENT
     996    // Return a disabled network reply if network access is disabled.
     997    // Except if the scheme is empty or file://.
     998    if (!d->networkAccessible && !(req.url().scheme() == QLatin1String("file") ||
     999                                      req.url().scheme().isEmpty())) {
     1000        return new QDisabledNetworkReply(this, req, op);
     1001    }
     1002
     1003    if (!d->networkSession && (d->initializeSession || !d->networkConfiguration.isEmpty())) {
     1004        QNetworkConfigurationManager manager;
     1005        if (!d->networkConfiguration.isEmpty()) {
     1006            d->createSession(manager.configurationFromIdentifier(d->networkConfiguration));
     1007        } else {
     1008            if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
     1009                d->createSession(manager.defaultConfiguration());
     1010            else
     1011                d->initializeSession = false;
     1012        }
     1013    }
     1014
     1015    if (d->networkSession)
     1016        d->networkSession->setSessionProperty(QLatin1String("AutoCloseSessionTimeout"), -1);
     1017#endif
    7121018
    7131019    QNetworkRequest request = req;
     
    7181024        request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
    7191025    }
    720     if (d->cookieJar) {
    721         QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
    722         if (!cookies.isEmpty())
    723             request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
     1026
     1027    if (static_cast<QNetworkRequest::LoadControl>
     1028        (request.attribute(QNetworkRequest::CookieLoadControlAttribute,
     1029                           QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic) {
     1030        if (d->cookieJar) {
     1031            QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
     1032            if (!cookies.isEmpty())
     1033                request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
     1034        }
    7241035    }
    7251036
     
    7271038    QUrl url = request.url();
    7281039    QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
     1040#ifndef QT_NO_BEARERMANAGEMENT
     1041    if (req.url().scheme() != QLatin1String("file") && !req.url().scheme().isEmpty()) {
     1042        connect(this, SIGNAL(networkSessionConnected()),
     1043                reply, SLOT(_q_networkSessionConnected()));
     1044    }
     1045#endif
    7291046    QNetworkReplyImplPrivate *priv = reply->d_func();
    7301047    priv->manager = this;
    7311048
    7321049    // second step: fetch cached credentials
    733     QNetworkAuthenticationCredential *cred = d->fetchCachedCredentials(url);
    734     if (cred) {
    735         url.setUserName(cred->user);
    736         url.setPassword(cred->password);
    737         priv->urlForLastAuthentication = url;
    738     }
     1050    // This is not done for the time being, we should use signal emissions to request
     1051    // the credentials from cache.
    7391052
    7401053    // third step: find a backend
     
    7491062        priv->backend->reply = priv;
    7501063    }
    751     // fourth step: setup the reply
    752     priv->setup(op, request, outgoingData);
    7531064
    7541065#ifndef QT_NO_OPENSSL
    7551066    reply->setSslConfiguration(request.sslConfiguration());
    7561067#endif
     1068
     1069    // fourth step: setup the reply
     1070    priv->setup(op, request, outgoingData);
     1071
    7571072    return reply;
    7581073}
     
    7611076{
    7621077    Q_Q(QNetworkAccessManager);
     1078
    7631079    QNetworkReply *reply = qobject_cast<QNetworkReply *>(q->sender());
    7641080    if (reply)
    7651081        emit q->finished(reply);
     1082
     1083#ifndef QT_NO_BEARERMANAGEMENT
     1084    if (networkSession && q->findChildren<QNetworkReply *>().count() == 1)
     1085        networkSession->setSessionProperty(QLatin1String("AutoCloseSessionTimeout"), 120000);
     1086#endif
    7661087}
    7671088
     
    8121133    // don't try the cache for the same URL twice in a row
    8131134    // being called twice for the same URL means the authentication failed
    814     if (url != backend->reply->urlForLastAuthentication) {
     1135    // also called when last URL is empty, e.g. on first call
     1136    if (backend->reply->urlForLastAuthentication.isEmpty()
     1137            || url != backend->reply->urlForLastAuthentication) {
    8151138        QNetworkAuthenticationCredential *cred = fetchCachedCredentials(url, authenticator);
    8161139        if (cred) {
     
    8221145    }
    8231146
     1147    // if we emit a signal here in synchronous mode, the user might spin
     1148    // an event loop, which might recurse and lead to problems
     1149    if (backend->isSynchronous())
     1150        return;
     1151
    8241152    backend->reply->urlForLastAuthentication = url;
    8251153    emit q->authenticationRequired(backend->reply->q_func(), authenticator);
    826     addCredentials(url, authenticator);
     1154    cacheCredentials(url, authenticator);
    8271155}
    8281156
     
    8411169    //      or a new function proxyAuthenticationSucceeded(true|false)
    8421170    if (proxy != backend->reply->lastProxyAuthentication) {
    843         QNetworkAuthenticationCredential *cred = fetchCachedCredentials(proxy);
     1171        QNetworkAuthenticationCredential *cred = fetchCachedProxyCredentials(proxy);
    8441172        if (cred) {
    8451173            authenticator->setUser(cred->user);
     
    8491177    }
    8501178
     1179    // if we emit a signal here in synchronous mode, the user might spin
     1180    // an event loop, which might recurse and lead to problems
     1181    if (backend->isSynchronous())
     1182        return;
     1183
    8511184    backend->reply->lastProxyAuthentication = proxy;
    8521185    emit q->proxyAuthenticationRequired(proxy, authenticator);
    853     addCredentials(proxy, authenticator);
    854 }
    855 
    856 void QNetworkAccessManagerPrivate::addCredentials(const QNetworkProxy &p,
     1186    cacheProxyCredentials(proxy, authenticator);
     1187}
     1188
     1189void QNetworkAccessManagerPrivate::cacheProxyCredentials(const QNetworkProxy &p,
    8571190                                                  const QAuthenticator *authenticator)
    8581191{
     
    8911224
    8921225QNetworkAuthenticationCredential *
    893 QNetworkAccessManagerPrivate::fetchCachedCredentials(const QNetworkProxy &p,
     1226QNetworkAccessManagerPrivate::fetchCachedProxyCredentials(const QNetworkProxy &p,
    8941227                                                     const QAuthenticator *authenticator)
    8951228{
     
    9431276#endif
    9441277
    945 void QNetworkAccessManagerPrivate::addCredentials(const QUrl &url,
     1278void QNetworkAccessManagerPrivate::cacheCredentials(const QUrl &url,
    9461279                                                  const QAuthenticator *authenticator)
    9471280{
     
    10161349}
    10171350
     1351#ifndef QT_NO_BEARERMANAGEMENT
     1352void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &config)
     1353{
     1354    Q_Q(QNetworkAccessManager);
     1355
     1356    initializeSession = false;
     1357
     1358    if (!config.isValid()) {
     1359        networkSession.clear();
     1360        online = false;
     1361
     1362        if (networkAccessible == QNetworkAccessManager::NotAccessible)
     1363            emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
     1364        else
     1365            emit q->networkAccessibleChanged(QNetworkAccessManager::UnknownAccessibility);
     1366
     1367        return;
     1368    }
     1369
     1370    networkSession = QSharedNetworkSessionManager::getSession(config);
     1371
     1372    QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection);
     1373    //QueuedConnection is used to avoid deleting the networkSession inside its closed signal
     1374    QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection);
     1375    QObject::connect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)),
     1376                     q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection);
     1377
     1378    _q_networkSessionStateChanged(networkSession->state());
     1379}
     1380
     1381void QNetworkAccessManagerPrivate::_q_networkSessionClosed()
     1382{
     1383    if (networkSession) {
     1384        networkConfiguration = networkSession->configuration().identifier();
     1385
     1386        networkSession.clear();
     1387    }
     1388}
     1389
     1390void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession::State state)
     1391{
     1392    Q_Q(QNetworkAccessManager);
     1393
     1394    if (state == QNetworkSession::Connected)
     1395        emit q->networkSessionConnected();
     1396    if (online) {
     1397        if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) {
     1398            online = false;
     1399            emit q->networkAccessibleChanged(QNetworkAccessManager::NotAccessible);
     1400        }
     1401    } else {
     1402        if (state == QNetworkSession::Connected || state == QNetworkSession::Roaming) {
     1403            online = true;
     1404            emit q->networkAccessibleChanged(networkAccessible);
     1405        }
     1406    }
     1407}
     1408#endif // QT_NO_BEARERMANAGEMENT
     1409
    10181410QT_END_NAMESPACE
    10191411
  • trunk/src/network/access/qnetworkaccessmanager.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6363class QNetworkProxyFactory;
    6464class QSslError;
     65#if !defined(QT_NO_BEARERMANAGEMENT) && !defined(QT_MOBILITY_BEARER)
     66class QNetworkConfiguration;
     67#endif
    6568
    6669class QNetworkReplyImplPrivate;
     
    6972{
    7073    Q_OBJECT
     74
     75#ifndef QT_NO_BEARERMANAGEMENT
     76    Q_PROPERTY(NetworkAccessibility networkAccessible READ networkAccessible WRITE setNetworkAccessible NOTIFY networkAccessibleChanged)
     77#endif
     78
    7179public:
    7280    enum Operation {
     
    7684        PostOperation,
    7785        DeleteOperation,
     86        CustomOperation,
    7887
    7988        UnknownOperation = 0
    8089    };
     90
     91#ifndef QT_NO_BEARERMANAGEMENT
     92    enum NetworkAccessibility {
     93        UnknownAccessibility = -1,
     94        NotAccessible = 0,
     95        Accessible = 1
     96    };
     97#endif
    8198
    8299    explicit QNetworkAccessManager(QObject *parent = 0);
     
    103120    QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data);
    104121    QNetworkReply *deleteResource(const QNetworkRequest &request);
     122    QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data = 0);
     123
     124#if !defined(QT_NO_BEARERMANAGEMENT) && !defined(QT_MOBILITY_BEARER)
     125    void setConfiguration(const QNetworkConfiguration &config);
     126    QNetworkConfiguration configuration() const;
     127    QNetworkConfiguration activeConfiguration() const;
     128#endif
     129
     130#ifndef QT_NO_BEARERMANAGEMENT
     131    void setNetworkAccessible(NetworkAccessibility accessible);
     132    NetworkAccessibility networkAccessible() const;
     133#endif
    105134
    106135Q_SIGNALS:
     
    114143#endif
    115144
     145#if !defined(QT_NO_BEARERMANAGEMENT) && !defined(QT_MOBILITY_BEARER)
     146    void networkSessionConnected();
     147#endif
     148
     149#ifndef QT_NO_BEARERMANAGEMENT
     150    void networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible);
     151#endif
     152
    116153protected:
    117154    virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &request,
     
    123160    Q_PRIVATE_SLOT(d_func(), void _q_replyFinished())
    124161    Q_PRIVATE_SLOT(d_func(), void _q_replySslErrors(QList<QSslError>))
     162#if !defined(QT_NO_BEARERMANAGEMENT) && !defined(QT_MOBILITY_BEARER)
     163    Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed())
     164    Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State))
     165#endif
    125166};
    126167
  • trunk/src/network/access/qnetworkaccessmanager_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5959#include "private/qobject_p.h"
    6060#include "QtNetwork/qnetworkproxy.h"
     61#include "QtNetwork/qnetworksession.h"
    6162
    6263QT_BEGIN_NAMESPACE
     
    7576          proxyFactory(0),
    7677#endif
     78#ifndef QT_NO_BEARERMANAGEMENT
     79          networkSession(0),
     80          networkAccessible(QNetworkAccessManager::Accessible),
     81          online(false),
     82          initializeSession(true),
     83#endif
    7784          cookieJarCreated(false)
    7885    { }
     
    8592
    8693    void authenticationRequired(QNetworkAccessBackend *backend, QAuthenticator *authenticator);
    87     void addCredentials(const QUrl &url, const QAuthenticator *auth);
     94    void cacheCredentials(const QUrl &url, const QAuthenticator *auth);
    8895    QNetworkAuthenticationCredential *fetchCachedCredentials(const QUrl &url,
    8996                                                             const QAuthenticator *auth = 0);
     
    9299    void proxyAuthenticationRequired(QNetworkAccessBackend *backend, const QNetworkProxy &proxy,
    93100                                     QAuthenticator *authenticator);
    94     void addCredentials(const QNetworkProxy &proxy, const QAuthenticator *auth);
    95     QNetworkAuthenticationCredential *fetchCachedCredentials(const QNetworkProxy &proxy,
     101    void cacheProxyCredentials(const QNetworkProxy &proxy, const QAuthenticator *auth);
     102    QNetworkAuthenticationCredential *fetchCachedProxyCredentials(const QNetworkProxy &proxy,
    96103                                                             const QAuthenticator *auth = 0);
    97104    QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query);
     
    99106
    100107    QNetworkAccessBackend *findBackend(QNetworkAccessManager::Operation op, const QNetworkRequest &request);
     108
     109#ifndef QT_NO_BEARERMANAGEMENT
     110    void createSession(const QNetworkConfiguration &config);
     111
     112    void _q_networkSessionClosed();
     113    void _q_networkSessionNewConfigurationActivated();
     114    void _q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &config,
     115                                                        bool isSeamless);
     116    void _q_networkSessionStateChanged(QNetworkSession::State state);
     117#endif
    101118
    102119    // this is the cache for storing downloaded files
     
    111128#endif
    112129
     130#ifndef QT_NO_BEARERMANAGEMENT
     131    QSharedPointer<QNetworkSession> networkSession;
     132    QString networkConfiguration;
     133    QNetworkAccessManager::NetworkAccessibility networkAccessible;
     134    bool online;
     135    bool initializeSession;
     136#endif
     137
    113138    bool cookieJarCreated;
    114 
    115139
    116140    // this cache can be used by individual backends to cache e.g. their TCP connections to a server
  • trunk/src/network/access/qnetworkcookie.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    992992
    993993                    QString normalizedDomain = QUrl::fromAce(QUrl::toAce(QString::fromUtf8(rawDomain)));
     994                    if (normalizedDomain.isEmpty() && !rawDomain.isEmpty())
     995                        return result;
    994996                    cookie.setDomain(maybeLeadingDot + normalizedDomain);
    995997                } else if (field.first == "max-age") {
  • trunk/src/network/access/qnetworkcookie.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qnetworkcookie_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qnetworkcookiejar.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4141
    4242#include "qnetworkcookiejar.h"
     43#include "qnetworkcookiejartlds_p.h"
    4344#include "qnetworkcookiejar_p.h"
    4445
     
    158159    url object.
    159160
    160     Returns true if one or more cookes are set for url otherwise false.
     161    Returns true if one or more cookies are set for \a url,
     162    otherwise false.
    161163
    162164    If a cookie already exists in the cookie jar, it will be
     
    209211            QString domain = cookie.domain();
    210212            if (!(isParentDomain(domain, defaultDomain)
    211                 || isParentDomain(defaultDomain, domain))) {
    212                     continue;           // not accepted
    213             }
    214 
    215             // reject if domain is like ".com"
    216             // (i.e., reject if domain does not contain embedded dots, see RFC 2109 section 4.3.2)
    217             // this is just a rudimentary check and does not cover all cases
    218             if (domain.lastIndexOf(QLatin1Char('.')) == 0)
    219                 continue;           // not accepted
    220 
     213                || isParentDomain(defaultDomain, domain)))
     214                continue; // not accepted
     215
     216            // the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2
     217            // redundant; the "leading dot" rule has been relaxed anyway, see above
     218            // we remove the leading dot for this check
     219            if (QNetworkCookieJarPrivate::isEffectiveTLD(domain.remove(0, 1)))
     220                continue; // not accepted
    221221        }
    222222
     
    251251    differing paths, the one with longer path is returned before the
    252252    one with shorter path. In other words, this function returns
    253     cookies sorted by path length.
     253    cookies sorted decreasingly by path length.
    254254
    255255    The default QNetworkCookieJar class implements only a very basic
     
    270270    QDateTime now = QDateTime::currentDateTime();
    271271    QList<QNetworkCookie> result;
     272    bool isEncrypted = url.scheme().toLower() == QLatin1String("https");
    272273
    273274    // scan our cookies for something that matches
     
    280281            continue;
    281282        if (!(*it).isSessionCookie() && (*it).expirationDate() < now)
     283            continue;
     284        if ((*it).isSecure() && !isEncrypted)
    282285            continue;
    283286
     
    302305}
    303306
     307bool QNetworkCookieJarPrivate::isEffectiveTLD(const QString &domain)
     308{
     309    // for domain 'foo.bar.com':
     310    // 1. return if TLD table contains 'foo.bar.com'
     311    if (containsTLDEntry(domain))
     312        return true;
     313
     314    if (domain.contains(QLatin1Char('.'))) {
     315        int count = domain.size() - domain.indexOf(QLatin1Char('.'));
     316        QString wildCardDomain;
     317        wildCardDomain.reserve(count + 1);
     318        wildCardDomain.append(QLatin1Char('*'));
     319        wildCardDomain.append(domain.right(count));
     320        // 2. if table contains '*.bar.com',
     321        // test if table contains '!foo.bar.com'
     322        if (containsTLDEntry(wildCardDomain)) {
     323            QString exceptionDomain;
     324            exceptionDomain.reserve(domain.size() + 1);
     325            exceptionDomain.append(QLatin1Char('!'));
     326            exceptionDomain.append(domain);
     327            return (! containsTLDEntry(exceptionDomain));
     328        }
     329    }
     330    return false;
     331}
     332
     333bool QNetworkCookieJarPrivate::containsTLDEntry(const QString &entry)
     334{
     335    int index = qHash(entry) % tldCount;
     336    int currentDomainIndex = tldIndices[index];
     337    while (currentDomainIndex < tldIndices[index+1]) {
     338        QString currentEntry = QString::fromUtf8(tldData + currentDomainIndex);
     339        if (currentEntry == entry)
     340            return true;
     341        currentDomainIndex += qstrlen(tldData + currentDomainIndex) + 1; // +1 for the ending \0
     342    }
     343    return false;
     344}
     345
    304346QT_END_NAMESPACE
  • trunk/src/network/access/qnetworkcookiejar.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qnetworkcookiejar_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    6464    QList<QNetworkCookie> allCookies;
    6565
     66    static bool Q_AUTOTEST_EXPORT isEffectiveTLD(const QString &domain);
     67    static bool containsTLDEntry(const QString &entry);
     68
    6669    Q_DECLARE_PUBLIC(QNetworkCookieJar)
    6770};
  • trunk/src/network/access/qnetworkdiskcache.cpp

    r774 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    512512    QDirIterator it(cacheDirectory(), filters, QDirIterator::Subdirectories);
    513513
    514     // performance tweak: we store the size together with the name in
    515     // order to avoid querying the size again before the file is deleted
    516     typedef QPair<QString, qint64> ExpireInfo;
    517 
    518     QMultiMap<QDateTime, ExpireInfo> cacheItems;
     514    QMultiMap<QDateTime, QString> cacheItems;
    519515    qint64 totalSize = 0;
    520516    while (it.hasNext()) {
     
    523519        QString fileName = info.fileName();
    524520        if (fileName.endsWith(CACHE_POSTFIX) && fileName.startsWith(CACHE_PREFIX)) {
    525             ExpireInfo item = qMakePair(path, info.size());
    526             cacheItems.insert(info.created(), item);
    527             totalSize += item.second;
     521            cacheItems.insert(info.created(), path);
     522            totalSize += info.size();
    528523        }
    529524    }
     
    531526    int removedFiles = 0;
    532527    qint64 goal = (maximumCacheSize() * 9) / 10;
    533     QMultiMap<QDateTime, ExpireInfo>::const_iterator i = cacheItems.constBegin();
     528    QMultiMap<QDateTime, QString>::const_iterator i = cacheItems.constBegin();
    534529    while (i != cacheItems.constEnd()) {
    535530        if (totalSize < goal)
    536531            break;
    537         const ExpireInfo &item = i.value();
    538         QFile::remove(item.first);
    539         totalSize -= item.second;
     532        QString name = i.value();
     533        QFile file(name);
     534        qint64 size = file.size();
     535        file.remove();
     536        totalSize -= size;
    540537        ++removedFiles;
    541538        ++i;
  • trunk/src/network/access/qnetworkdiskcache.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qnetworkdiskcache_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qnetworkreply.cpp

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    126126    should have been emitted.
    127127
     128    \value TemporaryNetworkFailureError the connection was broken due
     129    to disconnection from the network, however the system has initiated
     130    roaming to another access point. The request should be resubmitted
     131    and will be processed as soon as the connection is re-established.
     132
    128133    \value ProxyConnectionRefusedError the connection to the proxy
    129134    server was refused (the proxy server is not accepting requests)
     
    279284    bytesTotal. At that time, \a bytesTotal will not be -1.
    280285
    281     This signal is suitable to connecting to QProgressBar::setValue()
    282     to update the QProgressBar that provides user feedback.
    283 
    284286    \sa downloadProgress()
    285287*/
     
    301303    The download is finished when \a bytesReceived is equal to \a
    302304    bytesTotal. At that time, \a bytesTotal will not be -1.
    303 
    304     This signal is suitable to connecting to QProgressBar::setValue()
    305     to update the QProgressBar that provides user feedback.
    306305
    307306    Note that the values of both \a bytesReceived and \a bytesTotal
     
    532531        return it->second;
    533532    return QByteArray();
     533}
     534
     535/*! \typedef QNetworkReply::RawHeaderPair
     536
     537  RawHeaderPair is a QPair<QByteArray, QByteArray> where the first
     538  QByteArray is the header name and the second is the header.
     539 */
     540
     541/*!
     542  Returns a list of raw header pairs.
     543 */
     544const QList<QNetworkReply::RawHeaderPair>& QNetworkReply::rawHeaderPairs() const
     545{
     546    Q_D(const QNetworkReply);
     547    return d->rawHeaders;
    534548}
    535549
  • trunk/src/network/access/qnetworkreply.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7878        OperationCanceledError,
    7979        SslHandshakeFailedError,
     80        TemporaryNetworkFailureError,
    8081        UnknownNetworkError = 99,
    8182
     
    129130    QByteArray rawHeader(const QByteArray &headerName) const;
    130131
     132    typedef QPair<QByteArray, QByteArray> RawHeaderPair;
     133    const QList<RawHeaderPair>& rawHeaderPairs() const;
     134
    131135    // attributes
    132136    QVariant attribute(QNetworkRequest::Attribute code) const;
  • trunk/src/network/access/qnetworkreply_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
  • trunk/src/network/access/qnetworkreplyimpl.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    4747#include "QtCore/qdatetime.h"
    4848#include "QtNetwork/qsslconfiguration.h"
     49#include "QtNetwork/qnetworksession.h"
    4950#include "qnetworkaccesshttpbackend_p.h"
     51#include "qnetworkaccessmanager_p.h"
    5052
    5153#include <QtCore/QCoreApplication>
     
    5860      cacheEnabled(false), cacheSaveDevice(0),
    5961      notificationHandlingPaused(false),
    60       bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1),
     62      bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), preMigrationDownloaded(-1),
    6163      httpStatusCode(0),
    6264      state(Idle)
     
    8385    }
    8486
    85     backend->open();
    86     if (state != Finished) {
    87         if (operation == QNetworkAccessManager::GetOperation)
    88             pendingNotifications.append(NotifyDownstreamReadyWrite);
    89 
    90         handleNotifications();
     87#ifndef QT_NO_BEARERMANAGEMENT
     88    if (!backend->start()) { // ### we should call that method even if bearer is not used
     89        // backend failed to start because the session state is not Connected.
     90        // QNetworkAccessManager will call reply->backend->start() again for us when the session
     91        // state changes.
     92        state = WaitingForSession;
     93
     94        QNetworkSession *session = manager->d_func()->networkSession.data();
     95
     96        if (session) {
     97            Q_Q(QNetworkReplyImpl);
     98
     99            QObject::connect(session, SIGNAL(error(QNetworkSession::SessionError)),
     100                             q, SLOT(_q_networkSessionFailed()));
     101
     102            if (!session->isOpen())
     103                session->open();
     104        } else {
     105            qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
     106        }
     107
     108        return;
     109    }
     110#endif
     111
     112    if (backend && backend->isSynchronous()) {
     113        state = Finished;
     114    } else {
     115        if (state != Finished) {
     116            if (operation == QNetworkAccessManager::GetOperation)
     117                pendingNotifications.append(NotifyDownstreamReadyWrite);
     118
     119            handleNotifications();
     120        }
    91121    }
    92122}
     
    135165    lastBytesDownloaded = bytesDownloaded;
    136166    QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
     167    if (preMigrationDownloaded != Q_INT64_C(-1))
     168        totalSize = totalSize.toLongLong() + preMigrationDownloaded;
    137169    pauseNotificationHandling();
    138170    emit q->downloadProgress(bytesDownloaded,
     
    207239}
    208240
     241#ifndef QT_NO_BEARERMANAGEMENT
     242void QNetworkReplyImplPrivate::_q_networkSessionConnected()
     243{
     244    Q_Q(QNetworkReplyImpl);
     245
     246    if (manager.isNull())
     247        return;
     248
     249    QNetworkSession *session = manager->d_func()->networkSession.data();
     250    if (!session)
     251        return;
     252
     253    if (session->state() != QNetworkSession::Connected)
     254        return;
     255
     256    switch (state) {
     257    case QNetworkReplyImplPrivate::Buffering:
     258    case QNetworkReplyImplPrivate::Working:
     259    case QNetworkReplyImplPrivate::Reconnecting:
     260        // Migrate existing downloads to new network connection.
     261        migrateBackend();
     262        break;
     263    case QNetworkReplyImplPrivate::WaitingForSession:
     264        // Start waiting requests.
     265        QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
     266        break;
     267    default:
     268        ;
     269    }
     270}
     271
     272void QNetworkReplyImplPrivate::_q_networkSessionFailed()
     273{
     274    // Abort waiting and working replies.
     275    if (state == WaitingForSession || state == Working) {
     276        state = Working;
     277        error(QNetworkReplyImpl::UnknownNetworkError,
     278              QCoreApplication::translate("QNetworkReply", "Network session error."));
     279        finished();
     280    }
     281}
     282#endif
     283
    209284void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req,
    210285                                     QIODevice *data)
     
    217292    operation = op;
    218293
    219     if (outgoingData && backend) {
     294    q->QIODevice::open(QIODevice::ReadOnly);
     295    // Internal code that does a HTTP reply for the synchronous Ajax
     296    // in QtWebKit.
     297    QVariant synchronousHttpAttribute = req.attribute(
     298            static_cast<QNetworkRequest::Attribute>(QNetworkRequest::DownloadBufferAttribute + 1));
     299    if (backend && synchronousHttpAttribute.toBool()) {
     300        backend->setSynchronous(true);
     301        if (outgoingData && outgoingData->isSequential()) {
     302            outgoingDataBuffer = new QRingBuffer();
     303            QByteArray data;
     304            do {
     305                data = outgoingData->readAll();
     306                if (data.isEmpty())
     307                    break;
     308                outgoingDataBuffer->append(data);
     309            } while (1);
     310        }
     311    }
     312    if (outgoingData && backend && !backend->isSynchronous()) {
    220313        // there is data to be uploaded, e.g. HTTP POST.
    221314
     
    228321            bool bufferingDisallowed =
    229322                    req.attribute(QNetworkRequest::DoNotBufferUploadDataAttribute,
    230                                              false).toBool();
     323                                  false).toBool();
    231324
    232325            if (bufferingDisallowed) {
     
    252345        // for HTTP, we want to send out the request as fast as possible to the network, without
    253346        // invoking methods in a QueuedConnection
    254         if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
     347#ifndef QT_NO_HTTP
     348        if (qobject_cast<QNetworkAccessHttpBackend *>(backend) || (backend && backend->isSynchronous())) {
    255349            _q_startOperation();
    256350        } else {
    257351            QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
    258352        }
    259     }
    260 
    261     q->QIODevice::open(QIODevice::ReadOnly);
     353#else
     354        if (backend && backend->isSynchronous())
     355            _q_startOperation();
     356        else
     357            QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
     358#endif // QT_NO_HTTP
     359        }
    262360}
    263361
     
    472570
    473571    QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
     572    if (preMigrationDownloaded != Q_INT64_C(-1))
     573        totalSize = totalSize.toLongLong() + preMigrationDownloaded;
    474574    pauseNotificationHandling();
    475575    emit q->downloadProgress(bytesDownloaded,
     
    512612void QNetworkReplyImplPrivate::appendDownstreamData(const QByteArray &data)
    513613{
     614    Q_UNUSED(data)
    514615    // TODO implement
    515616
     
    522623{
    523624    Q_Q(QNetworkReplyImpl);
    524     if (state == Finished || state == Aborted)
    525         return;
     625
     626    if (state == Finished || state == Aborted || state == WaitingForSession)
     627        return;
     628
     629    pauseNotificationHandling();
     630    QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
     631    if (preMigrationDownloaded != Q_INT64_C(-1))
     632        totalSize = totalSize.toLongLong() + preMigrationDownloaded;
     633
     634    if (!manager.isNull()) {
     635#ifndef QT_NO_BEARERMANAGEMENT
     636        QNetworkSession *session = manager->d_func()->networkSession.data();
     637        if (session && session->state() == QNetworkSession::Roaming &&
     638            state == Working && errorCode != QNetworkReply::OperationCanceledError) {
     639            // only content with a known size will fail with a temporary network failure error
     640            if (!totalSize.isNull()) {
     641                if (bytesDownloaded != totalSize) {
     642                    if (migrateBackend()) {
     643                        // either we are migrating or the request is finished/aborted
     644                        if (state == Reconnecting || state == WaitingForSession) {
     645                            resumeNotificationHandling();
     646                            return; // exit early if we are migrating.
     647                        }
     648                    } else {
     649                        error(QNetworkReply::TemporaryNetworkFailureError,
     650                              QNetworkReply::tr("Temporary network failure."));
     651                    }
     652                }
     653            }
     654        }
     655#endif
     656    }
     657    resumeNotificationHandling();
    526658
    527659    state = Finished;
     
    529661
    530662    pauseNotificationHandling();
    531     QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
    532663    if (totalSize.isNull() || totalSize == -1) {
    533664        emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
     
    538669    resumeNotificationHandling();
    539670
    540     completeCacheSave();
     671    // if we don't know the total size of or we received everything save the cache
     672    if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
     673        completeCacheSave();
    541674
    542675    // note: might not be a good idea, since users could decide to delete us
     
    565698{
    566699    Q_Q(QNetworkReplyImpl);
    567     // do we have cookies?
    568     if (cookedHeaders.contains(QNetworkRequest::SetCookieHeader) && !manager.isNull()) {
     700    // 1. do we have cookies?
     701    // 2. are we allowed to set them?
     702    if (cookedHeaders.contains(QNetworkRequest::SetCookieHeader) && !manager.isNull()
     703        && (static_cast<QNetworkRequest::LoadControl>
     704            (request.attribute(QNetworkRequest::CookieSaveControlAttribute,
     705                               QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic)) {
    569706        QList<QNetworkCookie> cookies =
    570707            qvariant_cast<QList<QNetworkCookie> >(cookedHeaders.value(QNetworkRequest::SetCookieHeader));
     
    662799    d->finished();
    663800}
     801
     802bool QNetworkReplyImpl::canReadLine () const
     803{
     804    Q_D(const QNetworkReplyImpl);
     805    return QNetworkReply::canReadLine() || d->readBuffer.canReadLine();
     806}
     807
    664808
    665809/*!
     
    751895}
    752896
     897/*
     898    Migrates the backend of the QNetworkReply to a new network connection if required.  Returns
     899    true if the reply is migrated or it is not required; otherwise returns false.
     900*/
     901bool QNetworkReplyImplPrivate::migrateBackend()
     902{
     903    Q_Q(QNetworkReplyImpl);
     904
     905    // Network reply is already finished or aborted, don't need to migrate.
     906    if (state == Finished || state == Aborted)
     907        return true;
     908
     909    // Backend does not support resuming download.
     910    if (!backend->canResume())
     911        return false;
     912
     913    // Request has outgoing data, not migrating.
     914    if (outgoingData)
     915        return false;
     916
     917    // Request is serviced from the cache, don't need to migrate.
     918    if (copyDevice)
     919        return true;
     920
     921    state = QNetworkReplyImplPrivate::Reconnecting;
     922
     923    if (backend) {
     924        delete backend;
     925        backend = 0;
     926    }
     927
     928    cookedHeaders.clear();
     929    rawHeaders.clear();
     930
     931    preMigrationDownloaded = bytesDownloaded;
     932
     933    backend = manager->d_func()->findBackend(operation, request);
     934
     935    if (backend) {
     936        backend->setParent(q);
     937        backend->reply = this;
     938        backend->setResumeOffset(bytesDownloaded);
     939    }
     940
     941#ifndef QT_NO_HTTP
     942    if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
     943        _q_startOperation();
     944    } else {
     945        QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
     946    }
     947#else
     948    QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
     949#endif // QT_NO_HTTP
     950
     951    return true;
     952}
     953
     954#ifndef QT_NO_BEARERMANAGEMENT
     955QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent,
     956                                             const QNetworkRequest &req,
     957                                             QNetworkAccessManager::Operation op)
     958:   QNetworkReply(parent)
     959{
     960    setRequest(req);
     961    setUrl(req.url());
     962    setOperation(op);
     963
     964    qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
     965
     966    QString msg = QCoreApplication::translate("QNetworkAccessManager",
     967                                              "Network access is disabled.");
     968    setError(UnknownNetworkError, msg);
     969
     970    QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
     971        Q_ARG(QNetworkReply::NetworkError, UnknownNetworkError));
     972    QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
     973}
     974
     975QDisabledNetworkReply::~QDisabledNetworkReply()
     976{
     977}
     978#endif
     979
    753980QT_END_NAMESPACE
    754981
  • trunk/src/network/access/qnetworkreplyimpl_p.h

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7878    virtual void abort();
    7979
    80     // reimplemented from QNetworkReply
     80    // reimplemented from QNetworkReply / QIODevice
    8181    virtual void close();
    8282    virtual qint64 bytesAvailable() const;
    8383    virtual void setReadBufferSize(qint64 size);
     84    virtual bool canReadLine () const;
    8485
    8586    virtual qint64 readData(char *data, qint64 maxlen);
     
    99100    Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingData())
    100101    Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingDataFinished())
     102#ifndef QT_NO_BEARERMANAGEMENT
     103    Q_PRIVATE_SLOT(d_func(), void _q_networkSessionConnected())
     104    Q_PRIVATE_SLOT(d_func(), void _q_networkSessionFailed())
     105#endif
    101106};
    102107
     
    111116
    112117    enum State {
    113         Idle,
    114         Buffering,
    115         Working,
    116         Finished,
    117         Aborted
     118        Idle,               // The reply is idle.
     119        Buffering,          // The reply is buffering outgoing data.
     120        Working,            // The reply is uploading/downloading data.
     121        Finished,           // The reply has finished.
     122        Aborted,            // The reply has been aborted.
     123        WaitingForSession,  // The reply is waiting for the session to open before connecting.
     124        Reconnecting        // The reply will reconnect to once roaming has completed.
    118125    };
    119126
     
    129136    void _q_bufferOutgoingData();
    130137    void _q_bufferOutgoingDataFinished();
     138#ifndef QT_NO_BEARERMANAGEMENT
     139    void _q_networkSessionConnected();
     140    void _q_networkSessionFailed();
     141#endif
    131142
    132143    void setup(QNetworkAccessManager::Operation op, const QNetworkRequest &request,
     
    167178    QAbstractNetworkCache *networkCache() const;
    168179
     180    bool migrateBackend();
     181
    169182    bool cacheEnabled;
    170183    QIODevice *cacheSaveDevice;
     
    183196    qint64 lastBytesDownloaded;
    184197    qint64 bytesUploaded;
     198    qint64 preMigrationDownloaded;
    185199
    186200    QString httpReasonPhrase;
     
    192206};
    193207
     208#ifndef QT_NO_BEARERMANAGEMENT
     209class QDisabledNetworkReply : public QNetworkReply
     210{
     211    Q_OBJECT
     212
     213public:
     214    QDisabledNetworkReply(QObject *parent, const QNetworkRequest &req,
     215                          QNetworkAccessManager::Operation op);
     216    ~QDisabledNetworkReply();
     217
     218    void abort() { }
     219protected:
     220    qint64 readData(char *, qint64) { return -1; }
     221};
     222#endif
     223
    194224QT_END_NAMESPACE
    195225
  • trunk/src/network/access/qnetworkrequest.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    106106/*!
    107107    \enum QNetworkRequest::Attribute
    108 
     108    \since 4.7
     109   
    109110    Attribute codes for the QNetworkRequest and QNetworkReply.
    110111
     
    175176        header must be set.
    176177
    177      \value HttpPipeliningAllowedAttribute
     178    \value HttpPipeliningAllowedAttribute
    178179        Requests only, type: QVariant::Bool (default: false)
    179180        Indicates whether the QNetworkAccessManager code is
    180181        allowed to use HTTP pipelining with this request.
    181182
    182      \value HttpPipeliningWasUsedAttribute
     183    \value HttpPipeliningWasUsedAttribute
    183184        Replies only, type: QVariant::Bool
    184185        Indicates whether the HTTP pipelining was used for receiving
    185186        this reply.
     187
     188    \value CustomVerbAttribute
     189       Requests only, type: QVariant::ByteArray
     190       Holds the value for the custom HTTP verb to send (destined for usage
     191       of other verbs than GET, POST, PUT and DELETE). This verb is set
     192       when calling QNetworkAccessManager::sendCustomRequest().
     193
     194    \value CookieLoadControlAttribute
     195        Requests only, type: QVariant::Int (default: QNetworkRequest::Automatic)
     196        Indicates whether to send 'Cookie' headers in the request.
     197        This attribute is set to false by QtWebKit when creating a cross-origin
     198        XMLHttpRequest where withCredentials has not been set explicitly to true by the
     199        Javascript that created the request.
     200        See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag}{here} for more information.
     201        (This value was introduced in 4.7.)
     202
     203    \value CookieSaveControlAttribute
     204        Requests only, type: QVariant::Int (default: QNetworkRequest::Automatic)
     205        Indicates whether to save 'Cookie' headers received from the server in reply
     206        to the request.
     207        This attribute is set to false by QtWebKit when creating a cross-origin
     208        XMLHttpRequest where withCredentials has not been set explicitly to true by the
     209        Javascript that created the request.
     210        See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information.
     211        (This value was introduced in 4.7.)
     212
     213    \value AuthenticationReuseAttribute
     214        Requests only, type: QVariant::Int (default: QNetworkRequest::Automatic)
     215        Indicates whether to use cached authorization credentials in the request,
     216        if available. If this is set to QNetworkRequest::Manual and the authentication
     217        mechanism is 'Basic' or 'Digest', Qt will not send an an 'Authorization' HTTP
     218        header with any cached credentials it may have for the request's URL.
     219        This attribute is set to QNetworkRequest::Manual by QtWebKit when creating a cross-origin
     220        XMLHttpRequest where withCredentials has not been set explicitly to true by the
     221        Javascript that created the request.
     222        See \l{http://www.w3.org/TR/XMLHttpRequest2/#credentials-flag} {here} for more information.
     223        (This value was introduced in 4.7.)
     224
     225    \omitvalue MaximumDownloadBufferSizeAttribute
     226
     227    \omitvalue DownloadBufferAttribute
    186228
    187229    \value User
     
    217259*/
    218260
     261/*!
     262    \enum QNetworkRequest::LoadControl
     263    \since 4.7
     264
     265    Indicates if an aspect of the request's loading mechanism has been
     266    manually overridden, e.g. by QtWebKit.
     267
     268    \value Automatic            default value: indicates default behaviour.
     269
     270    \value Manual               indicates behaviour has been manually overridden.
     271*/
     272
    219273class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate
    220274{
    221275public:
    222276    inline QNetworkRequestPrivate()
     277        : priority(QNetworkRequest::NormalPriority)
    223278#ifndef QT_NO_OPENSSL
    224         : sslConfiguration(0)
     279        , sslConfiguration(0)
    225280#endif
    226281    { qRegisterMetaType<QNetworkRequest>(); }
     
    237292    {
    238293        url = other.url;
     294        priority = other.priority;
    239295
    240296#ifndef QT_NO_OPENSSL
     
    248304    {
    249305        return url == other.url &&
     306            priority == other.priority &&
    250307            rawHeaders == other.rawHeaders &&
    251308            attributes == other.attributes;
     
    254311
    255312    QUrl url;
     313    QNetworkRequest::Priority priority;
    256314#ifndef QT_NO_OPENSSL
    257315    mutable QSslConfiguration *sslConfiguration;
     
    517575{
    518576    return d->originatingObject.data();
     577}
     578
     579/*!
     580    \since 4.7
     581
     582    Return the priority of this request.
     583
     584    \sa setPriority()
     585*/
     586QNetworkRequest::Priority QNetworkRequest::priority() const
     587{
     588    return d->priority;
     589}
     590
     591/*! \enum QNetworkRequest::Priority
     592
     593  \since 4.7
     594 
     595  This enum lists the possible network request priorities.
     596
     597  \value HighPriority   High priority
     598  \value NormalPriority Normal priority
     599  \value LowPriority    Low priority
     600 */
     601
     602/*!
     603    \since 4.7
     604
     605    Set the priority of this request to \a priority.
     606
     607    \note The \a priority is only a hint to the network access
     608    manager.  It can use it or not. Currently it is used for HTTP to
     609    decide which request should be sent first to a server.
     610
     611    \sa priority()
     612*/
     613void QNetworkRequest::setPriority(Priority priority)
     614{
     615    d->priority = priority;
    519616}
    520617
     
    803900    QNetworkRequest::KnownHeaders parsedKey = parseHeaderName(key);
    804901    if (parsedKey != QNetworkRequest::KnownHeaders(-1)) {
    805         if (value.isNull())
     902        if (value.isNull()) {
    806903            cookedHeaders.remove(parsedKey);
    807         else
     904        } else if (parsedKey == QNetworkRequest::ContentLengthHeader
     905                 && cookedHeaders.contains(QNetworkRequest::ContentLengthHeader)) {
     906            // Only set the cooked header "Content-Length" once.
     907            // See bug QTBUG-15311
     908        } else {
    808909            cookedHeaders.insert(parsedKey, parseHeaderValue(parsedKey, value));
     910        }
     911
    809912    }
    810913}
  • trunk/src/network/access/qnetworkrequest.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    7979        HttpPipeliningAllowedAttribute,
    8080        HttpPipeliningWasUsedAttribute,
     81        CustomVerbAttribute,
     82        CookieLoadControlAttribute,
     83        AuthenticationReuseAttribute,
     84        CookieSaveControlAttribute,
     85        MaximumDownloadBufferSizeAttribute, // internal
     86        DownloadBufferAttribute, // internal
     87
     88        // (DownloadBufferAttribute + 1) is reserved internal for QSynchronousHttpNetworkReply
     89        // add the enum in 4.8
    8190
    8291        User = 1000,
     
    8897        PreferCache,
    8998        AlwaysCache
     99    };
     100    enum LoadControl {
     101        Automatic = 0,
     102        Manual
     103    };
     104
     105    enum Priority {
     106        HighPriority = 1,
     107        NormalPriority = 3,
     108        LowPriority = 5
    90109    };
    91110
     
    124143    QObject *originatingObject() const;
    125144
     145    Priority priority() const;
     146    void setPriority(Priority priority);
     147
    126148private:
    127149    QSharedDataPointer<QNetworkRequestPrivate> d;
  • trunk/src/network/access/qnetworkrequest_p.h

    r651 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
Note: See TracChangeset for help on using the changeset viewer.