The QNetworkReply::uploadProgress signal is intended for updating UI
elements such as a progress bar.
Limit the signal emissions to 10 per second to prevent overloading
the UI with updates.
As with the downloadProgress choke, this is implemented by dropping
signals that occur within 100ms of the previous emission.
The 100% signal is always emitted (bytesSent == bytesTotal)
When the upload size is initially unknown, this behaviour is still
provided by the upload device emitting a suitable readProgress
signal when EOF is reached.
Task-number: QTBUG-20449
Change-Id: I77e03c8a49109106e1c375ee00380293fd326b63
Reviewed-by: Martin Petersson <Martin.Petersson@nokia.com>
QPointer<QNetworkAccessManager> manager;
qint64 readBufferMaxSize;
QElapsedTimer downloadProgressSignalChoke;
QPointer<QNetworkAccessManager> manager;
qint64 readBufferMaxSize;
QElapsedTimer downloadProgressSignalChoke;
+ QElapsedTimer uploadProgressSignalChoke;
const static int progressSignalInterval;
QNetworkAccessManager::Operation operation;
QNetworkReply::NetworkError errorCode;
const static int progressSignalInterval;
QNetworkAccessManager::Operation operation;
QNetworkReply::NetworkError errorCode;
delegate->moveToThread(thread);
// This call automatically moves the uploadDevice too for the asynchronous case.
delegate->moveToThread(thread);
// This call automatically moves the uploadDevice too for the asynchronous case.
- // Start timer for progress notifications
+ // Prepare timers for progress notifications
downloadProgressSignalChoke.start();
downloadProgressSignalChoke.start();
+ uploadProgressSignalChoke.invalidate();
// Send an signal to the delegate so it starts working in the other thread
if (synchronous) {
// Send an signal to the delegate so it starts working in the other thread
if (synchronous) {
Q_Q(QNetworkReplyHttpImpl);
if (isFinished)
return;
Q_Q(QNetworkReplyHttpImpl);
if (isFinished)
return;
+
+ //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();
+ }
+
emit q->uploadProgress(bytesSent, bytesTotal);
}
emit q->uploadProgress(bytesSent, bytesTotal);
}
- // Start timer for progress notifications
+ // Prepare timer for progress notifications
downloadProgressSignalChoke.start();
downloadProgressSignalChoke.start();
+ uploadProgressSignalChoke.invalidate();
if (backend && backend->isSynchronous()) {
state = Finished;
if (backend && backend->isSynchronous()) {
state = Finished;
{
Q_Q(QNetworkReplyImpl);
bytesUploaded = bytesSent;
{
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();
pauseNotificationHandling();
emit q->uploadProgress(bytesSent, bytesTotal);
resumeNotificationHandling();
void tst_QNetworkReply::ioPostToHttpUploadProgress()
{
void tst_QNetworkReply::ioPostToHttpUploadProgress()
{
- QFile sourceFile(testDataDir + "/bigfile");
+ //test file must be larger than OS socket buffers (~830kB on MacOS 10.6)
+ QFile sourceFile(testDataDir + "/image1.jpg");
QVERIFY(sourceFile.open(QIODevice::ReadOnly));
// emulate a minimal http server
QVERIFY(sourceFile.open(QIODevice::ReadOnly));
// emulate a minimal http server
incomingSocket->setReadBufferSize(1*1024);
QTestEventLoop::instance().enterLoop(5);
// some progress should have been made
incomingSocket->setReadBufferSize(1*1024);
QTestEventLoop::instance().enterLoop(5);
// some progress should have been made
+ QVERIFY(!spy.isEmpty());
QList<QVariant> args = spy.last();
QVERIFY(!args.isEmpty());
QVERIFY(args.at(0).toLongLong() > 0);
QList<QVariant> args = spy.last();
QVERIFY(!args.isEmpty());
QVERIFY(args.at(0).toLongLong() > 0);
incomingSocket->setReadBufferSize(0);
QTestEventLoop::instance().enterLoop(10);
// progress should be finished
incomingSocket->setReadBufferSize(0);
QTestEventLoop::instance().enterLoop(10);
// progress should be finished
+ QVERIFY(!spy.isEmpty());
QList<QVariant> args3 = spy.last();
QVERIFY(!args3.isEmpty());
// More progress than before
QList<QVariant> args3 = spy.last();
QVERIFY(!args3.isEmpty());
// More progress than before