Advertisement
Guest User

shadeslayer

a guest
Sep 4th, 2010
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.63 KB | None | 0 0
  1. /*
  2.  * Copyright 2009 Benjamin C. Meyer <ben@meyerhome.net>
  3.  * Copyright 2009 Jakub Wieczorek <faw217@gmail.com>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
  18.  * Boston, MA  02110-1301  USA
  19.  */
  20.  
  21. #include "webpage.h"
  22.  
  23. #include "browserapplication.h"
  24. #include "downloadmanager.h"
  25. #include "historymanager.h"
  26. #include "networkaccessmanager.h"
  27. #include "opensearchengine.h"
  28. #include "opensearchmanager.h"
  29. #include "tabwidget.h"
  30. #include "toolbarsearch.h"
  31. #include "webpluginfactory.h"
  32. #include "webview.h"
  33.  
  34. #include <qbuffer.h>
  35. #include <qdesktopservices.h>
  36. #include <qmessagebox.h>
  37. #include <qnetworkreply.h>
  38. #include <qnetworkrequest.h>
  39. #include <qsettings.h>
  40. #include <qwebframe.h>
  41.  
  42. #if QT_VERSION >= 0x040600 || defined(WEBKIT_TRUNK)
  43. #include <qwebelement.h>
  44. #endif
  45.  
  46. WebPluginFactory *WebPage::s_webPluginFactory = 0;
  47. QString WebPage::s_userAgent;
  48.  
  49. JavaScriptExternalObject::JavaScriptExternalObject(QObject *parent)
  50.     : QObject(parent)
  51. {
  52. }
  53.  
  54. void JavaScriptExternalObject::AddSearchProvider(const QString &url)
  55. {
  56.     ToolbarSearch::openSearchManager()->addEngine(QUrl(url));
  57. }
  58.  
  59. Q_DECLARE_METATYPE(OpenSearchEngine*)
  60. JavaScriptAroraObject::JavaScriptAroraObject(QObject *parent)
  61.     : QObject(parent)
  62. {
  63.     static const char *translations[] = {
  64.         QT_TR_NOOP("Welcome to Arora!"),
  65.         QT_TR_NOOP("Arora Start"),
  66.         QT_TR_NOOP("Search!"),
  67.         QT_TR_NOOP("Search results provided by"),
  68.         QT_TR_NOOP("About Arora")
  69.     };
  70.     Q_UNUSED(translations);
  71.  
  72.     qRegisterMetaType<OpenSearchEngine*>("OpenSearchEngine*");
  73. }
  74.  
  75. QString JavaScriptAroraObject::translate(const QString &string)
  76. {
  77.     QString translatedString = trUtf8(string.toUtf8().constData());
  78.  
  79.     // If the translation is the same as the original string
  80.     // it could not be translated.  In that case
  81.     // try to translate using the QApplication domain
  82.     if (translatedString != string)
  83.         return translatedString;
  84.     else
  85.         return qApp->trUtf8(string.toUtf8().constData());
  86. }
  87.  
  88. QObject *JavaScriptAroraObject::currentEngine() const
  89. {
  90.     return ToolbarSearch::openSearchManager()->currentEngine();
  91. }
  92.  
  93. QString JavaScriptAroraObject::searchUrl(const QString &string) const
  94. {
  95.     return QString::fromUtf8(ToolbarSearch::openSearchManager()->currentEngine()->searchUrl(string).toEncoded());
  96. }
  97.  
  98. WebPage::WebPage(QObject *parent)
  99.     : WebPageProxy(parent)
  100.     , m_openTargetBlankLinksIn(TabWidget::NewWindow)
  101.     , m_javaScriptExternalObject(0)
  102.     , m_javaScriptAroraObject(0)
  103. {
  104.     setPluginFactory(webPluginFactory());
  105.     NetworkAccessManagerProxy *networkManagerProxy = new NetworkAccessManagerProxy(this);
  106.     networkManagerProxy->setWebPage(this);
  107.     networkManagerProxy->setPrimaryNetworkAccessManager(BrowserApplication::networkAccessManager());
  108.     setNetworkAccessManager(networkManagerProxy);
  109.     connect(this, SIGNAL(unsupportedContent(QNetworkReply *)),
  110.             this, SLOT(handleUnsupportedContent(QNetworkReply *)));
  111.     connect(this, SIGNAL(frameCreated(QWebFrame *)),
  112.             this, SLOT(addExternalBinding(QWebFrame *)));
  113.     addExternalBinding(mainFrame());
  114.     loadSettings();
  115. }
  116.  
  117. WebPage::~WebPage()
  118. {
  119.     setNetworkAccessManager(0);
  120. }
  121.  
  122. WebPluginFactory *WebPage::webPluginFactory()
  123. {
  124.     if (!s_webPluginFactory)
  125.         s_webPluginFactory = new WebPluginFactory(BrowserApplication::instance());
  126.     return s_webPluginFactory;
  127. }
  128.  
  129. QList<WebPageLinkedResource> WebPage::linkedResources(const QString &relation)
  130. {
  131.     QList<WebPageLinkedResource> resources;
  132.  
  133. #if QT_VERSION >= 0x040600 || defined(WEBKIT_TRUNK)
  134.     QUrl baseUrl = mainFrame()->baseUrl();
  135.  
  136.     QWebElementCollection linkElements = mainFrame()->findAllElements(QLatin1String("html > head > link"));
  137.  
  138.     foreach (const QWebElement &linkElement, linkElements) {
  139.         QString rel = linkElement.attribute(QLatin1String("rel"));
  140.         QString href = linkElement.attribute(QLatin1String("href"));
  141.         QString type = linkElement.attribute(QLatin1String("type"));
  142.         QString title = linkElement.attribute(QLatin1String("title"));
  143.  
  144.         if (href.isEmpty() || type.isEmpty())
  145.             continue;
  146.         if (!relation.isEmpty() && rel != relation)
  147.             continue;
  148.  
  149.         WebPageLinkedResource resource;
  150.         resource.rel = rel;
  151.         resource.type = type;
  152.         resource.href = baseUrl.resolved(QUrl::fromEncoded(href.toUtf8()));
  153.         resource.title = title;
  154.  
  155.         resources.append(resource);
  156.     }
  157. #else
  158.     QString baseUrlString = mainFrame()->evaluateJavaScript(QLatin1String("document.baseURI")).toString();
  159.     QUrl baseUrl = QUrl::fromEncoded(baseUrlString.toUtf8());
  160.  
  161.     QFile file(QLatin1String(":fetchLinks.js"));
  162.     if (!file.open(QFile::ReadOnly))
  163.         return resources;
  164.     QString script = QString::fromUtf8(file.readAll());
  165.  
  166.     QVariantList list = mainFrame()->evaluateJavaScript(script).toList();
  167.     foreach (const QVariant &variant, list) {
  168.         QVariantMap map = variant.toMap();
  169.         QString rel = map[QLatin1String("rel")].toString();
  170.         QString type = map[QLatin1String("type")].toString();
  171.         QString href = map[QLatin1String("href")].toString();
  172.         QString title = map[QLatin1String("title")].toString();
  173.  
  174.         if (href.isEmpty() || type.isEmpty())
  175.             continue;
  176.         if (!relation.isEmpty() && rel != relation)
  177.             continue;
  178.  
  179.         WebPageLinkedResource resource;
  180.         resource.rel = rel;
  181.         resource.type = type;
  182.         resource.href = baseUrl.resolved(QUrl::fromEncoded(href.toUtf8()));
  183.         resource.title = title;
  184.  
  185.         resources.append(resource);
  186.     }
  187. #endif
  188.  
  189.     return resources;
  190. }
  191.  
  192. void WebPage::populateNetworkRequest(QNetworkRequest &request)
  193. {
  194.     if (request == lastRequest) {
  195.         request.setAttribute((QNetworkRequest::Attribute)(pageAttributeId() + 1), lastRequestType);
  196.     }
  197.     WebPageProxy::populateNetworkRequest(request);
  198. }
  199.  
  200. void WebPage::addExternalBinding(QWebFrame *frame)
  201. {
  202. #if QT_VERSION < 0x040600
  203.     QWebSettings *defaultSettings = QWebSettings::globalSettings();
  204.     if (!defaultSettings->testAttribute(QWebSettings::JavascriptEnabled))
  205.         return;
  206. #endif
  207.     if (!m_javaScriptExternalObject)
  208.         m_javaScriptExternalObject = new JavaScriptExternalObject(this);
  209.  
  210.     if (frame == 0) { // called from QWebFrame::javaScriptWindowObjectCleared
  211.         frame = qobject_cast<QWebFrame*>(sender());
  212.  
  213.         if (frame->url().scheme() == QLatin1String("qrc")
  214.             && frame->url().path() == QLatin1String("/startpage.html")) {
  215.  
  216.             if (!m_javaScriptAroraObject)
  217.                 m_javaScriptAroraObject = new JavaScriptAroraObject(this);
  218.  
  219.             frame->addToJavaScriptWindowObject(QLatin1String("arora"), m_javaScriptAroraObject);
  220.         }
  221.     } else { // called from QWebPage::frameCreated
  222.         connect(frame, SIGNAL(javaScriptWindowObjectCleared()),
  223.                 this, SLOT(addExternalBinding()));
  224.     }
  225.     frame->addToJavaScriptWindowObject(QLatin1String("external"), m_javaScriptExternalObject);
  226. }
  227.  
  228. QString WebPage::userAgent()
  229. {
  230.     return s_userAgent;
  231. }
  232.  
  233. void WebPage::setUserAgent(const QString &userAgent)
  234. {
  235.     if (userAgent == s_userAgent)
  236.         return;
  237.  
  238.     QSettings settings;
  239.     if (userAgent.isEmpty()) {
  240.         settings.remove(QLatin1String("userAgent"));
  241.     } else {
  242.         settings.setValue(QLatin1String("userAgent"), userAgent);
  243.     }
  244.  
  245.     s_userAgent = userAgent;
  246. }
  247.  
  248. QString WebPage::userAgentForUrl(const QUrl &url) const
  249. {
  250.     if (s_userAgent.isEmpty())
  251.         s_userAgent = QWebPage::userAgentForUrl(url);
  252.     return s_userAgent;
  253. }
  254.  
  255. bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request,
  256.                                       NavigationType type)
  257. {
  258.     lastRequest = request;
  259.     lastRequestType = type;
  260.  
  261.     QString scheme = request.url().scheme();
  262.     if (scheme == QLatin1String("mailto")
  263.         || scheme == QLatin1String("ftp")) {
  264.         BrowserApplication::instance()->askDesktopToOpenUrl(request.url());
  265.         return false;
  266.     }
  267.  
  268.     if (type == QWebPage::NavigationTypeFormResubmitted) {
  269.         QMessageBox::StandardButton button = QMessageBox::warning(view(), tr("Resending POST request"),
  270.                              tr("In order to display the site, the request along with all the data must be sent once again, "
  271.                                 "which may lead to some unexpected behaviour of the site e.g. the same action might be "
  272.                                 "performed once again. Do you want to continue anyway?"), QMessageBox::Yes | QMessageBox::No);
  273.         if (button != QMessageBox::Yes)
  274.             return false;
  275.     }
  276.  
  277.     TabWidget::OpenUrlIn openIn = frame ? TabWidget::CurrentTab : TabWidget::NewWindow;
  278.     openIn = TabWidget::modifyWithUserBehavior(openIn);
  279.  
  280.     // handle the case where we want to do something different then
  281.     // what qwebpage would do
  282.     if (openIn == TabWidget::NewSelectedTab
  283.         || openIn == TabWidget::NewNotSelectedTab
  284.         || (frame && openIn == TabWidget::NewWindow)) {
  285.         if (WebView *webView = qobject_cast<WebView*>(view())) {
  286.             TabWidget *tabWidget = webView->tabWidget();
  287.             if (tabWidget) {
  288.                 WebView *newView = tabWidget->getView(openIn, webView);
  289.                 QWebPage *page = 0;
  290.                 if (newView)
  291.                     page = newView->page();
  292.                 if (page && page->mainFrame())
  293.                     page->mainFrame()->load(request);
  294.             }
  295.         }
  296.         return false;
  297.     }
  298.  
  299.     bool accepted = QWebPage::acceptNavigationRequest(frame, request, type);
  300.     if (accepted && frame == mainFrame()) {
  301.         m_requestedUrl = request.url();
  302.         emit aboutToLoadUrl(request.url());
  303.     }
  304.  
  305.     return accepted;
  306. }
  307.  
  308. void WebPage::loadSettings()
  309. {
  310.     QSettings settings;
  311.     settings.beginGroup(QLatin1String("tabs"));
  312.     m_openTargetBlankLinksIn = (TabWidget::OpenUrlIn)settings.value(QLatin1String("openTargetBlankLinksIn"),
  313.                                                                     TabWidget::NewSelectedTab).toInt();
  314.     settings.endGroup();
  315.     s_userAgent = settings.value(QLatin1String("userAgent")).toString();
  316. }
  317.  
  318. QWebPage *WebPage::createWindow(QWebPage::WebWindowType type)
  319. {
  320.     Q_UNUSED(type);
  321.     if (WebView *webView = qobject_cast<WebView*>(view())) {
  322.         TabWidget *tabWidget = webView->tabWidget();
  323.         if (tabWidget) {
  324.             TabWidget::OpenUrlIn openIn = m_openTargetBlankLinksIn;
  325.             openIn = TabWidget::modifyWithUserBehavior(openIn);
  326.             return tabWidget->getView(openIn, webView)->page();
  327.         }
  328.     }
  329.     return 0;
  330. }
  331.  
  332. QObject *WebPage::createPlugin(const QString &classId, const QUrl &url,
  333.                                const QStringList &paramNames, const QStringList &paramValues)
  334. {
  335.     Q_UNUSED(classId);
  336.     Q_UNUSED(url);
  337.     Q_UNUSED(paramNames);
  338.     Q_UNUSED(paramValues);
  339. #if !defined(QT_NO_UITOOLS)
  340.     QUiLoader loader;
  341.     return loader.createWidget(classId, view());
  342. #else
  343.     return 0;
  344. #endif
  345. }
  346.  
  347. // The chromium guys have documented many examples of incompatibilities that
  348. // different browsers have when they mime sniff.
  349. // http://src.chromium.org/viewvc/chrome/trunk/src/net/base/mime_sniffer.cc
  350. //
  351. // All WebKit ports should share a common set of rules to sniff content.
  352. // By having this here we are yet another browser that has different behavior :(
  353. // But sadly QtWebKit does no sniffing at all so we are forced to do something.
  354. static bool contentSniff(const QByteArray &data)
  355. {
  356.     if (data.contains("<!doctype")
  357.         || data.contains("<script")
  358.         || data.contains("<html")
  359.         || data.contains("<!--")
  360.         || data.contains("<head")
  361.         || data.contains("<iframe")
  362.         || data.contains("<h1")
  363.         || data.contains("<div")
  364.         || data.contains("<font")
  365.         || data.contains("<table")
  366.         || data.contains("<a")
  367.         || data.contains("<style")
  368.         || data.contains("<title")
  369.         || data.contains("<b")
  370.         || data.contains("<body")
  371.         || data.contains("<br")
  372.         || data.contains("<p"))
  373.         return true;
  374.     return false;
  375. }
  376.  
  377. void WebPage::handleUnsupportedContent(QNetworkReply *reply)
  378. {
  379.     if (!reply)
  380.         return;
  381.  
  382.     QUrl replyUrl = reply->url();
  383.  
  384.     if (replyUrl.scheme() == QLatin1String("abp"))
  385.         return;
  386.  
  387.     switch (reply->error()) {
  388.     case QNetworkReply::NoError:
  389.         if (reply->header(QNetworkRequest::ContentTypeHeader).isValid()) {
  390.             BrowserApplication::downloadManager()->handleUnsupportedContent(reply);
  391.             return;
  392.         }
  393.         break;
  394.     case QNetworkReply::ProtocolUnknownError: {
  395.         QSettings settings;
  396.         settings.beginGroup(QLatin1String("WebView"));
  397.         QStringList externalSchemes = settings.value(QLatin1String("externalSchemes")).toStringList();
  398.         if (externalSchemes.contains(replyUrl.scheme())) {
  399.             QDesktopServices::openUrl(replyUrl);
  400.             return;
  401.         }
  402.         break;
  403.     }
  404.     default:
  405.         break;
  406.     }
  407.  
  408.     // Find the frame that has the unsupported content
  409.     if (replyUrl.isEmpty() || replyUrl != m_requestedUrl)
  410.         return;
  411.  
  412.     QWebFrame *notFoundFrame = mainFrame();
  413.     if (!notFoundFrame)
  414.         return;
  415.  
  416.     if (reply->header(QNetworkRequest::ContentTypeHeader).toString().isEmpty()) {
  417.         // do evil
  418.         QByteArray data = reply->readAll();
  419.         if (contentSniff(data)) {
  420.             notFoundFrame->setHtml(QLatin1String(data), replyUrl);
  421.             return;
  422.         }
  423.     }
  424.  
  425.     // Generate translated not found error page with an image
  426.     QFile notFoundErrorFile(QLatin1String(":/notfound.html"));
  427.     if (!notFoundErrorFile.open(QIODevice::ReadOnly))
  428.         return;
  429.     QString title = tr("Error loading page: %1").arg(QString::fromUtf8(replyUrl.toEncoded()));
  430.     QString html = QLatin1String(notFoundErrorFile.readAll());
  431.     QPixmap pixmap = qApp->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, view()).pixmap(QSize(32, 32));
  432.     QBuffer imageBuffer;
  433.     imageBuffer.open(QBuffer::ReadWrite);
  434.     if (pixmap.save(&imageBuffer, "PNG")) {
  435.         html.replace(QLatin1String("IMAGE_BINARY_DATA_HERE"),
  436.                      QLatin1String(imageBuffer.buffer().toBase64()));
  437.     }
  438.     html = html.arg(title,
  439.                     reply->errorString(),
  440.                     tr("When connecting to: %1.").arg(QString::fromUtf8(replyUrl.toEncoded())),
  441.                     tr("Check the address for errors such as <b>ww</b>.arora-browser.org instead of <b>www</b>.arora-browser.org"),
  442.                     tr("If the address is correct, try checking the network connection."),
  443.                     tr("If your computer or network is protected by a firewall or proxy, make sure that the browser is permitted to access the network."));
  444.     notFoundFrame->setHtml(html, replyUrl);
  445.     // Don't put error pages to the history.
  446.     BrowserApplication::instance()->historyManager()->removeHistoryEntry(replyUrl, notFoundFrame->title());
  447. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement