src/network/access/qnetworkreplyimpl.cpp
changeset 30 5dc02b23752f
parent 23 89e065397ea6
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    44 #include "qnetworkcookie.h"
    44 #include "qnetworkcookie.h"
    45 #include "qabstractnetworkcache.h"
    45 #include "qabstractnetworkcache.h"
    46 #include "QtCore/qcoreapplication.h"
    46 #include "QtCore/qcoreapplication.h"
    47 #include "QtCore/qdatetime.h"
    47 #include "QtCore/qdatetime.h"
    48 #include "QtNetwork/qsslconfiguration.h"
    48 #include "QtNetwork/qsslconfiguration.h"
       
    49 #include "QtNetwork/qnetworksession.h"
    49 #include "qnetworkaccesshttpbackend_p.h"
    50 #include "qnetworkaccesshttpbackend_p.h"
       
    51 #include "qnetworkaccessmanager_p.h"
    50 
    52 
    51 #include <QtCore/QCoreApplication>
    53 #include <QtCore/QCoreApplication>
    52 
    54 
    53 QT_BEGIN_NAMESPACE
    55 QT_BEGIN_NAMESPACE
    54 
    56 
    55 inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
    57 inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate()
    56     : backend(0), outgoingData(0), outgoingDataBuffer(0),
    58     : backend(0), outgoingData(0), outgoingDataBuffer(0),
    57       copyDevice(0),
    59       copyDevice(0),
    58       cacheEnabled(false), cacheSaveDevice(0),
    60       cacheEnabled(false), cacheSaveDevice(0),
    59       notificationHandlingPaused(false),
    61       notificationHandlingPaused(false),
    60       bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1),
    62       bytesDownloaded(0), lastBytesDownloaded(-1), bytesUploaded(-1), preMigrationDownloaded(-1),
    61       httpStatusCode(0),
    63       httpStatusCode(0),
    62       state(Idle)
    64       state(Idle)
    63 {
    65 {
    64 }
    66 }
    65 
    67 
    80               QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!;
    82               QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!;
    81         finished();
    83         finished();
    82         return;
    84         return;
    83     }
    85     }
    84 
    86 
    85     backend->open();
    87 #ifndef QT_NO_BEARERMANAGEMENT
       
    88     if (!backend->start()) {
       
    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;
       
    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 
    86     if (state != Finished) {
   112     if (state != Finished) {
    87         if (operation == QNetworkAccessManager::GetOperation)
   113         if (operation == QNetworkAccessManager::GetOperation)
    88             pendingNotifications.append(NotifyDownstreamReadyWrite);
   114             pendingNotifications.append(NotifyDownstreamReadyWrite);
    89 
   115 
    90         handleNotifications();
   116         handleNotifications();
   132         return;
   158         return;
   133     }
   159     }
   134 
   160 
   135     lastBytesDownloaded = bytesDownloaded;
   161     lastBytesDownloaded = bytesDownloaded;
   136     QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
   162     QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
       
   163     if (preMigrationDownloaded != Q_INT64_C(-1))
       
   164         totalSize = totalSize.toLongLong() + preMigrationDownloaded;
   137     pauseNotificationHandling();
   165     pauseNotificationHandling();
   138     emit q->downloadProgress(bytesDownloaded,
   166     emit q->downloadProgress(bytesDownloaded,
   139                              totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
   167                              totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
   140     emit q->readyRead();
   168     emit q->readyRead();
   141     resumeNotificationHandling();
   169     resumeNotificationHandling();
   203             // don't break, try to read() again
   231             // don't break, try to read() again
   204             outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered);
   232             outgoingDataBuffer->chop(bytesToBuffer - bytesBuffered);
   205         }
   233         }
   206     }
   234     }
   207 }
   235 }
       
   236 
       
   237 #ifndef QT_NO_BEARERMANAGEMENT
       
   238 void QNetworkReplyImplPrivate::_q_networkSessionConnected()
       
   239 {
       
   240     Q_Q(QNetworkReplyImpl);
       
   241 
       
   242     if (manager.isNull())
       
   243         return;
       
   244 
       
   245     QNetworkSession *session = manager->d_func()->networkSession;
       
   246     if (!session)
       
   247         return;
       
   248 
       
   249     if (session->state() != QNetworkSession::Connected)
       
   250         return;
       
   251 
       
   252     switch (state) {
       
   253     case QNetworkReplyImplPrivate::Buffering:
       
   254     case QNetworkReplyImplPrivate::Working:
       
   255     case QNetworkReplyImplPrivate::Reconnecting:
       
   256         // Migrate existing downloads to new network connection.
       
   257         migrateBackend();
       
   258         break;
       
   259     case QNetworkReplyImplPrivate::WaitingForSession:
       
   260         // Start waiting requests.
       
   261         QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
       
   262         break;
       
   263     default:
       
   264         ;
       
   265     }
       
   266 }
       
   267 
       
   268 void QNetworkReplyImplPrivate::_q_networkSessionFailed()
       
   269 {
       
   270     // Abort waiting replies.
       
   271     if (state == WaitingForSession) {
       
   272         state = Working;
       
   273         error(QNetworkReplyImpl::UnknownNetworkError,
       
   274               QCoreApplication::translate("QNetworkReply", "Network session error."));
       
   275         finished();
       
   276     }
       
   277 }
       
   278 #endif
   208 
   279 
   209 void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req,
   280 void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req,
   210                                      QIODevice *data)
   281                                      QIODevice *data)
   211 {
   282 {
   212     Q_Q(QNetworkReplyImpl);
   283     Q_Q(QNetworkReplyImpl);
   249         // or no backend
   320         // or no backend
   250         // if no backend, _q_startOperation will handle the error of this
   321         // if no backend, _q_startOperation will handle the error of this
   251 
   322 
   252         // for HTTP, we want to send out the request as fast as possible to the network, without
   323         // for HTTP, we want to send out the request as fast as possible to the network, without
   253         // invoking methods in a QueuedConnection
   324         // invoking methods in a QueuedConnection
       
   325 #ifndef QT_NO_HTTP
   254         if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
   326         if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
   255             _q_startOperation();
   327             _q_startOperation();
   256         } else {
   328         } else {
   257             QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
   329             QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
   258         }
   330         }
       
   331 #else
       
   332         QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
       
   333 #endif // QT_NO_HTTP
   259     }
   334     }
   260 
   335 
   261     q->QIODevice::open(QIODevice::ReadOnly);
   336     q->QIODevice::open(QIODevice::ReadOnly);
   262 }
   337 }
   263 
   338 
   469     Q_Q(QNetworkReplyImpl);
   544     Q_Q(QNetworkReplyImpl);
   470 
   545 
   471     QPointer<QNetworkReplyImpl> qq = q;
   546     QPointer<QNetworkReplyImpl> qq = q;
   472 
   547 
   473     QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
   548     QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
       
   549     if (preMigrationDownloaded != Q_INT64_C(-1))
       
   550         totalSize = totalSize.toLongLong() + preMigrationDownloaded;
   474     pauseNotificationHandling();
   551     pauseNotificationHandling();
   475     emit q->downloadProgress(bytesDownloaded,
   552     emit q->downloadProgress(bytesDownloaded,
   476                              totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
   553                              totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
   477     // important: At the point of this readyRead(), the data parameter list must be empty,
   554     // important: At the point of this readyRead(), the data parameter list must be empty,
   478     // else implicit sharing will trigger memcpy when the user is reading data!
   555     // else implicit sharing will trigger memcpy when the user is reading data!
   519 }
   596 }
   520 
   597 
   521 void QNetworkReplyImplPrivate::finished()
   598 void QNetworkReplyImplPrivate::finished()
   522 {
   599 {
   523     Q_Q(QNetworkReplyImpl);
   600     Q_Q(QNetworkReplyImpl);
   524     if (state == Finished || state == Aborted)
   601 
   525         return;
   602     if (state == Finished || state == Aborted || state == WaitingForSession)
       
   603         return;
       
   604 
       
   605     pauseNotificationHandling();
       
   606     QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
       
   607     if (preMigrationDownloaded != Q_INT64_C(-1))
       
   608         totalSize = totalSize.toLongLong() + preMigrationDownloaded;
       
   609 
       
   610     if (!manager.isNull()) {
       
   611 #ifndef QT_NO_BEARERMANAGEMENT
       
   612         QNetworkSession *session = manager->d_func()->networkSession;
       
   613         if (session && session->state() == QNetworkSession::Roaming &&
       
   614             state == Working && errorCode != QNetworkReply::OperationCanceledError) {
       
   615             // only content with a known size will fail with a temporary network failure error
       
   616             if (!totalSize.isNull()) {
       
   617                 if (bytesDownloaded != totalSize) {
       
   618                     if (migrateBackend()) {
       
   619                         // either we are migrating or the request is finished/aborted
       
   620                         if (state == Reconnecting || state == WaitingForSession) {
       
   621                             resumeNotificationHandling();
       
   622                             return; // exit early if we are migrating.
       
   623                         }
       
   624                     } else {
       
   625                         error(QNetworkReply::TemporaryNetworkFailureError,
       
   626                               QNetworkReply::tr("Temporary network failure."));
       
   627                     }
       
   628                 }
       
   629             }
       
   630         }
       
   631 #endif
       
   632     }
       
   633     resumeNotificationHandling();
   526 
   634 
   527     state = Finished;
   635     state = Finished;
   528     pendingNotifications.clear();
   636     pendingNotifications.clear();
   529 
   637 
   530     pauseNotificationHandling();
   638     pauseNotificationHandling();
   531     QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
       
   532     if (totalSize.isNull() || totalSize == -1) {
   639     if (totalSize.isNull() || totalSize == -1) {
   533         emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
   640         emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
   534     }
   641     }
   535 
   642 
   536     if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer))
   643     if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer))
   537         emit q->uploadProgress(0, 0);
   644         emit q->uploadProgress(0, 0);
   538     resumeNotificationHandling();
   645     resumeNotificationHandling();
   539 
   646 
   540     completeCacheSave();
   647     // if we don't know the total size of or we received everything save the cache
       
   648     if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
       
   649         completeCacheSave();
   541 
   650 
   542     // note: might not be a good idea, since users could decide to delete us
   651     // note: might not be a good idea, since users could decide to delete us
   543     // which would delete the backend too...
   652     // which would delete the backend too...
   544     // maybe we should protect the backend
   653     // maybe we should protect the backend
   545     pauseNotificationHandling();
   654     pauseNotificationHandling();
   562 }
   671 }
   563 
   672 
   564 void QNetworkReplyImplPrivate::metaDataChanged()
   673 void QNetworkReplyImplPrivate::metaDataChanged()
   565 {
   674 {
   566     Q_Q(QNetworkReplyImpl);
   675     Q_Q(QNetworkReplyImpl);
   567     // do we have cookies?
   676     // 1. do we have cookies?
   568     if (cookedHeaders.contains(QNetworkRequest::SetCookieHeader) && !manager.isNull()) {
   677     // 2. are we allowed to set them?
       
   678     if (cookedHeaders.contains(QNetworkRequest::SetCookieHeader) && !manager.isNull()
       
   679         && (static_cast<QNetworkRequest::LoadControl>
       
   680             (request.attribute(QNetworkRequest::CookieSaveControlAttribute,
       
   681                                QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Automatic)) {
   569         QList<QNetworkCookie> cookies =
   682         QList<QNetworkCookie> cookies =
   570             qvariant_cast<QList<QNetworkCookie> >(cookedHeaders.value(QNetworkRequest::SetCookieHeader));
   683             qvariant_cast<QList<QNetworkCookie> >(cookedHeaders.value(QNetworkRequest::SetCookieHeader));
   571         QNetworkCookieJar *jar = manager->cookieJar();
   684         QNetworkCookieJar *jar = manager->cookieJar();
   572         if (jar)
   685         if (jar)
   573             jar->setCookiesFromUrl(cookies, url);
   686             jar->setCookiesFromUrl(cookies, url);
   659 
   772 
   660     // emit signals
   773     // emit signals
   661     d->error(OperationCanceledError, tr("Operation canceled"));
   774     d->error(OperationCanceledError, tr("Operation canceled"));
   662     d->finished();
   775     d->finished();
   663 }
   776 }
       
   777 
       
   778 bool QNetworkReplyImpl::canReadLine () const
       
   779 {
       
   780     Q_D(const QNetworkReplyImpl);
       
   781     return QNetworkReply::canReadLine() || d->readBuffer.canReadLine();
       
   782 }
       
   783 
   664 
   784 
   665 /*!
   785 /*!
   666     Returns the number of bytes available for reading with
   786     Returns the number of bytes available for reading with
   667     QIODevice::read(). The number of bytes available may grow until
   787     QIODevice::read(). The number of bytes available may grow until
   668     the finished() signal is emitted.
   788     the finished() signal is emitted.
   748     }
   868     }
   749 
   869 
   750     return QObject::event(e);
   870     return QObject::event(e);
   751 }
   871 }
   752 
   872 
       
   873 /*
       
   874     Migrates the backend of the QNetworkReply to a new network connection if required.  Returns
       
   875     true if the reply is migrated or it is not required; otherwise returns false.
       
   876 */
       
   877 bool QNetworkReplyImplPrivate::migrateBackend()
       
   878 {
       
   879     Q_Q(QNetworkReplyImpl);
       
   880 
       
   881     // Network reply is already finished or aborted, don't need to migrate.
       
   882     if (state == Finished || state == Aborted)
       
   883         return true;
       
   884 
       
   885     // Backend does not support resuming download.
       
   886     if (!backend->canResume())
       
   887         return false;
       
   888 
       
   889     // Request has outgoing data, not migrating.
       
   890     if (outgoingData)
       
   891         return false;
       
   892 
       
   893     // Request is serviced from the cache, don't need to migrate.
       
   894     if (copyDevice)
       
   895         return true;
       
   896 
       
   897     state = QNetworkReplyImplPrivate::Reconnecting;
       
   898 
       
   899     if (backend) {
       
   900         delete backend;
       
   901         backend = 0;
       
   902     }
       
   903 
       
   904     cookedHeaders.clear();
       
   905     rawHeaders.clear();
       
   906 
       
   907     preMigrationDownloaded = bytesDownloaded;
       
   908 
       
   909     backend = manager->d_func()->findBackend(operation, request);
       
   910 
       
   911     if (backend) {
       
   912         backend->setParent(q);
       
   913         backend->reply = this;
       
   914         backend->setResumeOffset(bytesDownloaded);
       
   915     }
       
   916 
       
   917 #ifndef QT_NO_HTTP
       
   918     if (qobject_cast<QNetworkAccessHttpBackend *>(backend)) {
       
   919         _q_startOperation();
       
   920     } else {
       
   921         QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
       
   922     }
       
   923 #else
       
   924     QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
       
   925 #endif // QT_NO_HTTP
       
   926 
       
   927     return true;
       
   928 }
       
   929 
       
   930 #ifndef QT_NO_BEARERMANAGEMENT
       
   931 QDisabledNetworkReply::QDisabledNetworkReply(QObject *parent,
       
   932                                              const QNetworkRequest &req,
       
   933                                              QNetworkAccessManager::Operation op)
       
   934 :   QNetworkReply(parent)
       
   935 {
       
   936     setRequest(req);
       
   937     setUrl(req.url());
       
   938     setOperation(op);
       
   939 
       
   940     qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
       
   941 
       
   942     QString msg = QCoreApplication::translate("QNetworkAccessManager",
       
   943                                               "Network access is disabled.");
       
   944     setError(UnknownNetworkError, msg);
       
   945 
       
   946     QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
       
   947         Q_ARG(QNetworkReply::NetworkError, UnknownNetworkError));
       
   948     QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
       
   949 }
       
   950 
       
   951 QDisabledNetworkReply::~QDisabledNetworkReply()
       
   952 {
       
   953 }
       
   954 #endif
       
   955 
   753 QT_END_NAMESPACE
   956 QT_END_NAMESPACE
   754 
   957 
   755 #include "moc_qnetworkreplyimpl_p.cpp"
   958 #include "moc_qnetworkreplyimpl_p.cpp"
   756 
   959