QT QNetworkAccessManager+QNetworkReply

QtWebkit problems with custom QNetworkAccessManager+QNetworkReply

Hi

I have run into a mysterious issue with QNetworkAccessManager and/or QtWebkit. Using qt 4.6.2 with vs2008.

My app uses webkit to provide a user interface so the user can navigate through and display app-specific data structure held within the app's memory.

To do this the app has a very similar structure to the 'fancybrowser' sample included with Qt, but to which I added a custom QNetworkAccessManager which detects url's that use a private scheme (I used "myp:") and passes them to my own QNetworkReply derivation which knows how to supply the app specific html. All other urls are passed to the QNetworkAccessManager base class for default handling. This is exactly the same code structure as described in a recent Qt Quarterly article describing these techniques.

This appears to work however there is a problem. I have found that whenever the webview is displaying html obtained from an app-private url e.g myp:/fred, any image within the returned html whose source url is not http based just does not get displayed. Why is this?

Here's a more specific description of the problem.

Lets say I create a trivial bit of html which just displays three different images using <img> tags. The first image is stored locally and referenced with a file: based url. The second image is built into the app's binary as a Qt resource and is referenced with a qrc: url. The final image is taken from the net and so has a http: url. I store this html snippet in a local file C:\test.html:
 

<html><body>
FROM file:///c:/Dalmatian.jpg:<br><img src='file:///c:/Dalmatian.jpg'><br>
FROM qrc:/5453039.jpg:<br><img src='qrc:/5453039.jpg'><br>
FROM http://www.google.co.uk/intl/en_uk/images/logo.gif:<br>
<img src='http://www.google.co.uk/intl/en_uk/images/logo.gif'>
</body></html>

Using my modded fancybrowser I can display this by entering "file:///c:/test.html" in the url box and all is fine, with the 3 images displaying as expected. Here's a screenshot (like my classy images!):



BUT if I arrange for the precise same html snippet to be returned by my own QNetworkReply class, in response to entering an app-private url starting "myp:", what I find is that the only image that displays is the one with the http: url; the images with file: and qrc: urls just dont appear. Here's the screenshot after I put 'myp:' in the url bar. Note images 1+2 missing.



Why is this? What is going on? Is there a workaround/fix? Why is it that the provider of the html seems to affect how QtWebkit displays it?

Thanks.

Here is the relevant code. Note I can reproduce this problem by taking a copy of the qt fancybrowser sample, adding in the code below. Oh and I bind the jpg image referred to (using the qrc: url) into the app by adding a Q_INIT_RESOURCE line to main(). But that is all. No other changes.

First the QNetworkAccessManager derivation which is virtually identical to the example code from a recent Qt Quarterly.

Qt Code:

​​​​​​

// header

#include <QNetworkAccessManager>

class MyNetworkAccessManager : public QNetworkAccessManager
{
    Q_OBJECT

    public:
    MyNetworkAccessManager(QNetworkAccessManager *oldManager, QObject *parent = 0);
    protected:
    QNetworkReply* createRequest(QNetworkAccessManager::Operation op,
    const QNetworkRequest &req, QIODevice *device);
};

// code
MyNetworkAccessManager::MyNetworkAccessManager(

QNetworkAccessManager *oldManager, QObject *parent )
    : QNetworkAccessManager(parent)
{
    setCache(oldManager->cache());
    setCookieJar(oldManager->cookieJar());
    setProxy(oldManager->proxy());
    setProxyFactory(oldManager->proxyFactory());
}


QNetworkReply* MyNetworkAccessManager::createRequest(

    QNetworkAccessManager::Operation op, const QNetworkRequest &req,QIODevice *device)
{
    if ((op == QNetworkAccessManager::GetOperation ||
    op == QNetworkAccessManager::HeadOperation) && req.url().scheme() == "myp")
        return new MyNetworkReply(this, req, op);
    // defer to default:
    return QNetworkAccessManager::createRequest(op, req, device);
}

To copy to clipboard, switch view to plain text mode 

The code to install this network manager is placed in the main window class immediately after creation of the QWebView:
Qt Code:
Switch view



.

.

view = new QWebView(this);

// MYCODE BEGINS

QNetworkAccessManager *oldManager = view->page()->networkAccessManager();

MyNetworkAccessManager *newManager = new MyNetworkAccessManager(oldManager, this);

view->page()->setNetworkAccessManager(newManager);

/ MYCODE ENDS

.

.

To copy to clipboard, switch view to plain text mode 


The QNetworkReply class. Here I have cut it down to its barest minimum, all this does is setup a reply containing a fixed snippet of html above. It just sticks the html in a QByteArray and set up readData/bytesAvailable etc to access this.

Qt Code:
Switch view



class MyNetworkReply : public QNetworkReply

{

    Q_OBJECT



    public:

    MyNetworkReply(QObject *parent, const QNetworkRequest &req,

    const QNetworkAccessManager::Operation op)

    : QNetworkReply(parent)

{

    setRequest(req);

    setUrl(req.url());

    setOperation(op);

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



    QString string = "<html><body>FROM MyNetworkReply:<br>\
    
    FROM file:///c:/Dalmatian.jpg:<br><img src='file:///c:/Dalmatian.jpg'><br>\

    FROM qrc:/5453039.jpg:<br><img src='qrc:/5453039.jpg'><br>\

    FROM http://www.google.co.uk/intl/en_uk/images/logo.gif:<br>\

    <img src='http://www.google.co.uk/intl/en_uk/images/logo.gif'>\

    </body></html>\n";



    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, "finished",

    Qt::QueuedConnection);

}

    void abort() { QNetworkReply::close(); }

    qint64 bytesAvailable() const { return m_content.size() - m_lOffset; }

    bool isSequential() const { return true; }



    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;

};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值