Add a new CefRequestHandler::OnOpenURLFromTab method for handling certain limited cases where navigating a new or different browser might be desirable (issue #1526).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@2054 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2015-03-09 20:22:31 +00:00
parent 5de989e306
commit c49473729d
10 changed files with 515 additions and 139 deletions

View File

@ -118,6 +118,27 @@ typedef struct _cef_request_handler_t {
struct _cef_browser_t* browser, struct _cef_frame_t* frame,
struct _cef_request_t* request, int is_redirect);
///
// Called on the UI thread before OnBeforeBrowse in certain limited cases
// where navigating a new or different browser might be desirable. This
// includes user-initiated navigation that might open in a special way (e.g.
// links clicked via middle-click or ctrl + left-click) and certain types of
// cross-origin navigation initiated from the renderer process (e.g.
// navigating the top-level frame to/from a file URL). The |browser| and
// |frame| values represent the source of the navigation. The
// |target_disposition| value indicates where the user intended to navigate
// the browser based on standard Chromium behaviors (e.g. current tab, new
// tab, etc). The |user_gesture| value will be true (1) if the browser
// navigated via explicit user gesture (e.g. clicking a link) or false (0) if
// it navigated automatically (e.g. via the DomContentLoaded event). Return
// true (1) to cancel the navigation or false (0) to allow the navigation to
// proceed in the source browser's top-level frame.
///
int (CEF_CALLBACK *on_open_urlfrom_tab)(struct _cef_request_handler_t* self,
struct _cef_browser_t* browser, struct _cef_frame_t* frame,
const cef_string_t* target_url,
cef_window_open_disposition_t target_disposition, int user_gesture);
///
// Called on the IO thread before a resource request is loaded. The |request|
// object may be modified. To cancel the request return true (1) otherwise

View File

@ -93,6 +93,7 @@ class CefAllowCertificateErrorCallback : public virtual CefBase {
class CefRequestHandler : public virtual CefBase {
public:
typedef cef_termination_status_t TerminationStatus;
typedef cef_window_open_disposition_t WindowOpenDisposition;
///
// Called on the UI thread before browser navigation. Return true to cancel
@ -112,6 +113,31 @@ class CefRequestHandler : public virtual CefBase {
return false;
}
///
// Called on the UI thread before OnBeforeBrowse in certain limited cases
// where navigating a new or different browser might be desirable. This
// includes user-initiated navigation that might open in a special way (e.g.
// links clicked via middle-click or ctrl + left-click) and certain types of
// cross-origin navigation initiated from the renderer process (e.g.
// navigating the top-level frame to/from a file URL). The |browser| and
// |frame| values represent the source of the navigation. The
// |target_disposition| value indicates where the user intended to navigate
// the browser based on standard Chromium behaviors (e.g. current tab,
// new tab, etc). The |user_gesture| value will be true if the browser
// navigated via explicit user gesture (e.g. clicking a link) or false if it
// navigated automatically (e.g. via the DomContentLoaded event). Return true
// to cancel the navigation or false to allow the navigation to proceed in the
// source browser's top-level frame.
///
/*--cef()--*/
virtual bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
WindowOpenDisposition target_disposition,
bool user_gesture) {
return false;
}
///
// Called on the IO thread before a resource request is loaded. The |request|
// object may be modified. To cancel the request return true otherwise return

View File

@ -2005,12 +2005,30 @@ void CefBrowserHostImpl::DragSourceEndedAt(
content::WebContents* CefBrowserHostImpl::OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params) {
// Start a navigation that will result in the creation of a new render
// process.
LoadURL(CefFrameHostImpl::kMainFrameId, params.url.spec(), params.referrer,
params.transition, params.extra_headers);
bool cancel = false;
return source;
if (client_.get()) {
CefRefPtr<CefRequestHandler> handler = client_->GetRequestHandler();
if (handler.get()) {
cancel = handler->OnOpenURLFromTab(
this,
GetFrame(params.frame_tree_node_id),
params.url.spec(),
static_cast<cef_window_open_disposition_t>(params.disposition),
params.user_gesture);
}
}
if (!cancel) {
// Start a navigation in the current browser that will result in the
// creation of a new render process.
LoadURL(CefFrameHostImpl::kMainFrameId, params.url.spec(), params.referrer,
params.transition, params.extra_headers);
return source;
}
// We don't know where the navigation, if any, will occur.
return nullptr;
}
void CefBrowserHostImpl::LoadingStateChanged(content::WebContents* source,

View File

@ -56,6 +56,40 @@ int CEF_CALLBACK request_handler_on_before_browse(
return _retval;
}
int CEF_CALLBACK request_handler_on_open_urlfrom_tab(
struct _cef_request_handler_t* self, cef_browser_t* browser,
cef_frame_t* frame, const cef_string_t* target_url,
cef_window_open_disposition_t target_disposition, int user_gesture) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: browser; type: refptr_diff
DCHECK(browser);
if (!browser)
return 0;
// Verify param: frame; type: refptr_diff
DCHECK(frame);
if (!frame)
return 0;
// Verify param: target_url; type: string_byref_const
DCHECK(target_url);
if (!target_url)
return 0;
// Execute
bool _retval = CefRequestHandlerCppToC::Get(self)->OnOpenURLFromTab(
CefBrowserCToCpp::Wrap(browser),
CefFrameCToCpp::Wrap(frame),
CefString(target_url),
target_disposition,
user_gesture?true:false);
// Return type: bool
return _retval;
}
int CEF_CALLBACK request_handler_on_before_resource_load(
struct _cef_request_handler_t* self, cef_browser_t* browser,
cef_frame_t* frame, cef_request_t* request) {
@ -389,6 +423,7 @@ CefRequestHandlerCppToC::CefRequestHandlerCppToC(CefRequestHandler* cls)
: CefCppToC<CefRequestHandlerCppToC, CefRequestHandler,
cef_request_handler_t>(cls) {
struct_.struct_.on_before_browse = request_handler_on_before_browse;
struct_.struct_.on_open_urlfrom_tab = request_handler_on_open_urlfrom_tab;
struct_.struct_.on_before_resource_load =
request_handler_on_before_resource_load;
struct_.struct_.get_resource_handler = request_handler_get_resource_handler;

View File

@ -56,6 +56,39 @@ bool CefRequestHandlerCToCpp::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
return _retval?true:false;
}
bool CefRequestHandlerCToCpp::OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, const CefString& target_url,
WindowOpenDisposition target_disposition, bool user_gesture) {
if (CEF_MEMBER_MISSING(struct_, on_open_urlfrom_tab))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: browser; type: refptr_diff
DCHECK(browser.get());
if (!browser.get())
return false;
// Verify param: frame; type: refptr_diff
DCHECK(frame.get());
if (!frame.get())
return false;
// Verify param: target_url; type: string_byref_const
DCHECK(!target_url.empty());
if (target_url.empty())
return false;
// Execute
int _retval = struct_->on_open_urlfrom_tab(struct_,
CefBrowserCppToC::Wrap(browser),
CefFrameCppToC::Wrap(frame),
target_url.GetStruct(),
target_disposition,
user_gesture);
// Return type: bool
return _retval?true:false;
}
bool CefRequestHandlerCToCpp::OnBeforeResourceLoad(
CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) {

View File

@ -35,6 +35,9 @@ class CefRequestHandlerCToCpp
// CefRequestHandler methods
bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request, bool is_redirect) override;
bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, const CefString& target_url,
WindowOpenDisposition target_disposition, bool user_gesture) override;
bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request) override;
CefRefPtr<CefResourceHandler> GetResourceHandler(

View File

@ -322,17 +322,18 @@ bool ClientHandler::OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
return false;
}
bool ClientHandler::OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
WindowOpenDisposition target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
bool* no_javascript_access) {
bool ClientHandler::OnBeforePopup(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
bool* no_javascript_access) {
CEF_REQUIRE_IO_THREAD();
// Return true to cancel the popup window.
@ -434,6 +435,24 @@ bool ClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
return false;
}
bool ClientHandler::OnOpenURLFromTab(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
CefRequestHandler::WindowOpenDisposition target_disposition,
bool user_gesture) {
if (user_gesture && target_disposition == WOD_NEW_BACKGROUND_TAB) {
// Handle middle-click and ctrl + left-click by opening the URL in a new
// browser window.
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
true, is_osr(), CefRect(), target_url);
return true;
}
// Open the URL in the current browser window.
return false;
}
CefRefPtr<CefResourceHandler> ClientHandler::GetResourceHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,

View File

@ -166,17 +166,18 @@ class ClientHandler : public CefClient,
bool* is_keyboard_shortcut) OVERRIDE;
// CefLifeSpanHandler methods
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
WindowOpenDisposition target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
bool* no_javascript_access) OVERRIDE;
bool OnBeforePopup(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings,
bool* no_javascript_access) OVERRIDE;
void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
@ -197,6 +198,12 @@ class ClientHandler : public CefClient,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
bool is_redirect) OVERRIDE;
bool OnOpenURLFromTab(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
CefRequestHandler::WindowOpenDisposition target_disposition,
bool user_gesture) OVERRIDE;
CefRefPtr<CefResourceHandler> GetResourceHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,

View File

@ -1438,50 +1438,53 @@ TEST(NavigationTest, Order) {
namespace {
const char kCrossOriginNav1[] = "http://tests-conav1/nav1.html";
const char kCrossOriginNav2[] = "http://tests-conav2/nav2.html";
const char kCrossOriginNavMsg[] = "NavigationTest.CrossOriginNav";
const char kLoadNav1[] = "http://tests-conav1.com/nav1.html";
const char kLoadNavSameOrigin2[] = "http://tests-conav1.com/nav2.html";
const char kLoadNavCrossOrigin2[] = "http://tests-conav2.com/nav2.html";
const char kLoadNavMsg[] = "NavigationTest.LoadNav";
bool g_cross_origin_nav_test = false;
bool g_load_nav_test = false;
// Browser side.
class CrossOriginNavBrowserTest : public ClientAppBrowser::Delegate {
class LoadNavBrowserTest : public ClientAppBrowser::Delegate {
public:
CrossOriginNavBrowserTest() {}
LoadNavBrowserTest() {}
void OnBeforeChildProcessLaunch(
CefRefPtr<ClientAppBrowser> app,
CefRefPtr<CefCommandLine> command_line) override {
if (!g_cross_origin_nav_test)
if (!g_load_nav_test)
return;
// Indicate to the render process that the test should be run.
command_line->AppendSwitchWithValue("test", kCrossOriginNavMsg);
command_line->AppendSwitchWithValue("test", kLoadNavMsg);
}
protected:
IMPLEMENT_REFCOUNTING(CrossOriginNavBrowserTest);
IMPLEMENT_REFCOUNTING(LoadNavBrowserTest);
};
// Renderer side.
class CrossOriginNavRendererTest : public ClientAppRenderer::Delegate,
public CefLoadHandler {
class LoadNavRendererTest : public ClientAppRenderer::Delegate,
public CefLoadHandler {
public:
CrossOriginNavRendererTest()
: run_test_(false) {}
~CrossOriginNavRendererTest() override {
EXPECT_TRUE(status_list_.empty());
LoadNavRendererTest()
: run_test_(false),
browser_id_(0),
load_ct_(0) {}
~LoadNavRendererTest() override {
EXPECT_EQ(0, browser_id_);
}
void OnRenderThreadCreated(
CefRefPtr<ClientAppRenderer> app,
CefRefPtr<CefListValue> extra_info) override {
if (!g_cross_origin_nav_test) {
if (!g_load_nav_test) {
// Check that the test should be run.
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
const std::string& test = command_line->GetSwitchValue("test");
if (test != kCrossOriginNavMsg)
if (test != kLoadNavMsg)
return;
}
@ -1509,9 +1512,10 @@ class CrossOriginNavRendererTest : public ClientAppRenderer::Delegate,
EXPECT_TRUE(got_render_thread_created_);
EXPECT_TRUE(got_webkit_initialized_);
EXPECT_FALSE(GetStatus(browser));
Status* status = AddStatus(browser);
status->got_browser_created.yes();
EXPECT_EQ(0, browser_id_);
browser_id_ = browser->GetIdentifier();
EXPECT_GT(browser_id_, 0);
got_browser_created_.yes();
}
void OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,
@ -1522,15 +1526,11 @@ class CrossOriginNavRendererTest : public ClientAppRenderer::Delegate,
EXPECT_TRUE(got_render_thread_created_);
EXPECT_TRUE(got_webkit_initialized_);
Status* status = GetStatus(browser);
EXPECT_TRUE(status);
EXPECT_TRUE(got_browser_created_);
EXPECT_TRUE(got_loading_state_end_);
EXPECT_TRUE(status->got_browser_created);
EXPECT_TRUE(status->got_loading_state_end);
EXPECT_EQ(status->browser_id, browser->GetIdentifier());
EXPECT_TRUE(RemoveStatus(browser));
EXPECT_EQ(browser_id_, browser->GetIdentifier());
browser_id_ = 0;
}
CefRefPtr<CefLoadHandler> GetLoadHandler(
@ -1549,16 +1549,13 @@ class CrossOriginNavRendererTest : public ClientAppRenderer::Delegate,
EXPECT_TRUE(got_render_thread_created_);
EXPECT_TRUE(got_webkit_initialized_);
Status* status = GetStatus(browser);
EXPECT_TRUE(status);
EXPECT_TRUE(got_browser_created_);
EXPECT_TRUE(status->got_browser_created);
EXPECT_FALSE(status->got_loading_state_end);
got_loading_state_end_.yes();
status->got_loading_state_end.yes();
EXPECT_EQ(status->browser_id, browser->GetIdentifier());
EXPECT_EQ(browser_id_, browser->GetIdentifier());
load_ct_++;
SendTestResults(browser);
}
}
@ -1571,11 +1568,12 @@ class CrossOriginNavRendererTest : public ClientAppRenderer::Delegate,
// Return the result to the browser process.
CefRefPtr<CefProcessMessage> return_msg =
CefProcessMessage::Create(kCrossOriginNavMsg);
CefProcessMessage::Create(kLoadNavMsg);
CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
EXPECT_TRUE(args.get());
EXPECT_TRUE(args->SetBool(0, result));
EXPECT_TRUE(args->SetInt(1, browser->GetIdentifier()));
EXPECT_TRUE(args->SetInt(2, load_ct_));
EXPECT_TRUE(browser->SendProcessMessage(PID_BROWSER, return_msg));
}
@ -1584,68 +1582,60 @@ class CrossOriginNavRendererTest : public ClientAppRenderer::Delegate,
TrackCallback got_render_thread_created_;
TrackCallback got_webkit_initialized_;
struct Status {
Status() : browser_id(0) {}
int browser_id_;
int load_ct_;
TrackCallback got_browser_created_;
TrackCallback got_loading_state_end_;
CefRefPtr<CefBrowser> browser;
int browser_id;
TrackCallback got_browser_created;
TrackCallback got_loading_state_end;
};
typedef std::list<Status> StatusList;
StatusList status_list_;
Status* GetStatus(CefRefPtr<CefBrowser> browser) {
StatusList::iterator it = status_list_.begin();
for (; it != status_list_.end(); ++it) {
Status& status = (*it);
if (status.browser->IsSame(browser))
return &status;
}
return NULL;
}
Status* AddStatus(CefRefPtr<CefBrowser> browser) {
Status status;
status.browser = browser;
status.browser_id = browser->GetIdentifier();
EXPECT_GT(status.browser_id, 0);
status_list_.push_back(status);
return &status_list_.back();
}
bool RemoveStatus(CefRefPtr<CefBrowser> browser) {
StatusList::iterator it = status_list_.begin();
for (; it != status_list_.end(); ++it) {
Status& status = (*it);
if (status.browser->IsSame(browser)) {
status_list_.erase(it);
return true;
}
}
return false;
}
IMPLEMENT_REFCOUNTING(CrossOriginNavRendererTest);
IMPLEMENT_REFCOUNTING(LoadNavRendererTest);
};
// Browser side.
class CrossOriginNavTestHandler : public TestHandler {
class LoadNavTestHandler : public TestHandler {
public:
CrossOriginNavTestHandler()
: browser_id_current_(0),
got_message_(false),
got_load_end_(false) {}
enum TestMode {
LOAD,
LEFT_CLICK,
MIDDLE_CLICK,
CTRL_LEFT_CLICK,
};
LoadNavTestHandler(TestMode mode,
bool same_origin,
bool cancel_in_open_url = false)
: mode_(mode),
same_origin_(same_origin),
cancel_in_open_url_(cancel_in_open_url),
browser_id_current_(0),
renderer_load_ct_(0) {
g_load_nav_test = true;
}
~LoadNavTestHandler() override {
g_load_nav_test = false;
}
std::string GetURL2() const {
return same_origin_ ? kLoadNavSameOrigin2 : kLoadNavCrossOrigin2;
}
bool ExpectOpenURL() const {
return mode_ == MIDDLE_CLICK || mode_ == CTRL_LEFT_CLICK;
}
void RunTest() override {
const std::string& url2 = GetURL2();
std::string link;
if (mode_ != LOAD)
link = "<a href=\"" + url2 + "\">CLICK ME</a>";
// Add the resources that we will navigate to/from.
AddResource(kCrossOriginNav1, "<html>Nav1</html>", "text/html");
AddResource(kCrossOriginNav2, "<html>Nav2</html>", "text/html");
AddResource(kLoadNav1, "<html><body><h1>" + link +
"Nav1</h1></body></html>", "text/html");
AddResource(url2, "<html>Nav2</html>", "text/html");
// Create the browser.
CreateBrowser(kCrossOriginNav1);
CreateBrowser(kLoadNav1);
// Time out the test after a reasonable period of time.
SetTestTimeout();
@ -1655,13 +1645,48 @@ class CrossOriginNavTestHandler : public TestHandler {
if (!got_message_ || !got_load_end_)
return;
got_message_ = false;
got_load_end_ = false;
std::string url = browser->GetMainFrame()->GetURL();
if (url == kCrossOriginNav1) {
if (url == kLoadNav1) {
// Verify the behavior of the previous load.
EXPECT_TRUE(got_before_browse_);
EXPECT_TRUE(got_before_resource_load_);
EXPECT_TRUE(got_load_start_);
EXPECT_TRUE(got_load_end_);
EXPECT_FALSE(got_open_url_from_tab_);
got_before_browse_.reset();
got_before_resource_load_.reset();
got_load_start_.reset();
got_load_end_.reset();
got_message_.reset();
EXPECT_EQ(1, renderer_load_ct_);
// Load the next url.
browser->GetMainFrame()->LoadURL(kCrossOriginNav2);
if (mode_ == LOAD) {
browser->GetMainFrame()->LoadURL(GetURL2());
} else {
// Navigate to the URL by clicking a link.
CefMouseEvent mouse_event;
mouse_event.x = 20;
mouse_event.y = 20;
mouse_event.modifiers =
(mode_ == CTRL_LEFT_CLICK ? EVENTFLAG_CONTROL_DOWN : 0);
cef_mouse_button_type_t button_type =
(mode_ == MIDDLE_CLICK ? MBT_MIDDLE : MBT_LEFT);
browser->GetHost()->SendMouseClickEvent(
mouse_event, button_type, false, 1);
browser->GetHost()->SendMouseClickEvent(
mouse_event, button_type, true, 1);
}
if (cancel_in_open_url_) {
// The next navigation should not occur. Therefore call DestroyTest()
// after a reasonable timeout.
CefPostDelayedTask(TID_UI,
base::Bind(&LoadNavTestHandler::DestroyTest, this), 500);
}
} else {
// Done with the test.
DestroyTest();
@ -1681,22 +1706,67 @@ class CrossOriginNavTestHandler : public TestHandler {
CefRefPtr<CefRequest> request,
bool is_redirect) override {
EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
EXPECT_EQ(TT_EXPLICIT, request->GetTransitionType());
if (mode_ == LOAD || request->GetURL() == kLoadNav1)
EXPECT_EQ(TT_EXPLICIT, request->GetTransitionType());
else
EXPECT_EQ(TT_LINK, request->GetTransitionType());
EXPECT_GT(browser_id_current_, 0);
EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
if (ExpectOpenURL() && request->GetURL() == GetURL2()) {
// OnOpenURLFromTab should be called first for the file URL navigation.
EXPECT_TRUE(got_open_url_from_tab_);
} else {
EXPECT_FALSE(got_open_url_from_tab_);
}
got_before_browse_.yes();
return false;
}
bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& target_url,
cef_window_open_disposition_t target_disposition,
bool user_gesture) override {
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
EXPECT_GT(browser_id_current_, 0);
EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
// OnOpenURLFromTab should only be called for the file URL.
EXPECT_STREQ(GetURL2().c_str(), target_url.ToString().c_str());
if (mode_ == LOAD)
EXPECT_FALSE(user_gesture);
else
EXPECT_TRUE(user_gesture);
EXPECT_EQ(WOD_NEW_BACKGROUND_TAB, target_disposition);
// OnOpenURLFromTab should be called before OnBeforeBrowse for the file URL.
EXPECT_FALSE(got_before_browse_);
got_open_url_from_tab_.yes();
return cancel_in_open_url_;
}
bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override {
EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
EXPECT_EQ(TT_EXPLICIT, request->GetTransitionType());
if (mode_ == LOAD || request->GetURL() == kLoadNav1)
EXPECT_EQ(TT_EXPLICIT, request->GetTransitionType());
else
EXPECT_EQ(TT_LINK, request->GetTransitionType());
EXPECT_GT(browser_id_current_, 0);
EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
got_before_resource_load_.yes();
return false;
}
@ -1705,6 +1775,8 @@ class CrossOriginNavTestHandler : public TestHandler {
CefRefPtr<CefFrame> frame) override {
EXPECT_GT(browser_id_current_, 0);
EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
got_load_start_.yes();
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
@ -1713,7 +1785,7 @@ class CrossOriginNavTestHandler : public TestHandler {
EXPECT_GT(browser_id_current_, 0);
EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
got_load_end_ = true;
got_load_end_.yes();
ContinueIfReady(browser);
}
@ -1725,7 +1797,7 @@ class CrossOriginNavTestHandler : public TestHandler {
EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
const std::string& msg_name = message->GetName();
if (msg_name == kCrossOriginNavMsg) {
if (msg_name == kLoadNavMsg) {
// Test that the renderer side succeeded.
CefRefPtr<CefListValue> args = message->GetArgumentList();
EXPECT_TRUE(args.get());
@ -1733,8 +1805,11 @@ class CrossOriginNavTestHandler : public TestHandler {
EXPECT_EQ(browser_id_current_, args->GetInt(1));
renderer_load_ct_ = args->GetInt(2);
EXPECT_GE(renderer_load_ct_, 1);
// Continue with the test.
got_message_ = true;
got_message_.yes();
ContinueIfReady(browser);
return true;
@ -1744,22 +1819,161 @@ class CrossOriginNavTestHandler : public TestHandler {
return false;
}
protected:
int browser_id_current_;
void DestroyTest() override {
if (cancel_in_open_url_) {
EXPECT_FALSE(got_before_browse_);
EXPECT_FALSE(got_before_resource_load_);
EXPECT_FALSE(got_load_start_);
EXPECT_FALSE(got_load_end_);
EXPECT_FALSE(got_message_);
bool got_message_;
bool got_load_end_;
// We should only navigate a single time if the 2nd load is canceled.
EXPECT_EQ(1, renderer_load_ct_);
} else {
EXPECT_TRUE(got_before_browse_);
EXPECT_TRUE(got_before_resource_load_);
EXPECT_TRUE(got_load_start_);
EXPECT_TRUE(got_load_end_);
EXPECT_TRUE(got_message_);
if (same_origin_) {
// The renderer process should always be reused.
EXPECT_EQ(2, renderer_load_ct_);
} else {
if (mode_ == LEFT_CLICK) {
// For left click on link the renderer process will be reused.
EXPECT_EQ(2, renderer_load_ct_);
} else {
// Each renderer process is only used for a single navigation.
EXPECT_EQ(1, renderer_load_ct_);
}
}
}
if (ExpectOpenURL())
EXPECT_TRUE(got_open_url_from_tab_);
else
EXPECT_FALSE(got_open_url_from_tab_);
TestHandler::DestroyTest();
}
protected:
const TestMode mode_;
const bool same_origin_;
const bool cancel_in_open_url_;
int browser_id_current_;
int renderer_load_ct_;
TrackCallback got_before_browse_;
TrackCallback got_open_url_from_tab_;
TrackCallback got_before_resource_load_;
TrackCallback got_load_start_;
TrackCallback got_load_end_;
TrackCallback got_message_;
};
} // namespace
// Verify navigation-related callbacks when browsing cross-origin.
TEST(NavigationTest, CrossOrigin) {
g_cross_origin_nav_test = true;
CefRefPtr<CrossOriginNavTestHandler> handler =
new CrossOriginNavTestHandler();
// Verify navigation-related callbacks when browsing same-origin via LoadURL().
TEST(NavigationTest, SameOriginLoadURL) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::LOAD, true);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Verify navigation-related callbacks when browsing same-origin via left-click.
TEST(NavigationTest, SameOriginLeftClick) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, true);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Verify navigation-related callbacks when browsing same-origin via middle-
// click.
TEST(NavigationTest, SameOriginMiddleClick) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest, SameOriginMiddleClickCancel) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true, true);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Verify navigation-related callbacks when browsing same-origin via ctrl+left-
// click.
TEST(NavigationTest, SameOriginCtrlLeftClick) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest, SameOriginCtrlLeftClickCancel) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true, true);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Verify navigation-related callbacks when browsing cross-origin via LoadURL().
TEST(NavigationTest, CrossOriginLoadURL) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::LOAD, false);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Verify navigation-related callbacks when browsing cross-origin via left-
// click.
TEST(NavigationTest, CrossOriginLeftClick) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, false);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Verify navigation-related callbacks when browsing cross-origin via middle-
// click.
TEST(NavigationTest, CrossOriginMiddleClick) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest, CrossOriginMiddleClickCancel) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false, true);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Verify navigation-related callbacks when browsing cross-origin via ctrl+left-
// click.
TEST(NavigationTest, CrossOriginCtrlLeftClick) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest, CrossOriginCtrlLeftClickCancel) {
CefRefPtr<LoadNavTestHandler> handler =
new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false, true);
handler->ExecuteTest();
g_cross_origin_nav_test = false;
ReleaseAndWaitForDestructor(handler);
}
@ -1805,7 +2019,7 @@ class PopupNavTestHandler : public TestHandler {
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
WindowOpenDisposition target_disposition,
cef_window_open_disposition_t target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
@ -2079,7 +2293,7 @@ TEST(NavigationTest, BrowseDeny) {
void CreateNavigationBrowserTests(ClientAppBrowser::DelegateSet& delegates) {
delegates.insert(new HistoryNavBrowserTest);
delegates.insert(new OrderNavBrowserTest);
delegates.insert(new CrossOriginNavBrowserTest);
delegates.insert(new LoadNavBrowserTest);
}
// Entry point for creating navigation renderer test objects.
@ -2087,5 +2301,5 @@ void CreateNavigationBrowserTests(ClientAppBrowser::DelegateSet& delegates) {
void CreateNavigationRendererTests(ClientAppRenderer::DelegateSet& delegates) {
delegates.insert(new HistoryNavRendererTest);
delegates.insert(new OrderNavRendererTest);
delegates.insert(new CrossOriginNavRendererTest);
delegates.insert(new LoadNavRendererTest);
}

View File

@ -475,7 +475,7 @@ class PopupTestHandler : public TestHandler {
CefRefPtr<CefFrame> frame,
const CefString& target_url,
const CefString& target_frame_name,
WindowOpenDisposition target_disposition,
cef_window_open_disposition_t target_disposition,
bool user_gesture,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,