From ca30d0374020752d3ac367fdffef88a5c1fe4a48 Mon Sep 17 00:00:00 2001 From: Andras Becsi Date: Fri, 25 Jul 2014 15:53:07 +0200 Subject: Add QQuick API for intercepting navigation requests Add missing navigationRequested API to be able to intercept navigation requests. This is useful for ignoring requests for example in kiosk-like applications that want to restrinct navigation to a specific url or domain, or want to disable specific types of navigation requests (e.g. reloading, clicking links, form submissions). Change-Id: Ie375e635a3c3566527972d05f5d99b39489c5ca8 Reviewed-by: Jocelyn Turcotte --- src/core/core_gyp_generator.pro | 2 + src/core/network_delegate_qt.cpp | 140 ++++++++++++++++++++++++++++++++- src/core/network_delegate_qt.h | 38 ++++++--- src/core/web_contents_adapter_client.h | 16 ++++ 4 files changed, 184 insertions(+), 12 deletions(-) (limited to 'src/core') diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 27ee33e51..5e6d08214 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -55,6 +55,7 @@ SOURCES = \ javascript_dialog_controller.cpp \ javascript_dialog_manager_qt.cpp \ media_capture_devices_dispatcher.cpp \ + network_delegate_qt.cpp \ ozone_platform_eglfs.cpp \ process_main.cpp \ qrc_protocol_handler_qt.cpp \ @@ -99,6 +100,7 @@ HEADERS = \ javascript_dialog_controller.h \ javascript_dialog_manager_qt.h \ media_capture_devices_dispatcher.h \ + network_delegate_qt.h \ ozone_platform_eglfs.h \ process_main.h \ qrc_protocol_handler_qt.h \ diff --git a/src/core/network_delegate_qt.cpp b/src/core/network_delegate_qt.cpp index 27807c499..424d0e631 100644 --- a/src/core/network_delegate_qt.cpp +++ b/src/core/network_delegate_qt.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -40,3 +40,141 @@ ****************************************************************************/ #include "network_delegate_qt.h" + +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/resource_request_details.h" +#include "content/public/browser/resource_request_info.h" +#include "content/public/common/page_transition_types.h" +#include "net/base/load_flags.h" +#include "net/url_request/url_request.h" +#include "type_conversion.h" +#include "web_contents_adapter_client.h" +#include "web_contents_view_qt.h" + +namespace { + +int pageTransitionToNavigationType(content::PageTransition transition) +{ + int32 qualifier = content::PageTransitionGetQualifier(transition); + + if (qualifier & content::PAGE_TRANSITION_FORWARD_BACK) + return WebContentsAdapterClient::BackForwardNavigation; + + content::PageTransition stippedTransition = content::PageTransitionStripQualifier(transition); + + switch (stippedTransition) { + case content::PAGE_TRANSITION_LINK: + return WebContentsAdapterClient::LinkClickedNavigation; + case content::PAGE_TRANSITION_TYPED: + return WebContentsAdapterClient::TypedNavigation; + case content::PAGE_TRANSITION_FORM_SUBMIT: + return WebContentsAdapterClient::FormSubmittedNavigation; + case content::PAGE_TRANSITION_RELOAD: + return WebContentsAdapterClient::ReloadNavigation; + default: + return WebContentsAdapterClient::OtherNavigation; + } +} + +} + +int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, const net::CompletionCallback &callback, GURL *) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + const content::ResourceRequestInfo *info = content::ResourceRequestInfo::ForRequest(request); + int renderProcessId; + int renderViewId; + if (!info || !info->GetRenderViewForRequest(request, &renderProcessId, &renderViewId)) + // Abort the request if it has no associated render info / render view. + return net::ERR_ABORTED; + + ResourceType::Type resourceType = info->GetResourceType(); + // Only intercept MAIN_FRAME and SUB_FRAME. + if (!ResourceType::IsFrame(resourceType)) + return net::OK; + + // Track active requests since |callback| and |new_url| are valid + // only until OnURLRequestDestroyed is called for this request. + m_activeRequests.insert(request); + + int navigationType = pageTransitionToNavigationType(info->GetPageTransition()); + + RequestParams params = { + toQt(request->url()), + resourceType == ResourceType::MAIN_FRAME, + navigationType, + renderProcessId, + renderViewId + }; + + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&NetworkDelegateQt::NotifyNavigationRequestedOnUIThread, + base::Unretained(this), + request, + params, + callback) + ); + + // We'll run the callback after we notified the UI thread. + return net::ERR_IO_PENDING; +} + +void NetworkDelegateQt::OnURLRequestDestroyed(net::URLRequest* request) +{ + m_activeRequests.remove(request); +} + +void NetworkDelegateQt::CompleteURLRequestOnIOThread(net::URLRequest *request, + int navigationRequestAction, + const net::CompletionCallback &callback) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + if (!m_activeRequests.contains(request)) + return; + + int error = net::OK; + switch (navigationRequestAction) { + case WebContentsAdapterClient::AcceptRequest: + error = net::OK; + break; + case WebContentsAdapterClient::IgnoreRequest: + error = net::OK; + // We can cancel the request here since we are on the IO thread. + request->Cancel(); + break; + default: + error = net::ERR_FAILED; + Q_UNREACHABLE(); + } + callback.Run(error); +} + +void NetworkDelegateQt::NotifyNavigationRequestedOnUIThread(net::URLRequest *request, + RequestParams params, + const net::CompletionCallback &callback) +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + + int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; + content::RenderViewHost *rvh = content::RenderViewHost::FromID(params.renderProcessId, params.renderViewId); + + if (rvh) { + content::WebContents *webContents = content::WebContents::FromRenderViewHost(rvh); + WebContentsAdapterClient *client = WebContentsViewQt::from(webContents->GetView())->client(); + client->navigationRequested(params.navigationType, params.url, navigationRequestAction, params.isMainFrameRequest); + } + + // Run the callback on the IO thread. + content::BrowserThread::PostTask( + content::BrowserThread::IO, + FROM_HERE, + base::Bind(&NetworkDelegateQt::CompleteURLRequestOnIOThread, + base::Unretained(this), + request, + navigationRequestAction, + callback) + ); +} diff --git a/src/core/network_delegate_qt.h b/src/core/network_delegate_qt.h index 9413addb3..d057b9915 100644 --- a/src/core/network_delegate_qt.h +++ b/src/core/network_delegate_qt.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -42,22 +42,20 @@ #define NETWORK_DELEGATE_QT_H #include "net/base/network_delegate.h" +#include "net/base/net_errors.h" -#include "qglobal.h" +#include +#include +#include // Needed for Q_DECL_OVERRIDE class NetworkDelegateQt : public net::NetworkDelegate { public: NetworkDelegateQt() {} virtual ~NetworkDelegateQt() {} - - private: - // net::NetworkDelegate implementation. - virtual int OnBeforeURLRequest(net::URLRequest* request, const net::CompletionCallback& callback, GURL* new_url) Q_DECL_OVERRIDE - { - return net::OK; - } - +private: + // net::NetworkDelegate implementation + virtual int OnBeforeURLRequest(net::URLRequest* request, const net::CompletionCallback& callback, GURL* new_url) Q_DECL_OVERRIDE; virtual int OnBeforeSendHeaders(net::URLRequest* request, const net::CompletionCallback& callback, net::HttpRequestHeaders* headers) Q_DECL_OVERRIDE { return net::OK; @@ -72,7 +70,7 @@ public: virtual void OnResponseStarted(net::URLRequest* request) Q_DECL_OVERRIDE { } virtual void OnRawBytesRead(const net::URLRequest& request, int bytes_read) Q_DECL_OVERRIDE { } virtual void OnCompleted(net::URLRequest* request, bool started) Q_DECL_OVERRIDE { } - virtual void OnURLRequestDestroyed(net::URLRequest* request) Q_DECL_OVERRIDE { } + virtual void OnURLRequestDestroyed(net::URLRequest* request) Q_DECL_OVERRIDE; virtual void OnPACScriptError(int line_number, const base::string16& error) Q_DECL_OVERRIDE { } virtual AuthRequiredResponse OnAuthRequired(net::URLRequest* request, const net::AuthChallengeInfo& auth_info, @@ -84,6 +82,24 @@ public: virtual bool OnCanThrottleRequest(const net::URLRequest& request) const Q_DECL_OVERRIDE { return false; } virtual int OnBeforeSocketStreamConnect(net::SocketStream* stream, const net::CompletionCallback& callback) Q_DECL_OVERRIDE { return net::OK; } virtual void OnRequestWaitStateChange(const net::URLRequest& request, RequestWaitState state) Q_DECL_OVERRIDE { } + + struct RequestParams { + QUrl url; + bool isMainFrameRequest; + int navigationType; + int renderProcessId; + int renderViewId; + }; + + void NotifyNavigationRequestedOnUIThread(net::URLRequest *request, + RequestParams params, + const net::CompletionCallback &callback); + + void CompleteURLRequestOnIOThread(net::URLRequest *request, + int navigationRequestAction, + const net::CompletionCallback &callback); + + QSet m_activeRequests; }; #endif // NETWORK_DELEGATE_QT_H diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index f8f729f60..2dffb8fb5 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -110,6 +110,21 @@ public: Save }; + enum NavigationRequestAction { + AcceptRequest, + // Make room in the valid range of the enum for extra actions exposed in Experimental. + IgnoreRequest = 0xFF + }; + + enum NavigationType { + LinkClickedNavigation, + TypedNavigation, + FormSubmittedNavigation, + BackForwardNavigation, + ReloadNavigation, + OtherNavigation + }; + enum JavaScriptConsoleMessageLevel { Info = 0, Warning, @@ -144,6 +159,7 @@ public: virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect & initialGeometry) = 0; virtual void close() = 0; virtual bool contextMenuRequested(const WebEngineContextMenuData&) = 0; + virtual void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) = 0; virtual void requestFullScreen(bool) = 0; virtual bool isFullScreen() const = 0; virtual void javascriptDialog(QSharedPointer) = 0; -- cgit v1.2.3