Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Krizis от Июль 22, 2016, 12:43



Название: Реализация QNetworkReply для QWebView
Отправлено: Krizis от Июль 22, 2016, 12:43
Есть задача вернуть в веб QWebView ответ на запрос, отправленный в обход qt. Подменил QNetworkReply своим, в основном позаимствованным с просторов инета. код прилагается.


Код:
#include <QNetworkReply>
 #include <QWebSecurityOrigin>
#include <qcoreapplication.h>
#include <QtCore/QMetaObject>

class ProxyNetworkReply: public QNetworkReply
{
    Q_OBJECT

public:
    ProxyNetworkReply(QObject *parent, const QNetworkRequest &req,
            const QNetworkAccessManager::Operation op)
        : QNetworkReply(parent)
    {
        setRequest(req);
        setUrl(req.url());
        setOperation(op);

        setFinished(true);

        QNetworkReply::open(QIODevice::ReadOnly | QIODevice::Unbuffered);

        QString string = "<!DOCTYPE HTML><html> <head>  </head> <body><H1> description</H1></body></html>";

        m_content = string.toUtf8();
        m_lOffset = 0;

        setHeader(QNetworkRequest::ContentTypeHeader,
                QVariant("text/html; charset=UTF-8"));
        setHeader(QNetworkRequest::ContentLengthHeader,
                QVariant(m_content.size()));

        QMetaObject::invokeMethod(this, "metaDataChanged",
                Qt::QueuedConnection);
        QMetaObject::invokeMethod(this, "downloadProgress",
                Qt::QueuedConnection, Q_ARG(qint64, m_content.size()), Q_ARG(qint64, m_content.size()));
        QMetaObject::invokeMethod(this, "readyRead",
                Qt::QueuedConnection);

        QMetaObject::invokeMethod(this, "readChannelFinished",
                Qt::QueuedConnection);

        QMetaObject::invokeMethod(this, "finished",
                Qt::QueuedConnection);

            QCoreApplication::postEvent(this, new QEvent(QEvent::NetworkReplyUpdated));
    }
    void abort() { QNetworkReply::close(); }
    qint64 bytesAvailable() const { return m_content.size() - m_lOffset; }
    bool isSequential() const { return true; }

    qint64 size() const
    {
        return  m_content.size();
    }

protected:
    qint64 readData(char* pData, qint64 lMaxSize)
    {
        if (m_lOffset >= m_content.size())
            return -1;

        qint64 lCount = qMin(lMaxSize, m_content.size() - m_lOffset);
        memcpy(pData, m_content.constData() + m_lOffset, lCount);
        m_lOffset += lCount;
        return lCount;
    }

private slots:

private:
    QByteArray m_content;
    qint64 m_lOffset;
};

Сигналы вызываются, readData, тоже.  однако, страница браузера остаётся пустой.
Может кто нибудь подсказать, чего не хватает приведённой выше тестовой реализации? или , может, есть подсказка, как заставить QWebView отображать полученное?
Исходники смотре, может что пропустил, но вроде бы все нужные сигналы вызываются.



Название: Re: Реализация QNetworkReply для QWebView
Отправлено: gil9red от Июль 22, 2016, 12:48
А вы не пробовали логировать внутри методов? Может они вообще не вызываются


Название: Re: Реализация QNetworkReply для QWebView
Отправлено: Bepec от Июль 22, 2016, 13:07
На мой взгляд вы творите что то страшное. Вы лезете в нутро, непонятным образом пытаетесь имитировать работу QNetworkReply, так что мне непонятно что вы хотите получить.

PS одни сигналы в контрукторе чего стоят. Они скорее всего уходят в никуда, ибо при создании reply ещё никуда не подключено и подцепиться к сигналам вы времени не даёте :)


Название: Re: Реализация QNetworkReply для QWebView
Отправлено: Krizis от Июль 22, 2016, 14:26
Сигналы срабатывают, т.е. внешние подписчики их получают. В частности, управляющий всем этим хозяйством виджет по сигналу "onfinish"  прокручивает прогрессбар.
Проблема действительно в том, что я не очень представляю, что и зачем в этом объекте. Более - менее уловил основную идею. Если б сам раньше подходил к транспорту с такой архитектурой, может было бы проще.

Пока пытаюсь в обход засовывать полученный код и ответа через setContent.

Что страшного я собираюсь сделать: передавать запрос по своему протоколу через специализированный прокси. Для этого формирую тело запроса из полей QNetworkAccessManager::createRequest
Ответ приходится давать в виде своей реализации QNetworkReply. Код выше - конечно тестовый,  в реальном варианте все сигналы должны активироваться в передаче данных в QNetworkReply от внешнего транспорта.


Название: Re: Реализация QNetworkReply для QWebView
Отправлено: Krizis от Июль 22, 2016, 14:27
А вы не пробовали логировать внутри методов? Может они вообще не вызываются

Смотрел бряками, вызывается bytesAvailable, readData,  abort. В таком порядке.


Название: Re: Реализация QNetworkReply для QWebView
Отправлено: Bepec от Июль 22, 2016, 14:39
Зачем вам такие проблемы?
Сделайте приём нормальный на стороне прокси, а там уже создавайте какой вам нужно пакет.

Просто вы взяли и разобрали мотор, а на деле вам нужно топливо поменять. Смысла не вижу :)


Название: Re: Реализация QNetworkReply для QWebView
Отправлено: Krizis от Июль 22, 2016, 14:55
Зачем вам такие проблемы?
Сделайте приём нормальный на стороне прокси, а там уже создавайте какой вам нужно пакет.

Просто вы взяли и разобрали мотор, а на деле вам нужно топливо поменять. Смысла не вижу :)

не понял, о каком приёме на стороне прокси речь? транспорт используется внешний,  из qt забирается буфер, возвращается тоже буфер.
Есть какой то способ состыковать внешний транспорт и QWebView проще?


Название: Re: Реализация QNetworkReply для QWebView
Отправлено: Bepec от Июль 22, 2016, 15:06
Таки непонятно что вам надо. Запросы от QWebView это стандартные html'ные запросы, который любой прокси должен схавать без дополнительных причуд.



Название: Re: Реализация QNetworkReply для QWebView
Отправлено: Krizis от Июль 22, 2016, 16:05
Таки непонятно что вам надо. Запросы от QWebView это стандартные html'ные запросы, который любой прокси должен схавать без дополнительных причуд.



Мне надо именно сторонним транспортом передавать эти запросы.
Сейчас в основном это уже работает, повидимому, вебкит действительно не ожидает сигналов из того же потока, в котором создаётся запрос.  Что то похожее вы сразу и писали.
В приближенной к боевой, реализации - уже воспринимает:


Код:
#include <QNetworkReply>
#include <qcoreapplication.h>
#include <QtCore/QMetaObject>

class ProxyNetworkReply: public QNetworkReply
{
    Q_OBJECT

public:
    ProxyNetworkReply(QObject *parent, const QNetworkRequest &req,
            const QNetworkAccessManager::Operation op)
        : QNetworkReply(parent)
    {
        setRequest(req);
        setUrl(req.url());
        setOperation(op);


    }
    void abort() { QNetworkReply::close(); }
    qint64 bytesAvailable() const { return m_content.size() - m_lOffset; }
    bool isSequential() const { return true; }

    qint64 size() const
    {
        return  m_content.size();
    }


    void setData(QString string)
    {
        setFinished(true);

        QNetworkReply::open(QIODevice::ReadOnly | QIODevice::Unbuffered);

        //QString string = "<!DOCTYPE HTML><html> <head>  </head> <body><H1> description</H1></body></html>";

        m_content = string.toUtf8();
        m_lOffset = 0;

        setHeader(QNetworkRequest::ContentTypeHeader,
                QVariant("text/html; charset=UTF-8"));
        setHeader(QNetworkRequest::ContentLengthHeader,
                QVariant(m_content.size()));

        QMetaObject::invokeMethod(this, "metaDataChanged",
                Qt::QueuedConnection);
        QMetaObject::invokeMethod(this, "downloadProgress",
                Qt::QueuedConnection, Q_ARG(qint64, m_content.size()), Q_ARG(qint64, m_content.size()));
        QMetaObject::invokeMethod(this, "readyRead",
                Qt::QueuedConnection);

        QMetaObject::invokeMethod(this, "readChannelFinished",
                Qt::QueuedConnection);

        QMetaObject::invokeMethod(this, "finished",
                Qt::QueuedConnection);

            QCoreApplication::postEvent(this, new QEvent(QEvent::NetworkReplyUpdated));
    }

    protected:

    qint64 readData(char* pData, qint64 lMaxSize)
    {
        if (m_lOffset >= m_content.size())
            return -1;

        qint64 lCount = qMin(lMaxSize, m_content.size() - m_lOffset);
        memcpy(pData, m_content.constData() + m_lOffset, lCount);
        m_lOffset += lCount;
        return lCount;
    }

private slots:

private:
    QByteArray m_content;
    qint64 m_lOffset;
};



Название: Re: Реализация QNetworkReply для QWebView
Отправлено: Bepec от Июль 22, 2016, 16:12
Как я уже говорил - он не успевал подцепить connect к сигналам. И поэтому всё что вы в конструкторе писали летело куда угодно, но не webView.