Commit 82241a80 authored by Stefano Crocco's avatar Stefano Crocco
Browse files

Rely on QtWebEngine to determine the mimetype of http(s) URLs

When KonqRun::scanFile is called from a view using a WebEnginePart and
for a http or https URL with an unknown mimetype, don't use
BrowserRun::scanFile but always return "text/html". This is because
BrowserRun::scanFile issues a GET request to determine the mimetype, but
QtWebEngine will then issue the same request, causing a double GET
request. This way, instead, there will be only one GET request (from
QtWebEngine). If QtWebEngine determines that the mimetype is one it
can't open itself, the corresponding WebEnginePage will emit a
openUrlRequest signal, with the real mimetype. Since the mimetype is now
known, there isn't the risk of entering an endless loop.

There are two problems:
* the double GET request issue remains when the URL can't be displayed
  by QtWebEngine. QtWebEngine
  emits the downloadRequested signal after doing a GET request to determine the
  mimetype of the URL. Using KIO/KParts to download the file causes a second GET
  request.
* using QtWebEngine to determine the mimetype forces the user to use
  WebEnginePart to open URLs with mimetypes it can hanlde, even if the user has
  chosen another part for them. For example, clicking an a link to an image in a
  remote web page will cause the image to be opened in WebEnginePart even if the
  user chose to use GwenViewPart for images. This happens because, since
  QtWebEngine can handle images, it doesn't emit the downloadRequested signal.
parent 4517a381
......@@ -30,6 +30,9 @@
#include <KIO/ApplicationLauncherJob>
#include <KIO/JobUiDelegate>
#include <KService>
#include <KMimeTypeTrader>
// Local
#include "konqview.h"
#include "konqframestatusbar.h"
......@@ -197,8 +200,37 @@ void KonqRun::init()
}
}
bool KonqRun::usingWebEngine() const
{
if (m_pView) {
return m_pView->part()->componentName() == "webenginepart";
} else {
KService::Ptr service = KMimeTypeTrader::self()->preferredService("text/html", "KParts/ReadOnlyPart");
Q_ASSERT(service);
return service->desktopEntryName() == "webenginepart";
}
}
void KonqRun::scanFile()
{
//Since QtWebEngine can't use the KIO framework, attempting to determine the mimetype here when
//using QtWebEngine will lead to a double GET request. To avoid it, when using QtWebEngine, any URL with
//http or https protocol will be treated as if it were text/html: this means it'll be opened with WebEnginePart,
//which will determine its mimetype and proceed accordingly. However, this can lead to an endless loop when an http(s) URL
//is of type application/octet-stream:
// - WebEnginePart (indirectly) calls KonqMainWindow::openUrl with application/octet-stram as mimetype
// - KonqMainWindow needs to know a more specific mimetype, so it creates a KonqRun
// - KonqRun calls scanFile
// - Since the protocol is http(s), scanFile delegates finding out the mimetype to WebEnginePart,
// which finds application/octet-stream starting an endless loop
// To avoid this we assume that the creator of the KonqRun has set m_alreadyProcessedByWebEngine if the URL has
// already been passed to WebEnginePart: it means that it couldn't find a suitable mimetype and we need to do it
// by ourselves, even if it means doing a double GET request.
if (m_req.args.mimeType().isEmpty() && (url().scheme() == "http" || url().scheme() == "https") && usingWebEngine()) {
mimeTypeDetermined("text/html");
return;
}
KParts::BrowserRun::scanFile();
// could be a static cast as of now, but who would notify when
// BrowserRun changes
......
......@@ -74,6 +74,8 @@ protected Q_SLOTS:
private:
bool tryOpenView(const QString &mimeType, bool associatedAppIsKonqueror);
bool usingWebEngine() const;
QPointer<KonqMainWindow> m_pMainWindow;
QPointer<KonqView> m_pView;
bool m_bFoundMimeType;
......
......@@ -140,7 +140,7 @@ static void checkForDownloadManager(QWidget* widget, QString& cmd)
cmd = exeName;
}
void WebEnginePage::download(const QUrl& url, bool newWindow)
void WebEnginePage::download(const QUrl& url, const QString& mimetype, bool newWindow)
{
// Integration with a download manager...
if (!url.isLocalFile()) {
......@@ -156,7 +156,9 @@ void WebEnginePage::download(const QUrl& url, bool newWindow)
}
KParts::BrowserArguments bArgs;
bArgs.setForcesNewWindow(newWindow);
emit part()->browserExtension()->openUrlRequest(url, KParts::OpenUrlArguments(), bArgs);
KParts::OpenUrlArguments urlArgs;
urlArgs.setMimeType(mimetype);
emit part()->browserExtension()->openUrlRequest(url, urlArgs, bArgs);
}
void WebEnginePage::requestOpenFileAsTemporary(const QUrl& url, const QString &mimeType, bool newWindow)
......@@ -341,10 +343,7 @@ static int errorCodeFromReply(QNetworkReply* reply)
bool WebEnginePage::certificateError(const QWebEngineCertificateError& ce)
{
if (m_urlLoadedByPart == ce.url()) {
m_urlLoadedByPart = QUrl();
return true;
} else if (ce.isOverridable()) {
if (ce.isOverridable()) {
QString translatedDesc = i18n(ce.errorDescription().toUtf8());
QString text = i18n("<p>The server failed the authenticity check (%1). The error is:</p><p><tt>%2</tt></p>Do you want to ignore this error?",
ce.url().host(), translatedDesc);
......
......@@ -64,7 +64,7 @@ public:
*/
void setSslInfo (const WebSslInfo &other);
void download(const QUrl &url, bool newWindow = false);
void download(const QUrl &url, const QString &mimetype, bool newWindow = false);
void requestOpenFileAsTemporary(const QUrl &url, const QString &mimeType = "", bool newWindow = false);
......
......@@ -42,6 +42,7 @@
#include <sonnet/backgroundchecker.h>
#include <KIO/JobUiDelegate>
#include <KIO/OpenUrlJob>
#include <KParts/BrowserRun>
#include <QBuffer>
#include <QVariant>
......@@ -528,10 +529,15 @@ void WebEngineBrowserExtension::slotCopyEmailAddress()
#endif
}
void WebEngineBrowserExtension::slotSaveLinkAs()
void WebEngineBrowserExtension::slotSaveLinkAs(const QUrl &url)
{
if (view())
view()->triggerPageAction(QWebEnginePage::DownloadLinkToDisk);
if (view()) {
if (!url.isEmpty()) {
KParts::BrowserRun::saveUrl(url, url.path(), view(), KParts::OpenUrlArguments());
} else {
view()->triggerPageAction(QWebEnginePage::DownloadLinkToDisk);
}
}
}
void WebEngineBrowserExtension::slotViewDocumentSource()
......
......@@ -83,7 +83,7 @@ public Q_SLOTS:
void slotCopyLinkURL();
void slotCopyLinkText();
void slotSaveLinkAs();
void slotSaveLinkAs(const QUrl &url);
void slotCopyEmailAddress();
void slotViewDocumentSource();
......
......@@ -99,7 +99,7 @@ void WebEnginePartDownloadManager::performDownload(QWebEngineDownloadItem* it)
return;
}
if (it->url().scheme() != "blob") {
page->download(it->url(), forceNew);
page->download(it->url(), it->mimeType(), forceNew);
} else {
downloadBlob(it);
}
......
......@@ -26,6 +26,7 @@
#include "webenginepart.h"
#include "webenginepart_ext.h"
#include "settings/webenginesettings.h"
#include "webenginepart_ext.h"
#include <KIO/Global>
#include <KAboutData>
......@@ -485,7 +486,8 @@ void WebEngineView::linkActionPopupMenu(KParts::BrowserExtension::ActionGroupMap
action = new QAction(i18n("&Save Link As..."), this);
m_actionCollection->addAction(QL1S("savelinkas"), action);
connect(action, &QAction::triggered, ext, &WebEngineBrowserExtension::slotSaveLinkAs);
auto saveLinkAsLambda = [this, url](bool){qobject_cast<WebEngineBrowserExtension*>(m_part->browserExtension())->slotSaveLinkAs(url);};
connect(action, &QAction::triggered, m_part->browserExtension(), saveLinkAsLambda);
linkActions.append(action);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment