cef/tests/ceftests/scheme_handler_unittest.cc

2716 lines
92 KiB
C++
Raw Normal View History

// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include <algorithm>
#include <vector>
Introduce the use of Chromium types (issue #1336). Changes to the CEF public API: - Add base::Bind, base::Callback, base::Lock, base::WeakPtr, scoped_refptr, scoped_ptr and supporting types. - Add include/wrapper/cef_closure_task.h helpers for converting a base::Closure to a CefTask. - Change CefRefPtr to extend scoped_refptr. -- Change CefBase method signatures to match RefCountedThreadSafeBase. - Change IMPLEMENT_REFCOUNTING to use base::AtomicRefCount*. -- Remove the CefAtomic* functions. -- IMPLEMENT_REFCOUNTING now enforces via a compile-time error that the correct class name was passed to the macro. - Change IMPLEMENT_LOCKING to use base::Lock. -- Remove the CefCriticalSection class. -- Deprecate the IMPLEMENT_LOCKING macro. -- base::Lock will DCHECK() in Debug builds if lock usage is reentrant. - Move include/internal/cef_tuple.h to include/base/cef_tuple.h. - Allow an empty |callback| parameter passed to CefBeginTracing. Changes to the CEF implementation: - Fix incorrect names passed to the IMPLEMENT_REFCOUNTING macro. - Fix instances of reentrant locking in the CefXmlObject and CefRequest implementations. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cef_unittests: - Add tests/unittests/chromium_includes.h and always include it first from unit test .cc files to avoid name conflicts with Chromium types. - Fix wrong header include ordering. - Remove use of the IMPLEMENT_LOCKING macro. Changes to cefclient and cefsimple: - Use base::Bind and cef_closure_task.h instead of NewCefRunnable*. - Remove use of the IMPEMENT_LOCKING macro. - Fix incorrect/unnecessary locking. - Add additional runtime thread checks. - Windows: Perform actions on the UI thread instead of the main thread when running in multi-threaded-message-loop mode to avoid excessive locking. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1769 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
2014-07-15 00:18:51 +02:00
#include "include/base/cef_callback.h"
#include "include/cef_callback.h"
#include "include/cef_origin_whitelist.h"
#include "include/cef_request_context.h"
#include "include/cef_request_context_handler.h"
#include "include/cef_scheme.h"
#include "include/wrapper/cef_closure_task.h"
#include "tests/ceftests/test_handler.h"
#include "tests/ceftests/test_suite.h"
Implement NetworkService request interception/handling (see issue #2622). Implementation notes: - Chromium change: CookieMonster::SetCookieableSchemes needs to be called immediately after the CookieMonster is created in NetworkContext:: ApplyContextParamsToBuilder. Add a Profile::GetCookieableSchemes method and NetworkContextParams.cookieable_schemes member (set from ProfileNetworkContextService::CreateNetworkContextParams) to support that. - Chromium change: Add a ContentBrowserClient::HandleExternalProtocol variant that exposes additional NetworkService request information. - GetResourceResponseFilter is not yet implemented. API changes: - Resource-related callbacks have been moved from CefRequestHandler to a new CefResourceRequestHandler interface which is returned via the GetResourceRequestHandler method. If the CefRequestHandler declines to handle a resource it can optionally be handled by the CefRequestContextHandler, if any, associated with the loading context. - The OnProtocolExecution callback has been moved from CefRequestHandler to CefResourceRequestHandler and will be called if a custom scheme request is unhandled. - Cookie send/save permission callbacks have been moved from CefRequestHandler and CefResourceHandler to CefResourceRequestHandler. - New methods added to CefResourceHandler that better match NetworkService execution sequence expectations. The old methods are now deprecated. - New methods added to CefRequest and CefResponse. Known behavior changes with the NetworkService implementation: - Modifying the |new_url| parameter in OnResourceRedirect will no longer result in the method being called an additional time (likely a bug in the old implementation). - Modifying the request URL in OnResourceResponse would previously cause a redirect. This behavior is now deprecated because the NetworkService does not support this functionality when using default network loaders. Temporary support has been added in combination with CefResourceHandler usage only. - Other changes to the request object in OnResourceResponse will now cause the request to be restarted. This means that OnBeforeResourceLoad, etc, will be called an additional time with the new request information. - CefResponse::GetMimeType will now be empty for non-200 responses. - Requests using custom schemes can now be handled via CefResourceRequestHandler with the same callback behavior as builtin schemes. - Redirects of custom scheme requests will now be followed as expected. - Default handling of builtin schemes can now be disabled by setting |disable_default_handling| to true in GetResourceRequestHandler. - Unhandled requests (custom scheme or builtin scheme with default handling disabled) will fail with an CefResponse::GetError value of ERR_UNKNOWN_URL_SCHEME. - The CefSchemeHandlerFactory::Create callback will now include cookie headers. To test: - Run `cefclient --enable-network-service`. All resources should load successfully (this tests the transparent proxy capability). - All tests pass with NetworkService disabled. - The following tests pass with NetworkService enabled: - CookieTest.* - FrameTest.* (excluding .*Nav) - NavigationTest.* (excluding .Redirect*) - RequestHandlerTest.* - RequestContextTest.Basic* - RequestContextTest.Popup* - RequestTest.* - ResourceManagerTest.* - ResourceRequestHandlerTest.* (excluding .Filter*) - SchemeHandlerTest.* - StreamResourceHandlerTest.*
2019-04-24 04:50:25 +02:00
#include "tests/ceftests/test_util.h"
namespace {
class TestResults {
public:
TestResults() = default;
// Used for running tests in a custom request context.
CefRefPtr<CefRequestContext> request_context;
std::string url;
std::string html;
int status_code = 200;
// Error code set on the response.
cef_errorcode_t response_error_code = ERR_NONE;
// Error code expected in OnLoadError.
cef_errorcode_t expected_error_code = ERR_NONE;
// Used for testing redirects
std::string redirect_url;
// Used for testing XHR requests
std::string sub_url;
std::string sub_html;
int sub_status_code = 200;
std::string sub_allow_origin;
std::string sub_redirect_url;
std::string exit_url;
// Used for testing XSS requests
bool needs_same_origin_policy_relaxation = false;
// Used for testing Accept-Language.
std::string accept_language;
// Used for testing received console messages.
std::vector<std::string> console_messages;
// Delay for returning scheme handler results.
int delay = 0;
TrackCallback got_request, got_read, got_output, got_sub_output, got_redirect,
got_error, got_sub_error, got_sub_redirect, got_sub_request, got_sub_read,
git_exit_success, got_exit_request;
};
// Current scheme handler object. Used when destroying the test from
// ClientSchemeHandler::ProcessRequest().
class TestSchemeHandler;
TestSchemeHandler* g_current_handler = nullptr;
class TestSchemeHandler : public TestHandler {
public:
explicit TestSchemeHandler(TestResults* tr) : test_results_(tr) {
g_current_handler = this;
}
void RunTest() override {
CreateBrowser(test_results_->url, test_results_->request_context);
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
// Necessary to make the method public in order to destroy the test from
// ClientSchemeHandler::ProcessRequest().
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() {
if (!test_results_->exit_url.empty() && !test_results_->got_exit_request) {
return;
}
if (!test_results_->sub_url.empty() &&
!(test_results_->got_sub_output || test_results_->got_sub_error ||
test_results_->got_exit_request)) {
return;
}
if (!(test_results_->got_output || test_results_->got_error)) {
return;
}
DestroyTest();
}
bool IsExitURL(const std::string& url) const {
return !test_results_->exit_url.empty() &&
url.find(test_results_->exit_url) != std::string::npos;
}
cef_return_value_t OnBeforeResourceLoad(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
chrome: Add support for Alloy style browsers and windows (see #3681) Split the Alloy runtime into bootstrap and style components. Support creation of Alloy style browsers and windows with the Chrome runtime. Chrome runtime (`--enable-chrome-runtime`) + Alloy style (`--use-alloy-style`) supports Views (`--use-views`), native parent (`--use-native`) and windowless rendering (`--off-screen-rendering-enabled`). Print preview is supported in all cases except with windowless rendering on all platforms and native parent on MacOS. It is disabled by default with Alloy style for legacy compatibility. Where supported it can be enabled or disabled globally using `--[enable|disable]-print-preview` or configured on a per-RequestContext basis using the `printing.print_preview_disabled` preference. It also behaves as expected when triggered via the PDF viewer print button. Chrome runtime + Alloy style behavior differs from Alloy runtime in the following significant ways: - Supports Chrome error pages by default. - DevTools popups are Chrome style only (cannot be windowless). - The Alloy extension API will not supported. Chrome runtime + Alloy style passes all expected Alloy ceftests except the following: - `DisplayTest.AutoResize` (Alloy extension API not supported) - `DownloadTest.*` (Download API not yet supported) - `ExtensionTest.*` (Alloy extension API not supported) This change also adds Chrome runtime support for CefContextMenuHandler::RunContextMenu (see #3293). This change also explicitly blocks (and doesn't retry) FrameAttached requests from PDF viewer and print preview excluded frames (see #3664). Known issues specific to Chrome runtime + Alloy style: - DevTools popup with windowless rendering doesn't load successfully. Use windowed rendering or remote debugging as a workaround. - Chrome style Window with Alloy style BrowserView (`--use-alloy-style --use-chrome-style-window`) does not show Chrome theme changes. To test: - Run `ceftests --enable-chrome-runtime --use-alloy-style [--use-chrome-style-window] [--use-views|--use-native] --gtest_filter=...` - Run `cefclient --enable-chrome-runtime --use-alloy-style [--use-chrome-style-window] [--use-views|--use-native|--off-screen-rendering-enabled]` - Run `cefsimple --enable-chrome-runtime --use-alloy-style [--use-views]`
2024-04-17 18:01:26 +02:00
if (!use_alloy_style_browser() &&
request->GetResourceType() == RT_FAVICON) {
Add chrome runtime support for more callbacks and ceftests (see issue #2969) This change adds support for: - Protocol and request handling. - Loading and navigation events. - Display and focus events. - Mouse/keyboard events. - Popup browsers. - Callbacks in the renderer process. - Misc. functionality required for ceftests. This change also adds a new CefBrowserProcessHandler::GetCookieableSchemes callback for configuring global state that will be applied to all CefCookieManagers by default. This global callback is currently required by the chrome runtime because the primary ProfileImpl is created via ChromeBrowserMainParts::PreMainMessageLoopRun (CreatePrimaryProfile) before OnContextCreated can be called. ProfileImpl will use the "C:\Users\[user]\AppData\Local\CEF\User Data\Default" directory by default (on Windows). Cookies may persist in this directory when running ceftests and may need to be manually deleted if those tests fail. Remaining work includes: - Support for client-created request contexts. - Embedding the browser in a Views hierarchy (cefclient support). - TryCloseBrowser and DoClose support. - Most of the CefSettings configuration. - DevTools protocol and window control (ShowDevTools, ExecuteDevToolsMethod). - CEF-specific WebUI pages (about, license, webui-hosts). - Context menu customization (CefContextMenuHandler). - Auto resize (SetAutoResizeEnabled). - Zoom settings (SetZoomLevel). - File dialog runner (RunFileDialog). - File and JS dialog handlers (CefDialogHandler, CefJSDialogHandler). - Extension loading (LoadExtension, etc). - Plugin loading (OnBeforePluginLoad). - Widevine loading (CefRegisterWidevineCdm). - PDF and print preview does not display. - Crash reporting is untested. - Mac: Web content loads but does not display. The following ceftests are now passing when run with the "--enable-chrome-runtime" command-line flag: CorsTest.* DisplayTest.*:-DisplayTest.AutoResize DOMTest.* DraggableRegionsTest.* ImageTest.* MessageRouterTest.* NavigationTest.* ParserTest.* RequestContextTest.*Global* RequestTest.* ResourceManagerTest.* ResourceRequestHandlerTest.* ResponseTest.* SchemeHandlerTest.* ServerTest.* StreamResourceHandlerTest.* StreamTest.* StringTest.* TaskTest.* TestServerTest.* ThreadTest.* URLRequestTest.*Global* V8Test.*:-V8Test.OnUncaughtExceptionDevTools ValuesTest.* WaitableEventTest.* XmlReaderTest.* ZipReaderTest.*
2020-09-25 03:40:47 +02:00
// Ignore favicon requests.
return RV_CANCEL;
}
const std::string& newUrl = request->GetURL();
if (IsExitURL(newUrl)) {
test_results_->got_exit_request.yes();
// XHR tests use an exit URL to destroy the test.
2023-01-02 23:59:03 +01:00
if (newUrl.find("SUCCESS") != std::string::npos) {
test_results_->git_exit_success.yes();
2023-01-02 23:59:03 +01:00
}
DestroyTestIfDone();
return RV_CANCEL;
}
if (!test_results_->sub_redirect_url.empty() &&
newUrl == test_results_->sub_redirect_url) {
test_results_->got_sub_redirect.yes();
// Redirect to the sub URL.
request->SetURL(test_results_->sub_url);
} else if (newUrl == test_results_->redirect_url) {
test_results_->got_redirect.yes();
// No read should have occurred for the redirect.
EXPECT_TRUE(test_results_->got_request);
EXPECT_FALSE(test_results_->got_read);
// Now loading the redirect URL.
test_results_->url = test_results_->redirect_url;
test_results_->redirect_url.clear();
}
return RV_CONTINUE;
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) override {
const std::string& url = frame->GetURL();
2023-01-02 23:59:03 +01:00
if (url == test_results_->url) {
test_results_->got_output.yes();
2023-01-02 23:59:03 +01:00
} else if (url == test_results_->sub_url) {
test_results_->got_sub_output.yes();
2023-01-02 23:59:03 +01:00
} else if (IsExitURL(url)) {
return;
2023-01-02 23:59:03 +01:00
}
if (url == test_results_->url || test_results_->status_code != 200) {
// Test that the status code is correct.
EXPECT_EQ(httpStatusCode, test_results_->status_code);
}
DestroyTestIfDone();
}
void OnLoadError(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
ErrorCode errorCode,
const CefString& errorText,
const CefString& failedUrl) override {
const std::string& url = failedUrl;
2023-01-02 23:59:03 +01:00
if (url == test_results_->url) {
test_results_->got_error.yes();
2023-01-02 23:59:03 +01:00
} else if (url == test_results_->sub_url) {
test_results_->got_sub_error.yes();
2023-01-02 23:59:03 +01:00
} else if (IsExitURL(url)) {
return;
2023-01-02 23:59:03 +01:00
}
// Tests sometimes also fail with ERR_ABORTED or ERR_UNKNOWN_URL_SCHEME.
if (!(test_results_->expected_error_code == 0 &&
(errorCode == ERR_ABORTED || errorCode == ERR_UNKNOWN_URL_SCHEME))) {
Implement NetworkService request interception/handling (see issue #2622). Implementation notes: - Chromium change: CookieMonster::SetCookieableSchemes needs to be called immediately after the CookieMonster is created in NetworkContext:: ApplyContextParamsToBuilder. Add a Profile::GetCookieableSchemes method and NetworkContextParams.cookieable_schemes member (set from ProfileNetworkContextService::CreateNetworkContextParams) to support that. - Chromium change: Add a ContentBrowserClient::HandleExternalProtocol variant that exposes additional NetworkService request information. - GetResourceResponseFilter is not yet implemented. API changes: - Resource-related callbacks have been moved from CefRequestHandler to a new CefResourceRequestHandler interface which is returned via the GetResourceRequestHandler method. If the CefRequestHandler declines to handle a resource it can optionally be handled by the CefRequestContextHandler, if any, associated with the loading context. - The OnProtocolExecution callback has been moved from CefRequestHandler to CefResourceRequestHandler and will be called if a custom scheme request is unhandled. - Cookie send/save permission callbacks have been moved from CefRequestHandler and CefResourceHandler to CefResourceRequestHandler. - New methods added to CefResourceHandler that better match NetworkService execution sequence expectations. The old methods are now deprecated. - New methods added to CefRequest and CefResponse. Known behavior changes with the NetworkService implementation: - Modifying the |new_url| parameter in OnResourceRedirect will no longer result in the method being called an additional time (likely a bug in the old implementation). - Modifying the request URL in OnResourceResponse would previously cause a redirect. This behavior is now deprecated because the NetworkService does not support this functionality when using default network loaders. Temporary support has been added in combination with CefResourceHandler usage only. - Other changes to the request object in OnResourceResponse will now cause the request to be restarted. This means that OnBeforeResourceLoad, etc, will be called an additional time with the new request information. - CefResponse::GetMimeType will now be empty for non-200 responses. - Requests using custom schemes can now be handled via CefResourceRequestHandler with the same callback behavior as builtin schemes. - Redirects of custom scheme requests will now be followed as expected. - Default handling of builtin schemes can now be disabled by setting |disable_default_handling| to true in GetResourceRequestHandler. - Unhandled requests (custom scheme or builtin scheme with default handling disabled) will fail with an CefResponse::GetError value of ERR_UNKNOWN_URL_SCHEME. - The CefSchemeHandlerFactory::Create callback will now include cookie headers. To test: - Run `cefclient --enable-network-service`. All resources should load successfully (this tests the transparent proxy capability). - All tests pass with NetworkService disabled. - The following tests pass with NetworkService enabled: - CookieTest.* - FrameTest.* (excluding .*Nav) - NavigationTest.* (excluding .Redirect*) - RequestHandlerTest.* - RequestContextTest.Basic* - RequestContextTest.Popup* - RequestTest.* - ResourceManagerTest.* - ResourceRequestHandlerTest.* (excluding .Filter*) - SchemeHandlerTest.* - StreamResourceHandlerTest.*
2019-04-24 04:50:25 +02:00
EXPECT_EQ(test_results_->expected_error_code, errorCode)
<< failedUrl.ToString();
}
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:
TestResults* const test_results_;
IMPLEMENT_REFCOUNTING(TestSchemeHandler);
};
class ClientSchemeHandlerOld : public CefResourceHandler {
public:
explicit ClientSchemeHandlerOld(TestResults* tr) : test_results_(tr) {}
bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
bool handled = false;
std::string url = request->GetURL();
is_sub_ =
(!test_results_->sub_url.empty() && test_results_->sub_url == url);
if (is_sub_) {
test_results_->got_sub_request.yes();
2023-01-02 23:59:03 +01:00
if (!test_results_->sub_html.empty()) {
handled = true;
2023-01-02 23:59:03 +01:00
}
} else {
EXPECT_EQ(url, test_results_->url);
test_results_->got_request.yes();
2023-01-02 23:59:03 +01:00
if (!test_results_->html.empty()) {
handled = true;
2023-01-02 23:59:03 +01:00
}
}
std::string accept_language;
CefRequest::HeaderMap headerMap;
CefRequest::HeaderMap::iterator headerIter;
request->GetHeaderMap(headerMap);
headerIter = headerMap.find("Accept-Language");
2023-01-02 23:59:03 +01:00
if (headerIter != headerMap.end()) {
accept_language = headerIter->second;
2023-01-02 23:59:03 +01:00
}
EXPECT_TRUE(!accept_language.empty());
if (!test_results_->accept_language.empty()) {
// Value from CefRequestContextSettings.accept_language_list.
EXPECT_STREQ(test_results_->accept_language.data(),
accept_language.data());
} else {
// CEF_SETTINGS_ACCEPT_LANGUAGE value from
// CefSettings.accept_language_list set in CefTestSuite::GetSettings()
// and expanded internally by ComputeAcceptLanguageFromPref.
EXPECT_STREQ("en-GB,en;q=0.9", accept_language.data());
}
if (handled) {
if (test_results_->delay > 0) {
// Continue after the delay.
CefPostDelayedTask(
TID_IO, base::BindOnce(&CefCallback::Continue, callback.get()),
test_results_->delay);
} else {
// Continue immediately.
callback->Continue();
}
return true;
} else if (test_results_->response_error_code != ERR_NONE) {
// Propagate the error code.
callback->Continue();
return true;
}
// Response was canceled.
2023-01-02 23:59:03 +01:00
if (g_current_handler) {
g_current_handler->DestroyTest();
2023-01-02 23:59:03 +01:00
}
return false;
}
void GetResponseHeaders(CefRefPtr<CefResponse> response,
int64_t& response_length,
CefString& redirectUrl) override {
CefResponse::HeaderMap headers;
if (is_sub_) {
response->SetStatus(test_results_->sub_status_code);
if (!test_results_->sub_allow_origin.empty()) {
// Set the Access-Control-Allow-Origin header to allow cross-domain
// scripting.
headers.insert(std::make_pair("Access-Control-Allow-Origin",
test_results_->sub_allow_origin));
}
if (!test_results_->sub_html.empty()) {
response->SetMimeType("text/html");
response_length = test_results_->sub_html.size();
}
} else if (!test_results_->redirect_url.empty()) {
redirectUrl = test_results_->redirect_url;
} else if (test_results_->response_error_code != ERR_NONE) {
response->SetError(test_results_->response_error_code);
} else {
response->SetStatus(test_results_->status_code);
if (!test_results_->html.empty()) {
response->SetMimeType("text/html");
response_length = test_results_->html.size();
}
}
if (test_results_->needs_same_origin_policy_relaxation) {
// Apply same-origin policy relaxation for document.domain.
headers.insert(std::make_pair("Origin-Agent-Cluster", "?0"));
}
if (!headers.empty()) {
response->SetHeaderMap(headers);
}
}
void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); }
bool ReadResponse(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefCallback> callback) override {
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
if (test_results_->delay > 0) {
if (!has_delayed_) {
// Continue after a delay.
CefPostDelayedTask(
TID_IO,
base::BindOnce(&ClientSchemeHandlerOld::ContinueAfterDelay, this,
callback),
test_results_->delay);
bytes_read = 0;
return true;
}
has_delayed_ = false;
}
std::string* data;
if (is_sub_) {
test_results_->got_sub_read.yes();
data = &test_results_->sub_html;
} else {
test_results_->got_read.yes();
data = &test_results_->html;
}
bool has_data = false;
bytes_read = 0;
size_t size = data->size();
if (offset_ < size) {
int transfer_size =
std::min(bytes_to_read, static_cast<int>(size - offset_));
memcpy(data_out, data->c_str() + offset_, transfer_size);
offset_ += transfer_size;
bytes_read = transfer_size;
has_data = true;
}
return has_data;
}
private:
void ContinueAfterDelay(CefRefPtr<CefCallback> callback) {
has_delayed_ = true;
callback->Continue();
}
TestResults* const test_results_;
size_t offset_ = 0;
bool is_sub_ = false;
bool has_delayed_ = false;
IMPLEMENT_REFCOUNTING(ClientSchemeHandlerOld);
DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerOld);
};
class ClientSchemeHandler : public CefResourceHandler {
public:
explicit ClientSchemeHandler(TestResults* tr) : test_results_(tr) {}
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> callback) override {
EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
chrome: Add support for Alloy style browsers and windows (see #3681) Split the Alloy runtime into bootstrap and style components. Support creation of Alloy style browsers and windows with the Chrome runtime. Chrome runtime (`--enable-chrome-runtime`) + Alloy style (`--use-alloy-style`) supports Views (`--use-views`), native parent (`--use-native`) and windowless rendering (`--off-screen-rendering-enabled`). Print preview is supported in all cases except with windowless rendering on all platforms and native parent on MacOS. It is disabled by default with Alloy style for legacy compatibility. Where supported it can be enabled or disabled globally using `--[enable|disable]-print-preview` or configured on a per-RequestContext basis using the `printing.print_preview_disabled` preference. It also behaves as expected when triggered via the PDF viewer print button. Chrome runtime + Alloy style behavior differs from Alloy runtime in the following significant ways: - Supports Chrome error pages by default. - DevTools popups are Chrome style only (cannot be windowless). - The Alloy extension API will not supported. Chrome runtime + Alloy style passes all expected Alloy ceftests except the following: - `DisplayTest.AutoResize` (Alloy extension API not supported) - `DownloadTest.*` (Download API not yet supported) - `ExtensionTest.*` (Alloy extension API not supported) This change also adds Chrome runtime support for CefContextMenuHandler::RunContextMenu (see #3293). This change also explicitly blocks (and doesn't retry) FrameAttached requests from PDF viewer and print preview excluded frames (see #3664). Known issues specific to Chrome runtime + Alloy style: - DevTools popup with windowless rendering doesn't load successfully. Use windowed rendering or remote debugging as a workaround. - Chrome style Window with Alloy style BrowserView (`--use-alloy-style --use-chrome-style-window`) does not show Chrome theme changes. To test: - Run `ceftests --enable-chrome-runtime --use-alloy-style [--use-chrome-style-window] [--use-views|--use-native] --gtest_filter=...` - Run `cefclient --enable-chrome-runtime --use-alloy-style [--use-chrome-style-window] [--use-views|--use-native|--off-screen-rendering-enabled]` - Run `cefsimple --enable-chrome-runtime --use-alloy-style [--use-views]`
2024-04-17 18:01:26 +02:00
if (IsChromeBootstrap() && request->GetResourceType() == RT_FAVICON) {
Add chrome runtime support for more callbacks and ceftests (see issue #2969) This change adds support for: - Protocol and request handling. - Loading and navigation events. - Display and focus events. - Mouse/keyboard events. - Popup browsers. - Callbacks in the renderer process. - Misc. functionality required for ceftests. This change also adds a new CefBrowserProcessHandler::GetCookieableSchemes callback for configuring global state that will be applied to all CefCookieManagers by default. This global callback is currently required by the chrome runtime because the primary ProfileImpl is created via ChromeBrowserMainParts::PreMainMessageLoopRun (CreatePrimaryProfile) before OnContextCreated can be called. ProfileImpl will use the "C:\Users\[user]\AppData\Local\CEF\User Data\Default" directory by default (on Windows). Cookies may persist in this directory when running ceftests and may need to be manually deleted if those tests fail. Remaining work includes: - Support for client-created request contexts. - Embedding the browser in a Views hierarchy (cefclient support). - TryCloseBrowser and DoClose support. - Most of the CefSettings configuration. - DevTools protocol and window control (ShowDevTools, ExecuteDevToolsMethod). - CEF-specific WebUI pages (about, license, webui-hosts). - Context menu customization (CefContextMenuHandler). - Auto resize (SetAutoResizeEnabled). - Zoom settings (SetZoomLevel). - File dialog runner (RunFileDialog). - File and JS dialog handlers (CefDialogHandler, CefJSDialogHandler). - Extension loading (LoadExtension, etc). - Plugin loading (OnBeforePluginLoad). - Widevine loading (CefRegisterWidevineCdm). - PDF and print preview does not display. - Crash reporting is untested. - Mac: Web content loads but does not display. The following ceftests are now passing when run with the "--enable-chrome-runtime" command-line flag: CorsTest.* DisplayTest.*:-DisplayTest.AutoResize DOMTest.* DraggableRegionsTest.* ImageTest.* MessageRouterTest.* NavigationTest.* ParserTest.* RequestContextTest.*Global* RequestTest.* ResourceManagerTest.* ResourceRequestHandlerTest.* ResponseTest.* SchemeHandlerTest.* ServerTest.* StreamResourceHandlerTest.* StreamTest.* StringTest.* TaskTest.* TestServerTest.* ThreadTest.* URLRequestTest.*Global* V8Test.*:-V8Test.OnUncaughtExceptionDevTools ValuesTest.* WaitableEventTest.* XmlReaderTest.* ZipReaderTest.*
2020-09-25 03:40:47 +02:00
// Ignore favicon requests.
return false;
}
bool handled = false;
std::string url = request->GetURL();
is_sub_ =
(!test_results_->sub_url.empty() && test_results_->sub_url == url);
if (is_sub_) {
test_results_->got_sub_request.yes();
2023-01-02 23:59:03 +01:00
if (!test_results_->sub_html.empty()) {
handled = true;
2023-01-02 23:59:03 +01:00
}
} else {
EXPECT_EQ(url, test_results_->url);
test_results_->got_request.yes();
2023-01-02 23:59:03 +01:00
if (!test_results_->html.empty()) {
handled = true;
2023-01-02 23:59:03 +01:00
}
}
std::string accept_language;
CefRequest::HeaderMap headerMap;
CefRequest::HeaderMap::iterator headerIter;
request->GetHeaderMap(headerMap);
headerIter = headerMap.find("Accept-Language");
2023-01-02 23:59:03 +01:00
if (headerIter != headerMap.end()) {
accept_language = headerIter->second;
2023-01-02 23:59:03 +01:00
}
EXPECT_TRUE(!accept_language.empty());
if (!test_results_->accept_language.empty()) {
// Value from CefRequestContextSettings.accept_language_list.
EXPECT_STREQ(test_results_->accept_language.data(),
accept_language.data());
} else {
// CEF_SETTINGS_ACCEPT_LANGUAGE value from
// CefSettings.accept_language_list set in CefTestSuite::GetSettings()
// and expanded internally by ComputeAcceptLanguageFromPref.
EXPECT_STREQ("en-GB,en;q=0.9", accept_language.data());
}
// Continue or cancel the request immediately based on the return value.
handle_request = true;
if (handled) {
if (test_results_->delay > 0) {
// Continue after the delay.
handle_request = false;
CefPostDelayedTask(
TID_FILE_USER_BLOCKING,
base::BindOnce(&CefCallback::Continue, callback.get()),
test_results_->delay);
}
return true;
} else if (test_results_->response_error_code != ERR_NONE) {
// Propagate the error code.
return true;
}
// Response was canceled.
2023-01-02 23:59:03 +01:00
if (g_current_handler) {
g_current_handler->DestroyTest();
2023-01-02 23:59:03 +01:00
}
return false;
}
bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
chrome: Add support for Alloy style browsers and windows (see #3681) Split the Alloy runtime into bootstrap and style components. Support creation of Alloy style browsers and windows with the Chrome runtime. Chrome runtime (`--enable-chrome-runtime`) + Alloy style (`--use-alloy-style`) supports Views (`--use-views`), native parent (`--use-native`) and windowless rendering (`--off-screen-rendering-enabled`). Print preview is supported in all cases except with windowless rendering on all platforms and native parent on MacOS. It is disabled by default with Alloy style for legacy compatibility. Where supported it can be enabled or disabled globally using `--[enable|disable]-print-preview` or configured on a per-RequestContext basis using the `printing.print_preview_disabled` preference. It also behaves as expected when triggered via the PDF viewer print button. Chrome runtime + Alloy style behavior differs from Alloy runtime in the following significant ways: - Supports Chrome error pages by default. - DevTools popups are Chrome style only (cannot be windowless). - The Alloy extension API will not supported. Chrome runtime + Alloy style passes all expected Alloy ceftests except the following: - `DisplayTest.AutoResize` (Alloy extension API not supported) - `DownloadTest.*` (Download API not yet supported) - `ExtensionTest.*` (Alloy extension API not supported) This change also adds Chrome runtime support for CefContextMenuHandler::RunContextMenu (see #3293). This change also explicitly blocks (and doesn't retry) FrameAttached requests from PDF viewer and print preview excluded frames (see #3664). Known issues specific to Chrome runtime + Alloy style: - DevTools popup with windowless rendering doesn't load successfully. Use windowed rendering or remote debugging as a workaround. - Chrome style Window with Alloy style BrowserView (`--use-alloy-style --use-chrome-style-window`) does not show Chrome theme changes. To test: - Run `ceftests --enable-chrome-runtime --use-alloy-style [--use-chrome-style-window] [--use-views|--use-native] --gtest_filter=...` - Run `cefclient --enable-chrome-runtime --use-alloy-style [--use-chrome-style-window] [--use-views|--use-native|--off-screen-rendering-enabled]` - Run `cefsimple --enable-chrome-runtime --use-alloy-style [--use-views]`
2024-04-17 18:01:26 +02:00
if (IsChromeBootstrap() && request->GetResourceType() == RT_FAVICON) {
Add chrome runtime support for more callbacks and ceftests (see issue #2969) This change adds support for: - Protocol and request handling. - Loading and navigation events. - Display and focus events. - Mouse/keyboard events. - Popup browsers. - Callbacks in the renderer process. - Misc. functionality required for ceftests. This change also adds a new CefBrowserProcessHandler::GetCookieableSchemes callback for configuring global state that will be applied to all CefCookieManagers by default. This global callback is currently required by the chrome runtime because the primary ProfileImpl is created via ChromeBrowserMainParts::PreMainMessageLoopRun (CreatePrimaryProfile) before OnContextCreated can be called. ProfileImpl will use the "C:\Users\[user]\AppData\Local\CEF\User Data\Default" directory by default (on Windows). Cookies may persist in this directory when running ceftests and may need to be manually deleted if those tests fail. Remaining work includes: - Support for client-created request contexts. - Embedding the browser in a Views hierarchy (cefclient support). - TryCloseBrowser and DoClose support. - Most of the CefSettings configuration. - DevTools protocol and window control (ShowDevTools, ExecuteDevToolsMethod). - CEF-specific WebUI pages (about, license, webui-hosts). - Context menu customization (CefContextMenuHandler). - Auto resize (SetAutoResizeEnabled). - Zoom settings (SetZoomLevel). - File dialog runner (RunFileDialog). - File and JS dialog handlers (CefDialogHandler, CefJSDialogHandler). - Extension loading (LoadExtension, etc). - Plugin loading (OnBeforePluginLoad). - Widevine loading (CefRegisterWidevineCdm). - PDF and print preview does not display. - Crash reporting is untested. - Mac: Web content loads but does not display. The following ceftests are now passing when run with the "--enable-chrome-runtime" command-line flag: CorsTest.* DisplayTest.*:-DisplayTest.AutoResize DOMTest.* DraggableRegionsTest.* ImageTest.* MessageRouterTest.* NavigationTest.* ParserTest.* RequestContextTest.*Global* RequestTest.* ResourceManagerTest.* ResourceRequestHandlerTest.* ResponseTest.* SchemeHandlerTest.* ServerTest.* StreamResourceHandlerTest.* StreamTest.* StringTest.* TaskTest.* TestServerTest.* ThreadTest.* URLRequestTest.*Global* V8Test.*:-V8Test.OnUncaughtExceptionDevTools ValuesTest.* WaitableEventTest.* XmlReaderTest.* ZipReaderTest.*
2020-09-25 03:40:47 +02:00
// Ignore favicon requests.
return false;
}
EXPECT_TRUE(false); // Not reached.
return false;
}
void GetResponseHeaders(CefRefPtr<CefResponse> response,
int64_t& response_length,
CefString& redirectUrl) override {
CefResponse::HeaderMap headers;
if (is_sub_) {
response->SetStatus(test_results_->sub_status_code);
if (!test_results_->sub_allow_origin.empty()) {
// Set the Access-Control-Allow-Origin header to allow cross-domain
// scripting.
headers.insert(std::make_pair("Access-Control-Allow-Origin",
test_results_->sub_allow_origin));
}
if (!test_results_->sub_html.empty()) {
response->SetMimeType("text/html");
response_length = test_results_->sub_html.size();
}
} else if (!test_results_->redirect_url.empty()) {
redirectUrl = test_results_->redirect_url;
} else if (test_results_->response_error_code != ERR_NONE) {
response->SetError(test_results_->response_error_code);
} else {
response->SetStatus(test_results_->status_code);
if (!test_results_->html.empty()) {
response->SetMimeType("text/html");
response_length = test_results_->html.size();
}
}
if (test_results_->needs_same_origin_policy_relaxation) {
// Apply same-origin policy relaxation for document.domain.
headers.insert(std::make_pair("Origin-Agent-Cluster", "?0"));
}
if (!headers.empty()) {
response->SetHeaderMap(headers);
}
}
void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); }
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> callback) override {
EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
if (test_results_->delay > 0) {
if (!has_delayed_) {
// Continue after a delay.
CefPostDelayedTask(
TID_FILE_USER_BLOCKING,
base::BindOnce(&ClientSchemeHandler::ContinueAfterDelay, this,
data_out, bytes_to_read, callback),
test_results_->delay);
bytes_read = 0;
return true;
}
has_delayed_ = false;
}
return GetData(data_out, bytes_to_read, bytes_read);
}
bool ReadResponse(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefCallback> callback) override {
EXPECT_TRUE(false); // Not reached.
bytes_read = -2;
return false;
}
private:
void ContinueAfterDelay(void* data_out,
int bytes_to_read,
CefRefPtr<CefResourceReadCallback> callback) {
EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
has_delayed_ = true;
int bytes_read = 0;
GetData(data_out, bytes_to_read, bytes_read);
callback->Continue(bytes_read);
}
bool GetData(void* data_out, int bytes_to_read, int& bytes_read) {
std::string* data;
if (is_sub_) {
test_results_->got_sub_read.yes();
data = &test_results_->sub_html;
} else {
test_results_->got_read.yes();
data = &test_results_->html;
}
// Default to response complete.
bool has_data = false;
bytes_read = 0;
size_t size = data->size();
if (offset_ < size) {
int transfer_size =
std::min(bytes_to_read, static_cast<int>(size - offset_));
memcpy(data_out, data->c_str() + offset_, transfer_size);
offset_ += transfer_size;
bytes_read = transfer_size;
has_data = true;
}
return has_data;
}
TestResults* const test_results_;
size_t offset_ = 0;
bool is_sub_ = false;
bool has_delayed_ = false;
IMPLEMENT_REFCOUNTING(ClientSchemeHandler);
DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandler);
};
class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory {
public:
explicit ClientSchemeHandlerFactory(TestResults* tr) : test_results_(tr) {}
CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& scheme_name,
CefRefPtr<CefRequest> request) override {
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
if (TestOldResourceAPI()) {
return new ClientSchemeHandlerOld(test_results_);
}
return new ClientSchemeHandler(test_results_);
}
TestResults* const test_results_;
IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory);
DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory);
};
// If |domain| is empty the scheme will be registered as non-standard.
void RegisterTestScheme(TestResults* test_results,
const std::string& scheme,
const std::string& domain) {
if (test_results->request_context) {
EXPECT_TRUE(test_results->request_context->RegisterSchemeHandlerFactory(
scheme, domain, new ClientSchemeHandlerFactory(test_results)));
} else {
EXPECT_TRUE(CefRegisterSchemeHandlerFactory(
scheme, domain, new ClientSchemeHandlerFactory(test_results)));
}
WaitForIOThread();
}
void ClearTestSchemes(TestResults* test_results) {
if (test_results->request_context) {
EXPECT_TRUE(test_results->request_context->ClearSchemeHandlerFactories());
} else {
EXPECT_TRUE(CefClearSchemeHandlerFactories());
}
WaitForIOThread();
}
struct XHRTestSettings {
XHRTestSettings() = default;
std::string url;
std::string sub_url;
std::string sub_allow_origin;
std::string sub_redirect_url;
bool synchronous = true;
};
void SetUpXHR(TestResults* test_results, const XHRTestSettings& settings) {
test_results->sub_url = settings.sub_url;
test_results->sub_html = "SUCCESS";
test_results->sub_allow_origin = settings.sub_allow_origin;
test_results->sub_redirect_url = settings.sub_redirect_url;
std::string request_url;
2023-01-02 23:59:03 +01:00
if (!settings.sub_redirect_url.empty()) {
request_url = settings.sub_redirect_url;
2023-01-02 23:59:03 +01:00
} else {
request_url = settings.sub_url;
2023-01-02 23:59:03 +01:00
}
test_results->url = settings.url;
std::stringstream ss;
ss << "<html><head>"
"<script language=\"JavaScript\">"
"function onResult(val) {"
" document.location = \"https://tests/exit?result=\"+val;"
"}"
"function execXMLHttpRequest() {";
if (settings.synchronous) {
ss << "var result = 'FAILURE';"
"try {"
" xhr = new XMLHttpRequest();"
" xhr.open(\"GET\", \""
<< request_url.c_str()
<< "\", false);"
" xhr.send();"
" result = xhr.responseText;"
"} catch(e) {}"
"onResult(result)";
} else {
ss << "xhr = new XMLHttpRequest();"
"xhr.open(\"GET\", \""
<< request_url.c_str()
<< "\", true);"
"xhr.onload = function(e) {"
" if (xhr.readyState === 4) {"
" if (xhr.status === 200) {"
" onResult(xhr.responseText);"
" } else {"
" console.log('XMLHttpRequest failed with status ' + "
"xhr.status);"
" onResult('FAILURE');"
" }"
" }"
"};"
"xhr.onerror = function(e) {"
" onResult('FAILURE');"
"};"
"xhr.send()";
}
ss << "}"
"</script>"
"</head><body onload=\"execXMLHttpRequest();\">"
"Running execXMLHttpRequest..."
"</body></html>";
test_results->html = ss.str();
test_results->exit_url = "https://tests/exit";
}
struct FetchTestSettings {
FetchTestSettings() = default;
std::string url;
std::string sub_url;
std::string sub_allow_origin;
std::string sub_redirect_url;
};
void SetUpFetch(TestResults* test_results, const FetchTestSettings& settings) {
test_results->sub_url = settings.sub_url;
test_results->sub_html = "SUCCESS";
test_results->sub_allow_origin = settings.sub_allow_origin;
test_results->sub_redirect_url = settings.sub_redirect_url;
std::string request_url;
2023-01-02 23:59:03 +01:00
if (!settings.sub_redirect_url.empty()) {
request_url = settings.sub_redirect_url;
2023-01-02 23:59:03 +01:00
} else {
request_url = settings.sub_url;
2023-01-02 23:59:03 +01:00
}
test_results->url = settings.url;
std::stringstream ss;
ss << "<html><head>"
"<script language=\"JavaScript\">"
"function onResult(val) {"
" document.location = \"https://tests/exit?result=\"+val;"
"}"
"function execFetchHttpRequest() {";
ss << "fetch('" << request_url.c_str()
<< "')"
".then(function(response) {"
" if (response.status === 200) {"
" response.text().then(function(text) {"
" onResult(text);"
" }).catch(function(e) {"
" onResult('FAILURE'); "
" });"
" } else {"
" onResult('FAILURE');"
" }"
"}).catch(function(e) {"
" onResult('FAILURE');"
"});"
<< "}"
"</script>"
"</head><body onload=\"execFetchHttpRequest();\">"
"Running execFetchHttpRequest..."
"</body></html>";
test_results->html = ss.str();
test_results->exit_url = "https://tests/exit";
} // namespace
void SetUpXSS(TestResults* test_results,
const std::string& url,
const std::string& sub_url,
const std::string& domain = std::string()) {
// 1. Load |url| which contains an iframe.
// 2. The iframe loads |sub_url|.
// 3. |sub_url| tries to call a JS function in |url|.
// 4. |url| tries to call a JS function in |sub_url|.
std::stringstream ss;
std::string domain_line;
2023-01-02 23:59:03 +01:00
if (!domain.empty()) {
domain_line = "document.domain = '" + domain + "';";
if (url.find("http") == 0 && sub_url.find("http") == 0) {
test_results->needs_same_origin_policy_relaxation = true;
}
2023-01-02 23:59:03 +01:00
}
test_results->sub_url = sub_url;
ss << "<html><head>"
"<script language=\"JavaScript\">"
<< domain_line
<< "function getResult() {"
" return 'SUCCESS';"
"}"
"function execXSSRequest() {"
" var result = 'FAILURE';"
" try {"
" result = parent.getResult();"
" } catch(e) { console.log(e.stack); }"
" document.location = \"https://tests/exit?result=\"+result;"
"}"
"</script>"
"</head><body onload=\"execXSSRequest();\">"
"Running execXSSRequest..."
"</body></html>";
test_results->sub_html = ss.str();
test_results->url = url;
ss.str("");
ss << "<html><head>"
"<script language=\"JavaScript\">"
<< domain_line
<< ""
"function getResult() {"
" try {"
" return document.getElementById('s').contentWindow.getResult();"
" } catch(e) { console.log(e.stack); }"
" return 'FAILURE';"
"}"
"</script>"
"</head><body>"
"<iframe src=\""
<< sub_url.c_str()
<< "\" id=\"s\">"
"</body></html>";
test_results->html = ss.str();
test_results->exit_url = "https://tests/exit";
}
} // namespace
// Test that scheme registration/unregistration works as expected.
TEST(SchemeHandlerTest, Registration) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd://test/run.html";
test_results.html =
"<html><head></head><body><h1>Success!</h1></body></html>";
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
// Unregister the handler.
EXPECT_TRUE(CefRegisterSchemeHandlerFactory("customstd", "test", nullptr));
WaitForIOThread();
test_results.got_request.reset();
test_results.got_read.reset();
test_results.got_output.reset();
test_results.expected_error_code = ERR_UNKNOWN_URL_SCHEME;
handler->ExecuteTest();
EXPECT_TRUE(test_results.got_error);
EXPECT_FALSE(test_results.got_request);
EXPECT_FALSE(test_results.got_read);
EXPECT_FALSE(test_results.got_output);
// Re-register the handler.
EXPECT_TRUE(CefRegisterSchemeHandlerFactory(
"customstd", "test", new ClientSchemeHandlerFactory(&test_results)));
WaitForIOThread();
test_results.got_error.reset();
test_results.expected_error_code = ERR_NONE;
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_FALSE(test_results.got_error);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can return normal results.
TEST(SchemeHandlerTest, CustomStandardNormalResponse) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd://test/run.html";
test_results.html =
"<html><head></head><body><h1>Success!</h1></body></html>";
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can return normal results with delayed
// responses.
TEST(SchemeHandlerTest, CustomStandardNormalResponseDelayed) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd://test/run.html";
test_results.html =
"<html><head></head><body><h1>Success!</h1></body></html>";
test_results.delay = 100;
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
ClearTestSchemes(&test_results);
}
// Test that a custom nonstandard scheme can return normal results.
TEST(SchemeHandlerTest, CustomNonStandardNormalResponse) {
TestResults test_results;
RegisterTestScheme(&test_results, "customnonstd", std::string());
test_results.url = "customnonstd:some%20value";
test_results.html =
"<html><head></head><body><h1>Success!</h1></body></html>";
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can return an error code.
TEST(SchemeHandlerTest, CustomStandardErrorResponse) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd://test/run.html";
test_results.html = "<html><head></head><body><h1>404</h1></body></html>";
test_results.status_code = 404;
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can return a CEF error code in the
// response.
TEST(SchemeHandlerTest, CustomStandardErrorCodeResponse) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd://test/run.html";
test_results.response_error_code = ERR_FILE_TOO_BIG;
test_results.expected_error_code = ERR_FILE_TOO_BIG;
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_FALSE(test_results.got_read);
EXPECT_FALSE(test_results.got_output);
EXPECT_TRUE(test_results.got_error);
ClearTestSchemes(&test_results);
}
// Test that a custom nonstandard scheme can return an error code.
TEST(SchemeHandlerTest, CustomNonStandardErrorResponse) {
TestResults test_results;
RegisterTestScheme(&test_results, "customnonstd", std::string());
test_results.url = "customnonstd:some%20value";
test_results.html = "<html><head></head><body><h1>404</h1></body></html>";
test_results.status_code = 404;
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
ClearTestSchemes(&test_results);
}
// Test that custom standard scheme handling fails when the scheme name is
// incorrect.
TEST(SchemeHandlerTest, CustomStandardNameNotHandled) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd2://test/run.html";
test_results.expected_error_code = ERR_UNKNOWN_URL_SCHEME;
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_FALSE(test_results.got_request);
EXPECT_FALSE(test_results.got_read);
EXPECT_FALSE(test_results.got_output);
EXPECT_TRUE(test_results.got_error);
ClearTestSchemes(&test_results);
}
// Test that custom nonstandard scheme handling fails when the scheme name is
// incorrect.
TEST(SchemeHandlerTest, CustomNonStandardNameNotHandled) {
TestResults test_results;
RegisterTestScheme(&test_results, "customnonstd", std::string());
test_results.url = "customnonstd2:some%20value";
test_results.expected_error_code = ERR_UNKNOWN_URL_SCHEME;
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_FALSE(test_results.got_request);
EXPECT_FALSE(test_results.got_read);
EXPECT_FALSE(test_results.got_output);
EXPECT_TRUE(test_results.got_error);
ClearTestSchemes(&test_results);
}
// Test that custom standard scheme handling fails when the domain name is
// incorrect.
TEST(SchemeHandlerTest, CustomStandardDomainNotHandled) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd://noexist/run.html";
test_results.expected_error_code = ERR_UNKNOWN_URL_SCHEME;
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_FALSE(test_results.got_request);
EXPECT_FALSE(test_results.got_read);
EXPECT_FALSE(test_results.got_output);
EXPECT_TRUE(test_results.got_error);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can return no response.
TEST(SchemeHandlerTest, CustomStandardNoResponse) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd://test/run.html";
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_FALSE(test_results.got_read);
EXPECT_FALSE(test_results.got_output);
ClearTestSchemes(&test_results);
}
// Test that a custom nonstandard scheme can return no response.
TEST(SchemeHandlerTest, CustomNonStandardNoResponse) {
TestResults test_results;
RegisterTestScheme(&test_results, "customnonstd", std::string());
test_results.url = "customnonstd:some%20value";
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_FALSE(test_results.got_read);
EXPECT_FALSE(test_results.got_output);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate redirects.
TEST(SchemeHandlerTest, CustomStandardRedirect) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd://test/run.html";
test_results.redirect_url = "customstd://test/redirect.html";
test_results.html =
"<html><head></head><body><h1>Redirected</h1></body></html>";
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_redirect);
ClearTestSchemes(&test_results);
}
// Test that a custom nonstandard scheme can generate redirects.
TEST(SchemeHandlerTest, CustomNonStandardRedirect) {
TestResults test_results;
RegisterTestScheme(&test_results, "customnonstd", std::string());
test_results.url = "customnonstd:some%20value";
test_results.redirect_url = "customnonstd:some%20other%20value";
test_results.html =
"<html><head></head><body><h1>Redirected</h1></body></html>";
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_redirect);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate same origin XHR requests.
TEST(SchemeHandlerTest, CustomStandardXHRSameOriginSync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
XHRTestSettings settings;
settings.url = "customstd://test/run.html";
settings.sub_url = "customstd://test/xhr.html";
SetUpXHR(&test_results, settings);
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate same origin XHR requests.
TEST(SchemeHandlerTest, CustomStandardXHRSameOriginAsync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
XHRTestSettings settings;
settings.url = "customstd://test/run.html";
settings.sub_url = "customstd://test/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that custom nonstandard schemes are treated as unique origins that
// cannot generate XHR requests.
TEST(SchemeHandlerTest, CustomNonStandardXHRSameOriginSync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customnonstd", std::string());
XHRTestSettings settings;
settings.url = "customnonstd:some%20value";
settings.sub_url = "customnonstd:xhr%20value";
SetUpXHR(&test_results, settings);
test_results.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(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_FALSE(test_results.got_sub_request);
EXPECT_FALSE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that custom nonstandard schemes are treated as unique origins that
// cannot generate XHR requests.
TEST(SchemeHandlerTest, CustomNonStandardXHRSameOriginAsync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customnonstd", std::string());
XHRTestSettings settings;
settings.url = "customnonstd:some%20value";
settings.sub_url = "customnonstd:xhr%20value";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
test_results.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(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_FALSE(test_results.got_sub_request);
EXPECT_FALSE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a non fetch enabled custom standard scheme can't generate same
// origin Fetch requests.
TEST(SchemeHandlerTest, CustomStandardFetchSameOrigin) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
FetchTestSettings settings;
settings.url = "customstd://test/run.html";
settings.sub_url = "customstd://test/fetch.html";
SetUpFetch(&test_results, settings);
test_results.console_messages.push_back(
"Fetch API cannot load customstd://test/fetch.html. URL scheme "
"\"customstd\" is not supported.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_FALSE(test_results.got_sub_request);
EXPECT_FALSE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a fetch enabled custom standard scheme can generate same origin
// Fetch requests.
TEST(SchemeHandlerTest, FetchCustomStandardFetchSameOrigin) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test");
FetchTestSettings settings;
settings.url = "customstdfetch://test/run.html";
settings.sub_url = "customstdfetch://test/fetch.html";
SetUpFetch(&test_results, settings);
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that custom nonstandard schemes are treated as unique origins that
// cannot generate Fetch requests.
TEST(SchemeHandlerTest, CustomNonStandardFetchSameOrigin) {
TestResults test_results;
RegisterTestScheme(&test_results, "customnonstd", std::string());
FetchTestSettings settings;
settings.url = "customnonstd:some%20value";
settings.sub_url = "customnonstd:xhr%20value";
SetUpFetch(&test_results, settings);
test_results.console_messages.push_back(
"Fetch API cannot load customnonstd:xhr%20value. URL scheme "
"\"customnonstd\" is not supported.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_FALSE(test_results.got_sub_request);
EXPECT_FALSE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate same origin XSS requests.
TEST(SchemeHandlerTest, CustomStandardXSSSameOrigin) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test");
SetUpXSS(&test_results, "customstd://test/run.html",
"customstd://test/iframe.html");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that custom nonstandard schemes are treated as unique origins that
// cannot generate XSS requests.
TEST(SchemeHandlerTest, CustomNonStandardXSSSameOrigin) {
TestResults test_results;
RegisterTestScheme(&test_results, "customnonstd", std::string());
SetUpXSS(&test_results, "customnonstd:some%20value",
"customnonstd:xhr%20value");
test_results.console_messages.push_back(
"Error: Failed to read a named property 'getResult' from 'Window': "
"Blocked a frame with origin \"null\" from accessing a "
"cross-origin frame.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme cannot generate cross-domain XHR requests
// by default. Behavior should be the same as with HTTP.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginSync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
SetUpXHR(&test_results, settings);
test_results.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(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme cannot generate cross-domain XHR requests
// by default. Behavior should be the same as with HTTP.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginAsync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
test_results.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(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme cannot generate cross-domain Fetch
// requests by default. Behavior should be the same as with HTTP.
TEST(SchemeHandlerTest, CustomStandardFetchDifferentOrigin) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test1");
RegisterTestScheme(&test_results, "customstdfetch", "test2");
FetchTestSettings settings;
settings.url = "customstdfetch://test1/run.html";
settings.sub_url = "customstdfetch://test2/fetch.html";
SetUpFetch(&test_results, settings);
test_results.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(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme cannot generate cross-domain XSS requests
// by default.
TEST(SchemeHandlerTest, CustomStandardXSSDifferentOrigin) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
SetUpXSS(&test_results, "customstd://test1/run.html",
"customstd://test2/iframe.html");
test_results.console_messages.push_back(
"Error: Failed to read a named property 'getResult' from 'Window': "
"Blocked a frame with origin \"customstd://test2\" from accessing "
"a cross-origin frame.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a cross-protocol iframe load succeeds, and that the custom
// standard scheme cannot generate XSS requests to the HTTP protocol by default.
TEST(SchemeHandlerTest, CustomStandardXSSDifferentProtocolHttp) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "https", "test2");
SetUpXSS(&test_results, "customstd://test1/run.html",
"https://test2/iframe.html");
test_results.console_messages.push_back(
"Error: Failed to read a named property 'getResult' from 'Window': "
"Blocked a frame with origin \"https://test2\" from accessing a "
"cross-origin frame.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a cross-protocol iframe load succeeds, and that the custom
// standard scheme cannot generate XSS requests to a non-standard scheme by
// default.
TEST(SchemeHandlerTest, CustomStandardXSSDifferentProtocolCustomNonStandard) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customnonstd", std::string());
SetUpXSS(&test_results, "customstd://test1/run.html",
"customnonstd:some%20value");
test_results.console_messages.push_back(
"Error: Failed to read a named property 'getResult' from 'Window': "
"Blocked a frame with origin \"null\" from accessing a "
"cross-origin frame.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a cross-protocol iframe load succeeds, and that the HTTP protocol
// cannot generate XSS requests to the custom standard scheme by default.
TEST(SchemeHandlerTest, HttpXSSDifferentProtocolCustomStandard) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
SetUpXSS(&test_results, "https://test1/run.html",
"customstd://test2/iframe.html");
test_results.console_messages.push_back(
"Error: Failed to read a named property 'getResult' from 'Window': "
"Blocked a frame with origin \"customstd://test2\" from accessing "
"a cross-origin frame.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a cross-protocol iframe load succeeds, and that the HTTP protocol
// cannot generate XSS requests to the custom non-standard scheme by default.
TEST(SchemeHandlerTest, HttpXSSDifferentProtocolCustomNonStandard) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "test1");
RegisterTestScheme(&test_results, "customnonstd", std::string());
SetUpXSS(&test_results, "https://test1/run.html",
"customnonstd:some%20value");
test_results.console_messages.push_back(
"Error: Failed to read a named property 'getResult' from 'Window': "
"Blocked a frame with origin \"null\" from accessing a "
"cross-origin frame.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that an HTTP scheme cannot generate cross-domain XHR requests by
// default.
TEST(SchemeHandlerTest, HttpXHRDifferentOriginSync) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "test1");
RegisterTestScheme(&test_results, "https", "test2");
XHRTestSettings settings;
settings.url = "https://test1/run.html";
settings.sub_url = "https://test2/xhr.html";
SetUpXHR(&test_results, settings);
test_results.console_messages.push_back(
"Access to XMLHttpRequest at 'https://test2/xhr.html' from origin "
"'https://test1' has been blocked by CORS policy: No "
"'Access-Control-Allow-Origin' header is present on the requested "
"resource.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that an HTTP scheme cannot generate cross-domain XHR requests by
// default.
TEST(SchemeHandlerTest, HttpXHRDifferentOriginAsync) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "test1");
RegisterTestScheme(&test_results, "https", "test2");
XHRTestSettings settings;
settings.url = "https://test1/run.html";
settings.sub_url = "https://test2/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
test_results.console_messages.push_back(
"Access to XMLHttpRequest at 'https://test2/xhr.html' from origin "
"'https://test1' has been blocked by CORS policy: No "
"'Access-Control-Allow-Origin' header is present on the requested "
"resource.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that an HTTP scheme cannot generate cross-domain Fetch requests by
// default.
TEST(SchemeHandlerTest, HttpFetchDifferentOriginAsync) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "test1");
RegisterTestScheme(&test_results, "https", "test2");
FetchTestSettings settings;
settings.url = "https://test1/run.html";
settings.sub_url = "https://test2/fetch.html";
SetUpFetch(&test_results, settings);
test_results.console_messages.push_back(
"Access to fetch at 'https://test2/fetch.html' from origin "
"'https://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(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that an HTTP scheme cannot generate cross-domain XSS requests by
// default.
TEST(SchemeHandlerTest, HttpXSSDifferentOrigin) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "test1");
RegisterTestScheme(&test_results, "https", "test2");
SetUpXSS(&test_results, "https://test1/run.html", "https://test2/xss.html");
test_results.console_messages.push_back(
"Error: Failed to read a named property 'getResult' from 'Window': "
"Blocked a frame with origin \"https://test2\" from accessing a "
"cross-origin frame.");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain XHR requests
// when setting the Access-Control-Allow-Origin header. Should behave the same
// as HTTP.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithHeaderSync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.sub_allow_origin = "customstd://test1";
SetUpXHR(&test_results, settings);
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain XHR requests
// when setting the Access-Control-Allow-Origin header. Should behave the same
// as HTTP.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithHeaderAsync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.sub_allow_origin = "customstd://test1";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain Fetch requests
// when setting the Access-Control-Allow-Origin header. Should behave the same
// as HTTP.
TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginWithHeader) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test1");
RegisterTestScheme(&test_results, "customstdfetch", "test2");
FetchTestSettings settings;
settings.url = "customstdfetch://test1/run.html";
settings.sub_url = "customstdfetch://test2/fetch.html";
settings.sub_allow_origin = "customstdfetch://test1";
SetUpFetch(&test_results, settings);
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain XHR requests
// when using the cross-origin whitelist.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistSync1) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
"test2", false));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches any domain.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistSync2) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
CefString(), true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches sub-domains.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistSync3) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "a.test2.foo");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://a.test2.foo/xhr.html";
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
"test2.foo", true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain XHR requests
// when using the cross-origin whitelist.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistAsync1) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
"test2", false));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches any domain.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistAsync2) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
CefString(), true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches sub-domains.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistAsync3) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "a.test2.foo");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://a.test2.foo/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
"test2.foo", true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain Fetch requests
// when using the cross-origin whitelist.
TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginWithWhitelist1) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test1");
RegisterTestScheme(&test_results, "customstdfetch", "test2");
FetchTestSettings settings;
settings.url = "customstdfetch://test1/run.html";
settings.sub_url = "customstdfetch://test2/fetch.html";
SetUpFetch(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
"customstdfetch://test1", "customstdfetch", "test2", false));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches any domain.
TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginWithWhitelist2) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test1");
RegisterTestScheme(&test_results, "customstdfetch", "test2");
FetchTestSettings settings;
settings.url = "customstdfetch://test1/run.html";
settings.sub_url = "customstdfetch://test2/fetch.html";
SetUpFetch(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
"customstdfetch://test1", "customstdfetch", CefString(), true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches sub-domains.
TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginWithWhitelist3) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test1");
RegisterTestScheme(&test_results, "customstdfetch", "a.test2.foo");
FetchTestSettings settings;
settings.url = "customstdfetch://test1/run.html";
settings.sub_url = "customstdfetch://a.test2.foo/fetch.html";
SetUpFetch(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
"customstdfetch://test1", "customstdfetch", "test2.foo", true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Test that an HTTP scheme can generate cross-domain XHR requests when setting
// the Access-Control-Allow-Origin header.
TEST(SchemeHandlerTest, HttpXHRDifferentOriginWithHeaderSync) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "test1");
RegisterTestScheme(&test_results, "https", "test2");
XHRTestSettings settings;
settings.url = "https://test1/run.html";
settings.sub_url = "https://test2/xhr.html";
settings.sub_allow_origin = "https://test1";
SetUpXHR(&test_results, settings);
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that an HTTP scheme can generate cross-domain XHR requests when setting
// the Access-Control-Allow-Origin header.
TEST(SchemeHandlerTest, HttpXHRDifferentOriginWithHeaderAsync) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "test1");
RegisterTestScheme(&test_results, "https", "test2");
XHRTestSettings settings;
settings.url = "https://test1/run.html";
settings.sub_url = "https://test2/xhr.html";
settings.sub_allow_origin = "https://test1";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that an HTTP scheme can generate cross-domain XHR requests when setting
// the Access-Control-Allow-Origin header.
TEST(SchemeHandlerTest, HttpFetchDifferentOriginWithHeader) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "test1");
RegisterTestScheme(&test_results, "https", "test2");
FetchTestSettings settings;
settings.url = "https://test1/run.html";
settings.sub_url = "https://test2/fetch.html";
settings.sub_allow_origin = "https://test1";
SetUpFetch(&test_results, settings);
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain XSS requests
// when using document.domain.
TEST(SchemeHandlerTest, CustomStandardXSSDifferentOriginWithDomain) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "a.test.com");
RegisterTestScheme(&test_results, "customstd", "b.test.com");
SetUpXSS(&test_results, "customstd://a.test.com/run.html",
"customstd://b.test.com/iframe.html", "test.com");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that an HTTP scheme can generate cross-domain XSS requests when using
// document.domain.
TEST(SchemeHandlerTest, HttpXSSDifferentOriginWithDomain) {
TestResults test_results;
RegisterTestScheme(&test_results, "https", "a.test.com");
RegisterTestScheme(&test_results, "https", "b.test.com");
SetUpXSS(&test_results, "https://a.test.com/run.html",
"https://b.test.com/iframe.html", "test.com");
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme cannot generate cross-domain XHR requests
// that perform redirects.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginRedirectSync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.sub_redirect_url = "customstd://test1/xhr.html";
SetUpXHR(&test_results, settings);
test_results.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(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme cannot generate cross-domain XHR requests
// that perform redirects.
TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginRedirectAsync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.sub_redirect_url = "customstd://test1/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
test_results.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(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme cannot generate cross-domain Fetch
// requests that perform redirects.
TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginRedirect) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test1");
RegisterTestScheme(&test_results, "customstdfetch", "test2");
FetchTestSettings settings;
settings.url = "customstdfetch://test1/run.html";
settings.sub_url = "customstdfetch://test2/fetch.html";
settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
SetUpFetch(&test_results, settings);
test_results.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(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_FALSE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain XHR requests
// that perform redirects when using the cross-origin whitelist.
TEST(SchemeHandlerTest,
CustomStandardXHRDifferentOriginRedirectWithWhitelistSync) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.sub_redirect_url = "customstd://test1/xhr.html";
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
"test2", false));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain XHR requests
// that perform redirects when using the cross-origin whitelist.
TEST(SchemeHandlerTest,
CustomStandardXHRDifferentOriginRedirectWithWhitelistAsync1) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.sub_redirect_url = "customstd://test1/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
"test2", false));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches any domain.
TEST(SchemeHandlerTest,
CustomStandardXHRDifferentOriginRedirectWithWhitelistAsync2) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "test2");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://test2/xhr.html";
settings.sub_redirect_url = "customstd://test1/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
CefString(), true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches sub-domains.
TEST(SchemeHandlerTest,
CustomStandardXHRDifferentOriginRedirectWithWhitelistAsync3) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstd", "test1");
RegisterTestScheme(&test_results, "customstd", "a.test2.foo");
XHRTestSettings settings;
settings.url = "customstd://test1/run.html";
settings.sub_url = "customstd://a.test2.foo/xhr.html";
settings.sub_redirect_url = "customstd://test1/xhr.html";
settings.synchronous = false;
SetUpXHR(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
"test2.foo", true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Test that a custom standard scheme can generate cross-domain Fetch requests
// that perform redirects when using the cross-origin whitelist.
TEST(SchemeHandlerTest,
CustomStandardFetchDifferentOriginRedirectWithWhitelist1) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test1");
RegisterTestScheme(&test_results, "customstdfetch", "test2");
FetchTestSettings settings;
settings.url = "customstdfetch://test1/run.html";
settings.sub_url = "customstdfetch://test2/fetch.html";
settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
SetUpFetch(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
"customstdfetch://test1", "customstdfetch", "test2", false));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches any domain.
TEST(SchemeHandlerTest,
CustomStandardFetchDifferentOriginRedirectWithWhitelist2) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test1");
RegisterTestScheme(&test_results, "customstdfetch", "test2");
FetchTestSettings settings;
settings.url = "customstdfetch://test1/run.html";
settings.sub_url = "customstdfetch://test2/fetch.html";
settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
SetUpFetch(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
"customstdfetch://test1", "customstdfetch", CefString(), true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Same as above but origin whitelist matches sub-domains.
TEST(SchemeHandlerTest,
CustomStandardFetchDifferentOriginRedirectWithWhitelist3) {
TestResults test_results;
RegisterTestScheme(&test_results, "customstdfetch", "test1");
RegisterTestScheme(&test_results, "customstdfetch", "a.test2.foo");
FetchTestSettings settings;
settings.url = "customstdfetch://test1/run.html";
settings.sub_url = "customstdfetch://a.test2.foo/fetch.html";
settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
SetUpFetch(&test_results, settings);
EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
"customstdfetch://test1", "customstdfetch", "test2.foo", true));
WaitForUIThread();
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.got_sub_redirect);
EXPECT_TRUE(test_results.got_sub_request);
EXPECT_TRUE(test_results.got_sub_read);
EXPECT_TRUE(test_results.git_exit_success);
EXPECT_TRUE(CefClearCrossOriginWhitelist());
WaitForUIThread();
ClearTestSchemes(&test_results);
}
// Test that CefRequestContextSettings.accept_language_list configures both
// the Accept-Language request header and `navigator.language` JS attribute.
TEST(SchemeHandlerTest, AcceptLanguage) {
TestResults test_results;
// Value that will be set via CefRequestContextSettings.accept_language_list.
test_results.accept_language = "uk";
// Create an in-memory request context with custom settings.
CefRequestContextSettings settings;
CefString(&settings.accept_language_list) = test_results.accept_language;
test_results.request_context =
CefRequestContext::CreateContext(settings, nullptr);
RegisterTestScheme(&test_results, "customstd", "test");
test_results.url = "customstd://test/run.html";
test_results.html =
"<html><head></head><body>"
"<script>"
"if (navigator.language == 'uk') {"
" result = 'SUCCESS';"
"} else {"
" result = 'FAILURE';"
" console.log('navigator.language: '+navigator.language+' != uk');"
"}"
"document.location = 'https://tests/exit?result='+result;"
"</script>"
"</body></html>";
test_results.exit_url = "https://tests/exit";
CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&test_results);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
EXPECT_TRUE(test_results.got_request);
EXPECT_TRUE(test_results.got_read);
EXPECT_TRUE(test_results.got_output);
EXPECT_TRUE(test_results.git_exit_success);
ClearTestSchemes(&test_results);
}
// Entry point for registering custom schemes.
// Called from client_app_delegates.cc.
void RegisterSchemeHandlerCustomSchemes(
CefRawPtr<CefSchemeRegistrar> registrar) {
// Registering the custom standard schemes as secure because requests from
// non-secure origins to the loopback address will be blocked by
// https://chromestatus.com/feature/5436853517811712.
// Add a custom standard scheme.
registrar->AddCustomScheme("customstd", CEF_SCHEME_OPTION_STANDARD |
CEF_SCHEME_OPTION_SECURE |
CEF_SCHEME_OPTION_CORS_ENABLED);
// Also used in cors_unittest.cc.
registrar->AddCustomScheme(
"customstdfetch", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_SECURE |
CEF_SCHEME_OPTION_CORS_ENABLED |
CEF_SCHEME_OPTION_FETCH_ENABLED);
// Add a custom non-standard scheme.
registrar->AddCustomScheme("customnonstd", CEF_SCHEME_OPTION_NONE);
registrar->AddCustomScheme("customnonstdfetch",
CEF_SCHEME_OPTION_FETCH_ENABLED);
}
// Entry point for registering cookieable schemes.
// Called from client_app_delegates.cc.
void RegisterSchemeHandlerCookieableSchemes(
std::vector<std::string>& cookieable_schemes) {
cookieable_schemes.push_back("customstd");
// Also used in cors_unittest.cc.
cookieable_schemes.push_back("customstdfetch");
}