cef/tests/ceftests/request_context_unittest.cc

1031 lines
36 KiB
C++

// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "include/base/cef_callback.h"
#include "include/base/cef_weak_ptr.h"
#include "include/cef_request_context.h"
#include "include/cef_request_context_handler.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_scoped_temp_dir.h"
#include "tests/ceftests/test_handler.h"
#include "tests/ceftests/test_util.h"
#include "tests/gtest/include/gtest/gtest.h"
TEST(RequestContextTest, BasicGetGlobal) {
CefRefPtr<CefRequestContext> context1 = CefRequestContext::GetGlobalContext();
EXPECT_TRUE(context1.get());
EXPECT_TRUE(context1->IsGlobal());
EXPECT_TRUE(context1->IsSame(context1));
EXPECT_TRUE(context1->IsSharingWith(context1));
CefRefPtr<CefRequestContext> context2 = CefRequestContext::GetGlobalContext();
EXPECT_TRUE(context2.get());
EXPECT_TRUE(context2->IsGlobal());
EXPECT_TRUE(context2->IsSame(context2));
EXPECT_TRUE(context2->IsSharingWith(context2));
EXPECT_TRUE(context1->IsSame(context2));
EXPECT_TRUE(context2->IsSame(context1));
EXPECT_TRUE(context1->IsSharingWith(context2));
EXPECT_TRUE(context2->IsSharingWith(context1));
}
TEST(RequestContextTest, BasicCreate) {
class Handler : public CefRequestContextHandler {
public:
Handler() = default;
private:
IMPLEMENT_REFCOUNTING(Handler);
};
CefRefPtr<CefRequestContextHandler> handler = new Handler();
CefRequestContextSettings settings;
CefRefPtr<CefRequestContext> context1 =
CefRequestContext::CreateContext(settings, handler.get());
EXPECT_TRUE(context1.get());
EXPECT_FALSE(context1->IsGlobal());
EXPECT_TRUE(context1->IsSame(context1));
EXPECT_TRUE(context1->IsSharingWith(context1));
EXPECT_EQ(context1->GetHandler().get(), handler.get());
CefRefPtr<CefRequestContext> context2 =
CefRequestContext::CreateContext(settings, handler.get());
EXPECT_TRUE(context2.get());
EXPECT_FALSE(context2->IsGlobal());
EXPECT_TRUE(context2->IsSame(context2));
EXPECT_TRUE(context2->IsSharingWith(context2));
EXPECT_EQ(context2->GetHandler().get(), handler.get());
EXPECT_FALSE(context1->IsSame(context2));
EXPECT_FALSE(context1->IsSharingWith(context2));
EXPECT_FALSE(context2->IsSame(context1));
EXPECT_FALSE(context2->IsSharingWith(context1));
CefRefPtr<CefRequestContext> context3 = CefRequestContext::GetGlobalContext();
EXPECT_TRUE(context3.get());
EXPECT_FALSE(context3->IsSame(context1));
EXPECT_FALSE(context3->IsSharingWith(context1));
EXPECT_FALSE(context3->IsSame(context2));
EXPECT_FALSE(context3->IsSharingWith(context2));
EXPECT_FALSE(context1->IsSame(context3));
EXPECT_FALSE(context1->IsSharingWith(context3));
EXPECT_FALSE(context2->IsSame(context3));
EXPECT_FALSE(context2->IsSharingWith(context3));
}
TEST(RequestContextTest, BasicCreateNoHandler) {
CefRequestContextSettings settings;
CefRefPtr<CefRequestContext> context1 =
CefRequestContext::CreateContext(settings, nullptr);
EXPECT_TRUE(context1.get());
EXPECT_FALSE(context1->IsGlobal());
EXPECT_TRUE(context1->IsSame(context1));
EXPECT_TRUE(context1->IsSharingWith(context1));
EXPECT_FALSE(context1->GetHandler().get());
CefRefPtr<CefRequestContext> context2 =
CefRequestContext::CreateContext(settings, nullptr);
EXPECT_TRUE(context2.get());
EXPECT_FALSE(context2->IsGlobal());
EXPECT_TRUE(context2->IsSame(context2));
EXPECT_TRUE(context2->IsSharingWith(context2));
EXPECT_FALSE(context2->GetHandler().get());
EXPECT_FALSE(context1->IsSame(context2));
EXPECT_FALSE(context1->IsSharingWith(context2));
EXPECT_FALSE(context2->IsSame(context1));
EXPECT_FALSE(context2->IsSharingWith(context1));
CefRefPtr<CefRequestContext> context3 = CefRequestContext::GetGlobalContext();
EXPECT_TRUE(context3.get());
EXPECT_FALSE(context3->IsSame(context1));
EXPECT_FALSE(context3->IsSharingWith(context1));
EXPECT_FALSE(context3->IsSame(context2));
EXPECT_FALSE(context3->IsSharingWith(context2));
EXPECT_FALSE(context1->IsSame(context3));
EXPECT_FALSE(context1->IsSharingWith(context3));
EXPECT_FALSE(context2->IsSame(context3));
EXPECT_FALSE(context2->IsSharingWith(context3));
}
TEST(RequestContextTest, BasicCreateSharedGlobal) {
CefRequestContextSettings settings;
CefRefPtr<CefRequestContext> context1 = CefRequestContext::GetGlobalContext();
EXPECT_TRUE(context1.get());
EXPECT_TRUE(context1->IsGlobal());
EXPECT_TRUE(context1->IsSame(context1));
EXPECT_TRUE(context1->IsSharingWith(context1));
// Returns the same global context.
CefRefPtr<CefRequestContext> context2 =
CefRequestContext::CreateContext(context1, nullptr);
EXPECT_TRUE(context2.get());
EXPECT_TRUE(context2->IsGlobal());
EXPECT_TRUE(context2->IsSame(context2));
EXPECT_TRUE(context2->IsSame(context1));
EXPECT_TRUE(context1->IsSame(context2));
EXPECT_TRUE(context2->IsSharingWith(context2));
EXPECT_TRUE(context2->IsSharingWith(context1));
EXPECT_TRUE(context1->IsSharingWith(context2));
}
TEST(RequestContextTest, BasicCreateSharedOnDisk) {
CefScopedTempDir tempdir;
EXPECT_TRUE(tempdir.CreateUniqueTempDirUnderPath(
CefTestSuite::GetInstance()->root_cache_path()));
CefRequestContextSettings settings;
CefString(&settings.cache_path) = tempdir.GetPath();
CefRefPtr<CefRequestContext> context1 =
CefRequestContext::CreateContext(settings, nullptr);
EXPECT_TRUE(context1.get());
EXPECT_FALSE(context1->IsGlobal());
EXPECT_TRUE(context1->IsSame(context1));
EXPECT_TRUE(context1->IsSharingWith(context1));
CefRefPtr<CefRequestContext> context2 =
CefRequestContext::CreateContext(context1, nullptr);
EXPECT_TRUE(context2.get());
EXPECT_FALSE(context2->IsGlobal());
EXPECT_TRUE(context2->IsSame(context2));
EXPECT_FALSE(context2->IsSame(context1));
EXPECT_FALSE(context1->IsSame(context2));
EXPECT_TRUE(context2->IsSharingWith(context2));
EXPECT_TRUE(context2->IsSharingWith(context1));
EXPECT_TRUE(context1->IsSharingWith(context2));
CefRefPtr<CefRequestContext> context3 =
CefRequestContext::CreateContext(context2, nullptr);
EXPECT_TRUE(context3.get());
EXPECT_FALSE(context3->IsGlobal());
EXPECT_TRUE(context3->IsSame(context3));
EXPECT_FALSE(context3->IsSame(context2));
EXPECT_FALSE(context3->IsSame(context1));
EXPECT_FALSE(context1->IsSame(context3));
EXPECT_FALSE(context2->IsSame(context3));
EXPECT_TRUE(context3->IsSharingWith(context3));
EXPECT_TRUE(context3->IsSharingWith(context2));
EXPECT_TRUE(context3->IsSharingWith(context1));
EXPECT_TRUE(context1->IsSharingWith(context3));
EXPECT_TRUE(context2->IsSharingWith(context3));
CefRefPtr<CefRequestContext> context4 =
CefRequestContext::CreateContext(context1, nullptr);
EXPECT_TRUE(context4.get());
EXPECT_FALSE(context4->IsGlobal());
EXPECT_TRUE(context4->IsSame(context4));
EXPECT_FALSE(context4->IsSame(context3));
EXPECT_FALSE(context4->IsSame(context2));
EXPECT_FALSE(context4->IsSame(context1));
EXPECT_FALSE(context1->IsSame(context4));
EXPECT_FALSE(context2->IsSame(context4));
EXPECT_FALSE(context3->IsSame(context4));
EXPECT_TRUE(context4->IsSharingWith(context4));
EXPECT_TRUE(context4->IsSharingWith(context3));
EXPECT_TRUE(context4->IsSharingWith(context2));
EXPECT_TRUE(context4->IsSharingWith(context1));
EXPECT_TRUE(context1->IsSharingWith(context4));
EXPECT_TRUE(context2->IsSharingWith(context4));
EXPECT_TRUE(context3->IsSharingWith(context4));
}
namespace {
class PopupTestHandler : public TestHandler {
public:
enum Mode {
MODE_WINDOW_OPEN,
MODE_TARGETED_LINK,
// The no-referrer popup won't have an opener from the renderer's
// perspective, but we still track it from the browser's perspective.
MODE_NOREFERRER_LINK,
};
PopupTestHandler(bool same_origin, Mode mode) : mode_(mode) {
url_ = "https://tests-simple-rch1.com/nav1.html";
if (same_origin) {
popup_url_ = "https://tests-simple-rch1.com/pop1.html";
} else {
popup_url_ = "https://tests-simple-rch2.com/pop1.html";
}
}
void RunTest() override {
std::string link;
if (mode_ == MODE_TARGETED_LINK) {
link = "<a href=\"" + std::string(popup_url_) +
"\" target=\"mytarget\"\">CLICK ME</a>";
} else if (mode_ == MODE_NOREFERRER_LINK) {
link = "<a href=\"" + std::string(popup_url_) +
"\" rel=\"noreferrer\" target=\"_blank\"\">CLICK ME</a>";
}
AddResource(url_,
"<html>"
"<head><script>document.cookie='name1=value1';"
"function doPopup() { window.open('" +
std::string(popup_url_) +
"'); }"
"</script></head>"
"<body><h1>" +
link +
"</h1></body>"
"</html>",
"text/html");
AddResource(popup_url_,
"<html>"
"<head><script>document.cookie='name2=value2';</script></head>"
"<body>Nav1</body>"
"</html>",
"text/html");
CefRequestContextSettings settings;
context_ = CefRequestContext::CreateContext(settings, nullptr);
cookie_manager_ = context_->GetCookieManager(nullptr);
GrantPopupPermission(context_, url_);
// Create browser that loads the 1st URL.
CreateBrowser(url_, context_);
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) override {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
EXPECT_TRUE(context.get());
EXPECT_TRUE(context->IsSame(context_));
EXPECT_FALSE(context->IsGlobal());
EXPECT_TRUE(frame->IsMain());
const std::string& url = frame->GetURL();
if (url == url_) {
got_load_end1_.yes();
LaunchPopup(browser);
} else if (url == popup_url_) {
got_load_end2_.yes();
EXPECT_TRUE(browser->IsPopup());
// Close the popup window.
CloseBrowser(browser, true);
}
}
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int popup_id,
const CefString& target_url,
const CefString& target_frame_name,
cef_window_open_disposition_t target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue>& extra_info,
bool* no_javascript_access) override {
EXPECT_FALSE(got_on_before_popup_);
EXPECT_FALSE(got_on_before_popup_aborted_);
EXPECT_FALSE(got_on_after_created_popup_);
got_on_before_popup_.yes();
// Only ever a single popup with this test.
EXPECT_EQ(1, popup_id);
const std::string& url = target_url;
EXPECT_STREQ(url.c_str(), popup_url_.c_str());
EXPECT_EQ(CEF_WOD_NEW_FOREGROUND_TAB, target_disposition);
if (mode_ == MODE_WINDOW_OPEN) {
EXPECT_FALSE(user_gesture);
} else {
EXPECT_TRUE(user_gesture);
}
return false;
}
void OnBeforePopupAborted(CefRefPtr<CefBrowser> browser,
int popup_id) override {
EXPECT_TRUE(got_on_before_popup_);
EXPECT_FALSE(got_on_before_popup_aborted_);
EXPECT_FALSE(got_on_after_created_popup_);
got_on_before_popup_aborted_.yes();
// Only ever a single popup with this test.
EXPECT_EQ(1, popup_id);
}
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
if (browser->IsPopup()) {
EXPECT_TRUE(got_on_before_popup_);
EXPECT_FALSE(got_on_before_popup_aborted_);
got_on_after_created_popup_.yes();
// Opener is the main browser.
EXPECT_EQ(GetBrowserId(), browser->GetHost()->GetOpenerIdentifier());
} else {
EXPECT_EQ(0, browser->GetHost()->GetOpenerIdentifier());
}
TestHandler::OnAfterCreated(browser);
}
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
TestHandler::OnBeforeClose(browser);
if (browser->IsPopup()) {
FinishTest();
}
}
protected:
void LaunchPopup(CefRefPtr<CefBrowser> browser) {
if (mode_ == MODE_WINDOW_OPEN) {
browser->GetMainFrame()->ExecuteJavaScript("doPopup()", url_, 0);
} else if (mode_ == MODE_TARGETED_LINK || mode_ == MODE_NOREFERRER_LINK) {
CefMouseEvent mouse_event;
mouse_event.x = 20;
mouse_event.y = 20;
mouse_event.modifiers = 0;
SendMouseClickEvent(browser, mouse_event);
} else {
ADD_FAILURE(); // Not reached.
}
}
void FinishTest() {
// Verify that the cookies were set correctly.
class TestVisitor : public CefCookieVisitor {
public:
explicit TestVisitor(PopupTestHandler* handler) : handler_(handler) {}
~TestVisitor() override {
// Destroy the test.
CefPostTask(TID_UI,
base::BindOnce(&PopupTestHandler::DestroyTest, handler_));
}
bool Visit(const CefCookie& cookie,
int count,
int total,
bool& deleteCookie) override {
const std::string& name = CefString(&cookie.name);
const std::string& value = CefString(&cookie.value);
if (name == "name1" && value == "value1") {
handler_->got_cookie1_.yes();
deleteCookie = true;
} else if (name == "name2" && value == "value2") {
handler_->got_cookie2_.yes();
deleteCookie = true;
}
return true;
}
private:
PopupTestHandler* handler_;
IMPLEMENT_REFCOUNTING(TestVisitor);
};
cookie_manager_->VisitAllCookies(new TestVisitor(this));
}
void DestroyTest() override {
// Verify test expectations.
EXPECT_TRUE(got_load_end1_);
EXPECT_TRUE(got_on_before_popup_);
EXPECT_FALSE(got_on_before_popup_aborted_);
EXPECT_TRUE(got_on_after_created_popup_);
EXPECT_TRUE(got_load_end2_);
EXPECT_TRUE(got_cookie1_);
EXPECT_TRUE(got_cookie2_);
context_ = nullptr;
TestHandler::DestroyTest();
}
std::string url_;
std::string popup_url_;
Mode mode_;
CefRefPtr<CefRequestContext> context_;
CefRefPtr<CefCookieManager> cookie_manager_;
TrackCallback got_load_end1_;
TrackCallback got_on_before_popup_;
TrackCallback got_on_before_popup_aborted_;
TrackCallback got_on_after_created_popup_;
TrackCallback got_load_end2_;
TrackCallback got_cookie1_;
TrackCallback got_cookie2_;
IMPLEMENT_REFCOUNTING(PopupTestHandler);
};
} // namespace
// Test that a popup created using window.open() will get the same request
// context as the parent browser.
TEST(RequestContextTest, PopupBasicWindowOpenSameOrigin) {
CefRefPtr<PopupTestHandler> handler =
new PopupTestHandler(true, PopupTestHandler::MODE_WINDOW_OPEN);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
TEST(RequestContextTest, PopupBasicWindowOpenDifferentOrigin) {
CefRefPtr<PopupTestHandler> handler =
new PopupTestHandler(false, PopupTestHandler::MODE_WINDOW_OPEN);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test that a popup created using a targeted link will get the same request
// context as the parent browser.
TEST(RequestContextTest, PopupBasicTargetedLinkSameOrigin) {
CefRefPtr<PopupTestHandler> handler =
new PopupTestHandler(true, PopupTestHandler::MODE_TARGETED_LINK);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
TEST(RequestContextTest, PopupBasicTargetedLinkDifferentOrigin) {
CefRefPtr<PopupTestHandler> handler =
new PopupTestHandler(false, PopupTestHandler::MODE_TARGETED_LINK);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test that a popup created using a noreferrer link will get the same
// request context as the parent browser. A new render process will
// be created for the popup browser.
TEST(RequestContextTest, PopupBasicNoReferrerLinkSameOrigin) {
CefRefPtr<PopupTestHandler> handler =
new PopupTestHandler(true, PopupTestHandler::MODE_NOREFERRER_LINK);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
TEST(RequestContextTest, PopupBasicNoReferrerLinkDifferentOrigin) {
CefRefPtr<PopupTestHandler> handler =
new PopupTestHandler(false, PopupTestHandler::MODE_NOREFERRER_LINK);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
namespace {
const char kPopupNavPageUrl[] = "https://tests-popup.com/page.html";
const char kPopupNavPopupUrl[] = "https://tests-popup.com/popup.html";
const char kPopupNavPopupUrl2[] = "https://tests-popup2.com/popup.html";
const char kPopupNavPopupName[] = "my_popup";
// Browser side.
class PopupNavTestHandler : public TestHandler {
public:
enum TestMode {
ALLOW_CLOSE_POPUP_FIRST,
ALLOW_CLOSE_POPUP_LAST,
DENY,
NAVIGATE_AFTER_CREATION,
DESTROY_PARENT_BEFORE_CREATION,
DESTROY_PARENT_BEFORE_CREATION_FORCE,
DESTROY_PARENT_DURING_CREATION,
DESTROY_PARENT_DURING_CREATION_FORCE,
DESTROY_PARENT_AFTER_CREATION,
DESTROY_PARENT_AFTER_CREATION_FORCE,
};
PopupNavTestHandler(TestMode test_mode,
TestRequestContextMode rc_mode,
const std::string& rc_cache_path)
: mode_(test_mode), rc_mode_(rc_mode), rc_cache_path_(rc_cache_path) {}
void RunTest() override {
// Add the resources that we will navigate to/from.
std::string page = "<html><script>function doPopup() { window.open('" +
std::string(kPopupNavPopupUrl) + "', '" +
std::string(kPopupNavPopupName) +
"'); }</script>Page</html>";
AddResource(kPopupNavPageUrl, page, "text/html");
AddResource(kPopupNavPopupUrl, "<html>Popup</html>", "text/html");
if (mode_ == NAVIGATE_AFTER_CREATION) {
AddResource(kPopupNavPopupUrl2, "<html>Popup2</html>", "text/html");
}
// By default, TestHandler signals test completion when all CefBrowsers
// have closed. For this test we instead want to wait for an explicit call
// to DestroyTest before signaling test completion.
SetSignalTestCompletionCount(1U);
CreateTestRequestContext(
rc_mode_, rc_cache_path_,
base::BindOnce(&PopupNavTestHandler::RunTestContinue, this));
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
void RunTestContinue(CefRefPtr<CefRequestContext> request_context) {
EXPECT_UI_THREAD();
if (request_context) {
GrantPopupPermission(request_context, kPopupNavPageUrl);
} else {
GrantPopupPermission(CefRequestContext::GetGlobalContext(),
kPopupNavPageUrl);
}
// Create the browser.
CreateBrowser(kPopupNavPageUrl, request_context);
}
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int popup_id,
const CefString& target_url,
const CefString& target_frame_name,
cef_window_open_disposition_t target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue>& extra_info,
bool* no_javascript_access) override {
EXPECT_FALSE(got_on_before_popup_);
EXPECT_FALSE(got_on_before_popup_aborted_);
got_on_before_popup_.yes();
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
// Only ever a single popup with this test.
EXPECT_EQ(1, popup_id);
opener_browser_id_ = browser->GetIdentifier();
EXPECT_EQ(GetBrowserId(), opener_browser_id_);
EXPECT_STREQ(kPopupNavPageUrl, frame->GetURL().ToString().c_str());
EXPECT_STREQ(kPopupNavPopupUrl, target_url.ToString().c_str());
EXPECT_STREQ(kPopupNavPopupName, target_frame_name.ToString().c_str());
EXPECT_EQ(CEF_WOD_NEW_FOREGROUND_TAB, target_disposition);
EXPECT_FALSE(user_gesture);
EXPECT_FALSE(*no_javascript_access);
if (mode_ == DESTROY_PARENT_DURING_CREATION ||
mode_ == DESTROY_PARENT_DURING_CREATION_FORCE) {
// Destroy the main (parent) browser while popup creation is pending.
CloseBrowser(browser, mode_ == DESTROY_PARENT_DURING_CREATION_FORCE);
}
return (mode_ == DENY); // Return true to cancel the popup.
}
void OnBeforePopupAborted(CefRefPtr<CefBrowser> browser,
int popup_id) override {
EXPECT_TRUE(got_on_before_popup_);
EXPECT_FALSE(got_on_before_popup_aborted_);
got_on_before_popup_aborted_.yes();
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
// Can't use GetBrowserId() here because the opener is already closing.
EXPECT_EQ(opener_browser_id_, browser->GetIdentifier());
EXPECT_FALSE(browser->IsValid());
// Only ever a single popup with this test.
EXPECT_EQ(1, popup_id);
}
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
TestHandler::OnAfterCreated(browser);
if (browser->IsPopup()) {
EXPECT_TRUE(got_on_before_popup_);
EXPECT_EQ(opener_browser_id_, browser->GetHost()->GetOpenerIdentifier());
} else {
EXPECT_FALSE(got_on_before_popup_);
EXPECT_EQ(0, browser->GetHost()->GetOpenerIdentifier());
}
EXPECT_FALSE(got_on_before_popup_aborted_);
if (browser->IsPopup() && (mode_ == DESTROY_PARENT_AFTER_CREATION ||
mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE)) {
// Destroy the main (parent) browser immediately after the popup is
// created.
CloseBrowser(GetBrowser(), mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE);
}
if (mode_ == NAVIGATE_AFTER_CREATION && browser->IsPopup()) {
// Navigate to the 2nd popup URL instead of the 1st popup URL.
browser->GetMainFrame()->LoadURL(kPopupNavPopupUrl2);
}
}
void OnLoadStart(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
TransitionType transition_type) override {
const std::string& url = frame->GetURL();
if (url == kPopupNavPageUrl) {
EXPECT_FALSE(got_load_start_);
got_load_start_.yes();
} else if (url == kPopupNavPopupUrl) {
EXPECT_FALSE(got_popup_load_start_);
got_popup_load_start_.yes();
} else if (url == kPopupNavPopupUrl2) {
EXPECT_FALSE(got_popup_load_start2_);
got_popup_load_start2_.yes();
}
}
void OnLoadError(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
ErrorCode errorCode,
const CefString& errorText,
const CefString& failedUrl) override {
if (failedUrl == kPopupNavPageUrl) {
EXPECT_FALSE(got_load_error_);
got_load_error_.yes();
} else if (failedUrl == kPopupNavPopupUrl) {
EXPECT_FALSE(got_popup_load_error_);
got_popup_load_error_.yes();
} else if (failedUrl == kPopupNavPopupUrl2) {
EXPECT_FALSE(got_popup_load_error2_);
got_popup_load_error2_.yes();
}
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) override {
const std::string& url = frame->GetURL();
if (url == kPopupNavPageUrl) {
EXPECT_FALSE(got_load_end_);
got_load_end_.yes();
frame->ExecuteJavaScript("doPopup()", kPopupNavPageUrl, 0);
if (mode_ == DESTROY_PARENT_BEFORE_CREATION ||
mode_ == DESTROY_PARENT_BEFORE_CREATION_FORCE) {
// Destroy the main (parent) browser immediately before the popup is
// created.
CloseBrowser(browser, mode_ == DESTROY_PARENT_BEFORE_CREATION_FORCE);
}
if (mode_ == DENY) {
// Wait a bit to make sure the popup window isn't created.
CefPostDelayedTask(TID_UI,
base::BindOnce(&PopupNavTestHandler::DestroyTest,
weak_ptr_factory_.GetWeakPtr()),
200);
}
} else if (url == kPopupNavPopupUrl) {
EXPECT_FALSE(got_popup_load_end_);
got_popup_load_end_.yes();
if (mode_ == ALLOW_CLOSE_POPUP_FIRST) {
// Close the popup browser first.
CloseBrowser(browser, false);
} else if (mode_ == ALLOW_CLOSE_POPUP_LAST) {
// Close the main browser first.
CloseBrowser(GetBrowser(), false);
} else if (mode_ != NAVIGATE_AFTER_CREATION) {
EXPECT_FALSE(true); // Not reached.
}
} else if (url == kPopupNavPopupUrl2) {
EXPECT_FALSE(got_popup_load_end2_);
got_popup_load_end2_.yes();
if (mode_ == NAVIGATE_AFTER_CREATION) {
// Close the popup browser first.
CloseBrowser(browser, false);
} else {
EXPECT_FALSE(true); // Not reached.
}
} else {
EXPECT_FALSE(true); // Not reached.
}
}
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
TestHandler::OnBeforeClose(browser);
bool destroy_test = false;
if (mode_ == ALLOW_CLOSE_POPUP_FIRST || mode_ == NAVIGATE_AFTER_CREATION) {
// Destroy the test after the popup browser closes.
if (browser->IsPopup()) {
destroy_test = true;
}
} else if (mode_ == ALLOW_CLOSE_POPUP_LAST ||
mode_ == DESTROY_PARENT_BEFORE_CREATION ||
mode_ == DESTROY_PARENT_BEFORE_CREATION_FORCE ||
mode_ == DESTROY_PARENT_DURING_CREATION ||
mode_ == DESTROY_PARENT_DURING_CREATION_FORCE ||
mode_ == DESTROY_PARENT_AFTER_CREATION ||
mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE) {
// Destroy the test after the main browser closes.
if (!browser->IsPopup()) {
destroy_test = true;
}
}
if (destroy_test) {
// This may race with OnBeforeClose() for the remaining browser.
CefPostTask(TID_UI, base::BindOnce(&PopupNavTestHandler::DestroyTest,
weak_ptr_factory_.GetWeakPtr()));
}
}
private:
void DestroyTest() override {
EXPECT_TRUE(got_load_start_);
EXPECT_FALSE(got_load_error_);
EXPECT_TRUE(got_load_end_);
// OnBeforePopup may come before or after browser destruction with the
// DESTROY_PARENT_BEFORE_CREATION* tests and Alloy style browsers.
if (mode_ != DESTROY_PARENT_BEFORE_CREATION &&
mode_ != DESTROY_PARENT_BEFORE_CREATION_FORCE) {
EXPECT_TRUE(got_on_before_popup_);
} else if (!use_alloy_style_browser()) {
EXPECT_FALSE(got_on_before_popup_);
}
if (mode_ == DESTROY_PARENT_DURING_CREATION ||
mode_ == DESTROY_PARENT_DURING_CREATION_FORCE ||
mode_ == DESTROY_PARENT_AFTER_CREATION ||
mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE) {
// Timing of Alloy style browsers may not result in abort.
if (!use_alloy_style_browser()) {
EXPECT_TRUE(got_on_before_popup_aborted_);
}
} else {
EXPECT_FALSE(got_on_before_popup_aborted_);
}
if (mode_ == ALLOW_CLOSE_POPUP_FIRST || mode_ == ALLOW_CLOSE_POPUP_LAST) {
EXPECT_TRUE(got_popup_load_start_);
EXPECT_FALSE(got_popup_load_error_);
EXPECT_TRUE(got_popup_load_end_);
EXPECT_FALSE(got_popup_load_start2_);
EXPECT_FALSE(got_popup_load_error2_);
EXPECT_FALSE(got_popup_load_end2_);
} else if (mode_ == DENY || mode_ == DESTROY_PARENT_BEFORE_CREATION ||
mode_ == DESTROY_PARENT_BEFORE_CREATION_FORCE ||
mode_ == DESTROY_PARENT_DURING_CREATION ||
mode_ == DESTROY_PARENT_DURING_CREATION_FORCE ||
mode_ == DESTROY_PARENT_AFTER_CREATION ||
mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE) {
EXPECT_FALSE(got_popup_load_start_);
EXPECT_FALSE(got_popup_load_error_);
EXPECT_FALSE(got_popup_load_end_);
EXPECT_FALSE(got_popup_load_start2_);
EXPECT_FALSE(got_popup_load_error2_);
EXPECT_FALSE(got_popup_load_end2_);
} else if (mode_ == NAVIGATE_AFTER_CREATION) {
EXPECT_FALSE(got_popup_load_start_);
// With browser-side navigation we will never actually begin the
// navigation to the 1st popup URL, so there will be no load error.
EXPECT_FALSE(got_popup_load_error_);
EXPECT_FALSE(got_popup_load_end_);
EXPECT_TRUE(got_popup_load_start2_);
EXPECT_FALSE(got_popup_load_error2_);
EXPECT_TRUE(got_popup_load_end2_);
}
// Invalidate WeakPtrs now as |this| may be deleted on a different thread.
weak_ptr_factory_.InvalidateWeakPtrs();
// Will trigger destruction of any remaining browsers.
TestHandler::DestroyTest();
// Allow the the test to complete once all browsers are gone.
SignalTestCompletion();
}
const TestMode mode_;
const TestRequestContextMode rc_mode_;
const std::string rc_cache_path_;
TrackCallback got_on_before_popup_;
int opener_browser_id_ = 0;
TrackCallback got_on_before_popup_aborted_;
TrackCallback got_load_start_;
TrackCallback got_load_error_;
TrackCallback got_load_end_;
TrackCallback got_popup_load_start_;
TrackCallback got_popup_load_error_;
TrackCallback got_popup_load_end_;
TrackCallback got_popup_load_start2_;
TrackCallback got_popup_load_error2_;
TrackCallback got_popup_load_end2_;
base::WeakPtrFactory<PopupNavTestHandler> weak_ptr_factory_{this};
IMPLEMENT_REFCOUNTING(PopupNavTestHandler);
};
} // namespace
#define POPUP_TEST_GROUP(test_name, test_mode) \
RC_TEST_GROUP_IN_MEMORY(RequestContextTest, PopupNav##test_name, \
PopupNavTestHandler, test_mode)
// Test allowing popups and closing the popup browser first.
POPUP_TEST_GROUP(AllowClosePopupFirst, ALLOW_CLOSE_POPUP_FIRST)
// Test allowing popups and closing the main browser first to verify
// that internal objects are tracked correctly (see issue #2162).
POPUP_TEST_GROUP(AllowClosePopupLast, ALLOW_CLOSE_POPUP_LAST)
// Test denying popups.
POPUP_TEST_GROUP(Deny, DENY)
// Test navigation to a different origin after popup creation to
// verify that internal objects are tracked correctly (see issue
// #1392).
POPUP_TEST_GROUP(NavigateAfterCreation, NAVIGATE_AFTER_CREATION)
// Test destroying the parent browser during or immediately after
// popup creation to verify that internal objects are tracked
// correctly (see issue #2041).
POPUP_TEST_GROUP(DestroyParentBeforeCreation, DESTROY_PARENT_BEFORE_CREATION)
POPUP_TEST_GROUP(DestroyParentBeforeCreationForce,
DESTROY_PARENT_BEFORE_CREATION_FORCE)
POPUP_TEST_GROUP(DestroyParentDuringCreation, DESTROY_PARENT_DURING_CREATION)
POPUP_TEST_GROUP(DestroyParentDuringCreationForce,
DESTROY_PARENT_DURING_CREATION_FORCE)
POPUP_TEST_GROUP(DestroyParentAfterCreation, DESTROY_PARENT_AFTER_CREATION)
POPUP_TEST_GROUP(DestroyParentAfterCreationForce,
DESTROY_PARENT_AFTER_CREATION_FORCE)
namespace {
const char kResolveOrigin[] = "https://www.google.com";
class MethodTestHandler : public TestHandler {
public:
enum Method {
METHOD_CLEAR_CERTIFICATE_EXCEPTIONS,
METHOD_CLOSE_ALL_CONNECTIONS,
METHOD_RESOLVE_HOST,
};
class CompletionCallback : public CefCompletionCallback,
public CefResolveCallback {
public:
CompletionCallback(MethodTestHandler* test_handler,
CefRefPtr<CefBrowser> browser)
: test_handler_(test_handler), browser_(browser) {}
~CompletionCallback() override {
// OnComplete should be executed.
EXPECT_FALSE(test_handler_);
}
void OnComplete() override {
EXPECT_UI_THREAD();
// OnComplete should be executed only one time.
EXPECT_TRUE(test_handler_);
test_handler_->OnCompleteCallback(browser_);
test_handler_ = nullptr;
browser_ = nullptr;
}
void OnResolveCompleted(
cef_errorcode_t result,
const std::vector<CefString>& resolved_ips) override {
EXPECT_EQ(ERR_NONE, result);
EXPECT_TRUE(!resolved_ips.empty());
OnComplete();
}
private:
MethodTestHandler* test_handler_;
CefRefPtr<CefBrowser> browser_;
IMPLEMENT_REFCOUNTING(CompletionCallback);
};
MethodTestHandler(bool global_context, Method method)
: global_context_(global_context), method_(method) {}
void RunTest() override {
const char kUrl[] = "https://tests/method.html";
AddResource(kUrl, "<html><body>Method</body></html>", "text/html");
CefRefPtr<CefRequestContext> request_context;
if (!global_context_) {
CefRequestContextSettings settings;
request_context = CefRequestContext::CreateContext(settings, nullptr);
}
CreateBrowser(kUrl, request_context);
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) override {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
CefRefPtr<CompletionCallback> callback =
new CompletionCallback(this, browser);
if (method_ == METHOD_CLEAR_CERTIFICATE_EXCEPTIONS) {
context->ClearCertificateExceptions(callback);
} else if (method_ == METHOD_CLOSE_ALL_CONNECTIONS) {
context->CloseAllConnections(callback);
} else if (method_ == METHOD_RESOLVE_HOST) {
context->ResolveHost(kResolveOrigin, callback);
}
}
void OnCompleteCallback(CefRefPtr<CefBrowser> browser) {
EXPECT_UI_THREAD();
EXPECT_FALSE(got_completion_callback_);
got_completion_callback_.yes();
DestroyTest();
}
private:
void DestroyTest() override {
EXPECT_TRUE(got_completion_callback_);
TestHandler::DestroyTest();
}
const bool global_context_;
const Method method_;
TrackCallback got_completion_callback_;
IMPLEMENT_REFCOUNTING(MethodTestHandler);
};
} // namespace
// Test CefRequestContext::ClearCertificateExceptions with the global
// context.
TEST(RequestContextTest, ClearCertificateExceptionsGlobal) {
CefRefPtr<MethodTestHandler> handler = new MethodTestHandler(
true, MethodTestHandler::METHOD_CLEAR_CERTIFICATE_EXCEPTIONS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test CefRequestContext::ClearCertificateExceptions with a custom
// context.
TEST(RequestContextTest, ClearCertificateExceptionsCustom) {
CefRefPtr<MethodTestHandler> handler = new MethodTestHandler(
false, MethodTestHandler::METHOD_CLEAR_CERTIFICATE_EXCEPTIONS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test CefRequestContext::CloseAllConnections with the global
// context.
TEST(RequestContextTest, CloseAllConnectionsGlobal) {
CefRefPtr<MethodTestHandler> handler = new MethodTestHandler(
true, MethodTestHandler::METHOD_CLOSE_ALL_CONNECTIONS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test CefRequestContext::CloseAllConnections with a custom context.
TEST(RequestContextTest, CloseAllConnectionsCustom) {
CefRefPtr<MethodTestHandler> handler = new MethodTestHandler(
false, MethodTestHandler::METHOD_CLOSE_ALL_CONNECTIONS);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test CefRequestContext::ResolveHost with the global context.
TEST(RequestContextTest, ResolveHostGlobal) {
CefRefPtr<MethodTestHandler> handler =
new MethodTestHandler(true, MethodTestHandler::METHOD_RESOLVE_HOST);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Test CefRequestContext::ResolveHost with a custom context.
TEST(RequestContextTest, ResolveHostCustom) {
CefRefPtr<MethodTestHandler> handler =
new MethodTestHandler(false, MethodTestHandler::METHOD_RESOLVE_HOST);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}