diff options
Diffstat (limited to 'src/webpage.cpp')
-rw-r--r-- | src/webpage.cpp | 501 |
1 files changed, 370 insertions, 131 deletions
diff --git a/src/webpage.cpp b/src/webpage.cpp index b2bedffc..b510311e 100644 --- a/src/webpage.cpp +++ b/src/webpage.cpp @@ -6,7 +6,8 @@ * Copyright (C) 2008 Dirk Mueller <mueller@kde.org> * Copyright (C) 2008 Urs Wolfer <uwolfer @ kde.org> * Copyright (C) 2008 Michael Howell <mhowell123@gmail.com> -* Copyright (C) 2008-2009 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2008-2010 by Andrea Diamantini <adjam7 at gmail dot com> +* Copyright (C) 2010 by Matthieu Gicquel <matgic78 at gmail dot com> * * * This program is free software; you can redistribute it and/or @@ -14,9 +15,9 @@ * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved -* by the membership of KDE e.V.), which shall act as a proxy +* by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. -* +* * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -44,10 +45,11 @@ #include "networkaccessmanager.h" #include "adblockmanager.h" +#include "sslinfodialog_p.h" + // KDE Includes #include <KStandardDirs> #include <KUrl> -#include <KDebug> #include <KToolInvocation> #include <KProtocolManager> #include <kwebwallet.h> @@ -69,31 +71,68 @@ #include <QtGui/QClipboard> #include <QtGui/QKeyEvent> +#include <QtWebKit/QWebFrame> + + +// Returns true if the scheme and domain of the two urls match... +static bool domainSchemeMatch(const QUrl& u1, const QUrl& u2) +{ + if (u1.scheme() != u2.scheme()) + return false; + + QStringList u1List = u1.host().split(QL1C('.'), QString::SkipEmptyParts); + QStringList u2List = u2.host().split(QL1C('.'), QString::SkipEmptyParts); + + if (qMin(u1List.count(), u2List.count()) < 2) + return false; // better safe than sorry... -WebPage::WebPage(QObject *parent) + while (u1List.count() > 2) + u1List.removeFirst(); + + while (u2List.count() > 2) + u2List.removeFirst(); + + return (u1List == u2List); +} + + +// --------------------------------------------------------------------------------- + + +WebPage::WebPage(QWidget *parent) : KWebPage(parent, KWalletIntegration) { + // ----- handling unsupported content... setForwardUnsupportedContent(true); + connect(this, SIGNAL(unsupportedContent(QNetworkReply *)), this, SLOT(handleUnsupportedContent(QNetworkReply *))); - // rekonq Network Manager + // ----- rekonq Network Manager NetworkAccessManager *manager = new NetworkAccessManager(this); - - // disable QtWebKit cache to just use KIO one.. - manager->setCache(0); - + manager->setCache(0); // disable QtWebKit cache to just use KIO one.. + + // set cookieJar window ID.. + if (parent && parent->window()) + manager->setCookieJarWindowId(parent->window()->winId()); + setNetworkAccessManager(manager); - - // Web Plugin Factory + + // activate ssl warnings + setSessionMetaData("ssl_activate_warnings", "TRUE"); + + // Override the 'Accept' header sent by QtWebKit which favors XML over HTML! + // Setting the accept meta-data to null will force kio_http to use its own + // default settings for this header. + setSessionMetaData(QL1S("accept"), QString()); + + // ----- Web Plugin Factory setPluginFactory(new WebPluginFactory(this)); - - connect(networkAccessManager(), SIGNAL(finished(QNetworkReply*)), this, SLOT(manageNetworkErrors(QNetworkReply*))); - - connect(this, SIGNAL(unsupportedContent(QNetworkReply *)), this, SLOT(handleUnsupportedContent(QNetworkReply *))); + // ----- last stuffs + connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(manageNetworkErrors(QNetworkReply*))); connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool))); // protocol handler signals - connect(&m_protHandler, SIGNAL(downloadUrl(const KUrl &)), this, SLOT(downloadUrl(const KUrl &))); + connect(&_protHandler, SIGNAL(downloadUrl(const KUrl &)), this, SLOT(downloadUrl(const KUrl &))); } @@ -105,23 +144,68 @@ WebPage::~WebPage() bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type) { - // advise users on resubmitting data - if(type == QWebPage::NavigationTypeFormResubmitted) + _loadingUrl = request.url(); + + KIO::AccessManager *manager = qobject_cast<KIO::AccessManager*>(networkAccessManager()); + KIO::MetaData metaData = manager->requestMetaData(); + + // Get the SSL information sent, if any... + if (metaData.contains(QL1S("ssl_in_use"))) { - int risp = KMessageBox::warningContinueCancel(view(), - i18n("Are you sure you want to send your data again?"), - i18n("Resend form data") ); - if(risp == KMessageBox::Cancel) - return false; + WebSslInfo info; + info.fromMetaData(metaData.toVariant()); + info.setUrl(request.url()); + _sslInfo = info; } - if (frame && m_protHandler.preHandling( request, frame )) + if (frame) { - return false; - } + if (_protHandler.preHandling(request, frame)) + { + return false; + } - m_requestedUrl = request.url(); + switch (type) + { + case QWebPage::NavigationTypeLinkClicked: + if (_sslInfo.isValid()) + { + setRequestMetaData("ssl_was_in_use", "TRUE"); + } + break; + + case QWebPage::NavigationTypeFormSubmitted: + break; + + case QWebPage::NavigationTypeFormResubmitted: + if (KMessageBox::warningContinueCancel(view(), + i18n("Are you sure you want to send your data again?"), + i18n("Resend form data") + ) + == KMessageBox::Cancel) + { + return false; + } + break; + + case QWebPage::NavigationTypeReload: + case QWebPage::NavigationTypeBackOrForward: + case QWebPage::NavigationTypeOther: + break; + + default: + break; + } + if (frame == mainFrame()) + { + setRequestMetaData("main_frame_request", "TRUE"); + } + else + { + setRequestMetaData("main_frame_request", "FALSE"); + } + } return KWebPage::acceptNavigationRequest(frame, request, type); } @@ -135,9 +219,9 @@ WebPage *WebPage::createWindow(QWebPage::WebWindowType type) kDebug() << "Modal Dialog"; WebTab *w = 0; - if(ReKonfig::openTabNoWindow()) + if (ReKonfig::openTabNoWindow()) { - w = Application::instance()->mainWindow()->mainView()->newWebTab(!ReKonfig::openTabsBack()); + w = Application::instance()->mainWindow()->mainView()->newWebTab(!ReKonfig::openTabsBack(), ReKonfig::openTabsNearCurrent()); } else { @@ -149,95 +233,158 @@ WebPage *WebPage::createWindow(QWebPage::WebWindowType type) void WebPage::handleUnsupportedContent(QNetworkReply *reply) { + // NOTE + // This is probably needed just in ONE stupid case.. + if (_protHandler.postHandling(reply->request(), mainFrame())) + return; + if (reply->error() == QNetworkReply::NoError) { - const KUrl url( reply->url() ); + const KUrl url(reply->url()); QString mimeType = reply->header(QNetworkRequest::ContentTypeHeader).toString(); - KService::Ptr offer = KMimeTypeTrader::self()->preferredService(mimeType); + KService::Ptr appService = KMimeTypeTrader::self()->preferredService(mimeType); bool isLocal = url.isLocalFile(); - - if( offer.isNull() ) // no service can handle this. We can just download it.. + + if (appService.isNull()) // no service can handle this. We can just download it.. { - isLocal ? KMessageBox::sorry(view(), i18n("No service can handle this :(") ) : downloadRequest(reply->request()); + kDebug() << "no service can handle this. We can just download it.."; + + isLocal + ? KMessageBox::sorry(view(), i18n("No service can handle this :(")) + : downloadRequest(reply->request()); + return; } - if(!isLocal) + if (!isLocal) { - + KParts::BrowserOpenOrSaveQuestion dlg(Application::instance()->mainWindow(), url, mimeType); - switch ( dlg.askEmbedOrSave() ) + switch (dlg.askEmbedOrSave()) { - case KParts::BrowserOpenOrSaveQuestion::Save: - downloadRequested(reply->request()); - return; - case KParts::BrowserOpenOrSaveQuestion::Cancel: - return; - default: // non extant case - break; + case KParts::BrowserOpenOrSaveQuestion::Save: + kDebug() << "service handling: download!"; + downloadRequest(reply->request()); + return; + + case KParts::BrowserOpenOrSaveQuestion::Cancel: + return; + + default: // non extant case + break; } } + // case KParts::BrowserRun::Embed - KUrl::List list; - list.append(url); - KRun::run(*offer,url,0); + + KService::List partServices = KMimeTypeTrader::self()->query(mimeType, QL1S("KParts/ReadOnlyPart")); + if (partServices.count() > 0) + { + // A part can handle this. Embed it! + QString html; + html += "<html>"; + html += "<head>"; + html += "<title>"; + html += url.pathOrUrl(); + html += "</title>"; + html += "<style type=\"text/css\">"; + html += "* { border: 0; padding: 0; margin: 0; }"; + html += "</style>"; + html += "</head>"; + html += "<body>"; + html += "<embed src=\"" + url.pathOrUrl() + "\" width=\"100%\" height=\"100%\" />"; + html += "</body>"; + html += "</html>"; + + mainFrame()->setHtml(html, url); + } + else + { + // No parts, just app services. Load it! + KRun::run(*appService, url, 0); + } + + return; } } -void WebPage::loadFinished(bool) +void WebPage::loadFinished(bool ok) { + Q_UNUSED(ok); + Application::adblockManager()->applyHidingRules(this); - + + QStringList list = ReKonfig::walletBlackList(); + // KWallet Integration - // TODO: Add check for sites exempt from automatic form filling... - if (wallet()) + if (wallet() + && !list.contains(mainFrame()->url().toString()) + ) { wallet()->fillFormData(mainFrame()); } } -void WebPage::manageNetworkErrors(QNetworkReply* reply) +void WebPage::manageNetworkErrors(QNetworkReply *reply) { - if( reply->error() == QNetworkReply::NoError ) - return; + Q_ASSERT(reply); - if(m_protHandler.postHandling( reply->request(), mainFrame() )) - return; + QWebFrame* frame = qobject_cast<QWebFrame *>(reply->request().originatingObject()); + const bool isMainFrameRequest = (frame == mainFrame()); - // don't bother on adblocked urls - if( reply->error() == QNetworkReply::ContentAccessDenied ) - return; - - if( reply->url() != m_requestedUrl ) // prevent favicon loading - return; - - if( reply->error() == QNetworkReply::ContentNotFoundError ) + if (isMainFrameRequest + && _sslInfo.isValid() + && !domainSchemeMatch(reply->url(), _sslInfo.url()) + ) { - QList<QWebFrame*> frames; - frames.append(mainFrame()); - while (!frames.isEmpty()) - { - QWebFrame *firstFrame = frames.takeFirst(); - - if (firstFrame->url() == reply->url()) - { - firstFrame->setHtml(errorPage(reply), reply->url()); - return; - } - QList<QWebFrame *> children = firstFrame->childFrames(); - Q_FOREACH(QWebFrame *frame, children) - { - frames.append(frame); - } - } + //kDebug() << "Reseting cached SSL info..."; + _sslInfo = WebSslInfo(); } - else + + // NOTE: These are not all networkreply errors, + // but just that supported directly by KIO + switch (reply->error()) { - mainFrame()->setHtml(errorPage(reply), reply->url()); + + case QNetworkReply::NoError: // no error. Simple :) + if (isMainFrameRequest && !_sslInfo.isValid()) + { + // Obtain and set the SSL information if any... + _sslInfo.fromMetaData(reply->attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData))); + _sslInfo.setUrl(reply->url()); + } + break; + + case QNetworkReply::ContentAccessDenied: // access to remote content denied (similar to HTTP error 401) + kDebug() << "We (hopefully) are managing this through the adblock :)"; + break; + + case QNetworkReply::UnknownNetworkError: // unknown network-related error detected + if (_protHandler.postHandling(reply->request(), mainFrame())) + break; + + case QNetworkReply::ConnectionRefusedError: // remote server refused connection + case QNetworkReply::HostNotFoundError: // invalid hostname + case QNetworkReply::TimeoutError: // connection time out + case QNetworkReply::OperationCanceledError: // operation canceled via abort() or close() calls + case QNetworkReply::ProxyNotFoundError: // invalid proxy hostname + case QNetworkReply::ContentOperationNotPermittedError: // operation requested on remote content not permitted + case QNetworkReply::ContentNotFoundError: // remote content not found on server (similar to HTTP error 404) + case QNetworkReply::ProtocolUnknownError: // Unknown protocol + case QNetworkReply::ProtocolInvalidOperationError: // requested operation is invalid for this protocol + + if (reply->url() == _loadingUrl) + mainFrame()->setHtml(errorPage(reply), reply->url()); + break; + + default: + kDebug() << "Nothing to do here.."; + break; + } } @@ -254,11 +401,21 @@ QString WebPage::errorPage(QNetworkReply *reply) return QString("Couldn't open the rekonqinfo.html file"); } - QString title = i18n("Error loading: %1", reply->url().path()); - QString msg = "<h1>" + reply->errorString() + "</h1>"; - QString urlString = reply->url().toString( QUrl::RemoveUserInfo | QUrl::RemoveQuery ); - - msg += "<h2>" + i18nc("%1=an URL, e.g.'kde.org'", "When connecting to: %1", urlString ) + "</h2>"; + QString title = i18n("Error loading: %1", reply->url().path()); + QString urlString = reply->url().toString(QUrl::RemoveUserInfo | QUrl::RemoveQuery); + + QString iconPath = QString("file://") + KIconLoader::global()->iconPath("dialog-warning" , KIconLoader::Small); + iconPath.replace(QL1S("16"), QL1S("128")); + + QString msg; + msg += "<table>"; + msg += "<tr><td>"; + msg += "<img src=\"" + iconPath + "\" />"; + msg += "</td><td>"; + msg += "<h1>" + reply->errorString() + "</h1>"; + msg += "<h2>" + i18nc("%1=an URL, e.g.'kde.org'", "When connecting to: <b>%1</b>", urlString) + "</h2>"; + msg += "</td></tr></table>"; + msg += "<ul><li>" + i18n("Check the address for errors such as <b>ww</b>.kde.org instead of <b>www</b>.kde.org"); msg += "</li><li>" + i18n("If the address is correct, try to check the network connection.") + "</li><li>" ; msg += i18n("If your computer or network is protected by a firewall or proxy, make sure that rekonq is permitted to access the network."); @@ -266,83 +423,165 @@ QString WebPage::errorPage(QNetworkReply *reply) msg += "</li></ul><br/><br/>"; msg += "<input type=\"button\" id=\"reloadButton\" onClick=\"document.location.href='" + urlString + "';\" value=\""; msg += i18n("Try Again") + "\" />"; - - QString html = QString(QLatin1String(file.readAll())) - .arg(title) - .arg(msg) - ; + + QString html = QString(QL1S(file.readAll())) + .arg(title) + .arg(msg) + ; return html; } +// WARNING +// this code is actually copied from KWebPage::downloadRequest to save +// downloads data before. If you have some better ideas about, +// feel free to let us know about :) void WebPage::downloadRequest(const QNetworkRequest &request) { - if (ReKonfig::kgetDownload()) - { - //*Copy of kwebpage code (Shouldn't be done in kwepage ?) + KUrl destUrl; + KUrl srcUrl(request.url()); + int result = KIO::R_OVERWRITE; - KUrl destUrl; - KUrl srcUrl (request.url()); - int result = KIO::R_OVERWRITE; + do + { + destUrl = KFileDialog::getSaveFileName(srcUrl.fileName(), QString(), view()); - do + if (destUrl.isLocalFile()) { - destUrl = KFileDialog::getSaveFileName(srcUrl.fileName(), QString(), view()); - - if (destUrl.isLocalFile()) + QFileInfo finfo(destUrl.toLocalFile()); + if (finfo.exists()) { - QFileInfo finfo (destUrl.toLocalFile()); - if (finfo.exists()) - { - QDateTime now = QDateTime::currentDateTime(); - KIO::RenameDialog dlg (view(), i18n("Overwrite File?"), srcUrl, destUrl, - KIO::RenameDialog_Mode(KIO::M_OVERWRITE | KIO::M_SKIP), - -1, finfo.size(), - now.toTime_t(), finfo.created().toTime_t(), - now.toTime_t(), finfo.lastModified().toTime_t()); - result = dlg.exec(); - } + QDateTime now = QDateTime::currentDateTime(); + QPointer<KIO::RenameDialog> dlg = new KIO::RenameDialog(view(), + i18n("Overwrite File?"), + srcUrl, + destUrl, + KIO::RenameDialog_Mode(KIO::M_OVERWRITE | KIO::M_SKIP), + -1, + finfo.size(), + now.toTime_t(), + finfo.created().toTime_t(), + now.toTime_t(), + finfo.lastModified().toTime_t() + ); + result = dlg->exec(); + delete dlg; } - } - while (result == KIO::R_CANCEL && destUrl.isValid()); + } + } + while (result == KIO::R_CANCEL && destUrl.isValid()); + + if (result == KIO::R_OVERWRITE && destUrl.isValid()) + { + // now store data + // now, destUrl, srcUrl + Application::historyManager()->addDownload(srcUrl.pathOrUrl() , destUrl.pathOrUrl()); - if (result == KIO::R_OVERWRITE && destUrl.isValid()) + if (ReKonfig::kgetDownload()) { - //*End of copy code - //KGet integration: - if(!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) + if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) { KToolInvocation::kdeinitExecWait("kget"); } QDBusInterface kget("org.kde.kget", "/KGet", "org.kde.kget.main"); - kget.call("addTransfer", srcUrl.prettyUrl(), destUrl.prettyUrl(), true); + if (kget.isValid()) + { + kget.call("addTransfer", srcUrl.prettyUrl(), destUrl.prettyUrl(), true); + return; + } } + + // else, use KIO or fallback to it + KIO::Job *job = KIO::file_copy(srcUrl, destUrl, -1, KIO::Overwrite); + QVariant attr = request.attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData)); + if (attr.isValid() && attr.type() == QVariant::Map) + job->setMetaData(KIO::MetaData(attr.toMap())); + + job->addMetaData(QL1S("MaxCacheSize"), QL1S("0")); // Don't store in http cache. + job->addMetaData(QL1S("cache"), QL1S("cache")); // Use entry from cache if available. + job->uiDelegate()->setAutoErrorHandlingEnabled(true); } - else KWebPage::downloadRequest(request); } -void WebPage::downloadAllContentsWithKGet() +void WebPage::downloadAllContentsWithKGet(QPoint) { - QList<QString> contentList; + QSet<QString> contents; + KUrl baseUrl(currentFrame()->url()); + KUrl relativeUrl; QWebElementCollection images = mainFrame()->documentElement().findAll("img"); foreach(QWebElement img, images) { - contentList.append(img.attribute("src")); + relativeUrl.setEncodedUrl(img.attribute("src").toUtf8(), KUrl::TolerantMode); + contents << baseUrl.resolved(relativeUrl).toString(); } - + QWebElementCollection links = mainFrame()->documentElement().findAll("a"); foreach(QWebElement link, links) { - contentList.append(link.attribute("href")); + relativeUrl.setEncodedUrl(link.attribute("href").toUtf8(), KUrl::TolerantMode); + contents << baseUrl.resolved(relativeUrl).toString(); } - - if(!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) + + if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) { KToolInvocation::kdeinitExecWait("kget"); } QDBusInterface kget("org.kde.kget", "/KGet", "org.kde.kget.main"); - kget.call("importLinks", QVariant(contentList)); + if (kget.isValid()) + { + kget.call("importLinks", QVariant(contents.toList())); + } +} + + +void WebPage::showSSLInfo(QPoint) +{ + if (_sslInfo.isValid()) + { + QPointer<KSslInfoDialog> dlg = new KSslInfoDialog(view()); + dlg->setSslInfo(_sslInfo.certificateChain(), + _sslInfo.peerAddress().toString(), + mainFrame()->url().host(), + _sslInfo.protocol(), + _sslInfo.ciphers(), + _sslInfo.usedChiperBits(), + _sslInfo.supportedChiperBits(), + KSslInfoDialog::errorsFromString(_sslInfo.certificateErrors()) + ); + + dlg->exec(); + delete dlg; + + return; + } + + if (mainFrame()->url().scheme() == QL1S("https")) + { + KMessageBox::error(view(), + i18n("The SSL information for this site appears to be corrupt."), + i18nc("Secure Sockets Layer", "SSL") + ); + } + else + { + KMessageBox::information(view(), + i18n("This site doesn't contain SSL information."), + i18nc("Secure Sockets Layer", "SSL") + ); + } +} + + + + +void WebPage::updateImage(bool ok) +{ + if (ok) + { + NewTabPage p(mainFrame()); + p.snapFinished(); + } } |