diff options
Diffstat (limited to 'src/webpage.cpp')
-rw-r--r-- | src/webpage.cpp | 421 |
1 files changed, 313 insertions, 108 deletions
diff --git a/src/webpage.cpp b/src/webpage.cpp index b2bedffc..a75272cd 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 @@ -44,6 +45,8 @@ #include "networkaccessmanager.h" #include "adblockmanager.h" +#include "sslinfodialog_p.h" + // KDE Includes #include <KStandardDirs> #include <KUrl> @@ -68,32 +71,72 @@ #include <QtGui/QMouseEvent> #include <QtGui/QClipboard> #include <QtGui/QKeyEvent> +#include <QWebFrame> + +// Defines +#define QL1S(x) QLatin1String(x) +#define QL1C(x) QLatin1Char(x) + + +// 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... + + while (u1List.count() > 2) + u1List.removeFirst(); + + while (u2List.count() > 2) + u2List.removeFirst(); + + return (u1List == u2List); +} + + +// --------------------------------------------------------------------------------- -WebPage::WebPage(QObject *parent) - : KWebPage(parent, KWalletIntegration) +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); + manager->setCache(0); // disable QtWebKit cache to just use KIO one.. - // disable QtWebKit cache to just use KIO one.. - manager->setCache(0); - + // set cookieJar window ID.. + if (parent && parent->window()) + manager->setCookieJarWindowId(parent->window()->winId()); + setNetworkAccessManager(manager); - // Web Plugin Factory - setPluginFactory(new WebPluginFactory(this)); + // activate ssl warnings + setSessionMetaData("ssl_activate_warnings", "TRUE"); - - connect(networkAccessManager(), SIGNAL(finished(QNetworkReply*)), this, SLOT(manageNetworkErrors(QNetworkReply*))); + // 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()); - connect(this, SIGNAL(unsupportedContent(QNetworkReply *)), this, SLOT(handleUnsupportedContent(QNetworkReply *))); + // ----- Web Plugin Factory + setPluginFactory(new WebPluginFactory(this)); + + // ----- 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 +148,66 @@ WebPage::~WebPage() bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type) { - // advise users on resubmitting data - if(type == QWebPage::NavigationTypeFormResubmitted) + 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; + } + + 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"); + } } - - m_requestedUrl = request.url(); - return KWebPage::acceptNavigationRequest(frame, request, type); } @@ -137,7 +223,7 @@ WebPage *WebPage::createWindow(QWebPage::WebWindowType type) WebTab *w = 0; if(ReKonfig::openTabNoWindow()) { - w = Application::instance()->mainWindow()->mainView()->newWebTab(!ReKonfig::openTabsBack()); + w = Application::instance()->mainWindow()->mainView()->newWebTab(!ReKonfig::openTabsBack(), ReKonfig::openTabsNearCurrent()); } else { @@ -160,7 +246,12 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply) if( offer.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; } @@ -171,18 +262,35 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply) switch ( dlg.askEmbedOrSave() ) { case KParts::BrowserOpenOrSaveQuestion::Save: - downloadRequested(reply->request()); - return; + kDebug() << "service handling: download!"; + downloadRequest( reply->request() ); + return; + case KParts::BrowserOpenOrSaveQuestion::Cancel: - return; + return; + default: // non extant case break; } } // case KParts::BrowserRun::Embed - KUrl::List list; - list.append(url); - KRun::run(*offer,url,0); + 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); + return; } } @@ -191,53 +299,80 @@ void WebPage::loadFinished(bool) { 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; - - if(m_protHandler.postHandling( reply->request(), mainFrame() )) - return; - - // don't bother on adblocked urls - if( reply->error() == QNetworkReply::ContentAccessDenied ) - return; - - if( reply->url() != m_requestedUrl ) // prevent favicon loading - return; + Q_ASSERT(reply); + WebView *v = 0; + QWebFrame* frame = qobject_cast<QWebFrame *>(reply->request().originatingObject()); + const bool isMainFrameRequest = (frame == mainFrame()); - 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::UnknownNetworkError: // unknown network-related error detected + + if( _protHandler.postHandling(reply->request(), mainFrame()) ) + 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::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 + + // don't bother on elements loading errors: + // we'll manage just main url page ones + v = qobject_cast<WebView *>(view()); + if( reply->url() != v->url() ) + break; + + mainFrame()->setHtml( errorPage(reply), reply->url() ); + break; + + default: + kDebug() << "Nothing to do here.."; + break; + } } @@ -275,68 +410,97 @@ QString WebPage::errorPage(QNetworkReply *reply) } +// 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; - - do - { - destUrl = KFileDialog::getSaveFileName(srcUrl.fileName(), QString(), view()); - - if (destUrl.isLocalFile()) - { - 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(); - } - } - } - while (result == KIO::R_CANCEL && destUrl.isValid()); - - if (result == KIO::R_OVERWRITE && destUrl.isValid()) + KUrl destUrl; + KUrl srcUrl (request.url()); + int result = KIO::R_OVERWRITE; + + do + { + destUrl = KFileDialog::getSaveFileName(srcUrl.fileName(), QString(), view()); + + if (destUrl.isLocalFile()) + { + QFileInfo finfo( destUrl.toLocalFile() ); + if ( finfo.exists() ) + { + 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() ); + + if ( result == KIO::R_OVERWRITE && destUrl.isValid() ) + { + // now store data + // now, destUrl, srcUrl + Application::historyManager()->addDownload( srcUrl.pathOrUrl() , destUrl.pathOrUrl() ); + + if ( ReKonfig::kgetDownload() ) { - //*End of copy code - //KGet integration: 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 KWebPage::downloadRequest(request); + + // 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); + } } void WebPage::downloadAllContentsWithKGet() { - 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")) @@ -344,5 +508,46 @@ void WebPage::downloadAllContentsWithKGet() 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() +{ + 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") + ); + } } |