#StackBounty: #c++ #qt #qtnetwork Get requests canceled while posting with QNetworkAccessManager. How to trigger requests concurrently?

Bounty: 50

I am developing this software (in C++/Qt5.15.2, on Ubuntu 20.04) that exchanges with an electronic card via HTTP requests.
I have HTTP requests to get the status from the device and also some to post files, move or delete them. I am using QNetworkAccessManager to handle my post/get operations.

The problem I’m facing is the following : When I’m not posting, everything is going fine, my status requests work fine and I get the status of the card. When I’m posting (uploading a file), all the requests I send to get the status are canceled.

When I read the documentation, I see :

Note: QNetworkAccessManager queues the requests it receives. The number of requests executed in parallel is dependent on the protocol. Currently, for the HTTP protocol on desktop platforms, 6 requests are executed in parallel for one host/port combination.

From that, I understand that even though I’m posting I should still be able to send status requests and receive an answer.
But It’s not the case, Did I misunderstood something on the usage of QNetworkAccessManager ?

Here’s the code that sends status requests (every 2 sec) that works fine when I’m not posting :

    //Prepare request
    QUrl url = QUrl::fromUserInput(m_url+"/rr_model");
    QUrlQuery query;
    query.addQueryItem("flags", "d99fn");
    url.setQuery(query.query());
    QNetworkRequest request(url);
    request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/json"));

    //Send request
    QNetworkReply* reply = m_networkAccessManager->get(request);
    connect(reply, &QNetworkReply::finished, this, [this,reply]() {

        if(reply->error() == QNetworkReply::NoError)
        {
            QString answer = reply->readAll();
            QJsonDocument jsonResponse = QJsonDocument::fromJson(answer.toUtf8());
            QJsonObject jsonAnswer = jsonResponse.object();
            QJsonObject result = jsonAnswer["result"].toObject();
            if(result.isEmpty())
                return;

            ...Parsing...
        }
        else // handle error
        {
            handleError(reply);
        }
        reply->deleteLater();
    });
    return true;

And here is the post request :

//Get file data
QString filename = QFileInfo(fileToUploadPath).fileName();
QFile toUpload(fileToUploadPath);
qint32 crc = computeCRC32(fileToUploadPath);
if(!toUpload.open(QIODevice::ReadOnly))
    return false;
QByteArray data = toUpload.readAll();
toUpload.close();

//prepare the request
QUrl url = QUrl::fromUserInput(m_url+"/rr_upload");
QUrlQuery query;
QFileInfo info(fileToUploadPath);
QString crcStr = QString::number(crc,16).toLower().right(8);
query.addQueryItem("name", (uploadPath+info.fileName()));
query.addQueryItem("crc32",crcStr);
url.setQuery(query);

QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/octet-steam"));
request.setRawHeader("Accept", "*/*");
m_uploading = true;
QNetworkReply* reply = m_networkAccessManager->post(request,data);
connect(reply, &QNetworkReply::finished, this, [this,reply,filename,fileToUploadPath,uploadPath,commandToExecuterAfterCompletion]() {
    m_uploading = false;
    if(reply->error() == QNetworkReply::NoError)
    {
        QString answer = reply->readAll();
        QJsonDocument jsonResponse = QJsonDocument::fromJson(answer.toUtf8());
        bool err = (jsonResponse["err"].toInt(1))==1;
        if(err){
            logToFile(QString("Upload of file %1 to %2 failed (bad crc ?)").arg(fileToUploadPath,uploadPath));
            emit signalUploadProgressionUpdated(filename,100,false);
        }else{
            logToFile(QString("Upload of file %1 to %2 successful").arg(fileToUploadPath,uploadPath));
            emit signalUploadProgressionUpdated(filename,100,true);
        }

        ...Some code to update the content of the card...
    }
    else // handle error
    {
        logToFile(QString("Upload of file %1 to %2 failed").arg(fileToUploadPath,uploadPath));
        handleError(reply);
        emit signalUploadProgressionUpdated(filename,0,false);
    }
    reply->deleteLater();
});

connect(reply, &QNetworkReply::uploadProgress, this, [this,filename](qint64 sent, qint64 total) {
    double percent = total>0 ? sent*1.0/total*100.0 : 0;
    emit signalUploadProgressionUpdated(filename,percent,true);
});
return true;

Once this post request is triggered, all my get status requests will get an error (handleError is triggered, and I just print the error message) : Operation Canceled Error

Am I doing something wrong ? I thought that Qt would handle the concurrency on itself, but am I supposed to trigger the post request in a separated thread ?

QNetworkAccessManager has his own thread where I send the requests and get the replies. The rest of the software is updated via signals and slots.

An app in Vue.js is distributed with the card, and when I look on Wireshark I see that when it’s posting it can still exchange get requests with the card. The problem doesn’t come from the HTTP server. If I use Wireshark on my software, I see that the requests stop when the post request starts, and nothing happens until the completion of the post request.

Thanks in advance


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.