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");
return;
}
+#ifndef QT_NO_BEARERMANAGEMENT
+ // 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.
// 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::UnknownNetworkError,
+ error(QNetworkReplyImpl::NetworkSessionFailedError,
QCoreApplication::translate("QNetworkReply", "Network session error."));
finished();
}
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,
{
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))
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;
}