mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-03 04:27:43 +01:00
Improvements to scheme handling (issue #246).
- Break CefRegisterScheme into separate CefRegisterCustomScheme and CefRegisterSchemeHandlerFactory functions. - Allow registration of handlers for built-in schemes. - Supply scheme and request information to CefSchemeHandlerFactory::Create. - Add CrossOriginWhitelist functions for bypassing the same-origin policy with both built-in and custom standard schemes. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@247 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
parent
42b5597214
commit
63aa102a6a
1
cef.gyp
1
cef.gyp
@ -696,6 +696,7 @@
|
|||||||
'libcef/external_protocol_handler.h',
|
'libcef/external_protocol_handler.h',
|
||||||
'libcef/http_header_utils.cc',
|
'libcef/http_header_utils.cc',
|
||||||
'libcef/http_header_utils.h',
|
'libcef/http_header_utils.h',
|
||||||
|
'libcef/origin_whitelist_impl.cc',
|
||||||
'libcef/request_impl.cc',
|
'libcef/request_impl.cc',
|
||||||
'libcef/request_impl.h',
|
'libcef/request_impl.h',
|
||||||
'libcef/response_impl.cc',
|
'libcef/response_impl.cc',
|
||||||
|
@ -172,8 +172,10 @@ bool CefRegisterExtension(const CefString& extension_name,
|
|||||||
const CefString& javascript_code,
|
const CefString& javascript_code,
|
||||||
CefRefPtr<CefV8Handler> handler);
|
CefRefPtr<CefV8Handler> handler);
|
||||||
|
|
||||||
// CEF supports two types of schemes, standard and non-standard.
|
// Register a custom scheme. This method should not be called for the built-in
|
||||||
|
// HTTP, HTTPS, FILE, FTP, ABOUT and DATA schemes.
|
||||||
//
|
//
|
||||||
|
// If |is_standard| is true the scheme will be treated as a standard scheme.
|
||||||
// Standard schemes are subject to URL canonicalization and parsing rules as
|
// Standard schemes are subject to URL canonicalization and parsing rules as
|
||||||
// defined in the Common Internet Scheme Syntax RFC 1738 Section 3.1 available
|
// defined in the Common Internet Scheme Syntax RFC 1738 Section 3.1 available
|
||||||
// at http://www.ietf.org/rfc/rfc1738.txt
|
// at http://www.ietf.org/rfc/rfc1738.txt
|
||||||
@ -194,17 +196,87 @@ bool CefRegisterExtension(const CefString& extension_name,
|
|||||||
// For example, "scheme:///some%20text" will remain the same. Non-standard
|
// For example, "scheme:///some%20text" will remain the same. Non-standard
|
||||||
// scheme URLs cannot be used as a target for form submission.
|
// scheme URLs cannot be used as a target for form submission.
|
||||||
//
|
//
|
||||||
// Register a custom scheme handler factory for the specified |scheme_name| and
|
// If |is_local| is true the scheme will be treated as local (i.e., with the
|
||||||
// optional |host_name|. Specifying an empty |host_name| value for standard
|
// same security rules as those applied to "file" URLs). This means that normal
|
||||||
// schemes will match all host names. The |host_name| value will be ignored for
|
// pages cannot link to or access URLs of this scheme.
|
||||||
// non-standard schemes. Set |is_standard| to true to register as a standard
|
//
|
||||||
// scheme or false to register a non-standard scheme. This function may be
|
// If |is_display_isolated| is true the scheme will be treated as display-
|
||||||
// called on any thread.
|
// isolated. This means that pages cannot display these URLs unless they are
|
||||||
|
// from the same scheme. For example, pages in another origin cannot create
|
||||||
|
// iframes or hyperlinks to URLs with this scheme.
|
||||||
|
//
|
||||||
|
// This function may be called on any thread. It should only be called once
|
||||||
|
// per unique |scheme_name| value. If |scheme_name| is already registered or if
|
||||||
|
// an error occurs this method will return false.
|
||||||
/*--cef()--*/
|
/*--cef()--*/
|
||||||
bool CefRegisterScheme(const CefString& scheme_name,
|
bool CefRegisterCustomScheme(const CefString& scheme_name,
|
||||||
const CefString& host_name,
|
bool is_standard,
|
||||||
bool is_standard,
|
bool is_local,
|
||||||
CefRefPtr<CefSchemeHandlerFactory> factory);
|
bool is_display_isolated);
|
||||||
|
|
||||||
|
// Register a scheme handler factory for the specified |scheme_name| and
|
||||||
|
// optional |domain_name|. An empty |domain_name| value for a standard scheme
|
||||||
|
// will cause the factory to match all domain names. The |domain_name| value
|
||||||
|
// will be ignored for non-standard schemes. If |scheme_name| is a built-in
|
||||||
|
// scheme and no handler is returned by |factory| then the built-in scheme
|
||||||
|
// handler factory will be called. If |scheme_name| is a custom scheme the
|
||||||
|
// CefRegisterCustomScheme() function should be called for that scheme.
|
||||||
|
// This function may be called multiple times to change or remove the factory
|
||||||
|
// that matches the specified |scheme_name| and optional |domain_name|.
|
||||||
|
// Returns false if an error occurs. This function may be called on any thread.
|
||||||
|
/*--cef()--*/
|
||||||
|
bool CefRegisterSchemeHandlerFactory(const CefString& scheme_name,
|
||||||
|
const CefString& domain_name,
|
||||||
|
CefRefPtr<CefSchemeHandlerFactory> factory);
|
||||||
|
|
||||||
|
// Clear all registered scheme handler factories. Returns false on error. This
|
||||||
|
// function may be called on any thread.
|
||||||
|
/*--cef()--*/
|
||||||
|
bool CefClearSchemeHandlerFactories();
|
||||||
|
|
||||||
|
// Add an entry to the cross-origin access whitelist.
|
||||||
|
//
|
||||||
|
// The same-origin policy restricts how scripts hosted from different origins
|
||||||
|
// (scheme + domain) can communicate. By default, scripts can only access
|
||||||
|
// resources with the same origin. Scripts hosted on the HTTP and HTTPS schemes
|
||||||
|
// (but no other schemes) can use the "Access-Control-Allow-Origin" header to
|
||||||
|
// allow cross-origin requests. For example, https://source.example.com can make
|
||||||
|
// XMLHttpRequest requests on http://target.example.com if the
|
||||||
|
// http://target.example.com request returns an "Access-Control-Allow-Origin:
|
||||||
|
// https://source.example.com" response header.
|
||||||
|
//
|
||||||
|
// Scripts in separate frames or iframes and hosted from the same protocol and
|
||||||
|
// domain suffix can execute cross-origin JavaScript if both pages set the
|
||||||
|
// document.domain value to the same domain suffix. For example,
|
||||||
|
// scheme://foo.example.com and scheme://bar.example.com can communicate using
|
||||||
|
// JavaScript if both domains set document.domain="example.com".
|
||||||
|
//
|
||||||
|
// This method is used to allow access to origins that would otherwise violate
|
||||||
|
// the same-origin policy. Scripts hosted underneath the fully qualified
|
||||||
|
// |source_origin| URL (like http://www.example.com) will be allowed access to
|
||||||
|
// all resources hosted on the specified |target_protocol| and |target_domain|.
|
||||||
|
// If |allow_target_subdomains| is true access will also be allowed to all
|
||||||
|
// subdomains of the target domain. This function may be called on any thread.
|
||||||
|
// Returns false if |source_origin| is invalid or the whitelist cannot be
|
||||||
|
// accessed.
|
||||||
|
/*--cef()--*/
|
||||||
|
bool CefAddCrossOriginWhitelistEntry(const CefString& source_origin,
|
||||||
|
const CefString& target_protocol,
|
||||||
|
const CefString& target_domain,
|
||||||
|
bool allow_target_subdomains);
|
||||||
|
|
||||||
|
// Remove an entry from the cross-origin access whitelist. Returns false if
|
||||||
|
// |source_origin| is invalid or the whitelist cannot be accessed.
|
||||||
|
/*--cef()--*/
|
||||||
|
bool CefRemoveCrossOriginWhitelistEntry(const CefString& source_origin,
|
||||||
|
const CefString& target_protocol,
|
||||||
|
const CefString& target_domain,
|
||||||
|
bool allow_target_subdomains);
|
||||||
|
|
||||||
|
// Remove all entries from the cross-origin access whitelist. Returns false if
|
||||||
|
// the whitelist cannot be accessed.
|
||||||
|
/*--cef()--*/
|
||||||
|
bool CefClearCrossOriginWhitelist();
|
||||||
|
|
||||||
typedef cef_thread_id_t CefThreadId;
|
typedef cef_thread_id_t CefThreadId;
|
||||||
|
|
||||||
@ -1744,7 +1816,8 @@ class CefSchemeHandlerFactory : public virtual CefBase
|
|||||||
public:
|
public:
|
||||||
// Return a new scheme handler instance to handle the request.
|
// Return a new scheme handler instance to handle the request.
|
||||||
/*--cef()--*/
|
/*--cef()--*/
|
||||||
virtual CefRefPtr<CefSchemeHandler> Create() =0;
|
virtual CefRefPtr<CefSchemeHandler> Create(const CefString& scheme_name,
|
||||||
|
CefRefPtr<CefRequest> request) =0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,8 +133,10 @@ CEF_EXPORT void cef_run_message_loop();
|
|||||||
CEF_EXPORT int cef_register_extension(const cef_string_t* extension_name,
|
CEF_EXPORT int cef_register_extension(const cef_string_t* extension_name,
|
||||||
const cef_string_t* javascript_code, struct _cef_v8handler_t* handler);
|
const cef_string_t* javascript_code, struct _cef_v8handler_t* handler);
|
||||||
|
|
||||||
// CEF supports two types of schemes, standard and non-standard.
|
// Register a custom scheme. This function should not be called for the built-in
|
||||||
|
// HTTP, HTTPS, FILE, FTP, ABOUT and DATA schemes.
|
||||||
//
|
//
|
||||||
|
// If |is_standard| is true (1) the scheme will be treated as a standard scheme.
|
||||||
// Standard schemes are subject to URL canonicalization and parsing rules as
|
// Standard schemes are subject to URL canonicalization and parsing rules as
|
||||||
// defined in the Common Internet Scheme Syntax RFC 1738 Section 3.1 available
|
// defined in the Common Internet Scheme Syntax RFC 1738 Section 3.1 available
|
||||||
// at http://www.ietf.org/rfc/rfc1738.txt
|
// at http://www.ietf.org/rfc/rfc1738.txt
|
||||||
@ -155,16 +157,78 @@ CEF_EXPORT int cef_register_extension(const cef_string_t* extension_name,
|
|||||||
// For example, "scheme:///some%20text" will remain the same. Non-standard
|
// For example, "scheme:///some%20text" will remain the same. Non-standard
|
||||||
// scheme URLs cannot be used as a target for form submission.
|
// scheme URLs cannot be used as a target for form submission.
|
||||||
//
|
//
|
||||||
// Register a custom scheme handler factory for the specified |scheme_name| and
|
// If |is_local| is true (1) the scheme will be treated as local (i.e., with the
|
||||||
// optional |host_name|. Specifying an NULL |host_name| value for standard
|
// same security rules as those applied to "file" URLs). This means that normal
|
||||||
// schemes will match all host names. The |host_name| value will be ignored for
|
// pages cannot link to or access URLs of this scheme.
|
||||||
// non-standard schemes. Set |is_standard| to true (1) to register as a standard
|
//
|
||||||
// scheme or false (0) to register a non-standard scheme. This function may be
|
// If |is_display_isolated| is true (1) the scheme will be treated as display-
|
||||||
// called on any thread.
|
// isolated. This means that pages cannot display these URLs unless they are
|
||||||
CEF_EXPORT int cef_register_scheme(const cef_string_t* scheme_name,
|
// from the same scheme. For example, pages in another origin cannot create
|
||||||
const cef_string_t* host_name, int is_standard,
|
// iframes or hyperlinks to URLs with this scheme.
|
||||||
|
//
|
||||||
|
// This function may be called on any thread. It should only be called once per
|
||||||
|
// unique |scheme_name| value. If |scheme_name| is already registered or if an
|
||||||
|
// error occurs this function will return false (0).
|
||||||
|
CEF_EXPORT int cef_register_custom_scheme(const cef_string_t* scheme_name,
|
||||||
|
int is_standard, int is_local, int is_display_isolated);
|
||||||
|
|
||||||
|
// Register a scheme handler factory for the specified |scheme_name| and
|
||||||
|
// optional |domain_name|. An NULL |domain_name| value for a standard scheme
|
||||||
|
// will cause the factory to match all domain names. The |domain_name| value
|
||||||
|
// will be ignored for non-standard schemes. If |scheme_name| is a built-in
|
||||||
|
// scheme and no handler is returned by |factory| then the built-in scheme
|
||||||
|
// handler factory will be called. If |scheme_name| is a custom scheme the
|
||||||
|
// cef_register_custom_scheme() function should be called for that scheme. This
|
||||||
|
// function may be called multiple times to change or remove the factory that
|
||||||
|
// matches the specified |scheme_name| and optional |domain_name|. Returns false
|
||||||
|
// (0) if an error occurs. This function may be called on any thread.
|
||||||
|
CEF_EXPORT int cef_register_scheme_handler_factory(
|
||||||
|
const cef_string_t* scheme_name, const cef_string_t* domain_name,
|
||||||
struct _cef_scheme_handler_factory_t* factory);
|
struct _cef_scheme_handler_factory_t* factory);
|
||||||
|
|
||||||
|
// Clear all registered scheme handler factories. Returns false (0) on error.
|
||||||
|
// This function may be called on any thread.
|
||||||
|
CEF_EXPORT int cef_clear_scheme_handler_factories();
|
||||||
|
|
||||||
|
// Add an entry to the cross-origin access whitelist.
|
||||||
|
//
|
||||||
|
// The same-origin policy restricts how scripts hosted from different origins
|
||||||
|
// (scheme + domain) can communicate. By default, scripts can only access
|
||||||
|
// resources with the same origin. Scripts hosted on the HTTP and HTTPS schemes
|
||||||
|
// (but no other schemes) can use the "Access-Control-Allow-Origin" header to
|
||||||
|
// allow cross-origin requests. For example, https://source.example.com can make
|
||||||
|
// XMLHttpRequest requests on http://target.example.com if the
|
||||||
|
// http://target.example.com request returns an "Access-Control-Allow-Origin:
|
||||||
|
// https://source.example.com" response header.
|
||||||
|
//
|
||||||
|
// Scripts in separate frames or iframes and hosted from the same protocol and
|
||||||
|
// domain suffix can execute cross-origin JavaScript if both pages set the
|
||||||
|
// document.domain value to the same domain suffix. For example,
|
||||||
|
// scheme://foo.example.com and scheme://bar.example.com can communicate using
|
||||||
|
// JavaScript if both domains set document.domain="example.com".
|
||||||
|
//
|
||||||
|
// This function is used to allow access to origins that would otherwise violate
|
||||||
|
// the same-origin policy. Scripts hosted underneath the fully qualified
|
||||||
|
// |source_origin| URL (like http://www.example.com) will be allowed access to
|
||||||
|
// all resources hosted on the specified |target_protocol| and |target_domain|.
|
||||||
|
// If |allow_target_subdomains| is true (1) access will also be allowed to all
|
||||||
|
// subdomains of the target domain. This function may be called on any thread.
|
||||||
|
// Returns false (0) if |source_origin| is invalid or the whitelist cannot be
|
||||||
|
// accessed.
|
||||||
|
CEF_EXPORT int cef_add_cross_origin_whitelist_entry(
|
||||||
|
const cef_string_t* source_origin, const cef_string_t* target_protocol,
|
||||||
|
const cef_string_t* target_domain, int allow_target_subdomains);
|
||||||
|
|
||||||
|
// Remove an entry from the cross-origin access whitelist. Returns false (0) if
|
||||||
|
// |source_origin| is invalid or the whitelist cannot be accessed.
|
||||||
|
CEF_EXPORT int cef_remove_cross_origin_whitelist_entry(
|
||||||
|
const cef_string_t* source_origin, const cef_string_t* target_protocol,
|
||||||
|
const cef_string_t* target_domain, int allow_target_subdomains);
|
||||||
|
|
||||||
|
// Remove all entries from the cross-origin access whitelist. Returns false (0)
|
||||||
|
// if the whitelist cannot be accessed.
|
||||||
|
CEF_EXPORT int cef_clear_cross_origin_whitelist();
|
||||||
|
|
||||||
// CEF maintains multiple internal threads that are used for handling different
|
// CEF maintains multiple internal threads that are used for handling different
|
||||||
// types of tasks. The UI thread creates the browser window and is used for all
|
// types of tasks. The UI thread creates the browser window and is used for all
|
||||||
// interaction with the WebKit rendering engine and V8 JavaScript engine (The UI
|
// interaction with the WebKit rendering engine and V8 JavaScript engine (The UI
|
||||||
@ -1539,7 +1603,8 @@ typedef struct _cef_scheme_handler_factory_t
|
|||||||
|
|
||||||
// Return a new scheme handler instance to handle the request.
|
// Return a new scheme handler instance to handle the request.
|
||||||
struct _cef_scheme_handler_t* (CEF_CALLBACK *create)(
|
struct _cef_scheme_handler_t* (CEF_CALLBACK *create)(
|
||||||
struct _cef_scheme_handler_factory_t* self);
|
struct _cef_scheme_handler_factory_t* self,
|
||||||
|
const cef_string_t* scheme_name, struct _cef_request_t* request);
|
||||||
|
|
||||||
} cef_scheme_handler_factory_t;
|
} cef_scheme_handler_factory_t;
|
||||||
|
|
||||||
|
103
libcef/origin_whitelist_impl.cc
Normal file
103
libcef/origin_whitelist_impl.cc
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// Copyright (c) 2011 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 "include/cef.h"
|
||||||
|
#include "cef_context.h"
|
||||||
|
|
||||||
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h"
|
||||||
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
|
||||||
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
|
||||||
|
|
||||||
|
using WebKit::WebSecurityPolicy;
|
||||||
|
using WebKit::WebString;
|
||||||
|
|
||||||
|
bool CefAddCrossOriginWhitelistEntry(const CefString& source_origin,
|
||||||
|
const CefString& target_protocol,
|
||||||
|
const CefString& target_domain,
|
||||||
|
bool allow_target_subdomains)
|
||||||
|
{
|
||||||
|
// Verify that the context is in a valid state.
|
||||||
|
if (!CONTEXT_STATE_VALID()) {
|
||||||
|
NOTREACHED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string source_url = source_origin;
|
||||||
|
GURL gurl = GURL(source_url);
|
||||||
|
if (gurl.is_empty() || !gurl.is_valid()) {
|
||||||
|
NOTREACHED() << "Invalid source_origin URL: " << source_url;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CefThread::CurrentlyOn(CefThread::UI)) {
|
||||||
|
std::string target_protocol_str = target_protocol;
|
||||||
|
std::string target_domain_str = target_domain;
|
||||||
|
WebSecurityPolicy::addOriginAccessWhitelistEntry(
|
||||||
|
gurl,
|
||||||
|
WebString::fromUTF8(target_protocol_str),
|
||||||
|
WebString::fromUTF8(target_domain_str),
|
||||||
|
allow_target_subdomains);
|
||||||
|
} else {
|
||||||
|
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
||||||
|
NewRunnableFunction(&CefAddCrossOriginWhitelistEntry, source_origin,
|
||||||
|
target_protocol, target_domain,
|
||||||
|
allow_target_subdomains));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefRemoveCrossOriginWhitelistEntry(const CefString& source_origin,
|
||||||
|
const CefString& target_protocol,
|
||||||
|
const CefString& target_domain,
|
||||||
|
bool allow_target_subdomains)
|
||||||
|
{
|
||||||
|
// Verify that the context is in a valid state.
|
||||||
|
if (!CONTEXT_STATE_VALID()) {
|
||||||
|
NOTREACHED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string source_url = source_origin;
|
||||||
|
GURL gurl = GURL(source_url);
|
||||||
|
if (gurl.is_empty() || !gurl.is_valid()) {
|
||||||
|
NOTREACHED() << "Invalid source_origin URL: " << source_url;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CefThread::CurrentlyOn(CefThread::UI)) {
|
||||||
|
std::string target_protocol_str = target_protocol;
|
||||||
|
std::string target_domain_str = target_domain;
|
||||||
|
WebSecurityPolicy::removeOriginAccessWhitelistEntry(
|
||||||
|
gurl,
|
||||||
|
WebString::fromUTF8(target_protocol_str),
|
||||||
|
WebString::fromUTF8(target_domain_str),
|
||||||
|
allow_target_subdomains);
|
||||||
|
} else {
|
||||||
|
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
||||||
|
NewRunnableFunction(&CefRemoveCrossOriginWhitelistEntry, source_origin,
|
||||||
|
target_protocol, target_domain,
|
||||||
|
allow_target_subdomains));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefClearCrossOriginWhitelist()
|
||||||
|
{
|
||||||
|
// Verify that the context is in a valid state.
|
||||||
|
if (!CONTEXT_STATE_VALID()) {
|
||||||
|
NOTREACHED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CefThread::CurrentlyOn(CefThread::UI)) {
|
||||||
|
WebSecurityPolicy::resetOriginAccessWhitelists();
|
||||||
|
} else {
|
||||||
|
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
||||||
|
NewRunnableFunction(&CefClearCrossOriginWhitelist));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
@ -1,11 +1,18 @@
|
|||||||
// Copyright (c) 2009 The Chromium Embedded Framework Authors.
|
// Copyright (c) 2011 The Chromium Embedded Framework Authors.
|
||||||
// Portions copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
|
// Portions copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "include/cef.h"
|
||||||
|
#include "cef_context.h"
|
||||||
|
#include "request_impl.h"
|
||||||
|
#include "response_impl.h"
|
||||||
|
|
||||||
#include "base/lazy_instance.h"
|
#include "base/lazy_instance.h"
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/message_loop.h"
|
#include "base/message_loop.h"
|
||||||
|
#include "base/string_util.h"
|
||||||
|
#include "base/synchronization/lock.h"
|
||||||
#include "googleurl/src/url_util.h"
|
#include "googleurl/src/url_util.h"
|
||||||
#include "net/base/completion_callback.h"
|
#include "net/base/completion_callback.h"
|
||||||
#include "net/base/io_buffer.h"
|
#include "net/base/io_buffer.h"
|
||||||
@ -13,43 +20,89 @@
|
|||||||
#include "net/http/http_response_headers.h"
|
#include "net/http/http_response_headers.h"
|
||||||
#include "net/http/http_util.h"
|
#include "net/http/http_util.h"
|
||||||
#include "net/url_request/url_request.h"
|
#include "net/url_request/url_request.h"
|
||||||
|
#include "net/url_request/url_request_about_job.h"
|
||||||
|
#include "net/url_request/url_request_data_job.h"
|
||||||
|
#include "net/url_request/url_request_error_job.h"
|
||||||
|
#include "net/url_request/url_request_file_job.h"
|
||||||
#include "net/url_request/url_request_filter.h"
|
#include "net/url_request/url_request_filter.h"
|
||||||
|
#include "net/url_request/url_request_ftp_job.h"
|
||||||
|
#include "net/url_request/url_request_http_job.h"
|
||||||
#include "net/url_request/url_request_job.h"
|
#include "net/url_request/url_request_job.h"
|
||||||
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h"
|
||||||
#include "include/cef.h"
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
|
||||||
#include "tracker.h"
|
|
||||||
#include "cef_context.h"
|
|
||||||
#include "request_impl.h"
|
|
||||||
#include "response_impl.h"
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
using WebKit::WebSecurityPolicy;
|
||||||
|
using WebKit::WebString;
|
||||||
|
|
||||||
// Memory manager.
|
namespace {
|
||||||
|
|
||||||
base::LazyInstance<CefTrackManager> g_scheme_tracker(base::LINKER_INITIALIZED);
|
bool IsStandardScheme(const std::string& scheme)
|
||||||
|
|
||||||
class TrackBase : public CefTrackObject
|
|
||||||
{
|
{
|
||||||
public:
|
url_parse::Component scheme_comp(0, scheme.length());
|
||||||
TrackBase(CefBase* base) { base_ = base; }
|
return url_util::IsStandard(scheme.c_str(), scheme_comp);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
void RegisterStandardScheme(const std::string& scheme)
|
||||||
CefRefPtr<CefBase> base_;
|
{
|
||||||
|
REQUIRE_UIT();
|
||||||
|
url_parse::Component scheme_comp(0, scheme.length());
|
||||||
|
if (!url_util::IsStandard(scheme.c_str(), scheme_comp))
|
||||||
|
url_util::AddStandardScheme(scheme.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from net/url_request/url_request_job_manager.cc.
|
||||||
|
struct SchemeToFactory {
|
||||||
|
const char* scheme;
|
||||||
|
net::URLRequest::ProtocolFactory* factory;
|
||||||
|
};
|
||||||
|
static const SchemeToFactory kBuiltinFactories[] = {
|
||||||
|
{ "http", net::URLRequestHttpJob::Factory },
|
||||||
|
{ "https", net::URLRequestHttpJob::Factory },
|
||||||
|
{ "file", net::URLRequestFileJob::Factory },
|
||||||
|
{ "ftp", net::URLRequestFtpJob::Factory },
|
||||||
|
{ "about", net::URLRequestAboutJob::Factory },
|
||||||
|
{ "data", net::URLRequestDataJob::Factory },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void TrackAdd(CefTrackObject* object)
|
bool IsBuiltinScheme(const std::string& scheme)
|
||||||
{
|
{
|
||||||
g_scheme_tracker.Pointer()->Add(object);
|
for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i)
|
||||||
|
if (LowerCaseEqualsASCII(scheme, kBuiltinFactories[i].scheme))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
net::URLRequestJob* GetBuiltinSchemeRequestJob(net::URLRequest* request,
|
||||||
|
const std::string& scheme)
|
||||||
|
{
|
||||||
|
// See if the request should be handled by a built-in protocol factory.
|
||||||
|
for (size_t i = 0; i < arraysize(kBuiltinFactories); ++i) {
|
||||||
|
if (scheme == kBuiltinFactories[i].scheme) {
|
||||||
|
net::URLRequestJob* job = (kBuiltinFactories[i].factory)(request, scheme);
|
||||||
|
DCHECK(job); // The built-in factories are not expected to fail!
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToLower(const std::string& str)
|
||||||
|
{
|
||||||
|
std::string str_lower = str;
|
||||||
|
std::transform(str_lower.begin(), str_lower.end(), str_lower.begin(),
|
||||||
|
towlower);
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// net::URLRequestJob implementation.
|
// net::URLRequestJob implementation.
|
||||||
|
|
||||||
class CefUrlRequestJob : public net::URLRequestJob {
|
class CefUrlRequestJob : public net::URLRequestJob {
|
||||||
public:
|
public:
|
||||||
CefUrlRequestJob(net::URLRequest* request, CefRefPtr<CefSchemeHandler> handler)
|
CefUrlRequestJob(net::URLRequest* request,
|
||||||
|
CefRefPtr<CefSchemeHandler> handler)
|
||||||
: net::URLRequestJob(request),
|
: net::URLRequestJob(request),
|
||||||
handler_(handler),
|
handler_(handler),
|
||||||
response_length_(0),
|
response_length_(0),
|
||||||
@ -244,54 +297,64 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// net::URLRequestFilter clone that manages the CefSchemeHandlerFactory pointers.
|
// Class that manages the CefSchemeHandlerFactory instances.
|
||||||
|
class CefUrlRequestManager {
|
||||||
class CefUrlRequestFilter {
|
|
||||||
public:
|
public:
|
||||||
// scheme,hostname -> ProtocolFactory
|
CefUrlRequestManager() {}
|
||||||
typedef std::map<std::pair<std::string, std::string>,
|
|
||||||
CefSchemeHandlerFactory*> HandlerMap;
|
|
||||||
|
|
||||||
// Singleton instance for use.
|
// Retrieve the singleton instance.
|
||||||
static CefUrlRequestFilter* GetInstance()
|
static CefUrlRequestManager* GetInstance();
|
||||||
{
|
|
||||||
if (!shared_instance_)
|
|
||||||
shared_instance_ = new CefUrlRequestFilter;
|
|
||||||
return shared_instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
static net::URLRequestJob* Factory(net::URLRequest* request,
|
bool AddFactory(const std::string& scheme,
|
||||||
const std::string& scheme)
|
const std::string& domain,
|
||||||
|
CefRefPtr<CefSchemeHandlerFactory> factory)
|
||||||
{
|
{
|
||||||
// Returning null here just means that the built-in handler will be used.
|
if (!factory.get()) {
|
||||||
return GetInstance()->FindRequestHandler(request, scheme);
|
RemoveFactory(scheme, domain);
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void AddHostnameHandler(const std::string& scheme,
|
REQUIRE_IOT();
|
||||||
const std::string& hostname,
|
|
||||||
CefSchemeHandlerFactory* factory)
|
std::string scheme_lower = ToLower(scheme);
|
||||||
{
|
std::string domain_lower = ToLower(domain);
|
||||||
handler_map_[make_pair(scheme, hostname)] = factory;
|
|
||||||
|
// Hostname is only supported for standard schemes.
|
||||||
|
if (!IsStandardScheme(scheme_lower))
|
||||||
|
domain_lower.clear();
|
||||||
|
|
||||||
|
handler_map_[make_pair(scheme_lower, domain_lower)] = factory;
|
||||||
|
|
||||||
// Register with the ProtocolFactory.
|
// Register with the ProtocolFactory.
|
||||||
net::URLRequest::RegisterProtocolFactory(scheme,
|
net::URLRequest::RegisterProtocolFactory(scheme_lower,
|
||||||
&CefUrlRequestFilter::Factory);
|
&CefUrlRequestManager::Factory);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveHostnameHandler(const std::string& scheme,
|
void RemoveFactory(const std::string& scheme,
|
||||||
const std::string& hostname)
|
const std::string& domain)
|
||||||
{
|
{
|
||||||
|
REQUIRE_IOT();
|
||||||
|
|
||||||
|
std::string scheme_lower = ToLower(scheme);
|
||||||
|
std::string domain_lower = ToLower(domain);
|
||||||
|
|
||||||
|
// Hostname is only supported for standard schemes.
|
||||||
|
if (!IsStandardScheme(scheme_lower))
|
||||||
|
domain_lower.clear();
|
||||||
|
|
||||||
HandlerMap::iterator iter =
|
HandlerMap::iterator iter =
|
||||||
handler_map_.find(make_pair(scheme, hostname));
|
handler_map_.find(make_pair(scheme_lower, domain_lower));
|
||||||
DCHECK(iter != handler_map_.end());
|
if (iter != handler_map_.end())
|
||||||
|
handler_map_.erase(iter);
|
||||||
handler_map_.erase(iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear all the existing URL handlers and unregister with the
|
// Clear all the existing URL handlers and unregister the ProtocolFactory.
|
||||||
// ProtocolFactory. Resets the hit count.
|
void ClearFactories()
|
||||||
void ClearHandlers()
|
|
||||||
{
|
{
|
||||||
|
REQUIRE_IOT();
|
||||||
|
|
||||||
// Unregister with the ProtocolFactory.
|
// Unregister with the ProtocolFactory.
|
||||||
std::set<std::string> schemes;
|
std::set<std::string> schemes;
|
||||||
for (HandlerMap::const_iterator i = handler_map_.begin();
|
for (HandlerMap::const_iterator i = handler_map_.begin();
|
||||||
@ -304,24 +367,73 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
handler_map_.clear();
|
handler_map_.clear();
|
||||||
hit_count_ = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CefSchemeHandlerFactory* FindRequestHandlerFactory(net::URLRequest* request,
|
// Check if a scheme has already been registered.
|
||||||
const std::string& scheme)
|
bool HasRegisteredScheme(const std::string& scheme)
|
||||||
{
|
{
|
||||||
CefSchemeHandlerFactory* factory = NULL;
|
std::string scheme_lower = ToLower(scheme);
|
||||||
if (request->url().is_valid()) {
|
|
||||||
// Check for a map with a hostname first.
|
|
||||||
const std::string& hostname = request->url().host();
|
|
||||||
|
|
||||||
HandlerMap::iterator i = handler_map_.find(make_pair(scheme, hostname));
|
// Don't register builtin schemes.
|
||||||
|
if (IsBuiltinScheme(scheme_lower))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
scheme_set_lock_.Acquire();
|
||||||
|
bool registered = (scheme_set_.find(scheme_lower) != scheme_set_.end());
|
||||||
|
scheme_set_lock_.Release();
|
||||||
|
return registered;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register a scheme.
|
||||||
|
bool RegisterScheme(const std::string& scheme,
|
||||||
|
bool is_standard,
|
||||||
|
bool is_local,
|
||||||
|
bool is_display_isolated)
|
||||||
|
{
|
||||||
|
if (HasRegisteredScheme(scheme)) {
|
||||||
|
NOTREACHED() << "Scheme already registered: " << scheme;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string scheme_lower = ToLower(scheme);
|
||||||
|
|
||||||
|
scheme_set_lock_.Acquire();
|
||||||
|
scheme_set_.insert(scheme_lower);
|
||||||
|
scheme_set_lock_.Release();
|
||||||
|
|
||||||
|
if (is_standard)
|
||||||
|
RegisterStandardScheme(scheme_lower);
|
||||||
|
if (is_local) {
|
||||||
|
WebSecurityPolicy::registerURLSchemeAsLocal(
|
||||||
|
WebString::fromUTF8(scheme_lower));
|
||||||
|
}
|
||||||
|
if (is_display_isolated) {
|
||||||
|
WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(
|
||||||
|
WebString::fromUTF8(scheme_lower));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Retrieve the matching handler factory, if any. |scheme| will already be in
|
||||||
|
// lower case.
|
||||||
|
CefRefPtr<CefSchemeHandlerFactory> GetHandlerFactory(
|
||||||
|
net::URLRequest* request, const std::string& scheme)
|
||||||
|
{
|
||||||
|
CefRefPtr<CefSchemeHandlerFactory> factory;
|
||||||
|
|
||||||
|
if (request->url().is_valid() && IsStandardScheme(scheme)) {
|
||||||
|
// Check for a match with a domain first.
|
||||||
|
const std::string& domain = request->url().host();
|
||||||
|
|
||||||
|
HandlerMap::iterator i = handler_map_.find(make_pair(scheme, domain));
|
||||||
if (i != handler_map_.end())
|
if (i != handler_map_.end())
|
||||||
factory = i->second;
|
factory = i->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!factory) {
|
if (!factory.get()) {
|
||||||
// Check for a map with no specified hostname.
|
// Check for a match with no specified domain.
|
||||||
HandlerMap::iterator i =
|
HandlerMap::iterator i =
|
||||||
handler_map_.find(make_pair(scheme, std::string()));
|
handler_map_.find(make_pair(scheme, std::string()));
|
||||||
if (i != handler_map_.end())
|
if (i != handler_map_.end())
|
||||||
@ -331,90 +443,71 @@ public:
|
|||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of times a handler was used to service a request.
|
// Create the job that will handle the request. |scheme| will already be in
|
||||||
int hit_count() const { return hit_count_; }
|
// lower case.
|
||||||
|
net::URLRequestJob* GetRequestJob(net::URLRequest* request,
|
||||||
protected:
|
const std::string& scheme)
|
||||||
CefUrlRequestFilter() : hit_count_(0) { }
|
|
||||||
|
|
||||||
// Helper method that looks up the request in the handler_map_.
|
|
||||||
net::URLRequestJob* FindRequestHandler(net::URLRequest* request,
|
|
||||||
const std::string& scheme)
|
|
||||||
{
|
{
|
||||||
net::URLRequestJob* job = NULL;
|
net::URLRequestJob* job = NULL;
|
||||||
CefSchemeHandlerFactory* factory =
|
CefRefPtr<CefSchemeHandlerFactory> factory =
|
||||||
FindRequestHandlerFactory(request, scheme);
|
GetHandlerFactory(request, scheme);
|
||||||
if (factory) {
|
if (factory) {
|
||||||
CefRefPtr<CefSchemeHandler> handler = factory->Create();
|
// Call the handler factory to create the handler for the request.
|
||||||
|
CefRefPtr<CefRequest> requestPtr(new CefRequestImpl());
|
||||||
|
static_cast<CefRequestImpl*>(requestPtr.get())->Set(request);
|
||||||
|
CefRefPtr<CefSchemeHandler> handler = factory->Create(scheme, requestPtr);
|
||||||
if (handler.get())
|
if (handler.get())
|
||||||
job = new CefUrlRequestJob(request, handler);
|
job = new CefUrlRequestJob(request, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (job) {
|
if (!job && IsBuiltinScheme(scheme)) {
|
||||||
DLOG(INFO) << "net::URLRequestFilter hit for " << request->url().spec();
|
// Give the built-in scheme handler a chance to handle the request.
|
||||||
hit_count_++;
|
job = GetBuiltinSchemeRequestJob(request, scheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (job)
|
||||||
|
DLOG(INFO) << "CefUrlRequestManager hit for " << request->url().spec();
|
||||||
|
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maps hostnames to factories. Hostnames take priority over URLs.
|
// Factory method called by the ProtocolFactory. |scheme| will already be in
|
||||||
|
// lower case.
|
||||||
|
static net::URLRequestJob* Factory(net::URLRequest* request,
|
||||||
|
const std::string& scheme)
|
||||||
|
{
|
||||||
|
REQUIRE_IOT();
|
||||||
|
return GetInstance()->GetRequestJob(request, scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map (scheme, domain) to factories. This map will only be accessed on the IO
|
||||||
|
// thread.
|
||||||
|
typedef std::map<std::pair<std::string, std::string>,
|
||||||
|
CefRefPtr<CefSchemeHandlerFactory> > HandlerMap;
|
||||||
HandlerMap handler_map_;
|
HandlerMap handler_map_;
|
||||||
|
|
||||||
int hit_count_;
|
// Set of registered schemes. This set may be accessed from multiple threads.
|
||||||
|
typedef std::set<std::string> SchemeSet;
|
||||||
|
SchemeSet scheme_set_;
|
||||||
|
base::Lock scheme_set_lock_;
|
||||||
|
|
||||||
private:
|
DISALLOW_EVIL_CONSTRUCTORS(CefUrlRequestManager);
|
||||||
// Singleton instance.
|
|
||||||
static CefUrlRequestFilter* shared_instance_;
|
|
||||||
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(CefUrlRequestFilter);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CefUrlRequestFilter* CefUrlRequestFilter::shared_instance_ = NULL;
|
base::LazyInstance<CefUrlRequestManager> g_manager(base::LINKER_INITIALIZED);
|
||||||
|
|
||||||
|
CefUrlRequestManager* CefUrlRequestManager::GetInstance()
|
||||||
|
{
|
||||||
|
return g_manager.Pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous
|
||||||
|
|
||||||
|
|
||||||
class SchemeRequestJobWrapper : public CefBase {
|
bool CefRegisterCustomScheme(const CefString& scheme_name,
|
||||||
public:
|
bool is_standard,
|
||||||
SchemeRequestJobWrapper(const std::string& scheme_name,
|
bool is_local,
|
||||||
const std::string& host_name,
|
bool is_display_isolated)
|
||||||
bool is_standard,
|
|
||||||
CefSchemeHandlerFactory* factory)
|
|
||||||
: scheme_name_(scheme_name), host_name_(host_name),
|
|
||||||
is_standard_(is_standard), factory_(factory)
|
|
||||||
{
|
|
||||||
// The reference will be released when the application exits.
|
|
||||||
TrackAdd(new TrackBase(factory));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterScheme()
|
|
||||||
{
|
|
||||||
if(is_standard_) {
|
|
||||||
// Register the scheme as a standard scheme if it isn't already.
|
|
||||||
url_parse::Component scheme(0, scheme_name_.length());
|
|
||||||
if (!url_util::IsStandard(scheme_name_.c_str(), scheme))
|
|
||||||
url_util::AddStandardScheme(scheme_name_.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to store the pointer of this handler because
|
|
||||||
// we can't pass it as a parameter to the factory method
|
|
||||||
CefUrlRequestFilter::GetInstance()->AddHostnameHandler(
|
|
||||||
scheme_name_, host_name_, factory_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ImplementsThreadSafeReferenceCounting() { return true; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string scheme_name_;
|
|
||||||
std::string host_name_;
|
|
||||||
bool is_standard_;
|
|
||||||
CefSchemeHandlerFactory* factory_;
|
|
||||||
|
|
||||||
IMPLEMENT_REFCOUNTING(SchemeRequestJobWrapper);
|
|
||||||
};
|
|
||||||
|
|
||||||
bool CefRegisterScheme(const CefString& scheme_name,
|
|
||||||
const CefString& host_name,
|
|
||||||
bool is_standard,
|
|
||||||
CefRefPtr<CefSchemeHandlerFactory> factory)
|
|
||||||
{
|
{
|
||||||
// Verify that the context is in a valid state.
|
// Verify that the context is in a valid state.
|
||||||
if (!CONTEXT_STATE_VALID()) {
|
if (!CONTEXT_STATE_VALID()) {
|
||||||
@ -422,19 +515,60 @@ bool CefRegisterScheme(const CefString& scheme_name,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a smart pointer for the wrapper object because
|
if (CefThread::CurrentlyOn(CefThread::UI)) {
|
||||||
// RunnableMethodTraits::RetainCallee() (originating from NewRunnableMethod)
|
// Must be executed on the UI thread because it calls WebKit APIs.
|
||||||
// will call AddRef() and Release() on the object in debug mode, resulting in
|
return CefUrlRequestManager::GetInstance()->RegisterScheme(scheme_name,
|
||||||
// the object being deleted if it doesn't already have a reference.
|
is_standard, is_local, is_display_isolated);
|
||||||
std::string hostNameStr;
|
} else {
|
||||||
if (is_standard)
|
// Verify that the scheme has not already been registered.
|
||||||
hostNameStr = host_name;
|
if (CefUrlRequestManager::GetInstance()->HasRegisteredScheme(scheme_name)) {
|
||||||
CefRefPtr<SchemeRequestJobWrapper> wrapper(
|
NOTREACHED() << "Scheme already registered: " << scheme_name;
|
||||||
new SchemeRequestJobWrapper(scheme_name, hostNameStr, is_standard,
|
return false;
|
||||||
factory));
|
}
|
||||||
|
|
||||||
|
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
||||||
|
NewRunnableFunction(&CefRegisterCustomScheme, scheme_name, is_standard,
|
||||||
|
is_local, is_display_isolated));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod(wrapper.get(),
|
bool CefRegisterSchemeHandlerFactory(const CefString& scheme_name,
|
||||||
&SchemeRequestJobWrapper::RegisterScheme));
|
const CefString& domain_name,
|
||||||
|
CefRefPtr<CefSchemeHandlerFactory> factory)
|
||||||
|
{
|
||||||
|
// Verify that the context is in a valid state.
|
||||||
|
if (!CONTEXT_STATE_VALID()) {
|
||||||
|
NOTREACHED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CefThread::CurrentlyOn(CefThread::IO)) {
|
||||||
|
return CefUrlRequestManager::GetInstance()->AddFactory(scheme_name,
|
||||||
|
domain_name,
|
||||||
|
factory);
|
||||||
|
} else {
|
||||||
|
CefThread::PostTask(CefThread::IO, FROM_HERE,
|
||||||
|
NewRunnableFunction(&CefRegisterSchemeHandlerFactory, scheme_name,
|
||||||
|
domain_name, factory));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefClearSchemeHandlerFactories()
|
||||||
|
{
|
||||||
|
// Verify that the context is in a valid state.
|
||||||
|
if (!CONTEXT_STATE_VALID()) {
|
||||||
|
NOTREACHED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CefThread::CurrentlyOn(CefThread::IO)) {
|
||||||
|
CefUrlRequestManager::GetInstance()->ClearFactories();
|
||||||
|
} else {
|
||||||
|
CefThread::PostTask(CefThread::IO, FROM_HERE,
|
||||||
|
NewRunnableFunction(&CefClearSchemeHandlerFactories));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -12,17 +12,22 @@
|
|||||||
|
|
||||||
#include "libcef_dll/cpptoc/scheme_handler_cpptoc.h"
|
#include "libcef_dll/cpptoc/scheme_handler_cpptoc.h"
|
||||||
#include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h"
|
#include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h"
|
||||||
|
#include "libcef_dll/ctocpp/request_ctocpp.h"
|
||||||
|
|
||||||
|
|
||||||
// MEMBER FUNCTIONS - Body may be edited by hand.
|
// MEMBER FUNCTIONS - Body may be edited by hand.
|
||||||
|
|
||||||
struct _cef_scheme_handler_t* CEF_CALLBACK scheme_handler_factory_create(
|
struct _cef_scheme_handler_t* CEF_CALLBACK scheme_handler_factory_create(
|
||||||
struct _cef_scheme_handler_factory_t* self)
|
struct _cef_scheme_handler_factory_t* self, const cef_string_t* scheme_name,
|
||||||
|
cef_request_t* request)
|
||||||
{
|
{
|
||||||
CefRefPtr<CefSchemeHandler> rv =
|
CefRefPtr<CefSchemeHandler> rv =
|
||||||
CefSchemeHandlerFactoryCppToC::Get(self)->Create();
|
CefSchemeHandlerFactoryCppToC::Get(self)->Create(CefString(scheme_name),
|
||||||
|
CefRequestCToCpp::Wrap(request));
|
||||||
|
if (rv.get())
|
||||||
|
return CefSchemeHandlerCppToC::Wrap(rv);
|
||||||
|
|
||||||
return CefSchemeHandlerCppToC::Wrap(rv);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,20 +10,25 @@
|
|||||||
// tools directory for more information.
|
// tools directory for more information.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "libcef_dll/cpptoc/request_cpptoc.h"
|
||||||
#include "libcef_dll/ctocpp/scheme_handler_ctocpp.h"
|
#include "libcef_dll/ctocpp/scheme_handler_ctocpp.h"
|
||||||
#include "libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h"
|
#include "libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h"
|
||||||
|
|
||||||
|
|
||||||
// VIRTUAL METHODS - Body may be edited by hand.
|
// VIRTUAL METHODS - Body may be edited by hand.
|
||||||
|
|
||||||
CefRefPtr<CefSchemeHandler> CefSchemeHandlerFactoryCToCpp::Create()
|
CefRefPtr<CefSchemeHandler> CefSchemeHandlerFactoryCToCpp::Create(
|
||||||
|
const CefString& scheme_name, CefRefPtr<CefRequest> request)
|
||||||
{
|
{
|
||||||
if(CEF_MEMBER_MISSING(struct_, create))
|
if(CEF_MEMBER_MISSING(struct_, create))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
_cef_scheme_handler_t* rv = struct_->create(struct_);
|
cef_scheme_handler_t* rv = struct_->create(struct_, scheme_name.GetStruct(),
|
||||||
|
CefRequestCppToC::Wrap(request));
|
||||||
|
if (rv)
|
||||||
|
return CefSchemeHandlerCToCpp::Wrap(rv);
|
||||||
|
|
||||||
return CefSchemeHandlerCToCpp::Wrap(rv);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +33,8 @@ public:
|
|||||||
virtual ~CefSchemeHandlerFactoryCToCpp() {}
|
virtual ~CefSchemeHandlerFactoryCToCpp() {}
|
||||||
|
|
||||||
// CefSchemeHandlerFactory methods
|
// CefSchemeHandlerFactory methods
|
||||||
virtual CefRefPtr<CefSchemeHandler> Create() OVERRIDE;
|
virtual CefRefPtr<CefSchemeHandler> Create(const CefString& scheme_name,
|
||||||
|
CefRefPtr<CefRequest> request) OVERRIDE;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BUILDING_CEF_SHARED
|
#endif // BUILDING_CEF_SHARED
|
||||||
|
@ -118,17 +118,71 @@ CEF_EXPORT int cef_register_plugin(const cef_plugin_info_t* plugin_info)
|
|||||||
return CefRegisterPlugin(*plugin_info);
|
return CefRegisterPlugin(*plugin_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
CEF_EXPORT int cef_register_scheme(const cef_string_t* scheme_name,
|
CEF_EXPORT int cef_register_custom_scheme(const cef_string_t* scheme_name,
|
||||||
const cef_string_t* host_name, int is_standard,
|
int is_standard, int is_local, int is_display_isolated)
|
||||||
|
{
|
||||||
|
DCHECK(scheme_name);
|
||||||
|
if (!scheme_name)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return CefRegisterCustomScheme(CefString(scheme_name), is_standard?true:false,
|
||||||
|
is_local?true:false, is_display_isolated?true:false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CEF_EXPORT int cef_register_scheme_handler_factory(
|
||||||
|
const cef_string_t* scheme_name, const cef_string_t* domain_name,
|
||||||
struct _cef_scheme_handler_factory_t* factory)
|
struct _cef_scheme_handler_factory_t* factory)
|
||||||
{
|
{
|
||||||
DCHECK(scheme_name);
|
DCHECK(scheme_name);
|
||||||
DCHECK(factory);
|
if (!scheme_name)
|
||||||
if(!scheme_name || !factory)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return CefRegisterScheme(CefString(scheme_name), CefString(host_name),
|
CefRefPtr<CefSchemeHandlerFactory> factoryPtr;
|
||||||
(is_standard?true:false), CefSchemeHandlerFactoryCToCpp::Wrap(factory));
|
if (factory)
|
||||||
|
factoryPtr = CefSchemeHandlerFactoryCToCpp::Wrap(factory);
|
||||||
|
|
||||||
|
return CefRegisterSchemeHandlerFactory(CefString(scheme_name),
|
||||||
|
CefString(domain_name), factoryPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
CEF_EXPORT int cef_clear_scheme_handler_factories()
|
||||||
|
{
|
||||||
|
return CefClearSchemeHandlerFactories();
|
||||||
|
}
|
||||||
|
|
||||||
|
CEF_EXPORT int cef_add_cross_origin_whitelist_entry(
|
||||||
|
const cef_string_t* source_origin, const cef_string_t* target_protocol,
|
||||||
|
const cef_string_t* target_domain, int allow_target_subdomains)
|
||||||
|
{
|
||||||
|
DCHECK(source_origin);
|
||||||
|
DCHECK(target_protocol);
|
||||||
|
DCHECK(target_domain);
|
||||||
|
if (!source_origin || !target_protocol || !target_domain)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return CefAddCrossOriginWhitelistEntry(CefString(source_origin),
|
||||||
|
CefString(target_protocol), CefString(target_domain),
|
||||||
|
allow_target_subdomains?true:false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CEF_EXPORT int cef_remove_cross_origin_whitelist_entry(
|
||||||
|
const cef_string_t* source_origin, const cef_string_t* target_protocol,
|
||||||
|
const cef_string_t* target_domain, int allow_target_subdomains)
|
||||||
|
{
|
||||||
|
DCHECK(source_origin);
|
||||||
|
DCHECK(target_protocol);
|
||||||
|
DCHECK(target_domain);
|
||||||
|
if (!source_origin || !target_protocol || !target_domain)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return CefRemoveCrossOriginWhitelistEntry(CefString(source_origin),
|
||||||
|
CefString(target_protocol), CefString(target_domain),
|
||||||
|
allow_target_subdomains?true:false);
|
||||||
|
}
|
||||||
|
|
||||||
|
CEF_EXPORT int cef_clear_cross_origin_whitelist()
|
||||||
|
{
|
||||||
|
return CefClearCrossOriginWhitelist();
|
||||||
}
|
}
|
||||||
|
|
||||||
CEF_EXPORT int cef_currently_on(cef_thread_id_t threadId)
|
CEF_EXPORT int cef_currently_on(cef_thread_id_t threadId)
|
||||||
|
@ -99,13 +99,55 @@ bool CefRegisterPlugin(const CefPluginInfo& plugin_info)
|
|||||||
return cef_register_plugin(&plugin_info)?true:false;
|
return cef_register_plugin(&plugin_info)?true:false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CefRegisterScheme(const CefString& scheme_name,
|
bool CefRegisterCustomScheme(const CefString& scheme_name,
|
||||||
const CefString& host_name,
|
bool is_standard,
|
||||||
bool is_standard,
|
bool is_local,
|
||||||
CefRefPtr<CefSchemeHandlerFactory> factory)
|
bool is_display_isolated)
|
||||||
{
|
{
|
||||||
return cef_register_scheme(scheme_name.GetStruct(), host_name.GetStruct(),
|
return cef_register_custom_scheme(scheme_name.GetStruct(), is_standard,
|
||||||
is_standard, CefSchemeHandlerFactoryCppToC::Wrap(factory))?true:false;
|
is_local, is_display_isolated)?true:false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefRegisterSchemeHandlerFactory(const CefString& scheme_name,
|
||||||
|
const CefString& domain_name,
|
||||||
|
CefRefPtr<CefSchemeHandlerFactory> factory)
|
||||||
|
{
|
||||||
|
cef_scheme_handler_factory_t* factory_struct = NULL;
|
||||||
|
if (factory.get())
|
||||||
|
factory_struct = CefSchemeHandlerFactoryCppToC::Wrap(factory);
|
||||||
|
|
||||||
|
return cef_register_scheme_handler_factory(scheme_name.GetStruct(),
|
||||||
|
domain_name.GetStruct(), factory_struct)?true:false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefClearSchemeHandlerFactories()
|
||||||
|
{
|
||||||
|
return cef_clear_scheme_handler_factories()?true:false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefAddCrossOriginWhitelistEntry(const CefString& source_origin,
|
||||||
|
const CefString& target_protocol,
|
||||||
|
const CefString& target_domain,
|
||||||
|
bool allow_target_subdomains)
|
||||||
|
{
|
||||||
|
return cef_add_cross_origin_whitelist_entry(source_origin.GetStruct(),
|
||||||
|
target_protocol.GetStruct(), target_domain.GetStruct(),
|
||||||
|
allow_target_subdomains)?true:false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefRemoveCrossOriginWhitelistEntry(const CefString& source_origin,
|
||||||
|
const CefString& target_protocol,
|
||||||
|
const CefString& target_domain,
|
||||||
|
bool allow_target_subdomains)
|
||||||
|
{
|
||||||
|
return cef_remove_cross_origin_whitelist_entry(source_origin.GetStruct(),
|
||||||
|
target_protocol.GetStruct(), target_domain.GetStruct(),
|
||||||
|
allow_target_subdomains)?true:false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CefClearCrossOriginWhitelist()
|
||||||
|
{
|
||||||
|
return cef_clear_cross_origin_whitelist()?true:false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CefCurrentlyOn(CefThreadId threadId)
|
bool CefCurrentlyOn(CefThreadId threadId)
|
||||||
|
@ -141,7 +141,8 @@ class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Return a new scheme handler instance to handle the request.
|
// Return a new scheme handler instance to handle the request.
|
||||||
virtual CefRefPtr<CefSchemeHandler> Create()
|
virtual CefRefPtr<CefSchemeHandler> Create(const CefString& scheme_name,
|
||||||
|
CefRefPtr<CefRequest> request)
|
||||||
{
|
{
|
||||||
REQUIRE_IO_THREAD();
|
REQUIRE_IO_THREAD();
|
||||||
return new ClientSchemeHandler();
|
return new ClientSchemeHandler();
|
||||||
@ -152,7 +153,9 @@ public:
|
|||||||
|
|
||||||
void InitSchemeTest()
|
void InitSchemeTest()
|
||||||
{
|
{
|
||||||
CefRegisterScheme("client", "tests", true, new ClientSchemeHandlerFactory());
|
CefRegisterCustomScheme("client", true, false, false);
|
||||||
|
CefRegisterSchemeHandlerFactory("client", "tests",
|
||||||
|
new ClientSchemeHandlerFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunSchemeTest(CefRefPtr<CefBrowser> browser)
|
void RunSchemeTest(CefRefPtr<CefBrowser> browser)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// reserved. Use of this source code is governed by a BSD-style license that
|
// reserved. Use of this source code is governed by a BSD-style license that
|
||||||
// can be found in the LICENSE file.
|
// can be found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "include/cef_runnable.h"
|
||||||
#include "test_handler.h"
|
#include "test_handler.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -10,6 +11,8 @@ class TestResults
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestResults()
|
TestResults()
|
||||||
|
: status_code(0),
|
||||||
|
sub_status_code(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,22 +21,45 @@ public:
|
|||||||
url.clear();
|
url.clear();
|
||||||
html.clear();
|
html.clear();
|
||||||
status_code = 0;
|
status_code = 0;
|
||||||
|
redirect_url.clear();
|
||||||
|
sub_url.clear();
|
||||||
|
sub_html.clear();
|
||||||
|
sub_status_code = 0;
|
||||||
|
sub_allow_origin.clear();
|
||||||
|
exit_url.clear();
|
||||||
got_request.reset();
|
got_request.reset();
|
||||||
got_read.reset();
|
got_read.reset();
|
||||||
got_output.reset();
|
got_output.reset();
|
||||||
got_redirect.reset();
|
got_redirect.reset();
|
||||||
|
got_error.reset();
|
||||||
|
got_sub_request.reset();
|
||||||
|
got_sub_read.reset();
|
||||||
|
got_sub_success.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string url;
|
std::string url;
|
||||||
std::string html;
|
std::string html;
|
||||||
int status_code;
|
int status_code;
|
||||||
|
|
||||||
|
// Used for testing redirects
|
||||||
std::string redirect_url;
|
std::string redirect_url;
|
||||||
|
|
||||||
|
// Used for testing XHR requests
|
||||||
|
std::string sub_url;
|
||||||
|
std::string sub_html;
|
||||||
|
int sub_status_code;
|
||||||
|
std::string sub_allow_origin;
|
||||||
|
std::string exit_url;
|
||||||
|
|
||||||
TrackCallback
|
TrackCallback
|
||||||
got_request,
|
got_request,
|
||||||
got_read,
|
got_read,
|
||||||
got_output,
|
got_output,
|
||||||
got_redirect;
|
got_redirect,
|
||||||
|
got_error,
|
||||||
|
got_sub_request,
|
||||||
|
got_sub_read,
|
||||||
|
got_sub_success;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TestSchemeHandler : public TestHandler
|
class TestSchemeHandler : public TestHandler
|
||||||
@ -55,9 +81,18 @@ public:
|
|||||||
NavType navType,
|
NavType navType,
|
||||||
bool isRedirect) OVERRIDE
|
bool isRedirect) OVERRIDE
|
||||||
{
|
{
|
||||||
|
std::string newUrl = request->GetURL();
|
||||||
|
if (!test_results_->exit_url.empty() &&
|
||||||
|
newUrl.find(test_results_->exit_url) != std::string::npos) {
|
||||||
|
// XHR tests use an exit URL to destroy the test.
|
||||||
|
if (newUrl.find("SUCCESS") != std::string::npos)
|
||||||
|
test_results_->got_sub_success.yes();
|
||||||
|
DestroyTest();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (isRedirect) {
|
if (isRedirect) {
|
||||||
test_results_->got_redirect.yes();
|
test_results_->got_redirect.yes();
|
||||||
std::string newUrl = request->GetURL();
|
|
||||||
EXPECT_EQ(newUrl, test_results_->redirect_url);
|
EXPECT_EQ(newUrl, test_results_->redirect_url);
|
||||||
|
|
||||||
// No read should have occurred for the redirect.
|
// No read should have occurred for the redirect.
|
||||||
@ -76,15 +111,34 @@ public:
|
|||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
int httpStatusCode) OVERRIDE
|
int httpStatusCode) OVERRIDE
|
||||||
{
|
{
|
||||||
// Test that the output is correct.
|
std::string url = frame->GetURL();
|
||||||
std::string output = frame->GetSource();
|
if (url == test_results_->url || test_results_->status_code != 200) {
|
||||||
if (output == test_results_->html)
|
if (test_results_->sub_url.empty()) {
|
||||||
test_results_->got_output.yes();
|
// Test that the output is correct.
|
||||||
|
std::string output = frame->GetSource();
|
||||||
|
if (output == test_results_->html)
|
||||||
|
test_results_->got_output.yes();
|
||||||
|
} else {
|
||||||
|
test_results_->got_output.yes();
|
||||||
|
}
|
||||||
|
|
||||||
// Test that the status code is correct.
|
// Test that the status code is correct.
|
||||||
EXPECT_EQ(httpStatusCode, test_results_->status_code);
|
EXPECT_EQ(httpStatusCode, test_results_->status_code);
|
||||||
|
|
||||||
|
if (test_results_->sub_url.empty())
|
||||||
|
DestroyTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool OnLoadError(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
ErrorCode errorCode,
|
||||||
|
const CefString& failedUrl,
|
||||||
|
CefString& errorText) OVERRIDE
|
||||||
|
{
|
||||||
|
test_results_->got_error.yes();
|
||||||
DestroyTest();
|
DestroyTest();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -95,7 +149,7 @@ class ClientSchemeHandler : public CefSchemeHandler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClientSchemeHandler(TestResults* tr)
|
ClientSchemeHandler(TestResults* tr)
|
||||||
: test_results_(tr), offset_(0) {}
|
: test_results_(tr), offset_(0), is_sub_(false) {}
|
||||||
|
|
||||||
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
|
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
|
||||||
CefString& redirectUrl,
|
CefString& redirectUrl,
|
||||||
@ -104,20 +158,43 @@ public:
|
|||||||
{
|
{
|
||||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||||
|
|
||||||
test_results_->got_request.yes();
|
|
||||||
|
|
||||||
std::string url = request->GetURL();
|
std::string url = request->GetURL();
|
||||||
EXPECT_EQ(url, test_results_->url);
|
is_sub_ = (!test_results_->sub_url.empty() &&
|
||||||
|
test_results_->sub_url == url);
|
||||||
|
|
||||||
response->SetStatus(test_results_->status_code);
|
if (is_sub_) {
|
||||||
|
test_results_->got_sub_request.yes();
|
||||||
|
response->SetStatus(test_results_->sub_status_code);
|
||||||
|
|
||||||
if (!test_results_->redirect_url.empty()) {
|
if (!test_results_->sub_allow_origin.empty()) {
|
||||||
redirectUrl = test_results_->redirect_url;
|
// Set the Access-Control-Allow-Origin header to allow cross-domain
|
||||||
return true;
|
// scripting.
|
||||||
} else if (!test_results_->html.empty()) {
|
CefResponse::HeaderMap headers;
|
||||||
response->SetMimeType("text/html");
|
headers.insert(std::make_pair("Access-Control-Allow-Origin",
|
||||||
*response_length = test_results_->html.size();
|
test_results_->sub_allow_origin));
|
||||||
return true;
|
response->SetHeaderMap(headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!test_results_->sub_html.empty()) {
|
||||||
|
response->SetMimeType("text/html");
|
||||||
|
*response_length = test_results_->sub_html.size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EXPECT_EQ(url, test_results_->url);
|
||||||
|
|
||||||
|
test_results_->got_request.yes();
|
||||||
|
|
||||||
|
response->SetStatus(test_results_->status_code);
|
||||||
|
|
||||||
|
if (!test_results_->redirect_url.empty()) {
|
||||||
|
redirectUrl = test_results_->redirect_url;
|
||||||
|
return true;
|
||||||
|
} else if (!test_results_->html.empty()) {
|
||||||
|
response->SetMimeType("text/html");
|
||||||
|
*response_length = test_results_->html.size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -132,18 +209,26 @@ public:
|
|||||||
{
|
{
|
||||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||||
|
|
||||||
test_results_->got_read.yes();
|
std::string* data;
|
||||||
|
|
||||||
|
if (is_sub_) {
|
||||||
|
test_results_->got_sub_read.yes();
|
||||||
|
data = &test_results_->sub_html;
|
||||||
|
} else {
|
||||||
|
test_results_->got_read.yes();
|
||||||
|
data = &test_results_->html;
|
||||||
|
}
|
||||||
|
|
||||||
bool has_data = false;
|
bool has_data = false;
|
||||||
*bytes_read = 0;
|
*bytes_read = 0;
|
||||||
|
|
||||||
AutoLock lock_scope(this);
|
AutoLock lock_scope(this);
|
||||||
|
|
||||||
size_t size = test_results_->html.size();
|
size_t size = data->size();
|
||||||
if(offset_ < size) {
|
if(offset_ < size) {
|
||||||
int transfer_size =
|
int transfer_size =
|
||||||
std::min(bytes_to_read, static_cast<int>(size - offset_));
|
std::min(bytes_to_read, static_cast<int>(size - offset_));
|
||||||
memcpy(data_out, test_results_->html.c_str() + offset_, transfer_size);
|
memcpy(data_out, data->c_str() + offset_, transfer_size);
|
||||||
offset_ += transfer_size;
|
offset_ += transfer_size;
|
||||||
|
|
||||||
*bytes_read = transfer_size;
|
*bytes_read = transfer_size;
|
||||||
@ -156,6 +241,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
TestResults* test_results_;
|
TestResults* test_results_;
|
||||||
size_t offset_;
|
size_t offset_;
|
||||||
|
bool is_sub_;
|
||||||
|
|
||||||
IMPLEMENT_REFCOUNTING(ClientSchemeHandler);
|
IMPLEMENT_REFCOUNTING(ClientSchemeHandler);
|
||||||
IMPLEMENT_LOCKING(ClientSchemeHandler);
|
IMPLEMENT_LOCKING(ClientSchemeHandler);
|
||||||
@ -167,7 +253,8 @@ public:
|
|||||||
ClientSchemeHandlerFactory(TestResults* tr)
|
ClientSchemeHandlerFactory(TestResults* tr)
|
||||||
: test_results_(tr){}
|
: test_results_(tr){}
|
||||||
|
|
||||||
virtual CefRefPtr<CefSchemeHandler> Create()
|
virtual CefRefPtr<CefSchemeHandler> Create(const CefString& scheme_name,
|
||||||
|
CefRefPtr<CefRequest> request)
|
||||||
{
|
{
|
||||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||||
return new ClientSchemeHandler(test_results_);
|
return new ClientSchemeHandler(test_results_);
|
||||||
@ -181,35 +268,145 @@ public:
|
|||||||
// Global test results object.
|
// Global test results object.
|
||||||
TestResults g_TestResults;
|
TestResults g_TestResults;
|
||||||
|
|
||||||
void CreateStandardTestScheme()
|
void NotifyEvent(base::WaitableEvent* event)
|
||||||
{
|
{
|
||||||
g_TestResults.reset();
|
event->Signal();
|
||||||
static bool registered = false;
|
|
||||||
if (!registered) {
|
|
||||||
CefRegisterScheme("stdscheme", "tests", true,
|
|
||||||
new ClientSchemeHandlerFactory(&g_TestResults));
|
|
||||||
registered = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateNonStandardTestScheme()
|
// Post a task to the specified thread and wait for the task to execute as
|
||||||
|
// indication that all previously pending tasks on that thread have completed.
|
||||||
|
void WaitForThread(CefThreadId thread_id)
|
||||||
|
{
|
||||||
|
base::WaitableEvent event(true, false);
|
||||||
|
CefPostTask(thread_id, NewCefRunnableFunction(&NotifyEvent, &event));
|
||||||
|
event.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WaitForIOThread() WaitForThread(TID_IO)
|
||||||
|
#define WaitForUIThread() WaitForThread(TID_UI)
|
||||||
|
|
||||||
|
// If |domain| is empty the scheme will be registered as non-standard.
|
||||||
|
void RegisterTestScheme(const std::string& scheme, const std::string& domain)
|
||||||
{
|
{
|
||||||
g_TestResults.reset();
|
g_TestResults.reset();
|
||||||
static bool registered = false;
|
static std::set<std::string> schemes;
|
||||||
if (!registered) {
|
|
||||||
CefRegisterScheme("nonstdscheme", CefString(), false,
|
if (schemes.empty()) {
|
||||||
new ClientSchemeHandlerFactory(&g_TestResults));
|
// Never register built-in schemes.
|
||||||
registered = true;
|
schemes.insert("http");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only register custom schemes one time.
|
||||||
|
if (schemes.find(scheme) == schemes.end()) {
|
||||||
|
EXPECT_TRUE(CefRegisterCustomScheme(scheme, domain.empty()?false:true,
|
||||||
|
false, false));
|
||||||
|
WaitForUIThread();
|
||||||
|
schemes.insert(scheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(CefRegisterSchemeHandlerFactory(scheme, domain,
|
||||||
|
new ClientSchemeHandlerFactory(&g_TestResults)));
|
||||||
|
WaitForIOThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearTestSchemes()
|
||||||
|
{
|
||||||
|
EXPECT_TRUE(CefClearSchemeHandlerFactories());
|
||||||
|
WaitForIOThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetUpXHR(const std::string& url, const std::string& sub_url,
|
||||||
|
const std::string& sub_allow_origin = std::string())
|
||||||
|
{
|
||||||
|
g_TestResults.sub_url = sub_url;
|
||||||
|
g_TestResults.sub_html = "SUCCESS";
|
||||||
|
g_TestResults.sub_status_code = 200;
|
||||||
|
g_TestResults.sub_allow_origin = sub_allow_origin;
|
||||||
|
|
||||||
|
g_TestResults.url = url;
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "<html><head>\
|
||||||
|
<script language=\"JavaScript\">\
|
||||||
|
function execXMLHttpRequest() {\
|
||||||
|
var result = 'FAILURE';\
|
||||||
|
try {\
|
||||||
|
xhr = new XMLHttpRequest();\
|
||||||
|
xhr.open(\"GET\", \"" << sub_url.c_str() << "\", false);\
|
||||||
|
xhr.send();\
|
||||||
|
result = xhr.responseText;\
|
||||||
|
} catch(e) {}\
|
||||||
|
document.location = \"http://tests/exit?result=\"+result;\
|
||||||
|
}\
|
||||||
|
</script>\
|
||||||
|
</head><body onload=\"execXMLHttpRequest();\">\
|
||||||
|
Running execXMLHttpRequest...\
|
||||||
|
</body></html>";
|
||||||
|
g_TestResults.html = ss.str();
|
||||||
|
g_TestResults.status_code = 200;
|
||||||
|
|
||||||
|
g_TestResults.exit_url = "http://tests/exit";
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetUpXSS(const std::string& url, const std::string& sub_url,
|
||||||
|
const std::string& domain = std::string())
|
||||||
|
{
|
||||||
|
// 1. Load |url| which contains an iframe.
|
||||||
|
// 2. The iframe loads |xss_url|.
|
||||||
|
// 3. |xss_url| tries to call a JS function in |url|.
|
||||||
|
// 4. |url| tries to call a JS function in |xss_url|.
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
std::string domain_line;
|
||||||
|
if (!domain.empty())
|
||||||
|
domain_line = "document.domain = '" + domain + "';";
|
||||||
|
|
||||||
|
g_TestResults.sub_url = sub_url;
|
||||||
|
ss << "<html><head>\
|
||||||
|
<script language=\"JavaScript\">" << domain_line << "\
|
||||||
|
function getResult() {\
|
||||||
|
return 'SUCCESS';\
|
||||||
|
}\
|
||||||
|
function execXSSRequest() {\
|
||||||
|
var result = 'FAILURE';\
|
||||||
|
try {\
|
||||||
|
result = parent.getResult();\
|
||||||
|
} catch(e) {}\
|
||||||
|
document.location = \"http://tests/exit?result=\"+result;\
|
||||||
|
}\
|
||||||
|
</script>\
|
||||||
|
</head><body onload=\"execXSSRequest();\">\
|
||||||
|
Running execXSSRequest...\
|
||||||
|
</body></html>";
|
||||||
|
g_TestResults.sub_html = ss.str();
|
||||||
|
g_TestResults.sub_status_code = 200;
|
||||||
|
|
||||||
|
g_TestResults.url = url;
|
||||||
|
ss.str("");
|
||||||
|
ss << "<html><head>\
|
||||||
|
<script language=\"JavaScript\">" << domain_line << "\
|
||||||
|
function getResult() {\
|
||||||
|
try {\
|
||||||
|
return document.getElementById('s').contentWindow.getResult();\
|
||||||
|
} catch(e) {}\
|
||||||
|
return 'FAILURE';\
|
||||||
|
}\
|
||||||
|
</script>\
|
||||||
|
</head><body>\
|
||||||
|
<iframe src=\"" << sub_url.c_str() << "\" id=\"s\">\
|
||||||
|
</body></html>";
|
||||||
|
g_TestResults.html = ss.str();
|
||||||
|
g_TestResults.status_code = 200;
|
||||||
|
|
||||||
|
g_TestResults.exit_url = "http://tests/exit";
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous
|
} // anonymous
|
||||||
|
|
||||||
// Test that a standard scheme can return normal results.
|
// Test that scheme registration/unregistration works as expected.
|
||||||
TEST(SchemeHandlerTest, StandardSchemeNormalResponse)
|
TEST(SchemeHandlerTest, Registration)
|
||||||
{
|
{
|
||||||
CreateStandardTestScheme();
|
RegisterTestScheme("customstd", "test");
|
||||||
g_TestResults.url = "stdscheme://tests/run.html";
|
g_TestResults.url = "customstd://test/run.html";
|
||||||
g_TestResults.html =
|
g_TestResults.html =
|
||||||
"<html><head></head><body><h1>Success!</h1></body></html>";
|
"<html><head></head><body><h1>Success!</h1></body></html>";
|
||||||
g_TestResults.status_code = 200;
|
g_TestResults.status_code = 200;
|
||||||
@ -220,90 +417,41 @@ TEST(SchemeHandlerTest, StandardSchemeNormalResponse)
|
|||||||
EXPECT_TRUE(g_TestResults.got_request);
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_read);
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
EXPECT_TRUE(g_TestResults.got_output);
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a standard scheme can return an error code.
|
// Unregister the handler.
|
||||||
TEST(SchemeHandlerTest, StandardSchemeErrorResponse)
|
EXPECT_TRUE(CefRegisterSchemeHandlerFactory("customstd", "test", NULL));
|
||||||
{
|
WaitForIOThread();
|
||||||
CreateStandardTestScheme();
|
|
||||||
g_TestResults.url = "stdscheme://tests/run.html";
|
g_TestResults.got_request.reset();
|
||||||
g_TestResults.html =
|
g_TestResults.got_read.reset();
|
||||||
"<html><head></head><body><h1>404</h1></body></html>";
|
g_TestResults.got_output.reset();
|
||||||
g_TestResults.status_code = 404;
|
handler->ExecuteTest();
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
EXPECT_TRUE(g_TestResults.got_error);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_request);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_read);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
// Re-register the handler.
|
||||||
|
EXPECT_TRUE(CefRegisterSchemeHandlerFactory("customstd", "test",
|
||||||
|
new ClientSchemeHandlerFactory(&g_TestResults)));
|
||||||
|
WaitForIOThread();
|
||||||
|
|
||||||
|
g_TestResults.got_error.reset();
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
|
|
||||||
EXPECT_TRUE(g_TestResults.got_request);
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_read);
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
EXPECT_TRUE(g_TestResults.got_output);
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that standard scheme handling fails when the scheme name is incorrect.
|
// Test that a custom standard scheme can return normal results.
|
||||||
TEST(SchemeHandlerTest, StandardSchemeNameNotHandled)
|
TEST(SchemeHandlerTest, CustomStandardNormalResponse)
|
||||||
{
|
{
|
||||||
CreateStandardTestScheme();
|
RegisterTestScheme("customstd", "test");
|
||||||
g_TestResults.url = "stdscheme2://tests/run.html";
|
g_TestResults.url = "customstd://test/run.html";
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
|
|
||||||
EXPECT_FALSE(g_TestResults.got_request);
|
|
||||||
EXPECT_FALSE(g_TestResults.got_read);
|
|
||||||
EXPECT_FALSE(g_TestResults.got_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that standard scheme handling fails when the domain name is incorrect.
|
|
||||||
TEST(SchemeHandlerTest, StandardSchemeDomainNotHandled)
|
|
||||||
{
|
|
||||||
CreateStandardTestScheme();
|
|
||||||
g_TestResults.url = "stdscheme://tests2/run.html";
|
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
|
|
||||||
EXPECT_FALSE(g_TestResults.got_request);
|
|
||||||
EXPECT_FALSE(g_TestResults.got_read);
|
|
||||||
EXPECT_FALSE(g_TestResults.got_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a standard scheme can return no response.
|
|
||||||
TEST(SchemeHandlerTest, StandardSchemeNoResponse)
|
|
||||||
{
|
|
||||||
CreateStandardTestScheme();
|
|
||||||
g_TestResults.url = "stdscheme://tests/run.html";
|
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
|
|
||||||
EXPECT_TRUE(g_TestResults.got_request);
|
|
||||||
EXPECT_FALSE(g_TestResults.got_read);
|
|
||||||
EXPECT_FALSE(g_TestResults.got_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a standard scheme can generate redirects.
|
|
||||||
TEST(SchemeHandlerTest, StandardSchemeRedirect)
|
|
||||||
{
|
|
||||||
CreateStandardTestScheme();
|
|
||||||
g_TestResults.url = "stdscheme://tests/run.html";
|
|
||||||
g_TestResults.redirect_url = "stdscheme://tests/redirect.html";
|
|
||||||
g_TestResults.html =
|
|
||||||
"<html><head></head><body><h1>Redirected</h1></body></html>";
|
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
|
||||||
handler->ExecuteTest();
|
|
||||||
|
|
||||||
EXPECT_TRUE(g_TestResults.got_request);
|
|
||||||
EXPECT_TRUE(g_TestResults.got_read);
|
|
||||||
EXPECT_TRUE(g_TestResults.got_output);
|
|
||||||
EXPECT_TRUE(g_TestResults.got_redirect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that a non-standard scheme can return normal results.
|
|
||||||
TEST(SchemeHandlerTest, NonStandardSchemeNormalResponse)
|
|
||||||
{
|
|
||||||
CreateNonStandardTestScheme();
|
|
||||||
g_TestResults.url = "nonstdscheme:some%20value";
|
|
||||||
g_TestResults.html =
|
g_TestResults.html =
|
||||||
"<html><head></head><body><h1>Success!</h1></body></html>";
|
"<html><head></head><body><h1>Success!</h1></body></html>";
|
||||||
g_TestResults.status_code = 200;
|
g_TestResults.status_code = 200;
|
||||||
@ -314,13 +462,34 @@ TEST(SchemeHandlerTest, NonStandardSchemeNormalResponse)
|
|||||||
EXPECT_TRUE(g_TestResults.got_request);
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_read);
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
EXPECT_TRUE(g_TestResults.got_output);
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that a non-standard scheme can return an error code.
|
// Test that a custom nonstandard scheme can return normal results.
|
||||||
TEST(SchemeHandlerTest, NonStandardSchemeErrorResponse)
|
TEST(SchemeHandlerTest, CustomNonStandardNormalResponse)
|
||||||
{
|
{
|
||||||
CreateNonStandardTestScheme();
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
g_TestResults.url = "nonstdscheme:some%20value";
|
g_TestResults.url = "customnonstd:some%20value";
|
||||||
|
g_TestResults.html =
|
||||||
|
"<html><head></head><body><h1>Success!</h1></body></html>";
|
||||||
|
g_TestResults.status_code = 200;
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom standard scheme can return an error code.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardErrorResponse)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test");
|
||||||
|
g_TestResults.url = "customstd://test/run.html";
|
||||||
g_TestResults.html =
|
g_TestResults.html =
|
||||||
"<html><head></head><body><h1>404</h1></body></html>";
|
"<html><head></head><body><h1>404</h1></body></html>";
|
||||||
g_TestResults.status_code = 404;
|
g_TestResults.status_code = 404;
|
||||||
@ -331,14 +500,35 @@ TEST(SchemeHandlerTest, NonStandardSchemeErrorResponse)
|
|||||||
EXPECT_TRUE(g_TestResults.got_request);
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_read);
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
EXPECT_TRUE(g_TestResults.got_output);
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that non-standard scheme handling fails when the scheme name is
|
// Test that a custom nonstandard scheme can return an error code.
|
||||||
|
TEST(SchemeHandlerTest, CustomNonStandardErrorResponse)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
|
g_TestResults.url = "customnonstd:some%20value";
|
||||||
|
g_TestResults.html =
|
||||||
|
"<html><head></head><body><h1>404</h1></body></html>";
|
||||||
|
g_TestResults.status_code = 404;
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that custom standard scheme handling fails when the scheme name is
|
||||||
// incorrect.
|
// incorrect.
|
||||||
TEST(SchemeHandlerTest, NonStandardSchemeNameNotHandled)
|
TEST(SchemeHandlerTest, CustomStandardNameNotHandled)
|
||||||
{
|
{
|
||||||
CreateNonStandardTestScheme();
|
RegisterTestScheme("customstd", "test");
|
||||||
g_TestResults.url = "nonstdscheme2:some%20value";
|
g_TestResults.url = "customstd2://test/run.html";
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
@ -346,13 +536,49 @@ TEST(SchemeHandlerTest, NonStandardSchemeNameNotHandled)
|
|||||||
EXPECT_FALSE(g_TestResults.got_request);
|
EXPECT_FALSE(g_TestResults.got_request);
|
||||||
EXPECT_FALSE(g_TestResults.got_read);
|
EXPECT_FALSE(g_TestResults.got_read);
|
||||||
EXPECT_FALSE(g_TestResults.got_output);
|
EXPECT_FALSE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that a non-standard scheme can return no response.
|
// Test that custom nonstandard scheme handling fails when the scheme name is
|
||||||
TEST(SchemeHandlerTest, NonStandardSchemeNoResponse)
|
// incorrect.
|
||||||
|
TEST(SchemeHandlerTest, CustomNonStandardNameNotHandled)
|
||||||
{
|
{
|
||||||
CreateNonStandardTestScheme();
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
g_TestResults.url = "nonstdscheme:some%20value";
|
g_TestResults.url = "customnonstd2:some%20value";
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_FALSE(g_TestResults.got_request);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_read);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that custom standard scheme handling fails when the domain name is
|
||||||
|
// incorrect.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardDomainNotHandled)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test");
|
||||||
|
g_TestResults.url = "customstd://noexist/run.html";
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_FALSE(g_TestResults.got_request);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_read);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom standard scheme can return no response.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardNoResponse)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test");
|
||||||
|
g_TestResults.url = "customstd://test/run.html";
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
@ -360,14 +586,32 @@ TEST(SchemeHandlerTest, NonStandardSchemeNoResponse)
|
|||||||
EXPECT_TRUE(g_TestResults.got_request);
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
EXPECT_FALSE(g_TestResults.got_read);
|
EXPECT_FALSE(g_TestResults.got_read);
|
||||||
EXPECT_FALSE(g_TestResults.got_output);
|
EXPECT_FALSE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that a non-standard scheme can generate redirects.
|
// Test that a custom nonstandard scheme can return no response.
|
||||||
TEST(SchemeHandlerTest, NonStandardSchemeRedirect)
|
TEST(SchemeHandlerTest, CustomNonStandardNoResponse)
|
||||||
{
|
{
|
||||||
CreateNonStandardTestScheme();
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
g_TestResults.url = "nonstdscheme:some%20value";
|
g_TestResults.url = "customnonstd:some%20value";
|
||||||
g_TestResults.redirect_url = "nonstdscheme:some%20other%20value";
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_read);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_output);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom standard scheme can generate redirects.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardRedirect)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test");
|
||||||
|
g_TestResults.url = "customstd://test/run.html";
|
||||||
|
g_TestResults.redirect_url = "customstd://test/redirect.html";
|
||||||
g_TestResults.html =
|
g_TestResults.html =
|
||||||
"<html><head></head><body><h1>Redirected</h1></body></html>";
|
"<html><head></head><body><h1>Redirected</h1></body></html>";
|
||||||
|
|
||||||
@ -378,4 +622,314 @@ TEST(SchemeHandlerTest, NonStandardSchemeRedirect)
|
|||||||
EXPECT_TRUE(g_TestResults.got_read);
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
EXPECT_TRUE(g_TestResults.got_output);
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
EXPECT_TRUE(g_TestResults.got_redirect);
|
EXPECT_TRUE(g_TestResults.got_redirect);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom nonstandard scheme can generate redirects.
|
||||||
|
TEST(SchemeHandlerTest, CustomNonStandardRedirect)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
|
g_TestResults.url = "customnonstd:some%20value";
|
||||||
|
g_TestResults.redirect_url = "customnonstd:some%20other%20value";
|
||||||
|
g_TestResults.html =
|
||||||
|
"<html><head></head><body><h1>Redirected</h1></body></html>";
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_redirect);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom standard scheme can generate same origin XHR requests.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardXHRSameOrigin)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test");
|
||||||
|
SetUpXHR("customstd://test/run.html",
|
||||||
|
"customstd://test/xhr.html");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom nonstandard scheme can generate same origin XHR requests.
|
||||||
|
TEST(SchemeHandlerTest, CustomNonStandardXHRSameOrigin)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
|
SetUpXHR("customnonstd:some%20value",
|
||||||
|
"customnonstd:xhr%20value");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
// Test that a custom standard scheme can generate same origin XSS requests.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardXSSSameOrigin)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test");
|
||||||
|
SetUpXSS("customstd://test/run.html",
|
||||||
|
"customstd://test/iframe.html");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom nonstandard scheme can generate same origin XSS requests.
|
||||||
|
TEST(SchemeHandlerTest, CustomNonStandardXSSSameOrigin)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
|
SetUpXSS("customnonstd:some%20value",
|
||||||
|
"customnonstd:xhr%20value");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom standard scheme cannot generate cross-domain XHR requests
|
||||||
|
// by default.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOrigin)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test1");
|
||||||
|
RegisterTestScheme("customstd", "test2");
|
||||||
|
SetUpXHR("customstd://test1/run.html",
|
||||||
|
"customstd://test2/xhr.html");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom standard scheme cannot generate cross-domain XSS requests
|
||||||
|
// by default.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardXSSDifferentOrigin)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test1");
|
||||||
|
RegisterTestScheme("customstd", "test2");
|
||||||
|
SetUpXSS("customstd://test1/run.html",
|
||||||
|
"customstd://test2/iframe.html");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that an HTTP scheme cannot generate cross-domain XHR requests by
|
||||||
|
// default.
|
||||||
|
TEST(SchemeHandlerTest, HttpXHRDifferentOrigin)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("http", "test1");
|
||||||
|
RegisterTestScheme("http", "test2");
|
||||||
|
SetUpXHR("http://test1/run.html",
|
||||||
|
"http://test2/xhr.html");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that an HTTP scheme cannot generate cross-domain XSS requests by
|
||||||
|
// default.
|
||||||
|
TEST(SchemeHandlerTest, HttpXSSDifferentOrigin)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("http", "test1");
|
||||||
|
RegisterTestScheme("http", "test2");
|
||||||
|
SetUpXHR("http://test1/run.html",
|
||||||
|
"http://test2/xhr.html");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom standard scheme cannot generate cross-domain XHR requests
|
||||||
|
// even when setting the Access-Control-Allow-Origin header.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithHeader)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test1");
|
||||||
|
RegisterTestScheme("customstd", "test2");
|
||||||
|
SetUpXHR("customstd://test1/run.html",
|
||||||
|
"customstd://test2/xhr.html",
|
||||||
|
"customstd://test1");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom standard scheme can generate cross-domain XHR requests
|
||||||
|
// when using the cross-origin whitelist.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelist)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "test1");
|
||||||
|
RegisterTestScheme("customstd", "test2");
|
||||||
|
SetUpXHR("customstd://test1/run.html",
|
||||||
|
"customstd://test2/xhr.html");
|
||||||
|
|
||||||
|
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
|
||||||
|
"test2", false));
|
||||||
|
WaitForUIThread();
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
EXPECT_TRUE(CefClearCrossOriginWhitelist());
|
||||||
|
WaitForUIThread();
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that an HTTP scheme can generate cross-domain XHR requests when setting
|
||||||
|
// the Access-Control-Allow-Origin header.
|
||||||
|
TEST(SchemeHandlerTest, HttpXHRDifferentOriginWithHeader)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("http", "test1");
|
||||||
|
RegisterTestScheme("http", "test2");
|
||||||
|
SetUpXHR("http://test1/run.html",
|
||||||
|
"http://test2/xhr.html",
|
||||||
|
"http://test1");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a custom standard scheme can generate cross-domain XSS requests
|
||||||
|
// when using document.domain.
|
||||||
|
TEST(SchemeHandlerTest, CustomStandardXSSDifferentOriginWithDomain)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("customstd", "a.test");
|
||||||
|
RegisterTestScheme("customstd", "b.test");
|
||||||
|
SetUpXSS("customstd://a.test/run.html",
|
||||||
|
"customstd://b.test/iframe.html",
|
||||||
|
"test");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that an HTTP scheme can generate cross-domain XSS requests when using
|
||||||
|
// document.domain.
|
||||||
|
TEST(SchemeHandlerTest, HttpXSSDifferentOriginWithDomain)
|
||||||
|
{
|
||||||
|
RegisterTestScheme("http", "a.test");
|
||||||
|
RegisterTestScheme("http", "b.test");
|
||||||
|
SetUpXSS("http://a.test/run.html",
|
||||||
|
"http://b.test/iframe.html",
|
||||||
|
"test");
|
||||||
|
|
||||||
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
|
||||||
|
EXPECT_TRUE(g_TestResults.got_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
|
ClearTestSchemes();
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,9 @@ public:
|
|||||||
|
|
||||||
// Wait for the test to complete
|
// Wait for the test to complete
|
||||||
completion_event_.Wait();
|
completion_event_.Wait();
|
||||||
|
|
||||||
|
// Reset the event so the same test can be executed again.
|
||||||
|
completion_event_.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user