Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I read content (http response body) from a QNetworkReply

I'm using qt5.3 and I googled a lot before I post.

I want to read data from QNetworkReply. I have a QWebView and I also need the http response to be read by QWebView to display the webpage. What I need is just to log the web content or whatever response to http posts.

The problem is QNetworkReply is something that can only be read once.

  1. If I call readAll() when I pick readyRead() signal, I will get the full data. But it will be cleared so QWebView displays nothing (it won't get any reply data).

  2. Or if I pick finished() signal, since the data is already read by QWebView (or QNetworkAccessManager), I get nothing if I call readAll() here. Is there somewhere that QNetworkReply, or manager or any class, stores the data which I can still read?

In #1 I can get part of the data if I call peek(). This function does not clear the response data. But it won't work if the response body is big. The QNetworkReply is a sequential thing that I can neither know its data nor read further than buffered.

I have no idea of how to do with this.....

I just want to monitor and log the request and response body of any request made on my QWebView ...

Edit: note that my data to read from response is as large as 1MB so it won't be ok to peek the whole data without further reading.

like image 973
K-- Avatar asked Aug 05 '14 15:08

K--


1 Answers

You can create your own subclass of QNetworkAccessManager and override virtual function createRequest. Call base class implementation to get the response object and connect readyRead signal to some slot that will capture the data. In that slot call peek function to read data so that WebKit will get the data also :

class NetworkAccessManagerProxy : public QNetworkAccessManager {
Q_OBJECT

signals:

    void dataGot(QByteArray data);

public:
    NetworkAccessManagerProxy(QObject * parent = 0)
         : QNetworkAccessManager()
    {
    }

    virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice *outgoingData)
    {
        reply = QNetworkAccessManager::createRequest(op, request, outgoingData);
        connect(this,SIGNAL(readyRead()), SLOT(readInternal()));
        return reply;
    }

private slots:

     void readInternal()
     {
        QByteArray data = reply->peek(reply->bytesAvailable());
        emit dataGot(data);
     }

private:

    QNetworkReply* reply;
};

After creating QWebPage object, call setNetworkAccessManager and pass a newly created instance of your subclass :

QWebPage * page = new QWebPage; 
page->setNetworkAccessManager(new NetworkAccessManagerProxy());
page->mainFrame()->load(url);

webView->setPage(page);
like image 75
Nejat Avatar answered Oct 13 '22 00:10

Nejat