/****************************************************************************
**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
**
** This file is part of the QtNetwork module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
+** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
**
**
**
#include "qnetworkreplyimpl_p.h"
#include "qnetworkaccessbackend_p.h"
#include "qnetworkcookie.h"
+#include "qnetworkcookiejar.h"
#include "qabstractnetworkcache.h"
#include "QtCore/qcoreapplication.h"
#include "QtCore/qdatetime.h"
void QNetworkReplyImplPrivate::_q_startOperation()
{
+ Q_Q(QNetworkReplyImpl);
+
// ensure this function is only being called once
if (state == Working || state == Finished) {
qDebug("QNetworkReplyImpl::_q_startOperation was called more than once");
}
#ifndef QT_NO_BEARERMANAGEMENT
- if (!backend->start()) { // ### we should call that method even if bearer is not used
+ // Do not start background requests if they are not allowed by session policy
+ QSharedPointer<QNetworkSession> session(manager->d_func()->getNetworkSession());
+ QVariant isBackground = backend->request().attribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(false));
+ if (isBackground.toBool() && session && session->usagePolicies().testFlag(QNetworkSession::NoBackgroundTrafficPolicy)) {
+ error(QNetworkReply::BackgroundRequestNotAllowedError,
+ QCoreApplication::translate("QNetworkReply", "Background request not allowed."));
+ finished();
+ return;
+ }
+#endif
+
+ if (!backend->start()) {
+#ifndef QT_NO_BEARERMANAGEMENT
// backend failed to start because the session state is not Connected.
- // QNetworkAccessManager will call reply->backend->start() again for us when the session
+ // QNetworkAccessManager will call _q_startOperation again for us when the session
// state changes.
state = WaitingForSession;
- QNetworkSession *session = manager->d_func()->networkSession.data();
-
if (session) {
- Q_Q(QNetworkReplyImpl);
-
- QObject::connect(session, SIGNAL(error(QNetworkSession::SessionError)),
+ QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)),
q, SLOT(_q_networkSessionFailed()));
- if (!session->isOpen())
+ if (!session->isOpen()) {
+ session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground);
session->open();
+ }
} else {
qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
+ state = Working;
+ error(QNetworkReplyImpl::NetworkSessionFailedError,
+ QCoreApplication::translate("QNetworkReply", "Network session error."));
+ finished();
}
-
+#else
+ qWarning("Backend start failed");
+ state = Working;
+ error(QNetworkReplyImpl::UnknownNetworkError,
+ QCoreApplication::translate("QNetworkReply", "backend start error."));
+ finished();
+#endif
return;
}
+
+#ifndef QT_NO_BEARERMANAGEMENT
+ if (session) {
+ //get notification of policy changes.
+ QObject::connect(session.data(), SIGNAL(usagePoliciesChanged(QNetworkSession::UsagePolicies)),
+ q, SLOT(_q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies)));
+ }
#endif
+ // Prepare timer for progress notifications
+ downloadProgressSignalChoke.start();
+ uploadProgressSignalChoke.invalidate();
+
if (backend && backend->isSynchronous()) {
state = Finished;
q_func()->setFinished(true);
// emit readyRead before downloadProgress incase this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
emit q->readyRead();
- emit q->downloadProgress(bytesDownloaded,
+ if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
+ downloadProgressSignalChoke.restart();
+ emit q->downloadProgress(bytesDownloaded,
totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
+ }
resumeNotificationHandling();
}
if (manager.isNull())
return;
- QNetworkSession *session = manager->d_func()->networkSession.data();
+ QSharedPointer<QNetworkSession> session = manager->d_func()->getNetworkSession();
if (!session)
return;
// Abort waiting and working replies.
if (state == WaitingForSession || state == Working) {
state = Working;
- error(QNetworkReplyImpl::UnknownNetworkError,
- QCoreApplication::translate("QNetworkReply", "Network session error."));
+ QSharedPointer<QNetworkSession> session(manager->d_func()->getNetworkSession());
+ QString errorStr;
+ if (session)
+ errorStr = session->errorString();
+ else
+ errorStr = QCoreApplication::translate("QNetworkReply", "Network session error.");
+ error(QNetworkReplyImpl::NetworkSessionFailedError, errorStr);
finished();
}
}
+
+void QNetworkReplyImplPrivate::_q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies newPolicies)
+{
+ if (backend->request().attribute(QNetworkRequest::BackgroundRequestAttribute).toBool()) {
+ if (newPolicies & QNetworkSession::NoBackgroundTrafficPolicy) {
+ // Abort waiting and working replies.
+ if (state == WaitingForSession || state == Working) {
+ state = Working;
+ error(QNetworkReply::BackgroundRequestNotAllowedError,
+ QCoreApplication::translate("QNetworkReply", "Background request not allowed."));
+ finished();
+ }
+ // ### if backend->canResume(), then we could resume automatically, however no backend supports resuming
+ }
+ }
+}
#endif
void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req,
{
// check if we can save and if we're allowed to
if (!networkCache()
- || !request.attribute(QNetworkRequest::CacheSaveControlAttribute, true).toBool()
- || request.attribute(QNetworkRequest::CacheLoadControlAttribute,
- QNetworkRequest::PreferNetwork).toInt()
- == QNetworkRequest::AlwaysNetwork)
+ || !request.attribute(QNetworkRequest::CacheSaveControlAttribute, true).toBool())
return;
cacheEnabled = true;
}
{
Q_Q(QNetworkReplyImpl);
bytesUploaded = bytesSent;
+
+ //choke signal emissions, except the first and last signals which are unconditional
+ if (uploadProgressSignalChoke.isValid()) {
+ if (bytesSent != bytesTotal && uploadProgressSignalChoke.elapsed() < progressSignalInterval) {
+ return;
+ }
+ uploadProgressSignalChoke.restart();
+ } else {
+ uploadProgressSignalChoke.start();
+ }
+
pauseNotificationHandling();
emit q->uploadProgress(bytesSent, bytesTotal);
resumeNotificationHandling();
emit q->readyRead();
// emit readyRead before downloadProgress incase this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
- emit q->downloadProgress(bytesDownloaded,
+ if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
+ downloadProgressSignalChoke.restart();
+ emit q->downloadProgress(bytesDownloaded,
totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
+ }
resumeNotificationHandling();
// do we still have room in the buffer?
downloadBuffer = new char[downloadBufferMaximumSize]; // throws if allocation fails
downloadBufferPointer = QSharedPointer<char>(downloadBuffer, downloadBufferDeleter);
- q->setAttribute(QNetworkRequest::DownloadBufferAttribute, qVariantFromValue<QSharedPointer<char> > (downloadBufferPointer));
+ q->setAttribute(QNetworkRequest::DownloadBufferAttribute, QVariant::fromValue<QSharedPointer<char> > (downloadBufferPointer));
}
}
downloadBuffer = downloadBufferPointer.data();
downloadBufferCurrentSize = 0;
downloadBufferMaximumSize = size;
- q->setAttribute(QNetworkRequest::DownloadBufferAttribute, qVariantFromValue<QSharedPointer<char> > (downloadBufferPointer));
+ q->setAttribute(QNetworkRequest::DownloadBufferAttribute, QVariant::fromValue<QSharedPointer<char> > (downloadBufferPointer));
}
// processed and we get into a recursive call (as in QProgressDialog).
if (bytesDownloaded > 0)
emit q->readyRead();
- emit q->downloadProgress(bytesDownloaded, bytesTotal);
+ if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
+ downloadProgressSignalChoke.restart();
+ emit q->downloadProgress(bytesDownloaded, bytesTotal);
+ }
}
void QNetworkReplyImplPrivate::finished()
if (!manager.isNull()) {
#ifndef QT_NO_BEARERMANAGEMENT
- QNetworkSession *session = manager->d_func()->networkSession.data();
+ QSharedPointer<QNetworkSession> session (manager->d_func()->getNetworkSession());
if (session && session->state() == QNetworkSession::Roaming &&
state == Working && errorCode != QNetworkReply::OperationCanceledError) {
// only content with a known size will fail with a temporary network failure error
pauseNotificationHandling();
if (totalSize.isNull() || totalSize == -1) {
emit q->downloadProgress(bytesDownloaded, bytesDownloaded);
+ } else {
+ emit q->downloadProgress(bytesDownloaded, totalSize.toLongLong());
}
if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer))
Q_Q(QNetworkReplyImpl);
// Can't set and emit multiple errors.
if (errorCode != QNetworkReply::NoError) {
- qWarning() << "QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.";
+ qWarning( "QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.");
return;
}
void QNetworkReplyImplPrivate::sslErrors(const QList<QSslError> &errors)
{
-#ifndef QT_NO_OPENSSL
+#ifndef QT_NO_SSL
Q_Q(QNetworkReplyImpl);
emit q->sslErrors(errors);
#else
if (d->state != QNetworkReplyImplPrivate::Finished) {
// call finished which will emit signals
d->error(OperationCanceledError, tr("Operation canceled"));
+ if (d->state == QNetworkReplyImplPrivate::WaitingForSession)
+ d->state = QNetworkReplyImplPrivate::Working;
d->finished();
}
d->state = QNetworkReplyImplPrivate::Aborted;
d->backend->setDownstreamLimited(d->readBufferMaxSize > 0);
}
-#ifndef QT_NO_OPENSSL
-QSslConfiguration QNetworkReplyImpl::sslConfigurationImplementation() const
+#ifndef QT_NO_SSL
+void QNetworkReplyImpl::sslConfigurationImplementation(QSslConfiguration &configuration) const
{
Q_D(const QNetworkReplyImpl);
- QSslConfiguration config;
if (d->backend)
- d->backend->fetchSslConfiguration(config);
- return config;
+ d->backend->fetchSslConfiguration(configuration);
}
void QNetworkReplyImpl::setSslConfigurationImplementation(const QSslConfiguration &config)
if (d->backend)
d->backend->ignoreSslErrors(errors);
}
-#endif // QT_NO_OPENSSL
+#endif // QT_NO_SSL
/*!
\internal
if (maxAvail == 0)
return d->state == QNetworkReplyImplPrivate::Finished ? -1 : 0;
// FIXME what about "Aborted" state?
- qMemCopy(data, d->downloadBuffer + d->downloadBufferReadPosition, maxAvail);
+ memcpy(data, d->downloadBuffer + d->downloadBufferReadPosition, maxAvail);
d->downloadBufferReadPosition += maxAvail;
return maxAvail;
}
if (state == Finished || state == Aborted)
return true;
- // Backend does not support resuming download.
- if (!backend->canResume())
- return false;
-
// Request has outgoing data, not migrating.
if (outgoingData)
return false;
if (copyDevice)
return true;
+ // Backend does not support resuming download.
+ if (!backend->canResume())
+ return false;
+
state = QNetworkReplyImplPrivate::Reconnecting;
if (backend) {