From fa19227c3ac7df7c0d2f8a548a9a36ac9a7b803c Mon Sep 17 00:00:00 2001
From: Szabolcs David <davidsz@inf.u-szeged.hu>
Date: Tue, 9 May 2017 14:52:45 +0200
Subject: [PATCH] Fix copying JavaScript URLs

Wire unfiltered link URL to the API layer.

[ChangeLog][QtWebEngine] linkUrl member of
QWebEngineContextMenuData and ContextMenuRequest was previously
returning with "about:blank" in case of non-standard URLs.
Now it contains the unvalidated URL and CopyLinkToClipboard action
has been fixed to handle such URLs (like javascript:) correctly.

Task-number: QTBUG-59307
Change-Id: I2e49767e1cc9ec8324d230c1bf346e21d7b8d9bb
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
---
 src/core/web_contents_adapter_client.h                 |  9 +++++++++
 src/core/web_contents_view_qt.cpp                      |  1 +
 .../api/qquickwebenginecontextmenurequest.cpp          |  3 ++-
 src/webengine/api/qquickwebengineview.cpp              | 10 ++++++----
 src/webenginewidgets/api/qwebenginecontextmenudata.cpp |  3 ++-
 src/webenginewidgets/api/qwebenginepage.cpp            |  8 ++++----
 6 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index d4b2974fc..9b454832e 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -90,6 +90,7 @@ public:
     uint mediaFlags;
     QPoint pos;
     QUrl linkUrl;
+    QUrl unfilteredLinkUrl;
     QUrl mediaUrl;
     QString linkText;
     QString selectedText;
@@ -156,6 +157,14 @@ public:
         return d->linkUrl;
     }
 
+    void setUnfilteredLinkUrl(const QUrl &url) {
+        d->unfilteredLinkUrl = url;
+    }
+
+    QUrl unfilteredLinkUrl() const {
+        return d->unfilteredLinkUrl;
+    }
+
     void setLinkText(const QString &text) {
         d->linkText = text;
     }
diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp
index 844544887..e627fa06d 100644
--- a/src/core/web_contents_view_qt.cpp
+++ b/src/core/web_contents_view_qt.cpp
@@ -164,6 +164,7 @@ static inline WebEngineContextMenuData fromParams(const content::ContextMenuPara
     ret.setPosition(QPoint(params.x, params.y));
     ret.setLinkUrl(toQt(params.link_url));
     ret.setLinkText(toQt(params.link_text.data()));
+    ret.setUnfilteredLinkUrl(toQt(params.unfiltered_link_url));
     ret.setSelectedText(toQt(params.selection_text.data()));
     ret.setMediaUrl(toQt(params.src_url));
     ret.setMediaType((WebEngineContextMenuData::MediaType)params.media_type);
diff --git a/src/webengine/api/qquickwebenginecontextmenurequest.cpp b/src/webengine/api/qquickwebenginecontextmenurequest.cpp
index df57442a1..c53e28d93 100644
--- a/src/webengine/api/qquickwebenginecontextmenurequest.cpp
+++ b/src/webengine/api/qquickwebenginecontextmenurequest.cpp
@@ -159,11 +159,12 @@ QString QQuickWebEngineContextMenuRequest::linkText() const
     \readonly
 
     The URL of the link if the selected web page content is a link.
+    It is not guaranteed to be a valid URL.
 */
 
 QUrl QQuickWebEngineContextMenuRequest::linkUrl() const
 {
-    return m_data->linkUrl();
+    return m_data->unfilteredLinkUrl();
 }
 
 /*!
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index ab6a9c79a..68a290df9 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -265,10 +265,12 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu
         ui()->addMenuItem(item, QQuickWebEngineView::tr("Unselect"));
     }
 
-    if (!data.linkText().isEmpty() && data.linkUrl().isValid()) {
+    if (!data.linkText().isEmpty() && !data.unfilteredLinkUrl().isEmpty()) {
         item = new MenuItemHandler(menu);
         QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyLinkToClipboard); });
         ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Link URL"));
+    }
+    if (!data.linkText().isEmpty() && data.linkUrl().isValid()) {
         item = new MenuItemHandler(menu);
         QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::DownloadLinkToDisk); });
         ui()->addMenuItem(item, QQuickWebEngineView::tr("Save Link"));
@@ -1609,14 +1611,14 @@ void QQuickWebEngineView::triggerWebAction(WebAction action)
         }
         break;
     case CopyLinkToClipboard:
-        if (d->m_contextMenuData.linkUrl().isValid()) {
-            QString urlString = d->m_contextMenuData.linkUrl().toString(QUrl::FullyEncoded);
+        if (!d->m_contextMenuData.unfilteredLinkUrl().isEmpty()) {
+            QString urlString = d->m_contextMenuData.unfilteredLinkUrl().toString(QUrl::FullyEncoded);
             QString title = d->m_contextMenuData.linkText().toHtmlEscaped();
             QMimeData *data = new QMimeData();
             data->setText(urlString);
             QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\">") + title + QStringLiteral("</a>");
             data->setHtml(html);
-            data->setUrls(QList<QUrl>() << d->m_contextMenuData.linkUrl());
+            data->setUrls(QList<QUrl>() << d->m_contextMenuData.unfilteredLinkUrl());
             qApp->clipboard()->setMimeData(data);
         }
         break;
diff --git a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp
index 5d68ed0ec..63e11175b 100644
--- a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp
+++ b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp
@@ -148,10 +148,11 @@ QString QWebEngineContextMenuData::linkText() const
 
 /*!
     Returns the URL of a link if the context is a link.
+    It is not guaranteed to be a valid URL.
 */
 QUrl QWebEngineContextMenuData::linkUrl() const
 {
-    return d ? d->linkUrl() : QUrl();
+    return d ? d->unfilteredLinkUrl() : QUrl();
 }
 
 /*!
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 03e5ac3f5..90574d60a 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -1271,14 +1271,14 @@ void QWebEnginePage::triggerAction(WebAction action, bool)
         }
         break;
     case CopyLinkToClipboard:
-        if (menuData.linkUrl().isValid()) {
-            QString urlString = menuData.linkUrl().toString(QUrl::FullyEncoded);
+        if (!menuData.unfilteredLinkUrl().isEmpty()) {
+            QString urlString = menuData.unfilteredLinkUrl().toString(QUrl::FullyEncoded);
             QString title = menuData.linkText().toHtmlEscaped();
             QMimeData *data = new QMimeData();
             data->setText(urlString);
             QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\">") + title + QStringLiteral("</a>");
             data->setHtml(html);
-            data->setUrls(QList<QUrl>() << menuData.linkUrl());
+            data->setUrls(QList<QUrl>() << menuData.unfilteredLinkUrl());
             qApp->clipboard()->setMimeData(data);
         }
         break;
@@ -1683,7 +1683,7 @@ QMenu *QWebEnginePage::createStandardContextMenu()
         menu->addAction(QWebEnginePage::action(Unselect));
     }
 
-    if (!contextMenuData.linkText().isEmpty() && contextMenuData.linkUrl().isValid()) {
+    if (!contextMenuData.linkText().isEmpty() && !contextMenuData.unfilteredLinkUrl().isEmpty()) {
         menu->addAction(QWebEnginePage::action(CopyLinkToClipboard));
     }
     if (contextMenuData.mediaUrl().isValid()) {
-- 
GitLab