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:
Marshall Greenblatt 2011-05-27 16:20:32 +00:00
parent 42b5597214
commit 63aa102a6a
13 changed files with 1362 additions and 319 deletions

View File

@ -696,6 +696,7 @@
'libcef/external_protocol_handler.h',
'libcef/http_header_utils.cc',
'libcef/http_header_utils.h',
'libcef/origin_whitelist_impl.cc',
'libcef/request_impl.cc',
'libcef/request_impl.h',
'libcef/response_impl.cc',

View File

@ -172,8 +172,10 @@ bool CefRegisterExtension(const CefString& extension_name,
const CefString& javascript_code,
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
// defined in the Common Internet Scheme Syntax RFC 1738 Section 3.1 available
// 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
// scheme URLs cannot be used as a target for form submission.
//
// Register a custom scheme handler factory for the specified |scheme_name| and
// optional |host_name|. Specifying an empty |host_name| value for standard
// schemes will match all host names. The |host_name| value will be ignored for
// 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
// called on any thread.
// If |is_local| is true the scheme will be treated as local (i.e., with the
// same security rules as those applied to "file" URLs). This means that normal
// pages cannot link to or access URLs of this scheme.
//
// If |is_display_isolated| is true the scheme will be treated as display-
// 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()--*/
bool CefRegisterScheme(const CefString& scheme_name,
const CefString& host_name,
bool is_standard,
CefRefPtr<CefSchemeHandlerFactory> factory);
bool CefRegisterCustomScheme(const CefString& scheme_name,
bool is_standard,
bool is_local,
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;
@ -1744,7 +1816,8 @@ class CefSchemeHandlerFactory : public virtual CefBase
public:
// Return a new scheme handler instance to handle the request.
/*--cef()--*/
virtual CefRefPtr<CefSchemeHandler> Create() =0;
virtual CefRefPtr<CefSchemeHandler> Create(const CefString& scheme_name,
CefRefPtr<CefRequest> request) =0;
};

View File

@ -133,8 +133,10 @@ CEF_EXPORT void cef_run_message_loop();
CEF_EXPORT int cef_register_extension(const cef_string_t* extension_name,
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
// defined in the Common Internet Scheme Syntax RFC 1738 Section 3.1 available
// 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
// scheme URLs cannot be used as a target for form submission.
//
// Register a custom scheme handler factory for the specified |scheme_name| and
// optional |host_name|. Specifying an NULL |host_name| value for standard
// schemes will match all host names. The |host_name| value will be ignored for
// 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
// called on any thread.
CEF_EXPORT int cef_register_scheme(const cef_string_t* scheme_name,
const cef_string_t* host_name, int is_standard,
// If |is_local| is true (1) the scheme will be treated as local (i.e., with the
// same security rules as those applied to "file" URLs). This means that normal
// pages cannot link to or access URLs of this scheme.
//
// If |is_display_isolated| is true (1) the scheme will be treated as display-
// 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 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);
// 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
// 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
@ -1539,7 +1603,8 @@ typedef struct _cef_scheme_handler_factory_t
// Return a new scheme handler instance to handle the request.
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;

View 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;
}

View File

@ -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.
// 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 "request_impl.h"
#include "response_impl.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/synchronization/lock.h"
#include "googleurl/src/url_util.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
@ -13,43 +20,89 @@
#include "net/http/http_response_headers.h"
#include "net/http/http_util.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_ftp_job.h"
#include "net/url_request/url_request_http_job.h"
#include "net/url_request/url_request_job.h"
#include "include/cef.h"
#include "tracker.h"
#include "cef_context.h"
#include "request_impl.h"
#include "response_impl.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
#include <map>
using WebKit::WebSecurityPolicy;
using WebKit::WebString;
// Memory manager.
namespace {
base::LazyInstance<CefTrackManager> g_scheme_tracker(base::LINKER_INITIALIZED);
class TrackBase : public CefTrackObject
bool IsStandardScheme(const std::string& scheme)
{
public:
TrackBase(CefBase* base) { base_ = base; }
url_parse::Component scheme_comp(0, scheme.length());
return url_util::IsStandard(scheme.c_str(), scheme_comp);
}
protected:
CefRefPtr<CefBase> base_;
void RegisterStandardScheme(const std::string& scheme)
{
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.
class CefUrlRequestJob : public net::URLRequestJob {
public:
CefUrlRequestJob(net::URLRequest* request, CefRefPtr<CefSchemeHandler> handler)
CefUrlRequestJob(net::URLRequest* request,
CefRefPtr<CefSchemeHandler> handler)
: net::URLRequestJob(request),
handler_(handler),
response_length_(0),
@ -244,54 +297,64 @@ private:
};
// net::URLRequestFilter clone that manages the CefSchemeHandlerFactory pointers.
class CefUrlRequestFilter {
// Class that manages the CefSchemeHandlerFactory instances.
class CefUrlRequestManager {
public:
// scheme,hostname -> ProtocolFactory
typedef std::map<std::pair<std::string, std::string>,
CefSchemeHandlerFactory*> HandlerMap;
CefUrlRequestManager() {}
// Singleton instance for use.
static CefUrlRequestFilter* GetInstance()
{
if (!shared_instance_)
shared_instance_ = new CefUrlRequestFilter;
return shared_instance_;
}
// Retrieve the singleton instance.
static CefUrlRequestManager* GetInstance();
static net::URLRequestJob* Factory(net::URLRequest* request,
const std::string& scheme)
bool AddFactory(const std::string& scheme,
const std::string& domain,
CefRefPtr<CefSchemeHandlerFactory> factory)
{
// Returning null here just means that the built-in handler will be used.
return GetInstance()->FindRequestHandler(request, scheme);
}
if (!factory.get()) {
RemoveFactory(scheme, domain);
return true;
}
void AddHostnameHandler(const std::string& scheme,
const std::string& hostname,
CefSchemeHandlerFactory* factory)
{
handler_map_[make_pair(scheme, hostname)] = factory;
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();
handler_map_[make_pair(scheme_lower, domain_lower)] = factory;
// Register with the ProtocolFactory.
net::URLRequest::RegisterProtocolFactory(scheme,
&CefUrlRequestFilter::Factory);
net::URLRequest::RegisterProtocolFactory(scheme_lower,
&CefUrlRequestManager::Factory);
return true;
}
void RemoveHostnameHandler(const std::string& scheme,
const std::string& hostname)
void RemoveFactory(const std::string& scheme,
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 =
handler_map_.find(make_pair(scheme, hostname));
DCHECK(iter != handler_map_.end());
handler_map_.erase(iter);
handler_map_.find(make_pair(scheme_lower, domain_lower));
if (iter != handler_map_.end())
handler_map_.erase(iter);
}
// Clear all the existing URL handlers and unregister with the
// ProtocolFactory. Resets the hit count.
void ClearHandlers()
// Clear all the existing URL handlers and unregister the ProtocolFactory.
void ClearFactories()
{
REQUIRE_IOT();
// Unregister with the ProtocolFactory.
std::set<std::string> schemes;
for (HandlerMap::const_iterator i = handler_map_.begin();
@ -304,24 +367,73 @@ public:
}
handler_map_.clear();
hit_count_ = 0;
}
CefSchemeHandlerFactory* FindRequestHandlerFactory(net::URLRequest* request,
const std::string& scheme)
// Check if a scheme has already been registered.
bool HasRegisteredScheme(const std::string& scheme)
{
CefSchemeHandlerFactory* factory = NULL;
if (request->url().is_valid()) {
// Check for a map with a hostname first.
const std::string& hostname = request->url().host();
std::string scheme_lower = ToLower(scheme);
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())
factory = i->second;
}
if (!factory) {
// Check for a map with no specified hostname.
if (!factory.get()) {
// Check for a match with no specified domain.
HandlerMap::iterator i =
handler_map_.find(make_pair(scheme, std::string()));
if (i != handler_map_.end())
@ -331,90 +443,71 @@ public:
return factory;
}
// Returns the number of times a handler was used to service a request.
int hit_count() const { return hit_count_; }
protected:
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)
// Create the job that will handle the request. |scheme| will already be in
// lower case.
net::URLRequestJob* GetRequestJob(net::URLRequest* request,
const std::string& scheme)
{
net::URLRequestJob* job = NULL;
CefSchemeHandlerFactory* factory =
FindRequestHandlerFactory(request, scheme);
CefRefPtr<CefSchemeHandlerFactory> factory =
GetHandlerFactory(request, scheme);
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())
job = new CefUrlRequestJob(request, handler);
}
if (job) {
DLOG(INFO) << "net::URLRequestFilter hit for " << request->url().spec();
hit_count_++;
if (!job && IsBuiltinScheme(scheme)) {
// Give the built-in scheme handler a chance to handle the request.
job = GetBuiltinSchemeRequestJob(request, scheme);
}
if (job)
DLOG(INFO) << "CefUrlRequestManager hit for " << request->url().spec();
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_;
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:
// Singleton instance.
static CefUrlRequestFilter* shared_instance_;
DISALLOW_EVIL_CONSTRUCTORS(CefUrlRequestFilter);
DISALLOW_EVIL_CONSTRUCTORS(CefUrlRequestManager);
};
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 {
public:
SchemeRequestJobWrapper(const std::string& scheme_name,
const std::string& host_name,
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)
bool CefRegisterCustomScheme(const CefString& scheme_name,
bool is_standard,
bool is_local,
bool is_display_isolated)
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
@ -422,19 +515,60 @@ bool CefRegisterScheme(const CefString& scheme_name,
return false;
}
// Use a smart pointer for the wrapper object because
// RunnableMethodTraits::RetainCallee() (originating from NewRunnableMethod)
// will call AddRef() and Release() on the object in debug mode, resulting in
// the object being deleted if it doesn't already have a reference.
std::string hostNameStr;
if (is_standard)
hostNameStr = host_name;
CefRefPtr<SchemeRequestJobWrapper> wrapper(
new SchemeRequestJobWrapper(scheme_name, hostNameStr, is_standard,
factory));
if (CefThread::CurrentlyOn(CefThread::UI)) {
// Must be executed on the UI thread because it calls WebKit APIs.
return CefUrlRequestManager::GetInstance()->RegisterScheme(scheme_name,
is_standard, is_local, is_display_isolated);
} else {
// Verify that the scheme has not already been registered.
if (CefUrlRequestManager::GetInstance()->HasRegisteredScheme(scheme_name)) {
NOTREACHED() << "Scheme already registered: " << scheme_name;
return false;
}
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(),
&SchemeRequestJobWrapper::RegisterScheme));
bool CefRegisterSchemeHandlerFactory(const CefString& scheme_name,
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;
}

View File

@ -12,17 +12,22 @@
#include "libcef_dll/cpptoc/scheme_handler_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.
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 =
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;
}

View File

@ -10,20 +10,25 @@
// 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_factory_ctocpp.h"
// 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))
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;
}

View File

@ -33,7 +33,8 @@ public:
virtual ~CefSchemeHandlerFactoryCToCpp() {}
// CefSchemeHandlerFactory methods
virtual CefRefPtr<CefSchemeHandler> Create() OVERRIDE;
virtual CefRefPtr<CefSchemeHandler> Create(const CefString& scheme_name,
CefRefPtr<CefRequest> request) OVERRIDE;
};
#endif // BUILDING_CEF_SHARED

View File

@ -118,17 +118,71 @@ CEF_EXPORT int cef_register_plugin(const cef_plugin_info_t* plugin_info)
return CefRegisterPlugin(*plugin_info);
}
CEF_EXPORT int cef_register_scheme(const cef_string_t* scheme_name,
const cef_string_t* host_name, int is_standard,
CEF_EXPORT int cef_register_custom_scheme(const cef_string_t* scheme_name,
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)
{
DCHECK(scheme_name);
DCHECK(factory);
if(!scheme_name || !factory)
if (!scheme_name)
return 0;
return CefRegisterScheme(CefString(scheme_name), CefString(host_name),
(is_standard?true:false), CefSchemeHandlerFactoryCToCpp::Wrap(factory));
CefRefPtr<CefSchemeHandlerFactory> factoryPtr;
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)

View File

@ -99,13 +99,55 @@ bool CefRegisterPlugin(const CefPluginInfo& plugin_info)
return cef_register_plugin(&plugin_info)?true:false;
}
bool CefRegisterScheme(const CefString& scheme_name,
const CefString& host_name,
bool is_standard,
CefRefPtr<CefSchemeHandlerFactory> factory)
bool CefRegisterCustomScheme(const CefString& scheme_name,
bool is_standard,
bool is_local,
bool is_display_isolated)
{
return cef_register_scheme(scheme_name.GetStruct(), host_name.GetStruct(),
is_standard, CefSchemeHandlerFactoryCppToC::Wrap(factory))?true:false;
return cef_register_custom_scheme(scheme_name.GetStruct(), is_standard,
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)

View File

@ -141,7 +141,8 @@ class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory
{
public:
// 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();
return new ClientSchemeHandler();
@ -152,7 +153,9 @@ public:
void InitSchemeTest()
{
CefRegisterScheme("client", "tests", true, new ClientSchemeHandlerFactory());
CefRegisterCustomScheme("client", true, false, false);
CefRegisterSchemeHandlerFactory("client", "tests",
new ClientSchemeHandlerFactory());
}
void RunSchemeTest(CefRefPtr<CefBrowser> browser)

View File

@ -2,6 +2,7 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "include/cef_runnable.h"
#include "test_handler.h"
namespace {
@ -10,6 +11,8 @@ class TestResults
{
public:
TestResults()
: status_code(0),
sub_status_code(0)
{
}
@ -18,22 +21,45 @@ public:
url.clear();
html.clear();
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_read.reset();
got_output.reset();
got_redirect.reset();
got_error.reset();
got_sub_request.reset();
got_sub_read.reset();
got_sub_success.reset();
}
std::string url;
std::string html;
int status_code;
// Used for testing redirects
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
got_request,
got_read,
got_output,
got_redirect;
got_redirect,
got_error,
got_sub_request,
got_sub_read,
got_sub_success;
};
class TestSchemeHandler : public TestHandler
@ -55,9 +81,18 @@ public:
NavType navType,
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) {
test_results_->got_redirect.yes();
std::string newUrl = request->GetURL();
EXPECT_EQ(newUrl, test_results_->redirect_url);
// No read should have occurred for the redirect.
@ -76,15 +111,34 @@ public:
CefRefPtr<CefFrame> frame,
int httpStatusCode) OVERRIDE
{
// Test that the output is correct.
std::string output = frame->GetSource();
if (output == test_results_->html)
test_results_->got_output.yes();
std::string url = frame->GetURL();
if (url == test_results_->url || test_results_->status_code != 200) {
if (test_results_->sub_url.empty()) {
// 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.
EXPECT_EQ(httpStatusCode, test_results_->status_code);
// Test that the status code is correct.
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();
return false;
}
protected:
@ -95,7 +149,7 @@ class ClientSchemeHandler : public CefSchemeHandler
{
public:
ClientSchemeHandler(TestResults* tr)
: test_results_(tr), offset_(0) {}
: test_results_(tr), offset_(0), is_sub_(false) {}
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
CefString& redirectUrl,
@ -104,20 +158,43 @@ public:
{
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
test_results_->got_request.yes();
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()) {
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;
if (!test_results_->sub_allow_origin.empty()) {
// Set the Access-Control-Allow-Origin header to allow cross-domain
// scripting.
CefResponse::HeaderMap headers;
headers.insert(std::make_pair("Access-Control-Allow-Origin",
test_results_->sub_allow_origin));
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;
@ -132,18 +209,26 @@ public:
{
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;
*bytes_read = 0;
AutoLock lock_scope(this);
size_t size = test_results_->html.size();
size_t size = data->size();
if(offset_ < size) {
int transfer_size =
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;
*bytes_read = transfer_size;
@ -156,6 +241,7 @@ public:
private:
TestResults* test_results_;
size_t offset_;
bool is_sub_;
IMPLEMENT_REFCOUNTING(ClientSchemeHandler);
IMPLEMENT_LOCKING(ClientSchemeHandler);
@ -167,7 +253,8 @@ public:
ClientSchemeHandlerFactory(TestResults* tr)
: test_results_(tr){}
virtual CefRefPtr<CefSchemeHandler> Create()
virtual CefRefPtr<CefSchemeHandler> Create(const CefString& scheme_name,
CefRefPtr<CefRequest> request)
{
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
return new ClientSchemeHandler(test_results_);
@ -181,35 +268,145 @@ public:
// Global test results object.
TestResults g_TestResults;
void CreateStandardTestScheme()
void NotifyEvent(base::WaitableEvent* event)
{
g_TestResults.reset();
static bool registered = false;
if (!registered) {
CefRegisterScheme("stdscheme", "tests", true,
new ClientSchemeHandlerFactory(&g_TestResults));
registered = true;
}
event->Signal();
}
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();
static bool registered = false;
if (!registered) {
CefRegisterScheme("nonstdscheme", CefString(), false,
new ClientSchemeHandlerFactory(&g_TestResults));
registered = true;
static std::set<std::string> schemes;
if (schemes.empty()) {
// Never register built-in schemes.
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
// Test that a standard scheme can return normal results.
TEST(SchemeHandlerTest, StandardSchemeNormalResponse)
// Test that scheme registration/unregistration works as expected.
TEST(SchemeHandlerTest, Registration)
{
CreateStandardTestScheme();
g_TestResults.url = "stdscheme://tests/run.html";
RegisterTestScheme("customstd", "test");
g_TestResults.url = "customstd://test/run.html";
g_TestResults.html =
"<html><head></head><body><h1>Success!</h1></body></html>";
g_TestResults.status_code = 200;
@ -220,90 +417,41 @@ TEST(SchemeHandlerTest, StandardSchemeNormalResponse)
EXPECT_TRUE(g_TestResults.got_request);
EXPECT_TRUE(g_TestResults.got_read);
EXPECT_TRUE(g_TestResults.got_output);
}
// Test that a standard scheme can return an error code.
TEST(SchemeHandlerTest, StandardSchemeErrorResponse)
{
CreateStandardTestScheme();
g_TestResults.url = "stdscheme://tests/run.html";
g_TestResults.html =
"<html><head></head><body><h1>404</h1></body></html>";
g_TestResults.status_code = 404;
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
// Unregister the handler.
EXPECT_TRUE(CefRegisterSchemeHandlerFactory("customstd", "test", NULL));
WaitForIOThread();
g_TestResults.got_request.reset();
g_TestResults.got_read.reset();
g_TestResults.got_output.reset();
handler->ExecuteTest();
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();
EXPECT_TRUE(g_TestResults.got_request);
EXPECT_TRUE(g_TestResults.got_read);
EXPECT_TRUE(g_TestResults.got_output);
ClearTestSchemes();
}
// Test that standard scheme handling fails when the scheme name is incorrect.
TEST(SchemeHandlerTest, StandardSchemeNameNotHandled)
// Test that a custom standard scheme can return normal results.
TEST(SchemeHandlerTest, CustomStandardNormalResponse)
{
CreateStandardTestScheme();
g_TestResults.url = "stdscheme2://tests/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";
RegisterTestScheme("customstd", "test");
g_TestResults.url = "customstd://test/run.html";
g_TestResults.html =
"<html><head></head><body><h1>Success!</h1></body></html>";
g_TestResults.status_code = 200;
@ -314,13 +462,34 @@ TEST(SchemeHandlerTest, NonStandardSchemeNormalResponse)
EXPECT_TRUE(g_TestResults.got_request);
EXPECT_TRUE(g_TestResults.got_read);
EXPECT_TRUE(g_TestResults.got_output);
ClearTestSchemes();
}
// Test that a non-standard scheme can return an error code.
TEST(SchemeHandlerTest, NonStandardSchemeErrorResponse)
// Test that a custom nonstandard scheme can return normal results.
TEST(SchemeHandlerTest, CustomNonStandardNormalResponse)
{
CreateNonStandardTestScheme();
g_TestResults.url = "nonstdscheme:some%20value";
RegisterTestScheme("customnonstd", std::string());
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 =
"<html><head></head><body><h1>404</h1></body></html>";
g_TestResults.status_code = 404;
@ -331,14 +500,35 @@ TEST(SchemeHandlerTest, NonStandardSchemeErrorResponse)
EXPECT_TRUE(g_TestResults.got_request);
EXPECT_TRUE(g_TestResults.got_read);
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.
TEST(SchemeHandlerTest, NonStandardSchemeNameNotHandled)
TEST(SchemeHandlerTest, CustomStandardNameNotHandled)
{
CreateNonStandardTestScheme();
g_TestResults.url = "nonstdscheme2:some%20value";
RegisterTestScheme("customstd", "test");
g_TestResults.url = "customstd2://test/run.html";
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
handler->ExecuteTest();
@ -346,13 +536,49 @@ TEST(SchemeHandlerTest, NonStandardSchemeNameNotHandled)
EXPECT_FALSE(g_TestResults.got_request);
EXPECT_FALSE(g_TestResults.got_read);
EXPECT_FALSE(g_TestResults.got_output);
ClearTestSchemes();
}
// Test that a non-standard scheme can return no response.
TEST(SchemeHandlerTest, NonStandardSchemeNoResponse)
// Test that custom nonstandard scheme handling fails when the scheme name is
// incorrect.
TEST(SchemeHandlerTest, CustomNonStandardNameNotHandled)
{
CreateNonStandardTestScheme();
g_TestResults.url = "nonstdscheme:some%20value";
RegisterTestScheme("customnonstd", std::string());
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);
handler->ExecuteTest();
@ -360,14 +586,32 @@ TEST(SchemeHandlerTest, NonStandardSchemeNoResponse)
EXPECT_TRUE(g_TestResults.got_request);
EXPECT_FALSE(g_TestResults.got_read);
EXPECT_FALSE(g_TestResults.got_output);
ClearTestSchemes();
}
// Test that a non-standard scheme can generate redirects.
TEST(SchemeHandlerTest, NonStandardSchemeRedirect)
// Test that a custom nonstandard scheme can return no response.
TEST(SchemeHandlerTest, CustomNonStandardNoResponse)
{
CreateNonStandardTestScheme();
g_TestResults.url = "nonstdscheme:some%20value";
g_TestResults.redirect_url = "nonstdscheme:some%20other%20value";
RegisterTestScheme("customnonstd", std::string());
g_TestResults.url = "customnonstd:some%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 =
"<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_output);
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();
}

View File

@ -123,6 +123,9 @@ public:
// Wait for the test to complete
completion_event_.Wait();
// Reset the event so the same test can be executed again.
completion_event_.Reset();
}
protected: