Resuming failed HTTP download with Qt & QNetworkRequest

I am trying to add automatic updating capabilities to the application that I am developing. I based this functionality on the Qt HTTP Example (and based on that, I mean that I accurately copied this example and then went from there). It downloads the ZIP file and then extracts its contents to fix the application.

Sometimes when downloading, the connection fails and the download stops. To be a little more user friendly, I decided that I would add the ability to automatically restart the bootloader, where it will try to restart the download once if it fails.

Here are the highlights of my code: the method names correspond to the method names in the example:

void Autopatcher::httpReadyRead()
{
    //file is a QFile that is opened when the download starts
    if (file) {
        QByteArray qba = reply->readAll();
        //keep track of how many bytes have been written to the file
        bytesWritten += qba.size();
        file->write(qba);
    }
}

void Autopatcher::startRequest(QUrl url)
{
    //doResume is set in httpFinished() if an error occurred
    if (doResume) {
        QNetworkRequest req(url);
        //bytesWritten is incremented in httpReadyRead()
        QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(bytesWritten) + "-";
        req.setRawHeader("Range",rangeHeaderValue);
        reply = qnam.get(req);
    } else {
        reply = qnam.get(QNetworkRequest(url));
    }
    //slot connections omitted for brevity
}

//connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(fileGetError(QNetworkReply::NetworkError)));
void Autopatcher::fileGetError(QNetworkReply::NetworkError error) {
    httpRequestAborted = true;
}

void Autopatcher::httpFinished() {
    //If an error occurred
    if (reply->error()) {
        //If we haven't retried yet
        if (!retried) {
            //Try to resume the download
            doResume=true;
            //downloadFile() is a method that handles some administrative tasks
            //like opening the file if doResume=false
            //and calling startRequest() with the appropriate URL
            QTimer::singleShot(5000,this,SLOT(downloadFile()));
        }
        //If we have retried already
        else {
            //Give up :(
            if (file) {
                file->close();
                file->remove();
                delete file;
                file = 0;
            }
        }
    //If no error, then we were successful!
    } else {
        if (file) {
            file->close();
            delete file;
            file = 0;
        }
        //Apply the patch
        doPatch();
    }
    reply->deleteLater();
    reply = 0;
}

, , . ZIP . , , , ZIP 7-zip, (7-zip - " ).

, - " ", , HTTP Range. , , , httpReadyRead. , .

Sysinternals TCPView TCP- . , , , !

+4
1

, . , + - , . , 2 .

, , VBinDiff ( , ), :

  • 0x0154 21F3.
  • 0x0178 1FD3 , .
  • 2,358,752, 2 , .

, , . , , bytesWritten, , . , , . (. httpReadyRead() ).

, , :

file->flush();
bytesWritten = file->size();

, , ,

bytesWritten = 28,947,923
file->size() = 26,589,171

, bytesWritten . , , bytesWritten, !

, . , , , , .

tl; dr , . .

+3

Source: https://habr.com/ru/post/1546432/


All Articles