How to set QNetworkReply timeout without external timer?

It's not possible without using a timer, but you don't have to explicitly write timer code. The functionality can be neatly packaged into a static function that acts as if the timeout was a settable property of the reply - see example below.

There are two issues:

  1. How to handle a timeout on a request that is in progress.

  2. How to determine whether a network request has begun processing. This problem is addressed in this question.

A simple timeout handler could be implemented as below (derived from this answer). The code is portable across Qt 4 and Qt 5.

You have a choice between abort-ing the request on timeout (the default), or close-ing it. The former releases network resources immediately, the latter allows the request to finish but discards any data received and is mostly useful with upload requests.

class ReplyTimeout : public QObject {
    Q_OBJECT
public:
    enum HandleMethod { Abort, Close };
    ReplyTimeout(QNetworkReply* reply, const int timeout, HandleMethod method = Abort) :
        QObject(reply), m_method(method)
    {
        Q_ASSERT(reply);
        if (reply && reply->isRunning()) {
            m_timer.start(timeout, this);
            connect(reply, &QNetworkReply::finished, this, &QObject::deleteLater);
        }
    }
    static void set(QNetworkReply* reply, const int timeout, HandleMethod method = Abort)
    {
        new ReplyTimeout(reply, timeout, method);
    }
protected:
    QBasicTimer m_timer;
    HandleMethod m_method;
    void timerEvent(QTimerEvent * ev) {
        if (!m_timer.isActive() || ev->timerId() != m_timer.timerId())
            return;
        auto reply = static_cast<QNetworkReply*>(parent());
        if (reply->isRunning())
        {
            if (m_method == Close)
                reply->close();
            else if (m_method == Abort)
                reply->abort();
            m_timer.stop();
        }
    }
};

Use:

QNetworkAccessManager networkAccessManger;
QNetworkReply* reply = 
  networkAccessManger.get(QNetworkRequest(QUrl("https://www.google.com")));
ReplyTimeout::set(reply, 100);

with Qt 5.15 it should be a built-in feature - just found out that a 10 yrs old bug is fixed :) https://codereview.qt-project.org/c/qt/qtbase/+/278064

Tags:

C++

Qt