Add OnProtocolExecution callback to CefRequestHandler (issue #582).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@711 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2012-06-25 21:21:27 +00:00
parent 89c70a8b11
commit d13cc9de1c
18 changed files with 253 additions and 0 deletions

View File

@ -787,6 +787,8 @@
'libcef/browser/origin_whitelist_impl.h',
'libcef/browser/resource_context.cc',
'libcef/browser/resource_context.h',
'libcef/browser/resource_dispatcher_host_delegate.cc',
'libcef/browser/resource_dispatcher_host_delegate.h',
'libcef/browser/resource_request_job.cc',
'libcef/browser/resource_request_job.h',
'libcef/browser/scheme_impl.cc',
@ -866,6 +868,7 @@
'libcef/renderer/v8_impl.h',
'libcef/renderer/webkit_glue.cc',
'libcef/renderer/webkit_glue.h',
# Include sources for persistent cookie storage.
'<(DEPTH)/chrome/browser/net/clear_on_exit_policy.cc',
'<(DEPTH)/chrome/browser/net/clear_on_exit_policy.h',
'<(DEPTH)/chrome/browser/net/sqlite_persistent_cookie_store.cc',

View File

@ -128,6 +128,17 @@ typedef struct _cef_request_handler_t {
struct _cef_cookie_manager_t* (CEF_CALLBACK *get_cookie_manager)(
struct _cef_request_handler_t* self, struct _cef_browser_t* browser,
const cef_string_t* main_url);
///
// Called on the UI thread to handle requests for URLs with an unknown
// protocol component. Set |allow_os_execution| to true (1) to attempt
// execution via the registered OS protocol handler, if any. SECURITY WARNING:
// YOU SHOULD USE THIS METHOD TO ENFORCE RESTRICTIONS BASED ON SCHEME, HOST OR
// OTHER URL ANALYSIS BEFORE ALLOWING OS EXECUTION.
///
void (CEF_CALLBACK *on_protocol_execution)(
struct _cef_request_handler_t* self, struct _cef_browser_t* browser,
const cef_string_t* url, int* allow_os_execution);
} cef_request_handler_t;

View File

@ -141,6 +141,18 @@ class CefRequestHandler : public virtual CefBase {
virtual CefRefPtr<CefCookieManager> GetCookieManager(
CefRefPtr<CefBrowser> browser,
const CefString& main_url) { return NULL; }
///
// Called on the UI thread to handle requests for URLs with an unknown
// protocol component. Set |allow_os_execution| to true to attempt execution
// via the registered OS protocol handler, if any.
// SECURITY WARNING: YOU SHOULD USE THIS METHOD TO ENFORCE RESTRICTIONS BASED
// ON SCHEME, HOST OR OTHER URL ANALYSIS BEFORE ALLOWING OS EXECUTION.
///
/*--cef()--*/
virtual void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
const CefString& url,
bool& allow_os_execution) {}
};
#endif // CEF_INCLUDE_CEF_REQUEST_HANDLER_H_

View File

@ -804,6 +804,24 @@ bool CefBrowserHostImpl::ViewText(const std::string& text) {
return PlatformViewText(text);
}
void CefBrowserHostImpl::HandleExternalProtocol(const GURL& url) {
if (CEF_CURRENTLY_ON_UIT()) {
bool allow_os_execution = false;
if (client_.get()) {
CefRefPtr<CefRequestHandler> handler = client_->GetRequestHandler();
if (handler.get())
handler->OnProtocolExecution(this, url.spec(), allow_os_execution);
}
if (allow_os_execution)
PlatformHandleExternalProtocol(url);
} else {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::HandleExternalProtocol, this, url));
}
}
bool CefBrowserHostImpl::HasIDMatch(int render_process_id, int render_view_id) {
base::AutoLock lock_scope(state_lock_);
if (render_process_id != render_process_id_)

View File

@ -176,6 +176,9 @@ class CefBrowserHostImpl : public CefBrowserHost,
// Open the specified text in the default text editor.
bool ViewText(const std::string& text);
// Handler for URLs involving external protocols.
void HandleExternalProtocol(const GURL& url);
// Returns true if this browser matches the specified ID values. If
// |render_view_id| is 0 any browser with the specified |render_process_id|
// will match.
@ -325,6 +328,8 @@ class CefBrowserHostImpl : public CefBrowserHost,
content::WebContents* contents,
const content::FileChooserParams& params,
std::vector<FilePath>& files);
// Invoke platform specific handling for the external protocol.
void PlatformHandleExternalProtocol(const GURL& url);
void OnAddressChange(CefRefPtr<CefFrame> frame,
const GURL& url);

View File

@ -138,3 +138,6 @@ void CefBrowserHostImpl::PlatformRunFileChooser(
std::vector<FilePath>& files) {
NOTIMPLEMENTED();
}
void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
}

View File

@ -237,3 +237,6 @@ void CefBrowserHostImpl::PlatformRunFileChooser(
}
[NSApp endSheet:openPanel];
}
void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
}

View File

@ -14,6 +14,8 @@
#include "libcef/browser/thread_util.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/windows_version.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/web_contents_view.h"
@ -133,6 +135,31 @@ bool RunOpenMultiFileDialog(const std::wstring& filter, HWND owner,
return success;
}
// According to Mozilla in uriloader/exthandler/win/nsOSHelperAppService.cpp:
// "Some versions of windows (Win2k before SP3, Win XP before SP1) crash in
// ShellExecute on long URLs (bug 161357 on bugzilla.mozilla.org). IE 5 and 6
// support URLS of 2083 chars in length, 2K is safe."
const int kMaxAddressLengthChars = 2048;
bool HasExternalHandler(const std::string& scheme) {
base::win::RegKey key;
const std::wstring registry_path =
ASCIIToWide(scheme + "\\shell\\open\\command");
key.Open(HKEY_CLASSES_ROOT, registry_path.c_str(), KEY_READ);
if (key.Valid()) {
DWORD size = 0;
key.ReadValue(NULL, NULL, &size, NULL);
if (size > 2) {
// ShellExecute crashes the process when the command is empty.
// We check for "2" because it always returns the trailing NULL.
return true;
}
}
return false;
}
} // namespace
// static
@ -358,3 +385,21 @@ void CefBrowserHostImpl::PlatformRunFileChooser(
files.push_back(file_name);
}
}
void CefBrowserHostImpl::PlatformHandleExternalProtocol(const GURL& url) {
if (CEF_CURRENTLY_ON_FILET()) {
if (!HasExternalHandler(url.scheme()))
return;
const std::string& address = url.spec();
if (address.length() > kMaxAddressLengthChars)
return;
ShellExecuteA(NULL, "open", address.c_str(), NULL, NULL, SW_SHOWNORMAL);
} else {
// Execute on the FILE thread.
CEF_POST_TASK(CEF_FILET,
base::Bind(&CefBrowserHostImpl::PlatformHandleExternalProtocol, this,
url));
}
}

View File

@ -9,6 +9,7 @@
#include "libcef/browser/browser_message_filter.h"
#include "libcef/browser/browser_settings.h"
#include "libcef/browser/context.h"
#include "libcef/browser/resource_dispatcher_host_delegate.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/cef_switches.h"
@ -17,6 +18,7 @@
#include "content/public/browser/access_token_store.h"
#include "content/public/browser/media_observer.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/common/content_switches.h"
#include "googleurl/src/gurl.h"
@ -122,6 +124,13 @@ content::AccessTokenStore* CefContentBrowserClient::CreateAccessTokenStore() {
return new CefAccessTokenStore;
}
void CefContentBrowserClient::ResourceDispatcherHostCreated() {
resource_dispatcher_host_delegate_.reset(
new CefResourceDispatcherHostDelegate());
content::ResourceDispatcherHost::Get()->SetDelegate(
resource_dispatcher_host_delegate_.get());
}
void CefContentBrowserClient::OverrideWebkitPrefs(
content::RenderViewHost* rvh,
const GURL& url,

View File

@ -16,6 +16,7 @@
class CefBrowserMainParts;
class CefMediaObserver;
class CefResourceDispatcherHostDelegate;
namespace content {
class SiteInstance;
@ -38,6 +39,7 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
int child_process_id) OVERRIDE;
virtual content::MediaObserver* GetMediaObserver() OVERRIDE;
virtual content::AccessTokenStore* CreateAccessTokenStore() OVERRIDE;
virtual void ResourceDispatcherHostCreated() OVERRIDE;
virtual void OverrideWebkitPrefs(content::RenderViewHost* rvh,
const GURL& url,
webkit_glue::WebPreferences* prefs) OVERRIDE;
@ -47,6 +49,8 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
CefBrowserMainParts* browser_main_parts_;
scoped_ptr<CefMediaObserver> media_observer_;
scoped_ptr<CefResourceDispatcherHostDelegate>
resource_dispatcher_host_delegate_;
};
#endif // CEF_LIBCEF_BROWSER_CONTENT_BROWSER_CLIENT_H_

View File

@ -0,0 +1,21 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "libcef/browser/resource_dispatcher_host_delegate.h"
#include "libcef/browser/browser_host_impl.h"
CefResourceDispatcherHostDelegate::CefResourceDispatcherHostDelegate() {
}
CefResourceDispatcherHostDelegate::~CefResourceDispatcherHostDelegate() {
}
void CefResourceDispatcherHostDelegate::HandleExternalProtocol(const GURL& url,
int child_id,
int route_id) {
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::GetBrowserByRoutingID(child_id, route_id);
if (browser.get())
browser->HandleExternalProtocol(url);
}

View File

@ -0,0 +1,27 @@
// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
#define CEF_LIBCEF_BROWSER_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
#pragma once
#include "content/public/browser/resource_dispatcher_host_delegate.h"
// Implements ResourceDispatcherHostDelegate.
class CefResourceDispatcherHostDelegate
: public content::ResourceDispatcherHostDelegate {
public:
CefResourceDispatcherHostDelegate();
virtual ~CefResourceDispatcherHostDelegate();
// ResourceDispatcherHostDelegate methods.
virtual void HandleExternalProtocol(const GURL& url,
int child_id,
int route_id) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(CefResourceDispatcherHostDelegate);
};
#endif // CEF_LIBCEF_BROWSER_RESOURCE_DISPATCHER_HOST_DELEGATE_H_

View File

@ -12,14 +12,17 @@
#define CEF_UIT content::BrowserThread::UI
#define CEF_IOT content::BrowserThread::IO
#define CEF_FILET content::BrowserThread::FILE
#define CEF_CURRENTLY_ON(id) content::BrowserThread::CurrentlyOn(id)
#define CEF_CURRENTLY_ON_UIT() CEF_CURRENTLY_ON(CEF_UIT)
#define CEF_CURRENTLY_ON_IOT() CEF_CURRENTLY_ON(CEF_IOT)
#define CEF_CURRENTLY_ON_FILET() CEF_CURRENTLY_ON(CEF_FILET)
#define CEF_REQUIRE(id) DCHECK(CEF_CURRENTLY_ON(id))
#define CEF_REQUIRE_UIT() CEF_REQUIRE(CEF_UIT)
#define CEF_REQUIRE_IOT() CEF_REQUIRE(CEF_IOT)
#define CEF_REQUIRE_FILET() CEF_REQUIRE(CEF_FILET)
#define CEF_REQUIRE_RETURN(id, var) \
if (!CEF_CURRENTLY_ON(id)) { \

View File

@ -194,6 +194,42 @@ cef_cookie_manager_t* CEF_CALLBACK request_handler_get_cookie_manager(
return CefCookieManagerCToCpp::Unwrap(_retval);
}
void CEF_CALLBACK request_handler_on_protocol_execution(
struct _cef_request_handler_t* self, cef_browser_t* browser,
const cef_string_t* url, int* allow_os_execution) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: browser; type: refptr_diff
DCHECK(browser);
if (!browser)
return;
// Verify param: url; type: string_byref_const
DCHECK(url);
if (!url)
return;
// Verify param: allow_os_execution; type: bool_byref
DCHECK(allow_os_execution);
if (!allow_os_execution)
return;
// Translate param: allow_os_execution; type: bool_byref
bool allow_os_executionBool = (
allow_os_execution && *allow_os_execution)?true:false;
// Execute
CefRequestHandlerCppToC::Get(self)->OnProtocolExecution(
CefBrowserCToCpp::Wrap(browser),
CefString(url),
allow_os_executionBool);
// Restore param: allow_os_execution; type: bool_byref
if (allow_os_execution)
*allow_os_execution = allow_os_executionBool?true:false;
}
// CONSTRUCTOR - Do not edit by hand.
@ -206,6 +242,7 @@ CefRequestHandlerCppToC::CefRequestHandlerCppToC(CefRequestHandler* cls)
struct_.struct_.on_resource_redirect = request_handler_on_resource_redirect;
struct_.struct_.get_auth_credentials = request_handler_get_auth_credentials;
struct_.struct_.get_cookie_manager = request_handler_get_cookie_manager;
struct_.struct_.on_protocol_execution = request_handler_on_protocol_execution;
}
#ifndef NDEBUG

View File

@ -182,6 +182,35 @@ CefRefPtr<CefCookieManager> CefRequestHandlerCToCpp::GetCookieManager(
return CefCookieManagerCppToC::Unwrap(_retval);
}
void CefRequestHandlerCToCpp::OnProtocolExecution(CefRefPtr<CefBrowser> browser,
const CefString& url, bool& allow_os_execution) {
if (CEF_MEMBER_MISSING(struct_, on_protocol_execution))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: browser; type: refptr_diff
DCHECK(browser.get());
if (!browser.get())
return;
// Verify param: url; type: string_byref_const
DCHECK(!url.empty());
if (url.empty())
return;
// Translate param: allow_os_execution; type: bool_byref
int allow_os_executionInt = allow_os_execution;
// Execute
struct_->on_protocol_execution(struct_,
CefBrowserCppToC::Wrap(browser),
url.GetStruct(),
&allow_os_executionInt);
// Restore param:allow_os_execution; type: bool_byref
allow_os_execution = allow_os_executionInt?true:false;
}
#ifndef NDEBUG
template<> long CefCToCpp<CefRequestHandlerCToCpp, CefRequestHandler,

View File

@ -48,6 +48,8 @@ class CefRequestHandlerCToCpp
CefRefPtr<CefAuthCallback> callback) OVERRIDE;
virtual CefRefPtr<CefCookieManager> GetCookieManager(
CefRefPtr<CefBrowser> browser, const CefString& main_url) OVERRIDE;
virtual void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
const CefString& url, bool& allow_os_execution) OVERRIDE;
};
#endif // BUILDING_CEF_SHARED

View File

@ -275,6 +275,14 @@ void ClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
if (errorCode == ERR_ABORTED)
return;
// Don't display an error for external protocols that we allow the OS to
// handle. See OnProtocolExecution().
if (errorCode == ERR_UNKNOWN_URL_SCHEME) {
std::string urlStr = frame->GetURL();
if (urlStr.find("spotify:") == 0)
return;
}
// Display a load error message.
std::stringstream ss;
ss << "<html><body><h2>Failed to load URL " << std::string(failedUrl) <<
@ -346,6 +354,16 @@ CefRefPtr<CefResourceHandler> ClientHandler::GetResourceHandler(
return handler;
}
void ClientHandler::OnProtocolExecution(CefRefPtr<CefBrowser> browser,
const CefString& url,
bool& allow_os_execution) {
std::string urlStr = url;
// Allow OS execution of Spotify URIs.
if (urlStr.find("spotify:") == 0)
allow_os_execution = true;
}
void ClientHandler::SetMainHwnd(CefWindowHandle hwnd) {
AutoLock lock_scope(this);
m_MainHwnd = hwnd;

View File

@ -157,6 +157,9 @@ class ClientHandler : public CefClient,
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) OVERRIDE;
virtual void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
const CefString& url,
bool& allow_os_execution) OVERRIDE;
void SetMainHwnd(CefWindowHandle hwnd);
CefWindowHandle GetMainHwnd() { return m_MainHwnd; }