Ilka
Ilka

Reputation: 90

QWebView: disable external resources

Qt's QWebView class allows to render some HTML content with QWebView::setHtml(const QString &html, const QUrl &baseUrl) and of course it tries to load external resources if the HTML contains some references like <script src="..."></script>.

How can I turn this feature off for security reasons? I took a look at the header file and found no according virtual method to override and no according method to set the desired behavior.

Any dirty workarounds are welcome!

Upvotes: 0

Views: 368

Answers (1)

Ilka
Ilka

Reputation: 90

I found two separate solutions for QWebView and QWebEngineView.

QWebView

This solution works well for QWebView but I did not test it for WebEngineView (v.i).

First, derive a class from QNetworkReply that contains no data:

#include <QNetworkReply>
class EmptyNetworkReply  :  public  QNetworkReply  {
    public:
        EmptyNetworkReply(QObject *parent=nullptr)
                : QNetworkReply(parent)  {
        }
        // implement pure virtual methdos of QNetworkReply
        virtual void abort()  override  {
        }
        // implement pure virtual methods of QIODevice
        virtual bool isSequential()  const override  {
            return true;
        }
        virtual qint64 bytesAvailable()  const override  {
            return 0;
        }
        virtual qint64 readData(char *data, qint64 maxlen)  override  {
            (void)data;
            (void)maxlen;
            return 0;  // number of bytes read
        }
};

Also derive a class from QNetworkAccessManager and make it block all requests by always returning an instance of the above EmptyNetworkReply:

#include <QtNetwork/QNetworkAccessManager>
#include <iostream>
class RestrictiveNetworkAccessManager  :  public  QNetworkAccessManager  {
    public:
        RestrictiveNetworkAccessManager(QWidget *parent)
                : QNetworkAccessManager(parent)  {
        }
    protected:
        virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &request,
                                             QIODevice *outgoingData = nullptr)  override  {
            (void)op;
            (void)outgoingData;
            std::cout << "intercepting request to URL >" << request.url().toString().toStdString() << "<" << std::endl;
            // block request by not forwarding to  QNetworkAccessManager::createRequest(op,request,outgoingData);
            return new EmptyNetworkReply(this);
        }
};

Finally, create a QWebView with a QWebPage that uses the above RestrictiveNetworkAccessManager:

QString myDocumentHtml = "<h1>foo</h1><img src=\"https://maxcdn.icons8.com/Share/icon/Logos/duckduckgo1600.png\" width='100%'><h2>bar</h2>";

QWebView *webView = new QWebView();
QWebPage *page = new QWebPage(webView);
page->setNetworkAccessManager(new RestrictiveNetworkAccessManager(webView));
page->mainFrame()->setHtml(myDocumentHtml);
webView->setPage(page);

console output of the above example:

intercepting request to URL >https://maxcdn.icons8.com/Share/icon/Logos/duckduckgo1600.png<

Btw, one might also want to disable JavaScript:

webView->settings()->setAttribute(QWebSettings::WebAttribute::JavascriptEnabled, false);

QWebEngineView

There is a solution that works with QWebEngineView (but not with QWebView as far as I can tell from the documentation). However, it is probably a good idea to migrate from QWebView to QWebEngineView, anyways (although I experienced an insane performance drop with QWebEngineView).

First, derive a class from QWebEngineUrlRequestInterceptor and make it block all requests except the very first one:

#include <QWebEngineUrlRequestInterceptor>
#include <QWebEngineView>
class RestrictingInterceptor  :  public QWebEngineUrlRequestInterceptor  {
    private:
        bool firstRequestPassed=false;
    protected:
        virtual void interceptRequest(QWebEngineUrlRequestInfo &info)  override  {
            std::cout << "intercepting request to URL >" << info.requestUrl().toString().toStdString() << "<" << std::endl;
            info.block(firstRequestPassed);
            firstRequestPassed = true;
        }
};

Then, make sure that the QWebEngineView uses that intercepter:

QString myDocumentHtml = "<h1>foo</h1><img src=\"https://maxcdn.icons8.com/Share/icon/Logos/duckduckgo1600.png\" width='100%'><h2>bar</h2>";

QWebEnginePage *page = new QWebEnginePage();
page->setUrlRequestInterceptor(new RestrictingInterceptor());
page->setHtml(myDocumentHtml);
QWebEngineView *webEngineView = new QWebEngineView();
webEngineView->setPage(page);

console output of the HTML loaded in the above example:

intercepting request to URL >data:text/html;charset=UTF-8,%3Ch1%3Efoo%3C%2Fh1%3E%3Cimg src%3D%22https%3A%2F%2Fmaxcdn.icons8.com%2FShare%2Ficon%2FLogos%2Fduckduckgo1600.png%22 width%3D%27100%25%27%3E%3Ch2%3Ebar%3C%2Fh2%3E<
intercepting request to URL >https://maxcdn.icons8.com/Share/icon/Logos/duckduckgo1600.png<

Btw, one might also want to disable JavaScript:

webEngineView->settings()->setAttribute(QWebEngineSettings::WebAttribute::JavascriptEnabled, false);

Upvotes: 0

Related Questions