How do I make my own custom QNetworkReply?



  • I've been trying to create my own custom QNetworkReply class which return custom bytes from reply. I do return that class from my QNetworkAccessManager::createRequest() overload that I also did overload. My problem is, none of my function overloads are called and consequently the QWebView's request fail, as the reply is "corrupted". I've tried to take some inspiration from Qt tests lib's FakeReply but I fail to make mine work.
    Here's my code:

    fakereply.h

    class FakeReply : public QNetworkReply
    {
        Q_OBJECT
    
    public:
        FakeReply(const QNetworkRequest& request, QByteArray &data, QObject* parent = 0);
        ~FakeReply();
        QByteArray readAll();
        QByteArray read(qint64 maxSize);
        qint64 peek(char *buffer, qint64 maxlen);
        QByteArray peek(qint64 maxLen);
        qint64 size() const;
        virtual qint64 bytesAvailable() const;
        bool isFinished() const;
        virtual void abort();
        virtual void close();
        bool isSequential() const;
    protected:
        qint64 readData(char*, qint64) override;
    private:
        QByteArray data;
    };
    

    fakereply.cpp

    FakeReply::FakeReply(const QNetworkRequest &request, QByteArray &bytes, QObject *parent)
        : QNetworkReply(parent),
          data(bytes)
    {
        setOperation(QNetworkAccessManager::GetOperation);
        setRequest(request);
        setUrl(request.url());
        open(QIODevice::ReadOnly);
        setFinished(true);
        emit finished();
    }
    

    the class is used like this:

    QNetworkReply *MyNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
    {
         QString path = request.url().path();
        QNetworkReply *reply = QNetworkAccessManager::createRequest(op, request, outgoingData);
    
         if(path == QStringLiteral("/testing")) {
             QByteArray response = waitThenReadAll(reply);
             return new FakeReply(request, response);
         }
         return reply;
       }
    
    FakeReply::~FakeReply()
    {
        close();
    }
    
    QByteArray FakeReply::readAll()
    {
        qDebug() << "FakeReply::readAll() got called!";
        size_t len = data.length();
        const char *bytes = static_cast<const char*>(data.data());
        char *buffer = static_cast<char*>(malloc(len));
        ASSERT(buffer != NULL, "run out of memory");
        memcpy(buffer, bytes, len);
        QByteArray output;
        output.setRawData(buffer, len);
        data = data.remove(0, len);
        return output;
    }
    
    QByteArray FakeReply::read(qint64 maxSize)
    {
        qDebug() << "QByteArray FakeReply::read() got called!";
        static char* buffer = nullptr;
        if(bytesAvailable() == 0) {
            return QByteArray();
        }
        size_t len = computeMaxNumberOfBytes(maxSize);
        if(buffer != nullptr) {
            free(buffer);
        }
        buffer = static_cast<char*>(malloc(len));
        ASSERT(buffer != NULL, "run out of memory");
        memcpy(buffer, data.data(), len);
        data = data.remove(0, len);
        QByteArray output;
        output.setRawData(buffer, len);
        return output;
    }
    
    qint64 FakeReply::peek(char *buffer, qint64 maxlen)
    {
        qDebug() << "FakeReply::peek() got called!";
        size_t len = computeMaxNumberOfBytes(maxlen);
        memcpy(buffer, data.data(), len);
        return static_cast<qint64>(len);
    }
    
    QByteArray FakeReply::peek(qint64 maxlen)
    {
        qDebug() << "FakeReply::peek(qint64 maxlen) got called!";
        QByteArray output;
        output.setRawData(data.data(), computeMaxNumberOfBytes(maxlen));
        return output;
    }
    
    qint64 FakeReply::size() const
    {
        return data.length();
    }
    
    qint64 FakeReply::bytesAvailable() const
    {
        qDebug() << "FakeReply::bytesAvailable()";
        return data.length();
    }
    
    bool FakeReply::isFinished() const
    {
        qDebug() << "FakeReply::isFinished() got called!";
        return true;
    }
    
    void FakeReply::abort()
    {
        qDebug() << "FakeReply::abort() got called!";
    }
    
    void FakeReply::close()
    {
        qDebug() << "FakeReply::close() got called!";
    }
    
    bool FakeReply::isSequential() const
    {
        qDebug() << "FakeReply::isSequential() const got called!";
        return false;
    }
    
    qint64 FakeReply::readData(char *, qint64)
    {
        qDebug() << "FakeReply::readData() got called!";
        return 0;
    }
    

  • Qt Champions 2016

    Hi
    It really looks like this sample
    https://github.com/richmoore/qt-examples/tree/master/qcustomnetworkreply

    Nothing jumped to eye with your code.



  • Thank you so much for that code samples! I've been trying to make it work for days. I've tried override/reimplement nearly every method from QNetworkReply and couldn't figure out why my methods weren't being called. My issue was rather simple. I was using emit finished() but then I noticied that your sampel was using:

    ```
    

    QTimer::singleShot(0, this, SIGNAL(readyRead()));
    QTimer::singleShot(0, this, SIGNAL(finished()));

    
    So I give try and it worked!

  • Qt Champions 2016

    Super :)
    It was a long shot but sometimes one is lucky :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.