Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override HTTP Error page in QtWebkit

Tags:

qt

qtwebkit

I would like to display an error page in a QWebView. For example if the server returns a 404 Error the QWebView should display a its own custom 404 Error instead of the one sent from the server.

I use the QWebPage::extension to handle error conditions and it works well for Network Errors. However if the server returns an error 404 and at the same time returns an error page, this page is displayed and the QWebPage::extension method is never called.

Is there a way to force QtWebKit to invoke the error handler and override the server error page?

like image 335
Pascal Avatar asked Feb 14 '12 15:02

Pascal


2 Answers

After hopping around the code long enough, trying various things, the following seems to solve at least my case:

MyWebPageSubclass::MyWebPageSubclass(...) {
    connect(networkAccessManager(), SIGNAL(finished(QNetworkReply*)), this, SLOT(handleNetworkFinished(QNetworkReply*)));
    // ...
}

void MyWebPageSubclass::handleNetworkFinished(QNetworkReply *reply) {
    bool ok = false;
    int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(&ok);

    if (ok && httpStatus / 100 != 1 && httpStatus / 100 != 2 && httpStatus / 100 != 3) {
        if (!supportsExtension(ErrorPageExtension)) {
            return;
        }

        ErrorPageExtensionOption option;
        option.domain = Http;
        option.error = httpStatus;
        option.url = reply->url();
        option.errorString = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
        ErrorPageExtensionReturn output;
        if (!extension(ErrorPageExtension, &option, &output)) {
            return;
        }

        mainFrame()->setContent(output.content, output.contentType, output.baseUrl);
    }
}
like image 129
Ivo Avatar answered Sep 20 '22 03:09

Ivo


One note, if you replace mainFrame content in handleNetworkFinished() slot you may see your error page instead of loaded page if network errors occurred with the page elements (like external images or scripts).

Another option would be re-implementing QWebPage::extension() and QWebPage::supportsExtension(), in which case QT Webkit will call your implementation of extension() for page errors and replace page content with the page you provided, like:

class WebPage : public QWebPage
{
  Q_OBJECT
public:
  WebPage(QObject *parent = 0);
  bool extension(Extension extension,
                 const ExtensionOption *option,
                 ExtensionReturn * output);
  bool supportsExtension(Extension extension) const;
};

bool WebPage::extension(Extension extension,
                        const ExtensionOption *option,
                        ExtensionReturn * output)
{
  if(!option || !output) {
      return false;
  }
  if(extension == QWebPage::ErrorPageExtension) {
    const ErrorPageExtensionOption *errOption =
           static_cast<const ErrorPageExtensionOption*>(option);
    QString errPage;
    errPage = "<html><body><h1>";
    errPage += "Page loading error, URL: ";
    errPage += errOption->url.toString();
    errPage += "</h1><h3>Error occurred in the ";
    switch (errOption->domain) {
      case QWebPage::QtNetwork:
        errPage += "QT network layer, code is: ";
        break;
      case QWebPage::Http:
        errPage += "HTTP layer, HTTP error code is: ";
        break;
      case QWebPage::WebKit:
        errPage += "WebKit internals, error code is: ";
        break;
      default:
        errPage += "Unknown domain, error code is: ";
    }
    errPage += errOption->error;
    errPage += "</h3><h4><br>Error text: ";
    errPage += errOption->errorString;
    errPage += "</h4></body></html>";
    ErrorPageExtensionReturn *errReturn =
                                static_cast<ErrorPageExtensionReturn*>(output);
    errReturn->baseUrl = errOption->url;
    errReturn->content = errPage.toUtf8();
    // errReturn->contentType = "text/html"
    // errReturn->encoding = "UTF-8"; // these values are defaults
    return true;
  }
  return false;
}

bool WebPage::supportsExtension(Extension extension) const
{
  if(extension == QWebPage::ErrorPageExtension) {
    return true;
  }
  return QWebPage::supportsExtension(extension);
}
like image 42
Eri Avatar answered Sep 18 '22 03:09

Eri