mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add support and enable out-of-Blink CORS (fixes issue #2716)
It can still be disabled for a short time by passing `--disable-features=OutOfBlinkCors` on the command-line.
This commit is contained in:
@@ -470,6 +470,7 @@
|
|||||||
'tests/ceftests/browser_info_map_unittest.cc',
|
'tests/ceftests/browser_info_map_unittest.cc',
|
||||||
'tests/ceftests/command_line_unittest.cc',
|
'tests/ceftests/command_line_unittest.cc',
|
||||||
'tests/ceftests/cookie_unittest.cc',
|
'tests/ceftests/cookie_unittest.cc',
|
||||||
|
'tests/ceftests/cors_unittest.cc',
|
||||||
'tests/ceftests/devtools_message_unittest.cc',
|
'tests/ceftests/devtools_message_unittest.cc',
|
||||||
'tests/ceftests/dialog_unittest.cc',
|
'tests/ceftests/dialog_unittest.cc',
|
||||||
'tests/ceftests/display_unittest.cc',
|
'tests/ceftests/display_unittest.cc',
|
||||||
|
@@ -1255,6 +1255,7 @@ void AlloyContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
|
|||||||
extensions::Manifest::IsComponentLocation(extension->location())) {
|
extensions::Manifest::IsComponentLocation(extension->location())) {
|
||||||
// Components of chrome that are implemented as extensions or platform apps
|
// Components of chrome that are implemented as extensions or platform apps
|
||||||
// are allowed to use chrome://resources/ and chrome://theme/ URLs.
|
// are allowed to use chrome://resources/ and chrome://theme/ URLs.
|
||||||
|
// See also HasCrossOriginWhitelistEntry.
|
||||||
allowed_webui_hosts.emplace_back(content::kChromeUIResourcesHost);
|
allowed_webui_hosts.emplace_back(content::kChromeUIResourcesHost);
|
||||||
allowed_webui_hosts.emplace_back(chrome::kChromeUIThemeHost);
|
allowed_webui_hosts.emplace_back(chrome::kChromeUIThemeHost);
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,9 @@
|
|||||||
#include "libcef/browser/net_service/proxy_url_loader_factory.h"
|
#include "libcef/browser/net_service/proxy_url_loader_factory.h"
|
||||||
|
|
||||||
#include "libcef/browser/context.h"
|
#include "libcef/browser/context.h"
|
||||||
|
#include "libcef/browser/origin_whitelist_impl.h"
|
||||||
#include "libcef/browser/thread_util.h"
|
#include "libcef/browser/thread_util.h"
|
||||||
|
#include "libcef/common/net/scheme_registration.h"
|
||||||
#include "libcef/common/net_service/net_service_util.h"
|
#include "libcef/common/net_service/net_service_util.h"
|
||||||
|
|
||||||
#include "base/barrier_closure.h"
|
#include "base/barrier_closure.h"
|
||||||
@@ -19,6 +21,7 @@
|
|||||||
#include "mojo/public/cpp/base/big_buffer.h"
|
#include "mojo/public/cpp/base/big_buffer.h"
|
||||||
#include "net/http/http_status_code.h"
|
#include "net/http/http_status_code.h"
|
||||||
#include "services/network/public/cpp/cors/cors.h"
|
#include "services/network/public/cpp/cors/cors.h"
|
||||||
|
#include "services/network/public/cpp/features.h"
|
||||||
|
|
||||||
namespace net_service {
|
namespace net_service {
|
||||||
|
|
||||||
@@ -27,6 +30,26 @@ namespace {
|
|||||||
// User data key for ResourceContextData.
|
// User data key for ResourceContextData.
|
||||||
const void* const kResourceContextUserDataKey = &kResourceContextUserDataKey;
|
const void* const kResourceContextUserDataKey = &kResourceContextUserDataKey;
|
||||||
|
|
||||||
|
base::Optional<std::string> GetHeaderString(
|
||||||
|
const net::HttpResponseHeaders* headers,
|
||||||
|
const std::string& header_name) {
|
||||||
|
std::string header_value;
|
||||||
|
if (!headers || !headers->GetNormalizedHeader(header_name, &header_value)) {
|
||||||
|
return base::nullopt;
|
||||||
|
}
|
||||||
|
return header_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsOutOfBlinkCorsEnabled() {
|
||||||
|
static int state = -1;
|
||||||
|
if (state == -1) {
|
||||||
|
state = base::FeatureList::IsEnabled(network::features::kOutOfBlinkCors)
|
||||||
|
? 1
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
return !!state;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Owns all of the ProxyURLLoaderFactorys for a given BrowserContext. Since
|
// Owns all of the ProxyURLLoaderFactorys for a given BrowserContext. Since
|
||||||
@@ -219,6 +242,8 @@ class InterceptedRequest : public network::mojom::URLLoader,
|
|||||||
bool wait_for_loader_error);
|
bool wait_for_loader_error);
|
||||||
|
|
||||||
void SendErrorAndCompleteImmediately(int error_code);
|
void SendErrorAndCompleteImmediately(int error_code);
|
||||||
|
void SendErrorStatusAndCompleteImmediately(
|
||||||
|
const network::URLLoaderCompletionStatus& status);
|
||||||
|
|
||||||
void SendErrorCallback(int error_code, bool safebrowsing_hit);
|
void SendErrorCallback(int error_code, bool safebrowsing_hit);
|
||||||
|
|
||||||
@@ -366,6 +391,27 @@ void InterceptedRequest::Restart() {
|
|||||||
current_request_uses_header_client_ =
|
current_request_uses_header_client_ =
|
||||||
!!factory_->url_loader_header_client_receiver_;
|
!!factory_->url_loader_header_client_receiver_;
|
||||||
|
|
||||||
|
if (IsOutOfBlinkCorsEnabled() && request_.request_initiator &&
|
||||||
|
network::cors::ShouldCheckCors(request_.url, request_.request_initiator,
|
||||||
|
request_.mode)) {
|
||||||
|
if (scheme::IsCorsEnabledScheme(request_.url.scheme())) {
|
||||||
|
// Add the Origin header for CORS-enabled scheme requests.
|
||||||
|
request_.headers.SetHeaderIfMissing(
|
||||||
|
net::HttpRequestHeaders::kOrigin,
|
||||||
|
request_.request_initiator->Serialize());
|
||||||
|
} else if (!HasCrossOriginWhitelistEntry(
|
||||||
|
*request_.request_initiator,
|
||||||
|
url::Origin::Create(request_.url))) {
|
||||||
|
// Fail requests if a CORS check is required and the scheme is not CORS
|
||||||
|
// enabled. This matches the error condition that would be generated by
|
||||||
|
// CorsURLLoader::StartRequest in the network process.
|
||||||
|
SendErrorStatusAndCompleteImmediately(
|
||||||
|
network::URLLoaderCompletionStatus(network::CorsErrorStatus(
|
||||||
|
network::mojom::CorsError::kCorsDisabledScheme)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const GURL original_url = request_.url;
|
const GURL original_url = request_.url;
|
||||||
|
|
||||||
factory_->request_handler_->OnBeforeRequest(
|
factory_->request_handler_->OnBeforeRequest(
|
||||||
@@ -881,10 +927,12 @@ void InterceptedRequest::ContinueToResponseStarted(int error_code) {
|
|||||||
override_headers_ = nullptr;
|
override_headers_ = nullptr;
|
||||||
redirect_url_ = GURL();
|
redirect_url_ = GURL();
|
||||||
|
|
||||||
|
scoped_refptr<net::HttpResponseHeaders> headers =
|
||||||
|
current_response_ ? current_response_->headers : nullptr;
|
||||||
|
|
||||||
std::string location;
|
std::string location;
|
||||||
const bool is_redirect = redirect_url.is_valid() ||
|
const bool is_redirect =
|
||||||
(current_response_->headers &&
|
redirect_url.is_valid() || (headers && headers->IsRedirect(&location));
|
||||||
current_response_->headers->IsRedirect(&location));
|
|
||||||
if (stream_loader_ && is_redirect) {
|
if (stream_loader_ && is_redirect) {
|
||||||
// Redirecting from OnReceiveResponse generally isn't supported by the
|
// Redirecting from OnReceiveResponse generally isn't supported by the
|
||||||
// NetworkService, so we can only support it when using a custom loader.
|
// NetworkService, so we can only support it when using a custom loader.
|
||||||
@@ -903,6 +951,30 @@ void InterceptedRequest::ContinueToResponseStarted(int error_code) {
|
|||||||
LOG_IF(WARNING, is_redirect) << "Redirect at this time is not supported by "
|
LOG_IF(WARNING, is_redirect) << "Redirect at this time is not supported by "
|
||||||
"the default network loader.";
|
"the default network loader.";
|
||||||
|
|
||||||
|
// CORS check for requests that are handled by the client. Requests handled
|
||||||
|
// by the network process will be checked there.
|
||||||
|
if (IsOutOfBlinkCorsEnabled() && stream_loader_ && !is_redirect &&
|
||||||
|
request_.request_initiator &&
|
||||||
|
network::cors::ShouldCheckCors(request_.url, request_.request_initiator,
|
||||||
|
request_.mode)) {
|
||||||
|
const auto error_status = network::cors::CheckAccess(
|
||||||
|
request_.url,
|
||||||
|
GetHeaderString(
|
||||||
|
headers.get(),
|
||||||
|
network::cors::header_names::kAccessControlAllowOrigin),
|
||||||
|
GetHeaderString(
|
||||||
|
headers.get(),
|
||||||
|
network::cors::header_names::kAccessControlAllowCredentials),
|
||||||
|
request_.credentials_mode, *request_.request_initiator);
|
||||||
|
if (error_status &&
|
||||||
|
!HasCrossOriginWhitelistEntry(*request_.request_initiator,
|
||||||
|
url::Origin::Create(request_.url))) {
|
||||||
|
SendErrorStatusAndCompleteImmediately(
|
||||||
|
network::URLLoaderCompletionStatus(*error_status));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Resume handling of client messages after continuing from an async
|
// Resume handling of client messages after continuing from an async
|
||||||
// callback.
|
// callback.
|
||||||
if (proxied_client_binding_)
|
if (proxied_client_binding_)
|
||||||
@@ -992,7 +1064,13 @@ void InterceptedRequest::CallOnComplete(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InterceptedRequest::SendErrorAndCompleteImmediately(int error_code) {
|
void InterceptedRequest::SendErrorAndCompleteImmediately(int error_code) {
|
||||||
status_ = network::URLLoaderCompletionStatus(error_code);
|
SendErrorStatusAndCompleteImmediately(
|
||||||
|
network::URLLoaderCompletionStatus(error_code));
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterceptedRequest::SendErrorStatusAndCompleteImmediately(
|
||||||
|
const network::URLLoaderCompletionStatus& status) {
|
||||||
|
status_ = status;
|
||||||
SendErrorCallback(status_.error_code, false);
|
SendErrorCallback(status_.error_code, false);
|
||||||
target_client_->OnComplete(status_);
|
target_client_->OnComplete(status_);
|
||||||
OnDestroy();
|
OnDestroy();
|
||||||
|
@@ -15,8 +15,12 @@
|
|||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/lazy_instance.h"
|
#include "base/lazy_instance.h"
|
||||||
#include "base/synchronization/lock.h"
|
#include "base/synchronization/lock.h"
|
||||||
|
#include "chrome/common/webui_url_constants.h"
|
||||||
#include "content/public/browser/render_process_host.h"
|
#include "content/public/browser/render_process_host.h"
|
||||||
|
#include "content/public/common/url_constants.h"
|
||||||
|
#include "extensions/common/constants.h"
|
||||||
#include "url/gurl.h"
|
#include "url/gurl.h"
|
||||||
|
#include "url/origin.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -157,10 +161,11 @@ CefOriginWhitelistManager* CefOriginWhitelistManager::GetInstance() {
|
|||||||
return g_manager.Pointer();
|
return g_manager.Pointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsMatch(const GURL& source_origin,
|
bool IsMatch(const url::Origin& source_origin,
|
||||||
const GURL& target_origin,
|
const url::Origin& target_origin,
|
||||||
const Cef_CrossOriginWhiteListEntry_Params& param) {
|
const Cef_CrossOriginWhiteListEntry_Params& param) {
|
||||||
if (source_origin.GetOrigin() != GURL(param.source_origin)) {
|
if (!source_origin.IsSameOriginWith(
|
||||||
|
url::Origin::Create(GURL(param.source_origin)))) {
|
||||||
// Source origin does not match.
|
// Source origin does not match.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -271,7 +276,18 @@ void GetCrossOriginWhitelistEntries(
|
|||||||
entries);
|
entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasCrossOriginWhitelistEntry(const GURL& source, const GURL& target) {
|
bool HasCrossOriginWhitelistEntry(const url::Origin& source,
|
||||||
|
const url::Origin& target) {
|
||||||
|
// Components of chrome that are implemented as extensions or platform apps
|
||||||
|
// are allowed to use chrome://resources/ and chrome://theme/ URLs.
|
||||||
|
// See also RegisterNonNetworkSubresourceURLLoaderFactories.
|
||||||
|
if (source.scheme() == extensions::kExtensionScheme &&
|
||||||
|
target.scheme() == content::kChromeUIScheme &&
|
||||||
|
(target.host() == chrome::kChromeUIThemeHost ||
|
||||||
|
target.host() == content::kChromeUIResourcesHost)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Cef_CrossOriginWhiteListEntry_Params> params;
|
std::vector<Cef_CrossOriginWhiteListEntry_Params> params;
|
||||||
CefOriginWhitelistManager::GetInstance()->GetCrossOriginWhitelistEntries(
|
CefOriginWhitelistManager::GetInstance()->GetCrossOriginWhitelistEntries(
|
||||||
¶ms);
|
¶ms);
|
||||||
|
@@ -12,7 +12,9 @@ namespace content {
|
|||||||
class RenderProcessHost;
|
class RenderProcessHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GURL;
|
namespace url {
|
||||||
|
class Origin;
|
||||||
|
}
|
||||||
|
|
||||||
struct Cef_CrossOriginWhiteListEntry_Params;
|
struct Cef_CrossOriginWhiteListEntry_Params;
|
||||||
|
|
||||||
@@ -23,6 +25,7 @@ void GetCrossOriginWhitelistEntries(
|
|||||||
|
|
||||||
// Returns true if |source| can access |target| based on the cross-origin white
|
// Returns true if |source| can access |target| based on the cross-origin white
|
||||||
// list settings.
|
// list settings.
|
||||||
bool HasCrossOriginWhitelistEntry(const GURL& source, const GURL& target);
|
bool HasCrossOriginWhitelistEntry(const url::Origin& source,
|
||||||
|
const url::Origin& target);
|
||||||
|
|
||||||
#endif // CEF_LIBCEF_BROWSER_ORIGIN_WHITELIST_IMPL_H_
|
#endif // CEF_LIBCEF_BROWSER_ORIGIN_WHITELIST_IMPL_H_
|
||||||
|
@@ -244,12 +244,6 @@ bool AlloyMainDelegate::BasicStartupComplete(int* exit_code) {
|
|||||||
|
|
||||||
std::vector<std::string> disable_features;
|
std::vector<std::string> disable_features;
|
||||||
|
|
||||||
if (network::features::kOutOfBlinkCors.default_state ==
|
|
||||||
base::FEATURE_ENABLED_BY_DEFAULT) {
|
|
||||||
// TODO: Add support for out-of-Blink CORS (see issue #2716)
|
|
||||||
disable_features.push_back(network::features::kOutOfBlinkCors.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
if (features::kCalculateNativeWinOcclusion.default_state ==
|
if (features::kCalculateNativeWinOcclusion.default_state ==
|
||||||
base::FEATURE_ENABLED_BY_DEFAULT) {
|
base::FEATURE_ENABLED_BY_DEFAULT) {
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include "libcef/common/net/scheme_info.h"
|
#include "libcef/common/net/scheme_info.h"
|
||||||
#include "libcef/features/runtime.h"
|
#include "libcef/features/runtime.h"
|
||||||
|
|
||||||
|
#include "base/stl_util.h"
|
||||||
#include "content/public/common/url_constants.h"
|
#include "content/public/common/url_constants.h"
|
||||||
#include "extensions/common/constants.h"
|
#include "extensions/common/constants.h"
|
||||||
#include "net/net_buildflags.h"
|
#include "net/net_buildflags.h"
|
||||||
@@ -86,4 +87,10 @@ bool IsStandardScheme(const std::string& scheme) {
|
|||||||
return url::IsStandard(scheme.c_str(), scheme_comp);
|
return url::IsStandard(scheme.c_str(), scheme_comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should return the same value as SecurityOrigin::isLocal and
|
||||||
|
// SchemeRegistry::shouldTreatURLSchemeAsCorsEnabled.
|
||||||
|
bool IsCorsEnabledScheme(const std::string& scheme) {
|
||||||
|
return base::Contains(url::GetCorsEnabledSchemes(), scheme);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace scheme
|
} // namespace scheme
|
||||||
|
@@ -22,6 +22,9 @@ bool IsInternalHandledScheme(const std::string& scheme);
|
|||||||
// Returns true if the specified |scheme| is a registered standard scheme.
|
// Returns true if the specified |scheme| is a registered standard scheme.
|
||||||
bool IsStandardScheme(const std::string& scheme);
|
bool IsStandardScheme(const std::string& scheme);
|
||||||
|
|
||||||
|
// Returns true if the specified |scheme| is a registered CORS enabled scheme.
|
||||||
|
bool IsCorsEnabledScheme(const std::string& scheme);
|
||||||
|
|
||||||
} // namespace scheme
|
} // namespace scheme
|
||||||
|
|
||||||
#endif // CEF_LIBCEF_COMMON_NET_SCHEME_REGISTRATION_H_
|
#endif // CEF_LIBCEF_COMMON_NET_SCHEME_REGISTRATION_H_
|
||||||
|
983
tests/ceftests/cors_unittest.cc
Normal file
983
tests/ceftests/cors_unittest.cc
Normal file
@@ -0,0 +1,983 @@
|
|||||||
|
// Copyright (c) 2020 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 <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "include/base/cef_bind.h"
|
||||||
|
#include "include/cef_callback.h"
|
||||||
|
#include "include/cef_origin_whitelist.h"
|
||||||
|
#include "include/cef_scheme.h"
|
||||||
|
#include "include/wrapper/cef_closure_task.h"
|
||||||
|
#include "tests/ceftests/routing_test_handler.h"
|
||||||
|
#include "tests/ceftests/test_request.h"
|
||||||
|
#include "tests/ceftests/test_server.h"
|
||||||
|
#include "tests/ceftests/test_util.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char kMimeTypeHtml[] = "text/html";
|
||||||
|
const char kMimeTypeText[] = "text/plain";
|
||||||
|
|
||||||
|
const char kDefaultHtml[] = "<html><body>TEST</body></html>";
|
||||||
|
const char kDefaultText[] = "TEST";
|
||||||
|
|
||||||
|
const char kSuccessMsg[] = "CorsTestHandler.Success";
|
||||||
|
const char kFailureMsg[] = "CorsTestHandler.Failure";
|
||||||
|
|
||||||
|
// Source that will handle the request.
|
||||||
|
enum class HandlerType {
|
||||||
|
SERVER,
|
||||||
|
HTTP_SCHEME,
|
||||||
|
CUSTOM_STANDARD_SCHEME,
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string GetOrigin(HandlerType handler) {
|
||||||
|
switch (handler) {
|
||||||
|
case HandlerType::SERVER:
|
||||||
|
return test_server::kServerOrigin;
|
||||||
|
case HandlerType::HTTP_SCHEME:
|
||||||
|
return "http://corstest.com";
|
||||||
|
case HandlerType::CUSTOM_STANDARD_SCHEME:
|
||||||
|
// Standard scheme that is CORS and fetch enabled.
|
||||||
|
// Registered in scheme_handler_unittest.cc.
|
||||||
|
return "customstdfetch://corstest";
|
||||||
|
case HandlerType::CUSTOM_NONSTANDARD_SCHEME:
|
||||||
|
// Non-sandard scheme that is not CORS or fetch enabled.
|
||||||
|
// Registered in scheme_handler_unittest.cc.
|
||||||
|
return "customnonstd:corstest";
|
||||||
|
}
|
||||||
|
NOTREACHED();
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetPathURL(HandlerType handler, const std::string& path) {
|
||||||
|
return GetOrigin(handler) + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Resource {
|
||||||
|
// Uniquely identifies the resource.
|
||||||
|
HandlerType handler = HandlerType::SERVER;
|
||||||
|
std::string path;
|
||||||
|
|
||||||
|
// Response information that will be returned.
|
||||||
|
CefRefPtr<CefResponse> response;
|
||||||
|
std::string response_data;
|
||||||
|
|
||||||
|
// Expected error code in OnLoadError.
|
||||||
|
cef_errorcode_t expected_error_code = ERR_NONE;
|
||||||
|
|
||||||
|
// Expected number of responses.
|
||||||
|
int expected_response_ct = 1;
|
||||||
|
|
||||||
|
// Expected number of OnQuery calls.
|
||||||
|
int expected_success_query_ct = 0;
|
||||||
|
int expected_failure_query_ct = 0;
|
||||||
|
|
||||||
|
// Actual number of responses.
|
||||||
|
int response_ct = 0;
|
||||||
|
|
||||||
|
// Actual number of OnQuery calls.
|
||||||
|
int success_query_ct = 0;
|
||||||
|
int failure_query_ct = 0;
|
||||||
|
|
||||||
|
Resource() {}
|
||||||
|
Resource(HandlerType request_handler,
|
||||||
|
const std::string& request_path,
|
||||||
|
const std::string& mime_type = kMimeTypeHtml,
|
||||||
|
const std::string& data = kDefaultHtml,
|
||||||
|
int status = 200) {
|
||||||
|
Init(request_handler, request_path, mime_type, data, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform basic initialization.
|
||||||
|
void Init(HandlerType request_handler,
|
||||||
|
const std::string& request_path,
|
||||||
|
const std::string& mime_type = kMimeTypeHtml,
|
||||||
|
const std::string& data = kDefaultHtml,
|
||||||
|
int status = 200) {
|
||||||
|
handler = request_handler;
|
||||||
|
path = request_path;
|
||||||
|
response_data = data;
|
||||||
|
response = CefResponse::Create();
|
||||||
|
response->SetMimeType(mime_type);
|
||||||
|
response->SetStatus(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate expected initial state.
|
||||||
|
void Validate() const {
|
||||||
|
DCHECK(!path.empty());
|
||||||
|
DCHECK(response);
|
||||||
|
DCHECK(!response->GetMimeType().empty());
|
||||||
|
DCHECK_EQ(0, response_ct);
|
||||||
|
DCHECK_GE(expected_response_ct, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetPathURL() const { return ::GetPathURL(handler, path); }
|
||||||
|
|
||||||
|
// Returns true if all expectations have been met.
|
||||||
|
bool IsDone() const {
|
||||||
|
return response_ct == expected_response_ct &&
|
||||||
|
success_query_ct == expected_success_query_ct &&
|
||||||
|
failure_query_ct == expected_failure_query_ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertDone() const {
|
||||||
|
EXPECT_EQ(expected_response_ct, response_ct) << GetPathURL();
|
||||||
|
EXPECT_EQ(expected_success_query_ct, success_query_ct) << GetPathURL();
|
||||||
|
EXPECT_EQ(expected_failure_query_ct, failure_query_ct) << GetPathURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optionally override to verify request contents.
|
||||||
|
virtual bool VerifyRequest(CefRefPtr<CefRequest> request) const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TestSetup {
|
||||||
|
// Available resources.
|
||||||
|
typedef std::vector<Resource*> ResourceList;
|
||||||
|
ResourceList resources;
|
||||||
|
|
||||||
|
// Used for testing received console messages.
|
||||||
|
std::vector<std::string> console_messages;
|
||||||
|
|
||||||
|
void AddResource(Resource* resource) {
|
||||||
|
DCHECK(resource);
|
||||||
|
resource->Validate();
|
||||||
|
resources.push_back(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddConsoleMessage(const std::string& message) {
|
||||||
|
DCHECK(!message.empty());
|
||||||
|
console_messages.push_back(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource* GetResource(const std::string& url) const {
|
||||||
|
if (resources.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
const std::string& path_url = test_request::GetPathURL(url);
|
||||||
|
ResourceList::const_iterator it = resources.begin();
|
||||||
|
for (; it != resources.end(); ++it) {
|
||||||
|
Resource* resource = *it;
|
||||||
|
if (resource->GetPathURL() == path_url)
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource* GetResource(CefRefPtr<CefRequest> request) const {
|
||||||
|
return GetResource(request->GetURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate expected initial state.
|
||||||
|
void Validate() const { DCHECK(!resources.empty()); }
|
||||||
|
|
||||||
|
std::string GetMainURL() const { return resources.front()->GetPathURL(); }
|
||||||
|
|
||||||
|
// Returns true if the server will be used.
|
||||||
|
bool NeedsServer() const {
|
||||||
|
ResourceList::const_iterator it = resources.begin();
|
||||||
|
for (; it != resources.end(); ++it) {
|
||||||
|
Resource* resource = *it;
|
||||||
|
if (resource->handler == HandlerType::SERVER)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if all expectations have been met.
|
||||||
|
bool IsDone() const {
|
||||||
|
ResourceList::const_iterator it = resources.begin();
|
||||||
|
for (; it != resources.end(); ++it) {
|
||||||
|
Resource* resource = *it;
|
||||||
|
if (!resource->IsDone())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssertDone() const {
|
||||||
|
ResourceList::const_iterator it = resources.begin();
|
||||||
|
for (; it != resources.end(); ++it) {
|
||||||
|
(*it)->AssertDone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestServerObserver : public test_server::ObserverHelper {
|
||||||
|
public:
|
||||||
|
typedef base::Callback<bool()> CheckDoneCallback;
|
||||||
|
|
||||||
|
TestServerObserver(TestSetup* setup,
|
||||||
|
const base::Closure& ready_callback,
|
||||||
|
const base::Closure& done_callback)
|
||||||
|
: setup_(setup),
|
||||||
|
ready_callback_(ready_callback),
|
||||||
|
done_callback_(done_callback),
|
||||||
|
weak_ptr_factory_(this) {
|
||||||
|
DCHECK(setup);
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
~TestServerObserver() override { done_callback_.Run(); }
|
||||||
|
|
||||||
|
void OnInitialized(const std::string& server_origin) override {
|
||||||
|
CEF_REQUIRE_UI_THREAD();
|
||||||
|
ready_callback_.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnHttpRequest(CefRefPtr<CefServer> server,
|
||||||
|
int connection_id,
|
||||||
|
const CefString& client_address,
|
||||||
|
CefRefPtr<CefRequest> request) override {
|
||||||
|
CEF_REQUIRE_UI_THREAD();
|
||||||
|
Resource* resource = setup_->GetResource(request);
|
||||||
|
if (!resource) {
|
||||||
|
// Not a request we handle.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
resource->response_ct++;
|
||||||
|
EXPECT_TRUE(resource->VerifyRequest(request))
|
||||||
|
<< request->GetURL().ToString();
|
||||||
|
test_server::SendResponse(server, connection_id, resource->response,
|
||||||
|
resource->response_data);
|
||||||
|
|
||||||
|
// Stop propagating the callback.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnShutdown() override {
|
||||||
|
CEF_REQUIRE_UI_THREAD();
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TestSetup* const setup_;
|
||||||
|
const base::Closure ready_callback_;
|
||||||
|
const base::Closure done_callback_;
|
||||||
|
|
||||||
|
base::WeakPtrFactory<TestServerObserver> weak_ptr_factory_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(TestServerObserver);
|
||||||
|
};
|
||||||
|
|
||||||
|
class CorsTestHandler : public RoutingTestHandler {
|
||||||
|
public:
|
||||||
|
explicit CorsTestHandler(TestSetup* setup) : setup_(setup) {
|
||||||
|
setup_->Validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunTest() override {
|
||||||
|
StartServer(base::Bind(&CorsTestHandler::TriggerCreateBrowser, this));
|
||||||
|
|
||||||
|
// Time out the test after a reasonable period of time.
|
||||||
|
SetTestTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Necessary to make the method public in order to destroy the test from
|
||||||
|
// ClientSchemeHandlerType::ProcessRequest().
|
||||||
|
void DestroyTest() override {
|
||||||
|
EXPECT_TRUE(shutting_down_);
|
||||||
|
|
||||||
|
setup_->AssertDone();
|
||||||
|
EXPECT_TRUE(setup_->console_messages.empty())
|
||||||
|
<< "Did not receive expected console message: "
|
||||||
|
<< setup_->console_messages.front();
|
||||||
|
|
||||||
|
RoutingTestHandler::DestroyTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyTestIfDone() {
|
||||||
|
CEF_REQUIRE_UI_THREAD();
|
||||||
|
if (shutting_down_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (setup_->IsDone()) {
|
||||||
|
shutting_down_ = true;
|
||||||
|
StopServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CefRefPtr<CefResourceHandler> GetResourceHandler(
|
||||||
|
CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
CefRefPtr<CefRequest> request) override {
|
||||||
|
CEF_REQUIRE_IO_THREAD();
|
||||||
|
Resource* resource = setup_->GetResource(request);
|
||||||
|
if (resource && resource->handler != HandlerType::SERVER) {
|
||||||
|
resource->response_ct++;
|
||||||
|
EXPECT_TRUE(resource->VerifyRequest(request))
|
||||||
|
<< request->GetURL().ToString();
|
||||||
|
return test_request::CreateResourceHandler(resource->response,
|
||||||
|
resource->response_data);
|
||||||
|
}
|
||||||
|
return RoutingTestHandler::GetResourceHandler(browser, frame, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int httpStatusCode) override {
|
||||||
|
const std::string& url = frame->GetURL();
|
||||||
|
Resource* resource = GetResource(url);
|
||||||
|
if (!resource)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const int expected_status = resource->response->GetStatus();
|
||||||
|
if (url == main_url_ || expected_status != 200) {
|
||||||
|
// Test that the status code is correct.
|
||||||
|
EXPECT_EQ(expected_status, httpStatusCode) << url;
|
||||||
|
}
|
||||||
|
|
||||||
|
TriggerDestroyTestIfDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnLoadError(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
ErrorCode errorCode,
|
||||||
|
const CefString& errorText,
|
||||||
|
const CefString& failedUrl) override {
|
||||||
|
Resource* resource = GetResource(failedUrl);
|
||||||
|
if (!resource)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const cef_errorcode_t expected_error = resource->response->GetError();
|
||||||
|
|
||||||
|
// Tests sometimes also fail with ERR_ABORTED.
|
||||||
|
if (!(expected_error == ERR_NONE && errorCode == ERR_ABORTED)) {
|
||||||
|
EXPECT_EQ(expected_error, errorCode) << failedUrl.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
TriggerDestroyTestIfDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||||
|
CefRefPtr<CefFrame> frame,
|
||||||
|
int64 query_id,
|
||||||
|
const CefString& request,
|
||||||
|
bool persistent,
|
||||||
|
CefRefPtr<Callback> callback) override {
|
||||||
|
Resource* resource = GetResource(frame->GetURL());
|
||||||
|
if (!resource)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (request.ToString() == kSuccessMsg ||
|
||||||
|
request.ToString() == kFailureMsg) {
|
||||||
|
callback->Success("");
|
||||||
|
if (request.ToString() == kSuccessMsg)
|
||||||
|
resource->success_query_ct++;
|
||||||
|
else
|
||||||
|
resource->failure_query_ct++;
|
||||||
|
TriggerDestroyTestIfDone();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
|
||||||
|
cef_log_severity_t level,
|
||||||
|
const CefString& message,
|
||||||
|
const CefString& source,
|
||||||
|
int line) override {
|
||||||
|
bool expected = false;
|
||||||
|
if (!setup_->console_messages.empty()) {
|
||||||
|
std::vector<std::string>::iterator it = setup_->console_messages.begin();
|
||||||
|
for (; it != setup_->console_messages.end(); ++it) {
|
||||||
|
const std::string& possible = *it;
|
||||||
|
const std::string& actual = message.ToString();
|
||||||
|
if (actual.find(possible) == 0U) {
|
||||||
|
expected = true;
|
||||||
|
setup_->console_messages.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(expected) << "Unexpected console message: "
|
||||||
|
<< message.ToString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void TriggerCreateBrowser() {
|
||||||
|
main_url_ = setup_->GetMainURL();
|
||||||
|
CreateBrowser(main_url_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TriggerDestroyTestIfDone() {
|
||||||
|
CefPostTask(TID_UI, base::Bind(&CorsTestHandler::DestroyTestIfDone, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartServer(const base::Closure& next_step) {
|
||||||
|
if (!CefCurrentlyOn(TID_UI)) {
|
||||||
|
CefPostTask(TID_UI,
|
||||||
|
base::Bind(&CorsTestHandler::StartServer, this, next_step));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setup_->NeedsServer()) {
|
||||||
|
next_step.Run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Will delete itself after the server stops.
|
||||||
|
server_ = new TestServerObserver(
|
||||||
|
setup_, next_step, base::Bind(&CorsTestHandler::StoppedServer, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopServer() {
|
||||||
|
CEF_REQUIRE_UI_THREAD();
|
||||||
|
if (!server_) {
|
||||||
|
DCHECK(!setup_->NeedsServer());
|
||||||
|
DestroyTest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Results in a call to StoppedServer().
|
||||||
|
server_->Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StoppedServer() {
|
||||||
|
CEF_REQUIRE_UI_THREAD();
|
||||||
|
server_ = nullptr;
|
||||||
|
DestroyTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
Resource* GetResource(const std::string& url) const {
|
||||||
|
Resource* resource = setup_->GetResource(url);
|
||||||
|
EXPECT_TRUE(resource) << url;
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSetup* setup_;
|
||||||
|
std::string main_url_;
|
||||||
|
TestServerObserver* server_ = nullptr;
|
||||||
|
bool shutting_down_ = false;
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(CorsTestHandler);
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(CorsTestHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
// JS that results in a call to CorsTestHandler::OnQuery.
|
||||||
|
std::string GetMsgJS(const std::string& msg) {
|
||||||
|
return "window.testQuery({request:'" + msg + "'});";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetSuccessMsgJS() {
|
||||||
|
return GetMsgJS(kSuccessMsg);
|
||||||
|
}
|
||||||
|
std::string GetFailureMsgJS() {
|
||||||
|
return GetMsgJS(kFailureMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetDefaultSuccessMsgHtml() {
|
||||||
|
return "<html><body>TEST<script>" + GetSuccessMsgJS() +
|
||||||
|
"</script></body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Verify the test harness for server requests.
|
||||||
|
TEST(CorsTest, BasicServer) {
|
||||||
|
TestSetup setup;
|
||||||
|
Resource resource(HandlerType::SERVER, "/CorsTest.BasicServer");
|
||||||
|
setup.AddResource(&resource);
|
||||||
|
|
||||||
|
CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
ReleaseAndWaitForDestructor(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like above, but also send a query JS message.
|
||||||
|
TEST(CorsTest, BasicServerWithQuery) {
|
||||||
|
TestSetup setup;
|
||||||
|
Resource resource(HandlerType::SERVER, "/CorsTest.BasicServerWithQuery",
|
||||||
|
kMimeTypeHtml, GetDefaultSuccessMsgHtml());
|
||||||
|
resource.expected_success_query_ct = 1;
|
||||||
|
setup.AddResource(&resource);
|
||||||
|
|
||||||
|
CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
ReleaseAndWaitForDestructor(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the test harness for http scheme requests.
|
||||||
|
TEST(CorsTest, BasicHttpScheme) {
|
||||||
|
TestSetup setup;
|
||||||
|
Resource resource(HandlerType::HTTP_SCHEME, "/CorsTest.BasicHttpScheme");
|
||||||
|
setup.AddResource(&resource);
|
||||||
|
|
||||||
|
CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
ReleaseAndWaitForDestructor(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like above, but also send a query JS message.
|
||||||
|
TEST(CorsTest, BasicHttpSchemeWithQuery) {
|
||||||
|
TestSetup setup;
|
||||||
|
Resource resource(HandlerType::HTTP_SCHEME,
|
||||||
|
"/CorsTest.BasicHttpSchemeWithQuery", kMimeTypeHtml,
|
||||||
|
GetDefaultSuccessMsgHtml());
|
||||||
|
resource.expected_success_query_ct = 1;
|
||||||
|
setup.AddResource(&resource);
|
||||||
|
|
||||||
|
CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
ReleaseAndWaitForDestructor(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the test harness for custom standard scheme requests.
|
||||||
|
TEST(CorsTest, BasicCustomStandardScheme) {
|
||||||
|
TestSetup setup;
|
||||||
|
Resource resource(HandlerType::CUSTOM_STANDARD_SCHEME,
|
||||||
|
"/CorsTest.BasicCustomStandardScheme");
|
||||||
|
setup.AddResource(&resource);
|
||||||
|
|
||||||
|
CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
ReleaseAndWaitForDestructor(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like above, but also send a query JS message.
|
||||||
|
TEST(CorsTest, BasicCustomStandardSchemeWithQuery) {
|
||||||
|
TestSetup setup;
|
||||||
|
Resource resource(HandlerType::CUSTOM_STANDARD_SCHEME,
|
||||||
|
"/CorsTest.BasicCustomStandardSchemeWithQuery",
|
||||||
|
kMimeTypeHtml, GetDefaultSuccessMsgHtml());
|
||||||
|
resource.expected_success_query_ct = 1;
|
||||||
|
setup.AddResource(&resource);
|
||||||
|
|
||||||
|
CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
|
||||||
|
handler->ExecuteTest();
|
||||||
|
ReleaseAndWaitForDestructor(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::string GetIframeMainHtml(const std::string& iframe_url,
|
||||||
|
const std::string& sandbox_attribs) {
|
||||||
|
return "<html><body>TEST<iframe src=\"" + iframe_url + "\" sandbox=\"" +
|
||||||
|
sandbox_attribs + "\"></iframe></body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetIframeSubHtml() {
|
||||||
|
// Try to script the parent frame, then send the SuccessMsg.
|
||||||
|
return "<html><body>TEST<script>try { parent.document.body; } catch "
|
||||||
|
"(exception) { console.log(exception.toString()); }" +
|
||||||
|
GetSuccessMsgJS() + "</script></body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasSandboxAttrib(const std::string& sandbox_attribs,
|
||||||
|
const std::string& attrib) {
|
||||||
|
return sandbox_attribs.find(attrib) != std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupIframeRequest(TestSetup* setup,
|
||||||
|
const std::string& test_name,
|
||||||
|
HandlerType main_handler,
|
||||||
|
Resource* main_resource,
|
||||||
|
HandlerType iframe_handler,
|
||||||
|
Resource* iframe_resource,
|
||||||
|
const std::string& sandbox_attribs) {
|
||||||
|
const std::string& base_path = "/" + test_name;
|
||||||
|
|
||||||
|
// Expect a single iframe request.
|
||||||
|
iframe_resource->Init(iframe_handler, base_path + ".iframe.html",
|
||||||
|
kMimeTypeHtml, GetIframeSubHtml());
|
||||||
|
|
||||||
|
// Expect a single main frame request.
|
||||||
|
const std::string& iframe_url = iframe_resource->GetPathURL();
|
||||||
|
main_resource->Init(main_handler, base_path, kMimeTypeHtml,
|
||||||
|
GetIframeMainHtml(iframe_url, sandbox_attribs));
|
||||||
|
|
||||||
|
if (HasSandboxAttrib(sandbox_attribs, "allow-scripts")) {
|
||||||
|
// Expect the iframe to load successfully and send the SuccessMsg.
|
||||||
|
iframe_resource->expected_success_query_ct = 1;
|
||||||
|
|
||||||
|
const bool has_same_origin =
|
||||||
|
HasSandboxAttrib(sandbox_attribs, "allow-same-origin");
|
||||||
|
if (!has_same_origin ||
|
||||||
|
(has_same_origin &&
|
||||||
|
(main_handler == HandlerType::CUSTOM_NONSTANDARD_SCHEME ||
|
||||||
|
main_handler != iframe_handler))) {
|
||||||
|
// Expect parent frame scripting to fail if:
|
||||||
|
// - "allow-same-origin" is not specified;
|
||||||
|
// - the main frame is a non-standard scheme (e.g. CORS disabled);
|
||||||
|
// - the main frame and iframe origins don't match.
|
||||||
|
// The reported origin will be "null" if "allow-same-origin" is not
|
||||||
|
// specified, or if the iframe is hosted on a non-standard scheme.
|
||||||
|
const std::string& origin =
|
||||||
|
!has_same_origin ||
|
||||||
|
iframe_handler == HandlerType::CUSTOM_NONSTANDARD_SCHEME
|
||||||
|
? "null"
|
||||||
|
: GetOrigin(iframe_handler);
|
||||||
|
setup->AddConsoleMessage("SecurityError: Blocked a frame with origin \"" +
|
||||||
|
origin +
|
||||||
|
"\" from accessing a cross-origin frame.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Expect JavaScript execution to fail.
|
||||||
|
setup->AddConsoleMessage("Blocked script execution in '" + iframe_url +
|
||||||
|
"' because the document's frame is sandboxed and "
|
||||||
|
"the 'allow-scripts' permission is not set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
setup->AddResource(main_resource);
|
||||||
|
setup->AddResource(iframe_resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Test iframe sandbox attributes with different origin combinations.
|
||||||
|
#define CORS_TEST_IFRAME(test_name, handler_main, handler_iframe, \
|
||||||
|
sandbox_attribs) \
|
||||||
|
TEST(CorsTest, Iframe##test_name) { \
|
||||||
|
TestSetup setup; \
|
||||||
|
Resource resource_main, resource_iframe; \
|
||||||
|
SetupIframeRequest(&setup, "CorsTest.Iframe" #test_name, \
|
||||||
|
HandlerType::handler_main, &resource_main, \
|
||||||
|
HandlerType::handler_iframe, &resource_iframe, \
|
||||||
|
sandbox_attribs); \
|
||||||
|
CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test all origin combinations (same and cross-origin).
|
||||||
|
#define CORS_TEST_IFRAME_ALL(name, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##ServerToServer, SERVER, SERVER, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##ServerToHttpScheme, SERVER, HTTP_SCHEME, \
|
||||||
|
sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##ServerToCustomStandardScheme, SERVER, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##ServerToCustomNonStandardScheme, SERVER, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##HttpSchemeToServer, HTTP_SCHEME, SERVER, \
|
||||||
|
sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##HttpSchemeToHttpScheme, HTTP_SCHEME, HTTP_SCHEME, \
|
||||||
|
sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##HttpSchemeToCustomStandardScheme, HTTP_SCHEME, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##HttpSchemeToCustomNonStandardScheme, HTTP_SCHEME, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##CustomStandardSchemeToServer, CUSTOM_STANDARD_SCHEME, \
|
||||||
|
SERVER, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##CustomStandardSchemeToHttpScheme, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, HTTP_SCHEME, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##CustomStandardSchemeToCustomStandardScheme, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, \
|
||||||
|
sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##CustomStandardSchemeToCustomNonStandardScheme, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
|
||||||
|
sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##CustomNonStandardSchemeToServer, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, SERVER, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##CustomNonStandardSchemeToHttpScheme, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, HTTP_SCHEME, sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##CustomNonStandardSchemeToCustomStandardScheme, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, \
|
||||||
|
sandbox_attribs) \
|
||||||
|
CORS_TEST_IFRAME(name##CustomNonStandardSchemeToCustomNonStandardScheme, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
|
||||||
|
sandbox_attribs)
|
||||||
|
|
||||||
|
// Everything is blocked.
|
||||||
|
CORS_TEST_IFRAME_ALL(None, "")
|
||||||
|
|
||||||
|
// JavaScript execution is allowed.
|
||||||
|
CORS_TEST_IFRAME_ALL(AllowScripts, "allow-scripts")
|
||||||
|
|
||||||
|
// JavaScript execution is allowed and scripting the parent is allowed for
|
||||||
|
// same-origin only.
|
||||||
|
CORS_TEST_IFRAME_ALL(AllowScriptsAndSameOrigin,
|
||||||
|
"allow-scripts allow-same-origin")
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct SubResource : Resource {
|
||||||
|
SubResource() {}
|
||||||
|
|
||||||
|
std::string main_origin;
|
||||||
|
bool supports_cors = false;
|
||||||
|
bool is_cross_origin = false;
|
||||||
|
|
||||||
|
void InitCors(HandlerType main_handler, bool add_header) {
|
||||||
|
// Origin is always "null" for non-standard schemes.
|
||||||
|
main_origin = main_handler == HandlerType::CUSTOM_NONSTANDARD_SCHEME
|
||||||
|
? "null"
|
||||||
|
: GetOrigin(main_handler);
|
||||||
|
|
||||||
|
// True if cross-origin requests are allowed. XHR requests to non-standard
|
||||||
|
// schemes are not allowed (due to the "null" origin).
|
||||||
|
supports_cors = handler != HandlerType::CUSTOM_NONSTANDARD_SCHEME;
|
||||||
|
if (!supports_cors) {
|
||||||
|
// Don't expect the xhr request.
|
||||||
|
expected_response_ct = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// True if the request is considered cross-origin. Any requests between
|
||||||
|
// non-standard schemes are considered cross-origin (due to the "null"
|
||||||
|
// origin).
|
||||||
|
is_cross_origin = main_handler != handler ||
|
||||||
|
(main_handler == HandlerType::CUSTOM_NONSTANDARD_SCHEME &&
|
||||||
|
handler == main_handler);
|
||||||
|
|
||||||
|
if (is_cross_origin && add_header) {
|
||||||
|
response->SetHeaderByName("Access-Control-Allow-Origin", main_origin,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VerifyRequest(CefRefPtr<CefRequest> request) const override {
|
||||||
|
// Verify that the "Origin" header contains the expected value.
|
||||||
|
const std::string& origin = request->GetHeaderByName("Origin");
|
||||||
|
if (is_cross_origin) {
|
||||||
|
EXPECT_STREQ(main_origin.c_str(), origin.c_str());
|
||||||
|
return main_origin == origin;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(origin.empty());
|
||||||
|
return origin.empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ExecMode {
|
||||||
|
XHR,
|
||||||
|
FETCH,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string GetXhrExecJS(const std::string& sub_url) {
|
||||||
|
return "xhr = new XMLHttpRequest();\n"
|
||||||
|
"xhr.open(\"GET\", \"" +
|
||||||
|
sub_url +
|
||||||
|
"\", true)\n;"
|
||||||
|
"xhr.onload = function(e) {\n"
|
||||||
|
" if (xhr.readyState === 4) {\n"
|
||||||
|
" if (xhr.status === 200) {\n"
|
||||||
|
" onResult(xhr.responseText);\n"
|
||||||
|
" } else {\n"
|
||||||
|
" console.log('XMLHttpRequest failed with status ' + "
|
||||||
|
"xhr.status);\n"
|
||||||
|
" onResult('FAILURE');\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
"};\n"
|
||||||
|
"xhr.onerror = function(e) {\n"
|
||||||
|
" onResult('FAILURE');\n"
|
||||||
|
"};\n"
|
||||||
|
"xhr.send();\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetFetchExecJS(const std::string& sub_url) {
|
||||||
|
return "fetch('" + sub_url +
|
||||||
|
"')\n"
|
||||||
|
".then(function(response) {\n"
|
||||||
|
" if (response.status === 200) {\n"
|
||||||
|
" response.text().then(function(text) {\n"
|
||||||
|
" onResult(text);\n"
|
||||||
|
" }).catch(function(e) {\n"
|
||||||
|
" onResult('FAILURE')\n; "
|
||||||
|
" })\n;"
|
||||||
|
" } else {\n"
|
||||||
|
" onResult('FAILURE');\n"
|
||||||
|
" }\n"
|
||||||
|
"}).catch(function(e) {\n"
|
||||||
|
" onResult('FAILURE');\n"
|
||||||
|
"});\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetExecMainHtml(ExecMode mode, const std::string& sub_url) {
|
||||||
|
return std::string() +
|
||||||
|
"<html><head>\n"
|
||||||
|
"<script language=\"JavaScript\">\n" +
|
||||||
|
"function onResult(val) {\n"
|
||||||
|
" if (val === '" +
|
||||||
|
kDefaultText + "') {" + GetSuccessMsgJS() + "} else {" +
|
||||||
|
GetFailureMsgJS() +
|
||||||
|
"}\n}\n"
|
||||||
|
"function execRequest() {\n" +
|
||||||
|
(mode == ExecMode::XHR ? GetXhrExecJS(sub_url)
|
||||||
|
: GetFetchExecJS(sub_url)) +
|
||||||
|
"}\n</script>\n"
|
||||||
|
"</head><body onload=\"execRequest();\">"
|
||||||
|
"Running execRequest..."
|
||||||
|
"</body></html>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// XHR and fetch requests behave the same, except for console message contents.
|
||||||
|
void SetupExecRequest(ExecMode mode,
|
||||||
|
TestSetup* setup,
|
||||||
|
const std::string& test_name,
|
||||||
|
HandlerType main_handler,
|
||||||
|
Resource* main_resource,
|
||||||
|
HandlerType sub_handler,
|
||||||
|
SubResource* sub_resource,
|
||||||
|
bool add_header) {
|
||||||
|
const std::string& base_path = "/" + test_name;
|
||||||
|
|
||||||
|
// Expect a single xhr request.
|
||||||
|
sub_resource->Init(sub_handler, base_path + ".sub.txt", kMimeTypeText,
|
||||||
|
kDefaultText);
|
||||||
|
sub_resource->InitCors(main_handler, add_header);
|
||||||
|
|
||||||
|
// Expect a single main frame request.
|
||||||
|
const std::string& sub_url = sub_resource->GetPathURL();
|
||||||
|
main_resource->Init(main_handler, base_path, kMimeTypeHtml,
|
||||||
|
GetExecMainHtml(mode, sub_url));
|
||||||
|
|
||||||
|
if (sub_resource->is_cross_origin &&
|
||||||
|
(!sub_resource->supports_cors || !add_header)) {
|
||||||
|
// Expect the cross-origin XHR to be blocked.
|
||||||
|
main_resource->expected_failure_query_ct = 1;
|
||||||
|
|
||||||
|
if (sub_resource->supports_cors && !add_header) {
|
||||||
|
// The request supports CORS, but we didn't add the header.
|
||||||
|
if (mode == ExecMode::XHR) {
|
||||||
|
setup->AddConsoleMessage(
|
||||||
|
"Access to XMLHttpRequest at '" + sub_url + "' from origin '" +
|
||||||
|
sub_resource->main_origin +
|
||||||
|
"' has been blocked by CORS policy: No "
|
||||||
|
"'Access-Control-Allow-Origin' "
|
||||||
|
"header is present on the requested resource.");
|
||||||
|
} else {
|
||||||
|
setup->AddConsoleMessage(
|
||||||
|
"Access to fetch at '" + sub_url + "' from origin '" +
|
||||||
|
sub_resource->main_origin +
|
||||||
|
"' has been blocked by CORS policy: No "
|
||||||
|
"'Access-Control-Allow-Origin' header is present on the requested "
|
||||||
|
"resource. If an opaque response serves your needs, set the "
|
||||||
|
"request's mode to 'no-cors' to fetch the resource with CORS "
|
||||||
|
"disabled.");
|
||||||
|
}
|
||||||
|
} else if (mode == ExecMode::XHR) {
|
||||||
|
setup->AddConsoleMessage(
|
||||||
|
"Access to XMLHttpRequest at '" + sub_url + "' from origin '" +
|
||||||
|
sub_resource->main_origin +
|
||||||
|
"' has been blocked by CORS policy: Cross origin requests are only "
|
||||||
|
"supported for protocol schemes:");
|
||||||
|
} else {
|
||||||
|
setup->AddConsoleMessage(
|
||||||
|
"Fetch API cannot load " + sub_url +
|
||||||
|
". URL scheme must be \"http\" or \"https\" for CORS request.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Expect the (possibly cross-origin) XHR to be allowed.
|
||||||
|
main_resource->expected_success_query_ct = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup->AddResource(main_resource);
|
||||||
|
setup->AddResource(sub_resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Test XHR requests with different origin combinations.
|
||||||
|
#define CORS_TEST_XHR(test_name, handler_main, handler_sub, add_header) \
|
||||||
|
TEST(CorsTest, Xhr##test_name) { \
|
||||||
|
TestSetup setup; \
|
||||||
|
Resource resource_main; \
|
||||||
|
SubResource resource_sub; \
|
||||||
|
SetupExecRequest(ExecMode::XHR, &setup, "CorsTest.Xhr" #test_name, \
|
||||||
|
HandlerType::handler_main, &resource_main, \
|
||||||
|
HandlerType::handler_sub, &resource_sub, add_header); \
|
||||||
|
CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test all origin combinations (same and cross-origin).
|
||||||
|
#define CORS_TEST_XHR_ALL(name, add_header) \
|
||||||
|
CORS_TEST_XHR(name##ServerToServer, SERVER, SERVER, add_header) \
|
||||||
|
CORS_TEST_XHR(name##ServerToHttpScheme, SERVER, HTTP_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##ServerToCustomStandardScheme, SERVER, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##ServerToCustomNonStandardScheme, SERVER, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##HttpSchemeToServer, HTTP_SCHEME, SERVER, add_header) \
|
||||||
|
CORS_TEST_XHR(name##HttpSchemeToHttpScheme, HTTP_SCHEME, HTTP_SCHEME, \
|
||||||
|
add_header) \
|
||||||
|
CORS_TEST_XHR(name##HttpSchemeToCustomStandardScheme, HTTP_SCHEME, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##HttpSchemeToCustomNonStandardScheme, HTTP_SCHEME, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##CustomStandardSchemeToServer, CUSTOM_STANDARD_SCHEME, \
|
||||||
|
SERVER, add_header) \
|
||||||
|
CORS_TEST_XHR(name##CustomStandardSchemeToHttpScheme, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, HTTP_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##CustomStandardSchemeToCustomStandardScheme, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##CustomStandardSchemeToCustomNonStandardScheme, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##CustomNonStandardSchemeToServer, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, SERVER, add_header) \
|
||||||
|
CORS_TEST_XHR(name##CustomNonStandardSchemeToHttpScheme, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, HTTP_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##CustomNonStandardSchemeToCustomStandardScheme, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_XHR(name##CustomNonStandardSchemeToCustomNonStandardScheme, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
|
||||||
|
add_header)
|
||||||
|
|
||||||
|
// XHR requests without the "Access-Control-Allow-Origin" header.
|
||||||
|
CORS_TEST_XHR_ALL(NoHeader, false)
|
||||||
|
|
||||||
|
// XHR requests with the "Access-Control-Allow-Origin" header.
|
||||||
|
CORS_TEST_XHR_ALL(WithHeader, true)
|
||||||
|
|
||||||
|
// Test fetch requests with different origin combinations.
|
||||||
|
#define CORS_TEST_FETCH(test_name, handler_main, handler_sub, add_header) \
|
||||||
|
TEST(CorsTest, Fetch##test_name) { \
|
||||||
|
TestSetup setup; \
|
||||||
|
Resource resource_main; \
|
||||||
|
SubResource resource_sub; \
|
||||||
|
SetupExecRequest(ExecMode::FETCH, &setup, "CorsTest.Fetch" #test_name, \
|
||||||
|
HandlerType::handler_main, &resource_main, \
|
||||||
|
HandlerType::handler_sub, &resource_sub, add_header); \
|
||||||
|
CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
|
||||||
|
handler->ExecuteTest(); \
|
||||||
|
ReleaseAndWaitForDestructor(handler); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test all origin combinations (same and cross-origin).
|
||||||
|
#define CORS_TEST_FETCH_ALL(name, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##ServerToServer, SERVER, SERVER, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##ServerToHttpScheme, SERVER, HTTP_SCHEME, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##ServerToCustomStandardScheme, SERVER, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##ServerToCustomNonStandardScheme, SERVER, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##HttpSchemeToServer, HTTP_SCHEME, SERVER, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##HttpSchemeToHttpScheme, HTTP_SCHEME, HTTP_SCHEME, \
|
||||||
|
add_header) \
|
||||||
|
CORS_TEST_FETCH(name##HttpSchemeToCustomStandardScheme, HTTP_SCHEME, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##HttpSchemeToCustomNonStandardScheme, HTTP_SCHEME, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##CustomStandardSchemeToServer, CUSTOM_STANDARD_SCHEME, \
|
||||||
|
SERVER, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##CustomStandardSchemeToHttpScheme, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, HTTP_SCHEME, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##CustomStandardSchemeToCustomStandardScheme, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##CustomStandardSchemeToCustomNonStandardScheme, \
|
||||||
|
CUSTOM_STANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
|
||||||
|
add_header) \
|
||||||
|
CORS_TEST_FETCH(name##CustomNonStandardSchemeToServer, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, SERVER, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##CustomNonStandardSchemeToHttpScheme, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, HTTP_SCHEME, add_header) \
|
||||||
|
CORS_TEST_FETCH(name##CustomNonStandardSchemeToCustomStandardScheme, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, \
|
||||||
|
add_header) \
|
||||||
|
CORS_TEST_FETCH(name##CustomNonStandardSchemeToCustomNonStandardScheme, \
|
||||||
|
CUSTOM_NONSTANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
|
||||||
|
add_header)
|
||||||
|
|
||||||
|
// Fetch requests without the "Access-Control-Allow-Origin" header.
|
||||||
|
CORS_TEST_FETCH_ALL(NoHeader, false)
|
||||||
|
|
||||||
|
// Fetch requests with the "Access-Control-Allow-Origin" header.
|
||||||
|
CORS_TEST_FETCH_ALL(WithHeader, true)
|
@@ -3,6 +3,7 @@
|
|||||||
// can be found in the LICENSE file.
|
// can be found in the LICENSE file.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "include/base/cef_bind.h"
|
#include "include/base/cef_bind.h"
|
||||||
#include "include/cef_callback.h"
|
#include "include/cef_callback.h"
|
||||||
@@ -32,6 +33,7 @@ class TestResults {
|
|||||||
sub_allow_origin.clear();
|
sub_allow_origin.clear();
|
||||||
exit_url.clear();
|
exit_url.clear();
|
||||||
accept_language.clear();
|
accept_language.clear();
|
||||||
|
console_messages.clear();
|
||||||
delay = 0;
|
delay = 0;
|
||||||
got_request.reset();
|
got_request.reset();
|
||||||
got_read.reset();
|
got_read.reset();
|
||||||
@@ -69,6 +71,9 @@ class TestResults {
|
|||||||
// Used for testing per-browser Accept-Language.
|
// Used for testing per-browser Accept-Language.
|
||||||
std::string accept_language;
|
std::string accept_language;
|
||||||
|
|
||||||
|
// Used for testing received console messages.
|
||||||
|
std::vector<std::string> console_messages;
|
||||||
|
|
||||||
// Delay for returning scheme handler results.
|
// Delay for returning scheme handler results.
|
||||||
int delay;
|
int delay;
|
||||||
|
|
||||||
@@ -104,7 +109,13 @@ class TestSchemeHandler : public TestHandler {
|
|||||||
|
|
||||||
// Necessary to make the method public in order to destroy the test from
|
// Necessary to make the method public in order to destroy the test from
|
||||||
// ClientSchemeHandler::ProcessRequest().
|
// ClientSchemeHandler::ProcessRequest().
|
||||||
void DestroyTest() override { TestHandler::DestroyTest(); }
|
void DestroyTest() override {
|
||||||
|
EXPECT_TRUE(test_results_->console_messages.empty())
|
||||||
|
<< "Did not receive expected console message: "
|
||||||
|
<< test_results_->console_messages.front();
|
||||||
|
|
||||||
|
TestHandler::DestroyTest();
|
||||||
|
}
|
||||||
|
|
||||||
void DestroyTestIfDone() {
|
void DestroyTestIfDone() {
|
||||||
if (!test_results_->exit_url.empty() && !test_results_->got_exit_request) {
|
if (!test_results_->exit_url.empty() && !test_results_->got_exit_request) {
|
||||||
@@ -206,6 +217,31 @@ class TestSchemeHandler : public TestHandler {
|
|||||||
DestroyTestIfDone();
|
DestroyTestIfDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
|
||||||
|
cef_log_severity_t level,
|
||||||
|
const CefString& message,
|
||||||
|
const CefString& source,
|
||||||
|
int line) override {
|
||||||
|
bool expected = false;
|
||||||
|
if (!test_results_->console_messages.empty()) {
|
||||||
|
std::vector<std::string>::iterator it =
|
||||||
|
test_results_->console_messages.begin();
|
||||||
|
for (; it != test_results_->console_messages.end(); ++it) {
|
||||||
|
const std::string& possible = *it;
|
||||||
|
const std::string& actual = message.ToString();
|
||||||
|
if (actual.find(possible) == 0U) {
|
||||||
|
expected = true;
|
||||||
|
test_results_->console_messages.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(expected) << "Unexpected console message: "
|
||||||
|
<< message.ToString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TestResults* test_results_;
|
TestResults* test_results_;
|
||||||
|
|
||||||
@@ -635,6 +671,11 @@ void SetUpXHR(const XHRTestSettings& settings) {
|
|||||||
g_TestResults.sub_allow_origin = settings.sub_allow_origin;
|
g_TestResults.sub_allow_origin = settings.sub_allow_origin;
|
||||||
g_TestResults.sub_redirect_url = settings.sub_redirect_url;
|
g_TestResults.sub_redirect_url = settings.sub_redirect_url;
|
||||||
|
|
||||||
|
if (settings.synchronous) {
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Synchronous XMLHttpRequest on the main thread is deprecated");
|
||||||
|
}
|
||||||
|
|
||||||
std::string request_url;
|
std::string request_url;
|
||||||
if (!settings.sub_redirect_url.empty())
|
if (!settings.sub_redirect_url.empty())
|
||||||
request_url = settings.sub_redirect_url;
|
request_url = settings.sub_redirect_url;
|
||||||
@@ -677,7 +718,6 @@ void SetUpXHR(const XHRTestSettings& settings) {
|
|||||||
" }"
|
" }"
|
||||||
"};"
|
"};"
|
||||||
"xhr.onerror = function(e) {"
|
"xhr.onerror = function(e) {"
|
||||||
" console.log('XMLHttpRequest failed with error ' + e);"
|
|
||||||
" onResult('FAILURE');"
|
" onResult('FAILURE');"
|
||||||
"};"
|
"};"
|
||||||
"xhr.send()";
|
"xhr.send()";
|
||||||
@@ -728,16 +768,12 @@ void SetUpFetch(const FetchTestSettings& settings) {
|
|||||||
" response.text().then(function(text) {"
|
" response.text().then(function(text) {"
|
||||||
" onResult(text);"
|
" onResult(text);"
|
||||||
" }).catch(function(e) {"
|
" }).catch(function(e) {"
|
||||||
" console.log('FetchHttpRequest failed with error ' + e);"
|
|
||||||
" onResult('FAILURE'); "
|
" onResult('FAILURE'); "
|
||||||
" });"
|
" });"
|
||||||
" } else {"
|
" } else {"
|
||||||
" console.log('XMLHttpRequest failed with status ' + "
|
|
||||||
" response.status);"
|
|
||||||
" onResult('FAILURE');"
|
" onResult('FAILURE');"
|
||||||
" }"
|
" }"
|
||||||
"}).catch(function(e) {"
|
"}).catch(function(e) {"
|
||||||
" console.log('FetchHttpRequest failed with error ' + e);"
|
|
||||||
" onResult('FAILURE');"
|
" onResult('FAILURE');"
|
||||||
"});"
|
"});"
|
||||||
<< "}"
|
<< "}"
|
||||||
@@ -1154,6 +1190,11 @@ TEST(SchemeHandlerTest, CustomNonStandardXHRSameOriginSync) {
|
|||||||
settings.sub_url = "customnonstd:xhr%20value";
|
settings.sub_url = "customnonstd:xhr%20value";
|
||||||
SetUpXHR(settings);
|
SetUpXHR(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to XMLHttpRequest at 'customnonstd:xhr%20value' from origin "
|
||||||
|
"'null' has been blocked by CORS policy: Cross origin requests are only "
|
||||||
|
"supported for protocol schemes:");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1179,6 +1220,11 @@ TEST(SchemeHandlerTest, CustomNonStandardXHRSameOriginAsync) {
|
|||||||
settings.synchronous = false;
|
settings.synchronous = false;
|
||||||
SetUpXHR(settings);
|
SetUpXHR(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to XMLHttpRequest at 'customnonstd:xhr%20value' from origin "
|
||||||
|
"'null' has been blocked by CORS policy: Cross origin requests are only "
|
||||||
|
"supported for protocol schemes:");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1203,6 +1249,10 @@ TEST(SchemeHandlerTest, CustomStandardFetchSameOrigin) {
|
|||||||
settings.sub_url = "customstd://test/fetch.html";
|
settings.sub_url = "customstd://test/fetch.html";
|
||||||
SetUpFetch(settings);
|
SetUpFetch(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Fetch API cannot load customstd://test/fetch.html. URL scheme "
|
||||||
|
"\"customstd\" is not supported.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1251,6 +1301,10 @@ TEST(SchemeHandlerTest, CustomNonStandardFetchSameOrigin) {
|
|||||||
settings.sub_url = "customnonstd:xhr%20value";
|
settings.sub_url = "customnonstd:xhr%20value";
|
||||||
SetUpFetch(settings);
|
SetUpFetch(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Fetch API cannot load customnonstd:xhr%20value. URL scheme must be "
|
||||||
|
"\"http\" or \"https\" for CORS request.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1290,6 +1344,10 @@ TEST(SchemeHandlerTest, CustomNonStandardXSSSameOrigin) {
|
|||||||
RegisterTestScheme("customnonstd", std::string());
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
SetUpXSS("customnonstd:some%20value", "customnonstd:xhr%20value");
|
SetUpXSS("customnonstd:some%20value", "customnonstd:xhr%20value");
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Error: Blocked a frame with origin \"null\" from accessing a "
|
||||||
|
"cross-origin frame.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1315,6 +1373,12 @@ TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginSync) {
|
|||||||
settings.sub_url = "customstd://test2/xhr.html";
|
settings.sub_url = "customstd://test2/xhr.html";
|
||||||
SetUpXHR(settings);
|
SetUpXHR(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to XMLHttpRequest at 'customstd://test2/xhr.html' from origin "
|
||||||
|
"'customstd://test1' has been blocked by CORS policy: No "
|
||||||
|
"'Access-Control-Allow-Origin' header is present on the requested "
|
||||||
|
"resource.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1323,7 +1387,11 @@ TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginSync) {
|
|||||||
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_sub_request);
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_read);
|
if (!IsOutOfBlinkCorsEnabled()) {
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
}
|
||||||
EXPECT_FALSE(g_TestResults.got_sub_success);
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
ClearTestSchemes();
|
ClearTestSchemes();
|
||||||
@@ -1341,6 +1409,12 @@ TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginAsync) {
|
|||||||
settings.synchronous = false;
|
settings.synchronous = false;
|
||||||
SetUpXHR(settings);
|
SetUpXHR(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to XMLHttpRequest at 'customstd://test2/xhr.html' from origin "
|
||||||
|
"'customstd://test1' has been blocked by CORS policy: No "
|
||||||
|
"'Access-Control-Allow-Origin' header is present on the requested "
|
||||||
|
"resource.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1349,7 +1423,11 @@ TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginAsync) {
|
|||||||
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_sub_request);
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_read);
|
if (!IsOutOfBlinkCorsEnabled()) {
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
}
|
||||||
EXPECT_FALSE(g_TestResults.got_sub_success);
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
ClearTestSchemes();
|
ClearTestSchemes();
|
||||||
@@ -1366,6 +1444,13 @@ TEST(SchemeHandlerTest, CustomStandardFetchDifferentOrigin) {
|
|||||||
settings.sub_url = "customstdfetch://test2/fetch.html";
|
settings.sub_url = "customstdfetch://test2/fetch.html";
|
||||||
SetUpFetch(settings);
|
SetUpFetch(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to fetch at 'customstdfetch://test2/fetch.html' from origin "
|
||||||
|
"'customstdfetch://test1' has been blocked by CORS policy: No "
|
||||||
|
"'Access-Control-Allow-Origin' header is present on the requested "
|
||||||
|
"resource. If an opaque response serves your needs, set the request's "
|
||||||
|
"mode to 'no-cors' to fetch the resource with CORS disabled.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1374,7 +1459,11 @@ TEST(SchemeHandlerTest, CustomStandardFetchDifferentOrigin) {
|
|||||||
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_sub_request);
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_read);
|
if (!IsOutOfBlinkCorsEnabled()) {
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
}
|
||||||
EXPECT_FALSE(g_TestResults.got_sub_success);
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
ClearTestSchemes();
|
ClearTestSchemes();
|
||||||
@@ -1387,6 +1476,10 @@ TEST(SchemeHandlerTest, CustomStandardXSSDifferentOrigin) {
|
|||||||
RegisterTestScheme("customstd", "test2");
|
RegisterTestScheme("customstd", "test2");
|
||||||
SetUpXSS("customstd://test1/run.html", "customstd://test2/iframe.html");
|
SetUpXSS("customstd://test1/run.html", "customstd://test2/iframe.html");
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Error: Blocked a frame with origin \"customstd://test2\" from accessing "
|
||||||
|
"a cross-origin frame.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1408,6 +1501,10 @@ TEST(SchemeHandlerTest, CustomStandardXSSDifferentProtocolHttp) {
|
|||||||
RegisterTestScheme("http", "test2");
|
RegisterTestScheme("http", "test2");
|
||||||
SetUpXSS("customstd://test1/run.html", "http://test2/iframe.html");
|
SetUpXSS("customstd://test1/run.html", "http://test2/iframe.html");
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Error: Blocked a frame with origin \"http://test2\" from accessing a "
|
||||||
|
"cross-origin frame.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1430,6 +1527,10 @@ TEST(SchemeHandlerTest, CustomStandardXSSDifferentProtocolCustomNonStandard) {
|
|||||||
RegisterTestScheme("customnonstd", std::string());
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
SetUpXSS("customstd://test1/run.html", "customnonstd:some%20value");
|
SetUpXSS("customstd://test1/run.html", "customnonstd:some%20value");
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Error: Blocked a frame with origin \"null\" from accessing a "
|
||||||
|
"cross-origin frame.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1451,6 +1552,10 @@ TEST(SchemeHandlerTest, HttpXSSDifferentProtocolCustomStandard) {
|
|||||||
RegisterTestScheme("customstd", "test2");
|
RegisterTestScheme("customstd", "test2");
|
||||||
SetUpXSS("http://test1/run.html", "customstd://test2/iframe.html");
|
SetUpXSS("http://test1/run.html", "customstd://test2/iframe.html");
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Error: Blocked a frame with origin \"customstd://test2\" from accessing "
|
||||||
|
"a cross-origin frame.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1472,6 +1577,10 @@ TEST(SchemeHandlerTest, HttpXSSDifferentProtocolCustomNonStandard) {
|
|||||||
RegisterTestScheme("customnonstd", std::string());
|
RegisterTestScheme("customnonstd", std::string());
|
||||||
SetUpXSS("http://test1/run.html", "customnonstd:some%20value");
|
SetUpXSS("http://test1/run.html", "customnonstd:some%20value");
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Error: Blocked a frame with origin \"null\" from accessing a "
|
||||||
|
"cross-origin frame.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1497,6 +1606,12 @@ TEST(SchemeHandlerTest, HttpXHRDifferentOriginSync) {
|
|||||||
settings.sub_url = "http://test2/xhr.html";
|
settings.sub_url = "http://test2/xhr.html";
|
||||||
SetUpXHR(settings);
|
SetUpXHR(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to XMLHttpRequest at 'http://test2/xhr.html' from origin "
|
||||||
|
"'http://test1' has been blocked by CORS policy: No "
|
||||||
|
"'Access-Control-Allow-Origin' header is present on the requested "
|
||||||
|
"resource.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1505,7 +1620,11 @@ TEST(SchemeHandlerTest, HttpXHRDifferentOriginSync) {
|
|||||||
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_sub_request);
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_read);
|
if (!IsOutOfBlinkCorsEnabled()) {
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
}
|
||||||
EXPECT_FALSE(g_TestResults.got_sub_success);
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
ClearTestSchemes();
|
ClearTestSchemes();
|
||||||
@@ -1523,6 +1642,12 @@ TEST(SchemeHandlerTest, HttpXHRDifferentOriginAsync) {
|
|||||||
settings.synchronous = false;
|
settings.synchronous = false;
|
||||||
SetUpXHR(settings);
|
SetUpXHR(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to XMLHttpRequest at 'http://test2/xhr.html' from origin "
|
||||||
|
"'http://test1' has been blocked by CORS policy: No "
|
||||||
|
"'Access-Control-Allow-Origin' header is present on the requested "
|
||||||
|
"resource.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1531,7 +1656,11 @@ TEST(SchemeHandlerTest, HttpXHRDifferentOriginAsync) {
|
|||||||
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_sub_request);
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_read);
|
if (!IsOutOfBlinkCorsEnabled()) {
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
}
|
||||||
EXPECT_FALSE(g_TestResults.got_sub_success);
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
ClearTestSchemes();
|
ClearTestSchemes();
|
||||||
@@ -1548,6 +1677,13 @@ TEST(SchemeHandlerTest, HttpFetchDifferentOriginAsync) {
|
|||||||
settings.sub_url = "http://test2/fetch.html";
|
settings.sub_url = "http://test2/fetch.html";
|
||||||
SetUpFetch(settings);
|
SetUpFetch(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to fetch at 'http://test2/fetch.html' from origin 'http://test1' "
|
||||||
|
"has been blocked by CORS policy: No 'Access-Control-Allow-Origin' "
|
||||||
|
"header is present on the requested resource. If an opaque response "
|
||||||
|
"serves your needs, set the request's mode to 'no-cors' to fetch the "
|
||||||
|
"resource with CORS disabled.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -1556,7 +1692,11 @@ TEST(SchemeHandlerTest, HttpFetchDifferentOriginAsync) {
|
|||||||
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_sub_request);
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_read);
|
if (!IsOutOfBlinkCorsEnabled()) {
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
}
|
||||||
EXPECT_FALSE(g_TestResults.got_sub_success);
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
ClearTestSchemes();
|
ClearTestSchemes();
|
||||||
@@ -1569,6 +1709,10 @@ TEST(SchemeHandlerTest, HttpXSSDifferentOrigin) {
|
|||||||
RegisterTestScheme("http", "test2");
|
RegisterTestScheme("http", "test2");
|
||||||
SetUpXSS("http://test1/run.html", "http://test2/xss.html");
|
SetUpXSS("http://test1/run.html", "http://test2/xss.html");
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Error: Blocked a frame with origin \"http://test2\" from accessing a "
|
||||||
|
"cross-origin frame.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -2085,6 +2229,12 @@ TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginRedirectSync) {
|
|||||||
settings.sub_redirect_url = "customstd://test1/xhr.html";
|
settings.sub_redirect_url = "customstd://test1/xhr.html";
|
||||||
SetUpXHR(settings);
|
SetUpXHR(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to XMLHttpRequest at 'customstd://test2/xhr.html' (redirected "
|
||||||
|
"from 'customstd://test1/xhr.html') from origin 'customstd://test1' has "
|
||||||
|
"been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is "
|
||||||
|
"present on the requested resource.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -2094,7 +2244,11 @@ TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginRedirectSync) {
|
|||||||
EXPECT_TRUE(g_TestResults.got_output);
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_redirect);
|
EXPECT_TRUE(g_TestResults.got_sub_redirect);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_request);
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_read);
|
if (!IsOutOfBlinkCorsEnabled()) {
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
}
|
||||||
EXPECT_FALSE(g_TestResults.got_sub_success);
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
ClearTestSchemes();
|
ClearTestSchemes();
|
||||||
@@ -2113,6 +2267,12 @@ TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginRedirectAsync) {
|
|||||||
settings.synchronous = false;
|
settings.synchronous = false;
|
||||||
SetUpXHR(settings);
|
SetUpXHR(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to XMLHttpRequest at 'customstd://test2/xhr.html' (redirected "
|
||||||
|
"from 'customstd://test1/xhr.html') from origin 'customstd://test1' has "
|
||||||
|
"been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is "
|
||||||
|
"present on the requested resource.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -2122,7 +2282,11 @@ TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginRedirectAsync) {
|
|||||||
EXPECT_TRUE(g_TestResults.got_output);
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_redirect);
|
EXPECT_TRUE(g_TestResults.got_sub_redirect);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_request);
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_read);
|
if (!IsOutOfBlinkCorsEnabled()) {
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
}
|
||||||
EXPECT_FALSE(g_TestResults.got_sub_success);
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
ClearTestSchemes();
|
ClearTestSchemes();
|
||||||
@@ -2140,6 +2304,14 @@ TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginRedirect) {
|
|||||||
settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
|
settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
|
||||||
SetUpFetch(settings);
|
SetUpFetch(settings);
|
||||||
|
|
||||||
|
g_TestResults.console_messages.push_back(
|
||||||
|
"Access to fetch at 'customstdfetch://test2/fetch.html' (redirected from "
|
||||||
|
"'customstdfetch://test1/fetch.html') from origin "
|
||||||
|
"'customstdfetch://test1' has been blocked by CORS policy: No "
|
||||||
|
"'Access-Control-Allow-Origin' header is present on the requested "
|
||||||
|
"resource. If an opaque response serves your needs, set the request's "
|
||||||
|
"mode to 'no-cors' to fetch the resource with CORS disabled.");
|
||||||
|
|
||||||
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
|
||||||
handler->ExecuteTest();
|
handler->ExecuteTest();
|
||||||
ReleaseAndWaitForDestructor(handler);
|
ReleaseAndWaitForDestructor(handler);
|
||||||
@@ -2149,7 +2321,11 @@ TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginRedirect) {
|
|||||||
EXPECT_TRUE(g_TestResults.got_output);
|
EXPECT_TRUE(g_TestResults.got_output);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_redirect);
|
EXPECT_TRUE(g_TestResults.got_sub_redirect);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_request);
|
EXPECT_TRUE(g_TestResults.got_sub_request);
|
||||||
EXPECT_TRUE(g_TestResults.got_sub_read);
|
if (!IsOutOfBlinkCorsEnabled()) {
|
||||||
|
EXPECT_TRUE(g_TestResults.got_sub_read);
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(g_TestResults.got_sub_read);
|
||||||
|
}
|
||||||
EXPECT_FALSE(g_TestResults.got_sub_success);
|
EXPECT_FALSE(g_TestResults.got_sub_success);
|
||||||
|
|
||||||
ClearTestSchemes();
|
ClearTestSchemes();
|
||||||
@@ -2429,6 +2605,7 @@ void RegisterSchemeHandlerCustomSchemes(
|
|||||||
// Add a custom standard scheme.
|
// Add a custom standard scheme.
|
||||||
registrar->AddCustomScheme(
|
registrar->AddCustomScheme(
|
||||||
"customstd", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED);
|
"customstd", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED);
|
||||||
|
// Also used in cors_unittest.cc.
|
||||||
registrar->AddCustomScheme("customstdfetch",
|
registrar->AddCustomScheme("customstdfetch",
|
||||||
CEF_SCHEME_OPTION_STANDARD |
|
CEF_SCHEME_OPTION_STANDARD |
|
||||||
CEF_SCHEME_OPTION_CORS_ENABLED |
|
CEF_SCHEME_OPTION_CORS_ENABLED |
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#include "include/cef_stream.h"
|
#include "include/cef_stream.h"
|
||||||
#include "include/wrapper/cef_closure_task.h"
|
#include "include/wrapper/cef_closure_task.h"
|
||||||
#include "include/wrapper/cef_stream_resource_handler.h"
|
#include "include/wrapper/cef_stream_resource_handler.h"
|
||||||
|
#include "tests/ceftests/test_request.h"
|
||||||
#include "tests/shared/common/client_switches.h"
|
#include "tests/shared/common/client_switches.h"
|
||||||
|
|
||||||
#if defined(USE_AURA)
|
#if defined(USE_AURA)
|
||||||
@@ -261,15 +262,8 @@ CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
|
|||||||
EXPECT_IO_THREAD();
|
EXPECT_IO_THREAD();
|
||||||
|
|
||||||
if (resource_map_.size() > 0) {
|
if (resource_map_.size() > 0) {
|
||||||
CefString url = request->GetURL();
|
const std::string& url = test_request::GetPathURL(request->GetURL());
|
||||||
|
ResourceMap::const_iterator it = resource_map_.find(url);
|
||||||
// Ignore the query component, if any.
|
|
||||||
std::string urlStr = url;
|
|
||||||
size_t idx = urlStr.find('?');
|
|
||||||
if (idx > 0)
|
|
||||||
urlStr = urlStr.substr(0, idx);
|
|
||||||
|
|
||||||
ResourceMap::const_iterator it = resource_map_.find(urlStr);
|
|
||||||
if (it != resource_map_.end()) {
|
if (it != resource_map_.end()) {
|
||||||
// Return the previously mapped resource
|
// Return the previously mapped resource
|
||||||
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
|
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
|
||||||
|
@@ -4,9 +4,13 @@
|
|||||||
|
|
||||||
#include "tests/ceftests/test_request.h"
|
#include "tests/ceftests/test_request.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "include/cef_stream.h"
|
||||||
#include "include/cef_urlrequest.h"
|
#include "include/cef_urlrequest.h"
|
||||||
#include "include/wrapper/cef_closure_task.h"
|
#include "include/wrapper/cef_closure_task.h"
|
||||||
#include "include/wrapper/cef_helpers.h"
|
#include "include/wrapper/cef_helpers.h"
|
||||||
|
#include "include/wrapper/cef_stream_resource_handler.h"
|
||||||
|
|
||||||
namespace test_request {
|
namespace test_request {
|
||||||
|
|
||||||
@@ -106,4 +110,39 @@ void Send(const SendConfig& config, const RequestDoneCallback& callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetPathURL(const std::string& url) {
|
||||||
|
const size_t index1 = url.find('?');
|
||||||
|
const size_t index2 = url.find('#');
|
||||||
|
size_t index = -1;
|
||||||
|
if (index1 >= 0 && index2 >= 0) {
|
||||||
|
index = std::min(index1, index2);
|
||||||
|
} else if (index1 >= 0) {
|
||||||
|
index = index1;
|
||||||
|
} else if (index2 >= 0) {
|
||||||
|
index = index2;
|
||||||
|
}
|
||||||
|
if (index >= 0) {
|
||||||
|
return url.substr(0, index);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
CefRefPtr<CefResourceHandler> CreateResourceHandler(
|
||||||
|
CefRefPtr<CefResponse> response,
|
||||||
|
const std::string& response_data) {
|
||||||
|
CefRefPtr<CefStreamReader> stream;
|
||||||
|
if (!response_data.empty()) {
|
||||||
|
stream = CefStreamReader::CreateForData(
|
||||||
|
static_cast<void*>(const_cast<char*>(response_data.c_str())),
|
||||||
|
response_data.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
CefResponse::HeaderMap headerMap;
|
||||||
|
response->GetHeaderMap(headerMap);
|
||||||
|
|
||||||
|
return new CefStreamResourceHandler(
|
||||||
|
response->GetStatus(), response->GetStatusText(), response->GetMimeType(),
|
||||||
|
headerMap, stream);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace test_request
|
} // namespace test_request
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#include "include/cef_frame.h"
|
#include "include/cef_frame.h"
|
||||||
#include "include/cef_request.h"
|
#include "include/cef_request.h"
|
||||||
#include "include/cef_request_context.h"
|
#include "include/cef_request_context.h"
|
||||||
|
#include "include/cef_resource_handler.h"
|
||||||
#include "include/cef_response.h"
|
#include "include/cef_response.h"
|
||||||
|
|
||||||
namespace test_request {
|
namespace test_request {
|
||||||
@@ -64,6 +65,14 @@ struct SendConfig {
|
|||||||
// request completes.
|
// request completes.
|
||||||
void Send(const SendConfig& config, const RequestDoneCallback& callback);
|
void Send(const SendConfig& config, const RequestDoneCallback& callback);
|
||||||
|
|
||||||
|
// Removes query and/or fragment components from |url|.
|
||||||
|
std::string GetPathURL(const std::string& url);
|
||||||
|
|
||||||
|
// Creates a new resource handler that returns the specified response.
|
||||||
|
CefRefPtr<CefResourceHandler> CreateResourceHandler(
|
||||||
|
CefRefPtr<CefResponse> response,
|
||||||
|
const std::string& response_data);
|
||||||
|
|
||||||
} // namespace test_request
|
} // namespace test_request
|
||||||
|
|
||||||
#endif // CEF_TESTS_CEFTESTS_TEST_REQUEST_H_
|
#endif // CEF_TESTS_CEFTESTS_TEST_REQUEST_H_
|
||||||
|
@@ -447,6 +447,27 @@ CefRefPtr<CefRegistration> AddObserverAndStart(
|
|||||||
return AddObserver(observer, base::Bind(Start, callback));
|
return AddObserver(observer, base::Bind(Start, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SendResponse(CefRefPtr<CefServer> server,
|
||||||
|
int connection_id,
|
||||||
|
CefRefPtr<CefResponse> response,
|
||||||
|
const std::string& response_data) {
|
||||||
|
const int response_code = response->GetStatus();
|
||||||
|
const CefString& content_type = response->GetMimeType();
|
||||||
|
int64 content_length = static_cast<int64>(response_data.size());
|
||||||
|
|
||||||
|
CefResponse::HeaderMap extra_headers;
|
||||||
|
response->GetHeaderMap(extra_headers);
|
||||||
|
|
||||||
|
server->SendHttpResponse(connection_id, response_code, content_type,
|
||||||
|
content_length, extra_headers);
|
||||||
|
|
||||||
|
if (content_length != 0) {
|
||||||
|
server->SendRawData(connection_id, response_data.data(),
|
||||||
|
response_data.size());
|
||||||
|
server->CloseConnection(connection_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ObserverHelper
|
// ObserverHelper
|
||||||
|
|
||||||
ObserverHelper::ObserverHelper() : weak_ptr_factory_(this) {
|
ObserverHelper::ObserverHelper() : weak_ptr_factory_(this) {
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include "include/base/cef_bind.h"
|
#include "include/base/cef_bind.h"
|
||||||
#include "include/cef_registration.h"
|
#include "include/cef_registration.h"
|
||||||
#include "include/cef_request.h"
|
#include "include/cef_request.h"
|
||||||
|
#include "include/cef_response.h"
|
||||||
#include "include/cef_server.h"
|
#include "include/cef_server.h"
|
||||||
|
|
||||||
namespace test_server {
|
namespace test_server {
|
||||||
@@ -76,6 +77,12 @@ CefRefPtr<CefRegistration> AddObserverAndStart(
|
|||||||
Observer* observer,
|
Observer* observer,
|
||||||
const StartDoneCallback& callback);
|
const StartDoneCallback& callback);
|
||||||
|
|
||||||
|
// Helper for sending a fully qualified response.
|
||||||
|
void SendResponse(CefRefPtr<CefServer> server,
|
||||||
|
int connection_id,
|
||||||
|
CefRefPtr<CefResponse> response,
|
||||||
|
const std::string& response_data);
|
||||||
|
|
||||||
// Helper for managing Observer registration and callbacks. Only used on the UI
|
// Helper for managing Observer registration and callbacks. Only used on the UI
|
||||||
// thread.
|
// thread.
|
||||||
class ObserverHelper : Observer {
|
class ObserverHelper : Observer {
|
||||||
|
@@ -281,6 +281,17 @@ bool TestOldResourceAPI() {
|
|||||||
return state ? true : false;
|
return state ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsOutOfBlinkCorsEnabled() {
|
||||||
|
static int state = -1;
|
||||||
|
if (state == -1) {
|
||||||
|
CefRefPtr<CefCommandLine> command_line =
|
||||||
|
CefCommandLine::GetGlobalCommandLine();
|
||||||
|
const std::string& value = command_line->GetSwitchValue("disable-features");
|
||||||
|
state = value.find("OutOfBlinkCors") == std::string::npos ? 1 : 0;
|
||||||
|
}
|
||||||
|
return state ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
CefRefPtr<CefRequestContext> CreateTestRequestContext(
|
CefRefPtr<CefRequestContext> CreateTestRequestContext(
|
||||||
TestRequestContextMode mode,
|
TestRequestContextMode mode,
|
||||||
const std::string& cache_path) {
|
const std::string& cache_path) {
|
||||||
|
@@ -81,6 +81,9 @@ inline bool IsTestRequestContextModeCustom(TestRequestContextMode mode) {
|
|||||||
// Returns true if the old CefResourceHandler API should be tested.
|
// Returns true if the old CefResourceHandler API should be tested.
|
||||||
bool TestOldResourceAPI();
|
bool TestOldResourceAPI();
|
||||||
|
|
||||||
|
// Returns true if OutOfBlinkCors is enabled.
|
||||||
|
bool IsOutOfBlinkCorsEnabled();
|
||||||
|
|
||||||
// Return a RequestContext object matching the specified |mode|.
|
// Return a RequestContext object matching the specified |mode|.
|
||||||
// |cache_path| may be specified for CUSTOM modes.
|
// |cache_path| may be specified for CUSTOM modes.
|
||||||
// Use the RC_TEST_GROUP_BASE macro to test all valid combinations.
|
// Use the RC_TEST_GROUP_BASE macro to test all valid combinations.
|
||||||
|
Reference in New Issue
Block a user