1 // Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include <algorithm>
6 #include <list>
7
8 #include "include/base/cef_callback.h"
9 #include "include/cef_callback.h"
10 #include "include/cef_scheme.h"
11 #include "include/wrapper/cef_closure_task.h"
12 #include "tests/ceftests/test_handler.h"
13 #include "tests/ceftests/test_util.h"
14 #include "tests/gtest/include/gtest/gtest.h"
15 #include "tests/shared/browser/client_app_browser.h"
16 #include "tests/shared/renderer/client_app_renderer.h"
17
18 using client::ClientAppBrowser;
19 using client::ClientAppRenderer;
20
21 namespace {
22
23 const char kHNav1[] = "http://tests-hnav.com/nav1.html";
24 const char kHNav2[] = "http://tests-hnav.com/nav2.html";
25 const char kHNav3[] = "http://tests-hnav.com/nav3.html";
26 const char kHistoryNavMsg[] = "NavigationTest.HistoryNav";
27 const char kHistoryNavTestCmdKey[] = "nav-history-test";
28
29 const cef_transition_type_t kTransitionExplicitLoad =
30 static_cast<cef_transition_type_t>(TT_EXPLICIT | TT_DIRECT_LOAD_FLAG);
31
32 // TT_FORWARD_BACK_FLAG is added to the original transition flags.
33 const cef_transition_type_t kTransitionExplicitForwardBack =
34 static_cast<cef_transition_type_t>(kTransitionExplicitLoad |
35 TT_FORWARD_BACK_FLAG);
36
37 enum NavAction { NA_LOAD = 1, NA_BACK, NA_FORWARD, NA_CLEAR };
38
39 typedef struct {
40 NavAction action; // What to do
41 const char* target; // Where to be after navigation
42 bool can_go_back; // After navigation, can go back?
43 bool can_go_forward; // After navigation, can go forward?
44 } NavListItem;
45
46 // Array of navigation actions: X = current page, . = history exists
47 static NavListItem kHNavList[] = {
48 // kHNav1 | kHNav2 | kHNav3
49 {NA_LOAD, kHNav1, false, false}, // X
50 {NA_LOAD, kHNav2, true, false}, // . X
51 {NA_BACK, kHNav1, false, true}, // X .
52 {NA_FORWARD, kHNav2, true, false}, // . X
53 {NA_LOAD, kHNav3, true, false}, // . . X
54 {NA_BACK, kHNav2, true, true}, // . X .
55 // TODO(cef): Enable once ClearHistory is implemented
56 // {NA_CLEAR, kHNav2, false, false}, // X
57 };
58
59 #define NAV_LIST_SIZE() (sizeof(kHNavList) / sizeof(NavListItem))
60
61 // Renderer side.
62 class HistoryNavRendererTest : public ClientAppRenderer::Delegate,
63 public CefLoadHandler {
64 public:
HistoryNavRendererTest()65 HistoryNavRendererTest() : run_test_(false), nav_(0) {}
66
OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefDictionaryValue> extra_info)67 void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
68 CefRefPtr<CefBrowser> browser,
69 CefRefPtr<CefDictionaryValue> extra_info) override {
70 run_test_ = extra_info && extra_info->HasKey(kHistoryNavTestCmdKey);
71 }
72
GetLoadHandler(CefRefPtr<ClientAppRenderer> app)73 CefRefPtr<CefLoadHandler> GetLoadHandler(
74 CefRefPtr<ClientAppRenderer> app) override {
75 if (!run_test_)
76 return nullptr;
77
78 return this;
79 }
80
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)81 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
82 bool isLoading,
83 bool canGoBack,
84 bool canGoForward) override {
85 const NavListItem& item = kHNavList[nav_];
86
87 const std::string& url = browser->GetMainFrame()->GetURL();
88 EXPECT_STREQ(item.target, url.c_str());
89
90 EXPECT_EQ(item.can_go_back, browser->CanGoBack())
91 << "nav: " << nav_ << " isLoading: " << isLoading;
92 EXPECT_EQ(item.can_go_back, canGoBack)
93 << "nav: " << nav_ << " isLoading: " << isLoading;
94 EXPECT_EQ(item.can_go_forward, browser->CanGoForward())
95 << "nav: " << nav_ << " isLoading: " << isLoading;
96 EXPECT_EQ(item.can_go_forward, canGoForward)
97 << "nav: " << nav_ << " isLoading: " << isLoading;
98
99 if (isLoading) {
100 got_loading_state_start_.yes();
101 } else {
102 got_loading_state_end_.yes();
103 SendTestResultsIfDone(browser, browser->GetMainFrame());
104 }
105 }
106
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)107 void OnLoadStart(CefRefPtr<CefBrowser> browser,
108 CefRefPtr<CefFrame> frame,
109 TransitionType transition_type) override {
110 const NavListItem& item = kHNavList[nav_];
111
112 got_load_start_.yes();
113
114 const std::string& url = frame->GetURL();
115 EXPECT_STREQ(item.target, url.c_str());
116
117 EXPECT_EQ(TT_EXPLICIT, transition_type);
118
119 EXPECT_EQ(item.can_go_back, browser->CanGoBack());
120 EXPECT_EQ(item.can_go_forward, browser->CanGoForward());
121 }
122
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)123 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
124 CefRefPtr<CefFrame> frame,
125 int httpStatusCode) override {
126 const NavListItem& item = kHNavList[nav_];
127
128 got_load_end_.yes();
129
130 const std::string& url = frame->GetURL();
131 EXPECT_STREQ(item.target, url.c_str());
132
133 EXPECT_EQ(item.can_go_back, browser->CanGoBack());
134 EXPECT_EQ(item.can_go_forward, browser->CanGoForward());
135
136 SendTestResultsIfDone(browser, frame);
137 }
138
139 protected:
SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)140 void SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,
141 CefRefPtr<CefFrame> frame) {
142 if (got_load_end_ && got_loading_state_end_)
143 SendTestResults(browser, frame);
144 }
145
146 // Send the test results.
SendTestResults(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)147 void SendTestResults(CefRefPtr<CefBrowser> browser,
148 CefRefPtr<CefFrame> frame) {
149 EXPECT_TRUE(got_loading_state_start_);
150 EXPECT_TRUE(got_loading_state_end_);
151 EXPECT_TRUE(got_load_start_);
152 EXPECT_TRUE(got_load_end_);
153
154 // Check if the test has failed.
155 bool result = !TestFailed();
156
157 // Return the result to the browser process.
158 CefRefPtr<CefProcessMessage> return_msg =
159 CefProcessMessage::Create(kHistoryNavMsg);
160 CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
161 EXPECT_TRUE(args.get());
162 EXPECT_TRUE(args->SetInt(0, nav_));
163 EXPECT_TRUE(args->SetBool(1, result));
164 frame->SendProcessMessage(PID_BROWSER, return_msg);
165
166 // Reset the test results for the next navigation.
167 got_loading_state_start_.reset();
168 got_loading_state_end_.reset();
169 got_load_start_.reset();
170 got_load_end_.reset();
171
172 nav_++;
173 }
174
175 bool run_test_;
176 int nav_;
177
178 TrackCallback got_loading_state_start_;
179 TrackCallback got_loading_state_end_;
180 TrackCallback got_load_start_;
181 TrackCallback got_load_end_;
182
183 IMPLEMENT_REFCOUNTING(HistoryNavRendererTest);
184 };
185
186 class NavigationEntryVisitor : public CefNavigationEntryVisitor {
187 public:
NavigationEntryVisitor(int nav,TrackCallback * callback)188 NavigationEntryVisitor(int nav, TrackCallback* callback)
189 : nav_(nav),
190 callback_(callback),
191 expected_total_(0),
192 expected_current_index_(-1),
193 expected_forwardback_(),
194 callback_count_(0) {
195 // Determine the expected values.
196 for (int i = 0; i <= nav_; ++i) {
197 if (kHNavList[i].action == NA_LOAD) {
198 expected_total_++;
199 expected_current_index_++;
200 } else if (kHNavList[i].action == NA_BACK) {
201 expected_current_index_--;
202 } else if (kHNavList[i].action == NA_FORWARD) {
203 expected_current_index_++;
204 }
205 expected_forwardback_[expected_current_index_] =
206 (kHNavList[i].action != NA_LOAD);
207 }
208 }
209
~NavigationEntryVisitor()210 ~NavigationEntryVisitor() override {
211 EXPECT_EQ(callback_count_, expected_total_);
212 callback_->yes();
213 }
214
Visit(CefRefPtr<CefNavigationEntry> entry,bool current,int index,int total)215 bool Visit(CefRefPtr<CefNavigationEntry> entry,
216 bool current,
217 int index,
218 int total) override {
219 // Only 3 loads total.
220 EXPECT_LT(index, 3);
221 EXPECT_LE(total, 3);
222
223 EXPECT_EQ((expected_current_index_ == index), current);
224 EXPECT_EQ(callback_count_, index);
225 EXPECT_EQ(expected_total_, total);
226
227 std::string expected_url;
228 std::string expected_title;
229 if (index == 0) {
230 expected_url = kHNav1;
231 expected_title = "Nav1";
232 } else if (index == 1) {
233 expected_url = kHNav2;
234 expected_title = "Nav2";
235 } else if (index == 2) {
236 expected_url = kHNav3;
237 expected_title = "Nav3";
238 }
239
240 EXPECT_TRUE(entry->IsValid());
241 EXPECT_STREQ(expected_url.c_str(), entry->GetURL().ToString().c_str());
242 EXPECT_STREQ(expected_url.c_str(),
243 entry->GetDisplayURL().ToString().c_str());
244 EXPECT_STREQ(expected_url.c_str(),
245 entry->GetOriginalURL().ToString().c_str());
246 EXPECT_STREQ(expected_title.c_str(), entry->GetTitle().ToString().c_str());
247
248 const auto transition_type = entry->GetTransitionType();
249 if (expected_forwardback_[index])
250 EXPECT_EQ(kTransitionExplicitForwardBack, transition_type);
251 else
252 EXPECT_EQ(kTransitionExplicitLoad, transition_type);
253
254 EXPECT_FALSE(entry->HasPostData());
255 EXPECT_GT(entry->GetCompletionTime().GetTimeT(), 0);
256 EXPECT_EQ(200, entry->GetHttpStatusCode());
257
258 callback_count_++;
259 return true;
260 }
261
262 private:
263 const int nav_;
264 TrackCallback* callback_;
265 int expected_total_;
266 int expected_current_index_;
267 bool expected_forwardback_[3]; // Only 3 loads total.
268 int callback_count_;
269
270 IMPLEMENT_REFCOUNTING(NavigationEntryVisitor);
271 };
272
273 // Browser side.
274 class HistoryNavTestHandler : public TestHandler {
275 public:
HistoryNavTestHandler()276 HistoryNavTestHandler()
277 : nav_(0),
278 load_end_confirmation_(false),
279 load_state_change_loaded_confirmation_(false),
280 renderer_confirmation_(false) {}
281
RunTest()282 void RunTest() override {
283 // Add the resources that we will navigate to/from.
284 AddResource(
285 kHNav1,
286 "<html><head><title>Nav1</title></head><body>Nav1</body></html>",
287 "text/html");
288 AddResource(kHNav2,
289 "<html><head><title>Nav2</title><body>Nav2</body></html>",
290 "text/html");
291 AddResource(kHNav3,
292 "<html><head><title>Nav3</title><body>Nav3</body></html>",
293 "text/html");
294
295 CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
296 extra_info->SetBool(kHistoryNavTestCmdKey, true);
297
298 // Create the browser.
299 CreateBrowser(CefString(), nullptr, extra_info);
300
301 // Time out the test after a reasonable period of time.
302 SetTestTimeout();
303 }
304
RunNav(CefRefPtr<CefBrowser> browser)305 void RunNav(CefRefPtr<CefBrowser> browser) {
306 if (nav_ == NAV_LIST_SIZE()) {
307 // End of the nav list.
308 DestroyTest();
309 return;
310 }
311
312 const NavListItem& item = kHNavList[nav_];
313
314 // Perform the action.
315 switch (item.action) {
316 case NA_LOAD:
317 browser->GetMainFrame()->LoadURL(item.target);
318 break;
319 case NA_BACK:
320 browser->GoBack();
321 break;
322 case NA_FORWARD:
323 browser->GoForward();
324 break;
325 case NA_CLEAR:
326 // TODO(cef): Enable once ClearHistory is implemented
327 // browser->GetHost()->ClearHistory();
328 // Not really a navigation action so go to the next one.
329 nav_++;
330 RunNav(browser);
331 break;
332 default:
333 break;
334 }
335 }
336
RunNextNavIfReady(CefRefPtr<CefBrowser> browser)337 void RunNextNavIfReady(CefRefPtr<CefBrowser> browser) {
338 if (load_end_confirmation_ && load_state_change_loaded_confirmation_ &&
339 renderer_confirmation_) {
340 load_end_confirmation_ = false;
341 load_state_change_loaded_confirmation_ = false;
342 renderer_confirmation_ = false;
343 nav_++;
344 RunNav(browser);
345 }
346 }
347
OnAfterCreated(CefRefPtr<CefBrowser> browser)348 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
349 TestHandler::OnAfterCreated(browser);
350
351 RunNav(browser);
352 }
353
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)354 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
355 CefRefPtr<CefFrame> frame,
356 CefRefPtr<CefRequest> request,
357 bool user_gesture,
358 bool is_redirect) override {
359 const NavListItem& item = kHNavList[nav_];
360
361 got_before_browse_[nav_].yes();
362
363 std::string url = request->GetURL();
364 EXPECT_STREQ(item.target, url.c_str());
365
366 EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
367
368 const auto transition_type = request->GetTransitionType();
369 if (item.action == NA_LOAD) {
370 EXPECT_EQ(kTransitionExplicitLoad, transition_type);
371 } else if (item.action == NA_BACK || item.action == NA_FORWARD) {
372 EXPECT_EQ(kTransitionExplicitForwardBack, transition_type);
373 }
374
375 if (nav_ > 0) {
376 const NavListItem& last_item = kHNavList[nav_ - 1];
377 EXPECT_EQ(last_item.can_go_back, browser->CanGoBack());
378 EXPECT_EQ(last_item.can_go_forward, browser->CanGoForward());
379 } else {
380 EXPECT_FALSE(browser->CanGoBack());
381 EXPECT_FALSE(browser->CanGoForward());
382 }
383
384 return false;
385 }
386
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)387 cef_return_value_t OnBeforeResourceLoad(
388 CefRefPtr<CefBrowser> browser,
389 CefRefPtr<CefFrame> frame,
390 CefRefPtr<CefRequest> request,
391 CefRefPtr<CefCallback> callback) override {
392 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
393 // Ignore favicon requests.
394 return RV_CANCEL;
395 }
396
397 const NavListItem& item = kHNavList[nav_];
398 const std::string& url = request->GetURL();
399
400 EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType())
401 << "nav=" << nav_ << " url=" << url;
402
403 const auto transition_type = request->GetTransitionType();
404 if (item.action == NA_LOAD) {
405 EXPECT_EQ(kTransitionExplicitLoad, transition_type)
406 << "nav=" << nav_ << " url=" << url;
407 } else if (item.action == NA_BACK || item.action == NA_FORWARD) {
408 EXPECT_EQ(kTransitionExplicitForwardBack, transition_type)
409 << "nav=" << nav_ << " url=" << url;
410 }
411
412 got_before_resource_load_[nav_].yes();
413
414 if (url == item.target)
415 got_correct_target_[nav_].yes();
416
417 return RV_CONTINUE;
418 }
419
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)420 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
421 bool isLoading,
422 bool canGoBack,
423 bool canGoForward) override {
424 if (isLoading)
425 return;
426
427 const NavListItem& item = kHNavList[nav_];
428
429 got_loading_state_change_[nav_].yes();
430
431 if (item.can_go_back == canGoBack)
432 got_correct_can_go_back_[nav_].yes();
433 if (item.can_go_forward == canGoForward)
434 got_correct_can_go_forward_[nav_].yes();
435
436 load_state_change_loaded_confirmation_ = true;
437 RunNextNavIfReady(browser);
438 }
439
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)440 void OnLoadStart(CefRefPtr<CefBrowser> browser,
441 CefRefPtr<CefFrame> frame,
442 TransitionType transition_type) override {
443 if (browser->IsPopup() || !frame->IsMain())
444 return;
445
446 const NavListItem& item = kHNavList[nav_];
447
448 got_load_start_[nav_].yes();
449
450 if (item.action == NA_LOAD) {
451 EXPECT_EQ(kTransitionExplicitLoad, transition_type);
452 } else if (item.action == NA_BACK || item.action == NA_FORWARD) {
453 EXPECT_EQ(kTransitionExplicitForwardBack, transition_type);
454 }
455
456 std::string url1 = browser->GetMainFrame()->GetURL();
457 std::string url2 = frame->GetURL();
458 if (url1 == item.target && url2 == item.target)
459 got_correct_load_start_url_[nav_].yes();
460 }
461
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)462 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
463 CefRefPtr<CefFrame> frame,
464 int httpStatusCode) override {
465 if (browser->IsPopup() || !frame->IsMain())
466 return;
467
468 const NavListItem& item = kHNavList[nav_];
469
470 got_load_end_[nav_].yes();
471
472 // Test that navigation entries are correct.
473 CefRefPtr<NavigationEntryVisitor> visitor =
474 new NavigationEntryVisitor(nav_, &got_correct_history_[nav_]);
475 browser->GetHost()->GetNavigationEntries(visitor.get(), false);
476 visitor = nullptr;
477
478 std::string url1 = browser->GetMainFrame()->GetURL();
479 std::string url2 = frame->GetURL();
480 if (url1 == item.target && url2 == item.target)
481 got_correct_load_end_url_[nav_].yes();
482
483 load_end_confirmation_ = true;
484 RunNextNavIfReady(browser);
485 }
486
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)487 bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
488 CefRefPtr<CefFrame> frame,
489 CefProcessId source_process,
490 CefRefPtr<CefProcessMessage> message) override {
491 if (message->GetName().ToString() == kHistoryNavMsg) {
492 got_before_navigation_[nav_].yes();
493
494 // Test that the renderer side succeeded.
495 CefRefPtr<CefListValue> args = message->GetArgumentList();
496 EXPECT_TRUE(args.get());
497 EXPECT_EQ(nav_, args->GetInt(0));
498 EXPECT_TRUE(args->GetBool(1));
499
500 renderer_confirmation_ = true;
501 RunNextNavIfReady(browser);
502 return true;
503 }
504
505 // Message not handled.
506 return false;
507 }
508
509 int nav_;
510 bool load_end_confirmation_;
511 bool load_state_change_loaded_confirmation_;
512 bool renderer_confirmation_;
513
514 TrackCallback got_before_browse_[NAV_LIST_SIZE()];
515 TrackCallback got_before_navigation_[NAV_LIST_SIZE()];
516 TrackCallback got_before_resource_load_[NAV_LIST_SIZE()];
517 TrackCallback got_correct_target_[NAV_LIST_SIZE()];
518 TrackCallback got_loading_state_change_[NAV_LIST_SIZE()];
519 TrackCallback got_correct_can_go_back_[NAV_LIST_SIZE()];
520 TrackCallback got_correct_can_go_forward_[NAV_LIST_SIZE()];
521 TrackCallback got_load_start_[NAV_LIST_SIZE()];
522 TrackCallback got_correct_load_start_url_[NAV_LIST_SIZE()];
523 TrackCallback got_load_end_[NAV_LIST_SIZE()];
524 TrackCallback got_correct_history_[NAV_LIST_SIZE()];
525 TrackCallback got_correct_load_end_url_[NAV_LIST_SIZE()];
526
527 IMPLEMENT_REFCOUNTING(HistoryNavTestHandler);
528 };
529
530 } // namespace
531
532 // Verify history navigation.
TEST(NavigationTest,History)533 TEST(NavigationTest, History) {
534 CefRefPtr<HistoryNavTestHandler> handler = new HistoryNavTestHandler();
535 handler->ExecuteTest();
536
537 for (size_t i = 0; i < NAV_LIST_SIZE(); ++i) {
538 if (kHNavList[i].action != NA_CLEAR) {
539 ASSERT_TRUE(handler->got_before_browse_[i]) << "i = " << i;
540 ASSERT_TRUE(handler->got_before_navigation_[i]) << "i = " << i;
541 ASSERT_TRUE(handler->got_before_resource_load_[i]) << "i = " << i;
542 ASSERT_TRUE(handler->got_correct_target_[i]) << "i = " << i;
543 ASSERT_TRUE(handler->got_load_start_[i]) << "i = " << i;
544 ASSERT_TRUE(handler->got_correct_load_start_url_[i]) << "i = " << i;
545 }
546
547 ASSERT_TRUE(handler->got_loading_state_change_[i]) << "i = " << i;
548 ASSERT_TRUE(handler->got_correct_can_go_back_[i]) << "i = " << i;
549 ASSERT_TRUE(handler->got_correct_can_go_forward_[i]) << "i = " << i;
550
551 if (kHNavList[i].action != NA_CLEAR) {
552 ASSERT_TRUE(handler->got_load_end_[i]) << "i = " << i;
553 ASSERT_TRUE(handler->got_correct_history_[i]) << "i = " << i;
554 ASSERT_TRUE(handler->got_correct_load_end_url_[i]) << "i = " << i;
555 }
556 }
557
558 ReleaseAndWaitForDestructor(handler);
559 }
560
561 namespace {
562
563 const char kDynIfrNav1[] = "http://tests-dynframe/nav1.html";
564 const char kDynIfrNav2[] = "http://tests-dynframe/nav2.html";
565
566 // Browser side.
567 class HistoryDynamicIFramesNavTestHandler : public TestHandler {
568 public:
HistoryDynamicIFramesNavTestHandler()569 HistoryDynamicIFramesNavTestHandler() : nav_(-1) {}
570
RunTest()571 void RunTest() override {
572 // Add the resources that we will navigate to/from.
573 AddResource(kDynIfrNav1,
574 "<html>"
575 " <head>"
576 " <title>Nav1</title>"
577 " <script language='javascript'>"
578 " function onload() {"
579 " fr = Math.floor(Math.random() * 10);"
580 " if(fr == 0) "
581 " fr = 1;"
582 " console.log('fr=' + fr);"
583 " for(i = 1; i <= fr; i++) {"
584 " try {"
585 " var n = 'DYN_' + Math.floor(Math.random() * 10000);"
586 " "
587 " d = document.createElement('div');"
588 " d.id = 'sf' + i; "
589 " d.innerText = n; "
590 " document.body.appendChild(d); "
591 " "
592 " f = document.createElement('iframe'); "
593 " f.id = 'f_' + i; "
594 " f.name = n; "
595 " f.src = 'nav2.html'; "
596 " document.body.appendChild(f); "
597 " } catch(e) { "
598 " console.log('frame[' + i + ']: ' + e); "
599 " } "
600 " } "
601 " } "
602 " </script> "
603 " </head> "
604 " <body onload='onload();'> "
605 " Nav1 "
606 " </body> "
607 "</html>",
608 "text/html");
609 AddResource(
610 kDynIfrNav2,
611 "<html><head><title>Nav2</title></head><body>Nav2</body></html>",
612 "text/html");
613
614 // Create the browser.
615 CreateBrowser(CefString());
616
617 // Time out the test after a reasonable period of time.
618 SetTestTimeout();
619 }
620
RunNav(CefRefPtr<CefBrowser> browser)621 void RunNav(CefRefPtr<CefBrowser> browser) {
622 EXPECT_LE(nav_, 3);
623 EXPECT_FALSE(got_load_start_[nav_]);
624 EXPECT_FALSE(got_load_end_[nav_]);
625
626 if (nav_ == 0) {
627 browser->GetMainFrame()->LoadURL(kDynIfrNav1);
628 } else if (nav_ == 1) {
629 browser->GetMainFrame()->LoadURL(kDynIfrNav2);
630 } else if (nav_ == 2) {
631 browser->GoBack();
632 } else if (nav_ == 3) {
633 browser->Reload();
634 }
635 }
636
OnAfterCreated(CefRefPtr<CefBrowser> browser)637 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
638 TestHandler::OnAfterCreated(browser);
639
640 nav_ = 0;
641 RunNav(browser);
642 }
643
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)644 void OnLoadStart(CefRefPtr<CefBrowser> browser,
645 CefRefPtr<CefFrame> frame,
646 TransitionType transition_type) override {
647 if (!frame->IsMain())
648 return;
649 got_load_start_[nav_].yes();
650 }
651
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)652 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
653 CefRefPtr<CefFrame> frame,
654 int httpStatusCode) override {
655 if (!frame->IsMain())
656 return;
657 CefString url = browser->GetMainFrame()->GetURL();
658 got_load_end_[nav_].yes();
659
660 if (nav_ == 3) {
661 EXPECT_STREQ(url.ToString().c_str(), kDynIfrNav1);
662 DestroyTest();
663 return;
664 }
665
666 nav_++;
667 RunNav(browser);
668 }
669
670 int nav_;
671 TrackCallback got_load_start_[4];
672 TrackCallback got_load_end_[4];
673
674 IMPLEMENT_REFCOUNTING(HistoryDynamicIFramesNavTestHandler);
675 };
676
677 } // namespace
678
679 // Verify history navigation of pages containing dynamically created iframes.
680 // See issue #2022 for background.
TEST(NavigationTest,HistoryDynamicIFrames)681 TEST(NavigationTest, HistoryDynamicIFrames) {
682 CefRefPtr<HistoryDynamicIFramesNavTestHandler> handler =
683 new HistoryDynamicIFramesNavTestHandler();
684 handler->ExecuteTest();
685
686 for (int i = 0; i < 4; ++i) {
687 EXPECT_TRUE(handler->got_load_start_[i]);
688 EXPECT_TRUE(handler->got_load_end_[i]);
689 }
690
691 ReleaseAndWaitForDestructor(handler);
692 }
693
694 namespace {
695
696 const char kRNav1[] = "http://tests/nav1.html";
697 const char kRNav2[] = "http://tests/nav2.html";
698 const char kRNav3[] = "http://tests/nav3.html";
699 const char kRNav4[] = "http://tests/nav4.html";
700
701 bool g_got_nav1_request = false;
702 bool g_got_nav3_request = false;
703 bool g_got_nav4_request = false;
704 bool g_got_invalid_request = false;
705
706 class RedirectSchemeHandler : public CefResourceHandler {
707 public:
RedirectSchemeHandler()708 RedirectSchemeHandler() : offset_(0), status_(0) {}
709
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)710 bool Open(CefRefPtr<CefRequest> request,
711 bool& handle_request,
712 CefRefPtr<CefCallback> callback) override {
713 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
714
715 std::string url = request->GetURL();
716 if (url == kRNav1) {
717 // Redirect using HTTP 302
718 g_got_nav1_request = true;
719 status_ = 302;
720 location_ = kRNav2;
721 content_ = "<html><body>Redirected Nav1</body></html>";
722 } else if (url == kRNav3) {
723 // Redirect using redirectUrl
724 g_got_nav3_request = true;
725 status_ = -1;
726 location_ = kRNav4;
727 content_ = "<html><body>Redirected Nav3</body></html>";
728 } else if (url == kRNav4) {
729 g_got_nav4_request = true;
730 status_ = 200;
731 content_ = "<html><body>Nav4</body></html>";
732 }
733
734 handle_request = true;
735
736 if (status_ != 0) {
737 // Continue request.
738 return true;
739 }
740
741 // Cancel request.
742 g_got_invalid_request = true;
743 return false;
744 }
745
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)746 void GetResponseHeaders(CefRefPtr<CefResponse> response,
747 int64& response_length,
748 CefString& redirectUrl) override {
749 EXPECT_TRUE(CefCurrentlyOn(TID_IO));
750
751 EXPECT_NE(status_, 0);
752
753 response->SetStatus(status_);
754 response->SetMimeType("text/html");
755 response_length = content_.size();
756
757 if (status_ == 302) {
758 // Redirect using HTTP 302
759 EXPECT_GT(location_.size(), static_cast<size_t>(0));
760 response->SetStatusText("Found");
761 CefResponse::HeaderMap headers;
762 response->GetHeaderMap(headers);
763 headers.insert(std::make_pair("Location", location_));
764 response->SetHeaderMap(headers);
765 } else if (status_ == -1) {
766 // Rdirect using redirectUrl
767 EXPECT_GT(location_.size(), static_cast<size_t>(0));
768 redirectUrl = location_;
769 }
770 }
771
Cancel()772 void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); }
773
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)774 bool Read(void* data_out,
775 int bytes_to_read,
776 int& bytes_read,
777 CefRefPtr<CefResourceReadCallback> callback) override {
778 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
779
780 bytes_read = 0;
781 bool has_data = false;
782
783 size_t size = content_.size();
784 if (offset_ < size) {
785 int transfer_size =
786 std::min(bytes_to_read, static_cast<int>(size - offset_));
787 memcpy(data_out, content_.c_str() + offset_, transfer_size);
788 offset_ += transfer_size;
789
790 bytes_read = transfer_size;
791 has_data = true;
792 }
793
794 return has_data;
795 }
796
797 protected:
798 std::string content_;
799 size_t offset_;
800 int status_;
801 std::string location_;
802
803 IMPLEMENT_REFCOUNTING(RedirectSchemeHandler);
804 DISALLOW_COPY_AND_ASSIGN(RedirectSchemeHandler);
805 };
806
807 class RedirectSchemeHandlerFactory : public CefSchemeHandlerFactory {
808 public:
RedirectSchemeHandlerFactory()809 RedirectSchemeHandlerFactory() {
810 g_got_nav1_request = false;
811 g_got_nav3_request = false;
812 g_got_nav4_request = false;
813 g_got_invalid_request = false;
814 }
815
Create(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & scheme_name,CefRefPtr<CefRequest> request)816 CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
817 CefRefPtr<CefFrame> frame,
818 const CefString& scheme_name,
819 CefRefPtr<CefRequest> request) override {
820 EXPECT_TRUE(CefCurrentlyOn(TID_IO));
821 return new RedirectSchemeHandler();
822 }
823
824 IMPLEMENT_REFCOUNTING(RedirectSchemeHandlerFactory);
825 DISALLOW_COPY_AND_ASSIGN(RedirectSchemeHandlerFactory);
826 };
827
828 class RedirectTestHandler : public TestHandler {
829 public:
RedirectTestHandler()830 RedirectTestHandler() {}
831
RunTest()832 void RunTest() override {
833 // Create the browser.
834 CreateBrowser(kRNav1);
835
836 // Time out the test after a reasonable period of time.
837 SetTestTimeout();
838 }
839
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)840 cef_return_value_t OnBeforeResourceLoad(
841 CefRefPtr<CefBrowser> browser,
842 CefRefPtr<CefFrame> frame,
843 CefRefPtr<CefRequest> request,
844 CefRefPtr<CefCallback> callback) override {
845 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
846 // Ignore favicon requests.
847 return RV_CANCEL;
848 }
849
850 // Should be called for all but the second URL.
851 std::string url = request->GetURL();
852
853 EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
854 EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
855
856 if (url == kRNav1) {
857 got_nav1_before_resource_load_.yes();
858 } else if (url == kRNav3) {
859 got_nav3_before_resource_load_.yes();
860 } else if (url == kRNav4) {
861 got_nav4_before_resource_load_.yes();
862 } else {
863 got_invalid_before_resource_load_.yes();
864 }
865
866 return RV_CONTINUE;
867 }
868
OnResourceRedirect(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,CefString & new_url)869 void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
870 CefRefPtr<CefFrame> frame,
871 CefRefPtr<CefRequest> request,
872 CefRefPtr<CefResponse> response,
873 CefString& new_url) override {
874 // Should be called for each redirected URL.
875
876 const std::string& old_url = request->GetURL();
877 if (old_url == kRNav1 && new_url == kRNav2) {
878 // Called due to the nav1 redirect response.
879 got_nav1_redirect_.yes();
880
881 EXPECT_EQ(302, response->GetStatus());
882 EXPECT_STREQ("Found", response->GetStatusText().ToString().c_str());
883 EXPECT_STREQ("", response->GetMimeType().ToString().c_str());
884 EXPECT_STREQ(kRNav2,
885 response->GetHeaderByName("Location").ToString().c_str());
886
887 // Change the redirect to the 3rd URL.
888 new_url = kRNav3;
889 } else if (old_url == kRNav1 && new_url == kRNav3) {
890 // Called due to the redirect change above.
891 got_nav2_redirect_.yes();
892
893 EXPECT_EQ(307, response->GetStatus());
894 EXPECT_STREQ("Internal Redirect",
895 response->GetStatusText().ToString().c_str());
896 EXPECT_TRUE(response->GetMimeType().empty());
897 EXPECT_STREQ(kRNav3,
898 response->GetHeaderByName("Location").ToString().c_str());
899 } else if (old_url == kRNav3 && new_url == kRNav4) {
900 // Called due to the nav3 redirect response.
901 got_nav3_redirect_.yes();
902
903 EXPECT_EQ(307, response->GetStatus());
904 EXPECT_STREQ("Temporary Redirect",
905 response->GetStatusText().ToString().c_str());
906 EXPECT_STREQ("", response->GetMimeType().ToString().c_str());
907 } else {
908 got_invalid_redirect_.yes();
909 }
910 }
911
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)912 void OnLoadStart(CefRefPtr<CefBrowser> browser,
913 CefRefPtr<CefFrame> frame,
914 TransitionType transition_type) override {
915 // Should only be called for the final loaded URL.
916 std::string url = frame->GetURL();
917
918 EXPECT_EQ(kTransitionExplicitLoad, transition_type);
919
920 if (url == kRNav4) {
921 got_nav4_load_start_.yes();
922 } else {
923 got_invalid_load_start_.yes();
924 }
925 }
926
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)927 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
928 CefRefPtr<CefFrame> frame,
929 int httpStatusCode) override {
930 // Should only be called for the final loaded URL.
931 std::string url = frame->GetURL();
932
933 if (url == kRNav4) {
934 got_nav4_load_end_.yes();
935 DestroyTest();
936 } else {
937 got_invalid_load_end_.yes();
938 }
939 }
940
941 TrackCallback got_nav1_before_resource_load_;
942 TrackCallback got_nav3_before_resource_load_;
943 TrackCallback got_nav4_before_resource_load_;
944 TrackCallback got_invalid_before_resource_load_;
945 TrackCallback got_nav4_load_start_;
946 TrackCallback got_invalid_load_start_;
947 TrackCallback got_nav4_load_end_;
948 TrackCallback got_invalid_load_end_;
949 TrackCallback got_nav1_redirect_;
950 TrackCallback got_nav2_redirect_;
951 TrackCallback got_nav3_redirect_;
952 TrackCallback got_invalid_redirect_;
953
954 IMPLEMENT_REFCOUNTING(RedirectTestHandler);
955 };
956
957 // Like above but destroy the WebContents while the redirect is in-progress.
958 class RedirectDestroyTestHandler : public TestHandler {
959 public:
RedirectDestroyTestHandler()960 RedirectDestroyTestHandler() {}
961
RunTest()962 void RunTest() override {
963 // Create the browser.
964 CreateBrowser(kRNav1);
965
966 // Time out the test after a reasonable period of time.
967 SetTestTimeout();
968 }
969
OnResourceRedirect(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefResponse> response,CefString & new_url)970 void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
971 CefRefPtr<CefFrame> frame,
972 CefRefPtr<CefRequest> request,
973 CefRefPtr<CefResponse> response,
974 CefString& new_url) override {
975 const std::string& old_url = request->GetURL();
976 if (old_url == kRNav1 && new_url == kRNav2) {
977 // Called due to the nav1 redirect response.
978 got_nav1_redirect_.yes();
979
980 new_url = "about:blank";
981
982 // Destroy the test (and the underlying WebContents) while the redirect
983 // is still pending.
984 DestroyTest();
985 }
986 }
987
988 TrackCallback got_nav1_redirect_;
989
990 IMPLEMENT_REFCOUNTING(RedirectDestroyTestHandler);
991 };
992
993 } // namespace
994
995 // Verify frame names and identifiers.
TEST(NavigationTest,Redirect)996 TEST(NavigationTest, Redirect) {
997 CefRegisterSchemeHandlerFactory("http", "tests",
998 new RedirectSchemeHandlerFactory());
999 WaitForIOThread();
1000
1001 CefRefPtr<RedirectTestHandler> handler = new RedirectTestHandler();
1002 handler->ExecuteTest();
1003
1004 CefClearSchemeHandlerFactories();
1005 WaitForIOThread();
1006
1007 ASSERT_TRUE(handler->got_nav1_before_resource_load_);
1008 ASSERT_TRUE(handler->got_nav3_before_resource_load_);
1009 ASSERT_TRUE(handler->got_nav4_before_resource_load_);
1010 ASSERT_FALSE(handler->got_invalid_before_resource_load_);
1011 ASSERT_TRUE(handler->got_nav4_load_start_);
1012 ASSERT_FALSE(handler->got_invalid_load_start_);
1013 ASSERT_TRUE(handler->got_nav4_load_end_);
1014 ASSERT_FALSE(handler->got_invalid_load_end_);
1015 ASSERT_TRUE(handler->got_nav1_redirect_);
1016 ASSERT_FALSE(handler->got_nav2_redirect_);
1017 ASSERT_TRUE(handler->got_nav3_redirect_);
1018 ASSERT_FALSE(handler->got_invalid_redirect_);
1019 ASSERT_TRUE(g_got_nav1_request);
1020 ASSERT_TRUE(g_got_nav3_request);
1021 ASSERT_TRUE(g_got_nav4_request);
1022 ASSERT_FALSE(g_got_invalid_request);
1023
1024 ReleaseAndWaitForDestructor(handler);
1025 }
1026
1027 // Verify that destroying the WebContents while the redirect is in-progress does
1028 // not result in a crash.
TEST(NavigationTest,RedirectDestroy)1029 TEST(NavigationTest, RedirectDestroy) {
1030 CefRegisterSchemeHandlerFactory("http", "tests",
1031 new RedirectSchemeHandlerFactory());
1032 WaitForIOThread();
1033
1034 CefRefPtr<RedirectDestroyTestHandler> handler =
1035 new RedirectDestroyTestHandler();
1036 handler->ExecuteTest();
1037
1038 CefClearSchemeHandlerFactories();
1039 WaitForIOThread();
1040
1041 ASSERT_TRUE(handler->got_nav1_redirect_);
1042 ASSERT_TRUE(g_got_nav1_request);
1043 ASSERT_FALSE(g_got_nav3_request);
1044 ASSERT_FALSE(g_got_nav4_request);
1045 ASSERT_FALSE(g_got_invalid_request);
1046
1047 ReleaseAndWaitForDestructor(handler);
1048 }
1049
1050 namespace {
1051
1052 const char KONav1[] = "http://tests-onav.com/nav1.html";
1053 const char KONav2[] = "http://tests-onav.com/nav2.html";
1054 const char kOrderNavMsg[] = "NavigationTest.OrderNav";
1055 const char kOrderNavClosedMsg[] = "NavigationTest.OrderNavClosed";
1056 const char kOrderNavTestCmdKey[] = "nav-order-test";
1057
1058 class OrderNavLoadState {
1059 public:
OrderNavLoadState(bool is_popup,bool browser_side)1060 OrderNavLoadState(bool is_popup, bool browser_side)
1061 : is_popup_(is_popup), browser_side_(browser_side) {}
1062
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)1063 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
1064 bool isLoading,
1065 bool canGoBack,
1066 bool canGoForward) {
1067 if (isLoading) {
1068 EXPECT_TRUE(Verify(false, false, false, false));
1069
1070 got_loading_state_start_.yes();
1071 } else {
1072 EXPECT_TRUE(Verify(true, false, true, true));
1073
1074 got_loading_state_end_.yes();
1075 }
1076 }
1077
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1078 void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
1079 EXPECT_TRUE(Verify(true, false, false, false));
1080
1081 got_load_start_.yes();
1082 }
1083
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1084 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1085 CefRefPtr<CefFrame> frame,
1086 int httpStatusCode) {
1087 EXPECT_TRUE(Verify(true, false, true, false));
1088
1089 got_load_end_.yes();
1090 }
1091
IsStarted() const1092 bool IsStarted() const {
1093 return got_loading_state_start_ || got_loading_state_end_ ||
1094 got_load_start_ || got_load_end_;
1095 }
1096
IsDone() const1097 bool IsDone() const {
1098 return got_loading_state_start_ && got_loading_state_end_ &&
1099 got_load_start_ && got_load_end_;
1100 }
1101
Verify(bool got_loading_state_start,bool got_loading_state_end,bool got_load_start,bool got_load_end) const1102 bool Verify(bool got_loading_state_start,
1103 bool got_loading_state_end,
1104 bool got_load_start,
1105 bool got_load_end) const {
1106 EXPECT_EQ(got_loading_state_start, got_loading_state_start_)
1107 << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
1108 EXPECT_EQ(got_loading_state_end, got_loading_state_end_)
1109 << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
1110 EXPECT_EQ(got_load_start, got_load_start_)
1111 << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
1112 EXPECT_EQ(got_load_end, got_load_end_)
1113 << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
1114
1115 return got_loading_state_start == got_loading_state_start_ &&
1116 got_loading_state_end == got_loading_state_end_ &&
1117 got_load_start == got_load_start_ && got_load_end == got_load_end_;
1118 }
1119
1120 private:
1121 bool is_popup_;
1122 bool browser_side_;
1123
1124 TrackCallback got_loading_state_start_;
1125 TrackCallback got_loading_state_end_;
1126 TrackCallback got_load_start_;
1127 TrackCallback got_load_end_;
1128 };
1129
1130 // Renderer side.
1131 class OrderNavRendererTest : public ClientAppRenderer::Delegate,
1132 public CefLoadHandler {
1133 public:
OrderNavRendererTest()1134 OrderNavRendererTest()
1135 : run_test_(false),
1136 browser_id_main_(0),
1137 browser_id_popup_(0),
1138 state_main_(false, false),
1139 state_popup_(true, false) {}
1140
OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app)1141 void OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) override {
1142 EXPECT_FALSE(got_webkit_initialized_);
1143
1144 got_webkit_initialized_.yes();
1145 }
1146
OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefDictionaryValue> extra_info)1147 void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
1148 CefRefPtr<CefBrowser> browser,
1149 CefRefPtr<CefDictionaryValue> extra_info) override {
1150 run_test_ = extra_info && extra_info->HasKey(kOrderNavTestCmdKey);
1151 if (!run_test_)
1152 return;
1153
1154 EXPECT_TRUE(got_webkit_initialized_);
1155
1156 if (browser->IsPopup()) {
1157 EXPECT_FALSE(got_browser_created_popup_);
1158 EXPECT_FALSE(got_browser_destroyed_popup_);
1159 EXPECT_FALSE(state_popup_.IsStarted());
1160
1161 got_browser_created_popup_.yes();
1162 browser_id_popup_ = browser->GetIdentifier();
1163 EXPECT_GT(browser->GetIdentifier(), 0);
1164 } else {
1165 EXPECT_FALSE(got_browser_created_main_);
1166 EXPECT_FALSE(got_browser_destroyed_main_);
1167 EXPECT_FALSE(state_main_.IsStarted());
1168
1169 got_browser_created_main_.yes();
1170 browser_id_main_ = browser->GetIdentifier();
1171 EXPECT_GT(browser->GetIdentifier(), 0);
1172
1173 browser_main_ = browser;
1174 }
1175 }
1176
OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser)1177 void OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,
1178 CefRefPtr<CefBrowser> browser) override {
1179 if (!run_test_)
1180 return;
1181
1182 EXPECT_TRUE(got_webkit_initialized_);
1183
1184 if (browser->IsPopup()) {
1185 EXPECT_TRUE(got_browser_created_popup_);
1186 EXPECT_FALSE(got_browser_destroyed_popup_);
1187 EXPECT_TRUE(state_popup_.IsDone());
1188
1189 got_browser_destroyed_popup_.yes();
1190 EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
1191 EXPECT_GT(browser->GetIdentifier(), 0);
1192
1193 // Use |browser_main_| to send the message otherwise it will fail.
1194 SendTestResults(browser_main_, browser_main_->GetMainFrame(),
1195 kOrderNavClosedMsg);
1196 } else {
1197 EXPECT_TRUE(got_browser_created_main_);
1198 EXPECT_FALSE(got_browser_destroyed_main_);
1199 EXPECT_TRUE(state_main_.IsDone());
1200
1201 got_browser_destroyed_main_.yes();
1202 EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
1203 EXPECT_GT(browser->GetIdentifier(), 0);
1204
1205 browser_main_ = nullptr;
1206 }
1207 }
1208
GetLoadHandler(CefRefPtr<ClientAppRenderer> app)1209 CefRefPtr<CefLoadHandler> GetLoadHandler(
1210 CefRefPtr<ClientAppRenderer> app) override {
1211 if (!run_test_)
1212 return nullptr;
1213
1214 return this;
1215 }
1216
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)1217 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
1218 bool isLoading,
1219 bool canGoBack,
1220 bool canGoForward) override {
1221 EXPECT_TRUE(got_webkit_initialized_);
1222
1223 if (browser->IsPopup()) {
1224 EXPECT_TRUE(got_browser_created_popup_);
1225 EXPECT_FALSE(got_browser_destroyed_popup_);
1226
1227 state_popup_.OnLoadingStateChange(browser, isLoading, canGoBack,
1228 canGoForward);
1229 } else {
1230 EXPECT_TRUE(got_browser_created_main_);
1231 EXPECT_FALSE(got_browser_destroyed_main_);
1232
1233 state_main_.OnLoadingStateChange(browser, isLoading, canGoBack,
1234 canGoForward);
1235 }
1236
1237 if (!isLoading)
1238 SendTestResultsIfDone(browser, browser->GetMainFrame());
1239 }
1240
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)1241 void OnLoadStart(CefRefPtr<CefBrowser> browser,
1242 CefRefPtr<CefFrame> frame,
1243 TransitionType transition_type) override {
1244 EXPECT_TRUE(got_webkit_initialized_);
1245
1246 if (browser->IsPopup()) {
1247 EXPECT_TRUE(got_browser_created_popup_);
1248 EXPECT_FALSE(got_browser_destroyed_popup_);
1249
1250 state_popup_.OnLoadStart(browser, frame);
1251 } else {
1252 EXPECT_TRUE(got_browser_created_main_);
1253 EXPECT_FALSE(got_browser_destroyed_main_);
1254
1255 state_main_.OnLoadStart(browser, frame);
1256 }
1257 }
1258
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1259 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1260 CefRefPtr<CefFrame> frame,
1261 int httpStatusCode) override {
1262 EXPECT_TRUE(got_webkit_initialized_);
1263
1264 if (browser->IsPopup()) {
1265 EXPECT_TRUE(got_browser_created_popup_);
1266 EXPECT_FALSE(got_browser_destroyed_popup_);
1267
1268 state_popup_.OnLoadEnd(browser, frame, httpStatusCode);
1269 } else {
1270 EXPECT_TRUE(got_browser_created_main_);
1271 EXPECT_FALSE(got_browser_destroyed_main_);
1272
1273 state_main_.OnLoadEnd(browser, frame, httpStatusCode);
1274 }
1275
1276 SendTestResultsIfDone(browser, frame);
1277 }
1278
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)1279 void OnLoadError(CefRefPtr<CefBrowser> browser,
1280 CefRefPtr<CefFrame> frame,
1281 ErrorCode errorCode,
1282 const CefString& errorText,
1283 const CefString& failedUrl) override {
1284 ADD_FAILURE() << "renderer OnLoadError url: " << failedUrl.ToString()
1285 << " error: " << errorCode;
1286 }
1287
1288 protected:
SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1289 void SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,
1290 CefRefPtr<CefFrame> frame) {
1291 bool done = false;
1292 if (browser->IsPopup())
1293 done = state_popup_.IsDone();
1294 else
1295 done = state_main_.IsDone();
1296
1297 if (done)
1298 SendTestResults(browser, frame, kOrderNavMsg);
1299 }
1300
1301 // Send the test results.
SendTestResults(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const char * msg_name)1302 void SendTestResults(CefRefPtr<CefBrowser> browser,
1303 CefRefPtr<CefFrame> frame,
1304 const char* msg_name) {
1305 // Check if the test has failed.
1306 bool result = !TestFailed();
1307
1308 // Return the result to the browser process.
1309 CefRefPtr<CefProcessMessage> return_msg =
1310 CefProcessMessage::Create(msg_name);
1311 CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
1312 EXPECT_TRUE(args.get());
1313 EXPECT_TRUE(args->SetBool(0, result));
1314 if (browser->IsPopup())
1315 EXPECT_TRUE(args->SetInt(1, browser_id_popup_));
1316 else
1317 EXPECT_TRUE(args->SetInt(1, browser_id_main_));
1318 frame->SendProcessMessage(PID_BROWSER, return_msg);
1319 }
1320
1321 bool run_test_;
1322
1323 int browser_id_main_;
1324 int browser_id_popup_;
1325 CefRefPtr<CefBrowser> browser_main_;
1326 TrackCallback got_webkit_initialized_;
1327 TrackCallback got_browser_created_main_;
1328 TrackCallback got_browser_destroyed_main_;
1329 TrackCallback got_browser_created_popup_;
1330 TrackCallback got_browser_destroyed_popup_;
1331
1332 OrderNavLoadState state_main_;
1333 OrderNavLoadState state_popup_;
1334
1335 IMPLEMENT_REFCOUNTING(OrderNavRendererTest);
1336 };
1337
1338 // Browser side.
1339 class OrderNavTestHandler : public TestHandler {
1340 public:
OrderNavTestHandler()1341 OrderNavTestHandler()
1342 : browser_id_main_(0),
1343 browser_id_popup_(0),
1344 state_main_(false, true),
1345 state_popup_(true, true),
1346 got_message_(false) {}
1347
1348 // Returns state that will be checked in the renderer process via
1349 // OrderNavRendererTest::OnBrowserCreated.
GetExtraInfo()1350 CefRefPtr<CefDictionaryValue> GetExtraInfo() {
1351 CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
1352 extra_info->SetBool(kOrderNavTestCmdKey, true);
1353 return extra_info;
1354 }
1355
RunTest()1356 void RunTest() override {
1357 // Add the resources that we will navigate to/from.
1358 AddResource(KONav1, "<html>Nav1</html>", "text/html");
1359 AddResource(KONav2, "<html>Nav2</html>", "text/html");
1360
1361 // Create the browser.
1362 CreateBrowser(KONav1, nullptr, GetExtraInfo());
1363
1364 // Time out the test after a reasonable period of time.
1365 SetTestTimeout();
1366 }
1367
ContinueIfReady(CefRefPtr<CefBrowser> browser)1368 void ContinueIfReady(CefRefPtr<CefBrowser> browser) {
1369 if (!got_message_)
1370 return;
1371
1372 bool done = false;
1373 if (browser->IsPopup())
1374 done = state_popup_.IsDone();
1375 else
1376 done = state_main_.IsDone();
1377 if (!done)
1378 return;
1379
1380 got_message_ = false;
1381
1382 if (!browser->IsPopup()) {
1383 // Create the popup window.
1384 browser->GetMainFrame()->ExecuteJavaScript(
1385 "window.open('" + std::string(KONav2) + "');", CefString(), 0);
1386 } else {
1387 // Close the popup window.
1388 CloseBrowser(browser_popup_, false);
1389 }
1390 }
1391
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,CefRefPtr<CefDictionaryValue> & extra_info,bool * no_javascript_access)1392 bool OnBeforePopup(
1393 CefRefPtr<CefBrowser> browser,
1394 CefRefPtr<CefFrame> frame,
1395 const CefString& target_url,
1396 const CefString& target_frame_name,
1397 CefLifeSpanHandler::WindowOpenDisposition target_disposition,
1398 bool user_gesture,
1399 const CefPopupFeatures& popupFeatures,
1400 CefWindowInfo& windowInfo,
1401 CefRefPtr<CefClient>& client,
1402 CefBrowserSettings& settings,
1403 CefRefPtr<CefDictionaryValue>& extra_info,
1404 bool* no_javascript_access) override {
1405 extra_info = GetExtraInfo();
1406 return false;
1407 }
1408
OnAfterCreated(CefRefPtr<CefBrowser> browser)1409 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
1410 TestHandler::OnAfterCreated(browser);
1411
1412 if (browser->IsPopup()) {
1413 browser_id_popup_ = browser->GetIdentifier();
1414 EXPECT_GT(browser_id_popup_, 0);
1415 browser_popup_ = browser;
1416 } else {
1417 browser_id_main_ = browser->GetIdentifier();
1418 EXPECT_GT(browser_id_main_, 0);
1419 }
1420 }
1421
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)1422 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
1423 CefRefPtr<CefFrame> frame,
1424 CefRefPtr<CefRequest> request,
1425 bool user_gesture,
1426 bool is_redirect) override {
1427 EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1428
1429 if (browser->IsPopup()) {
1430 EXPECT_EQ(TT_LINK, request->GetTransitionType());
1431 EXPECT_GT(browser->GetIdentifier(), 0);
1432 EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
1433 got_before_browse_popup_.yes();
1434 } else {
1435 EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
1436 EXPECT_GT(browser->GetIdentifier(), 0);
1437 EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
1438 got_before_browse_main_.yes();
1439 }
1440
1441 std::string url = request->GetURL();
1442 if (url == KONav1)
1443 EXPECT_FALSE(browser->IsPopup());
1444 else if (url == KONav2)
1445 EXPECT_TRUE(browser->IsPopup());
1446 else
1447 EXPECT_TRUE(false); // not reached
1448
1449 return false;
1450 }
1451
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)1452 cef_return_value_t OnBeforeResourceLoad(
1453 CefRefPtr<CefBrowser> browser,
1454 CefRefPtr<CefFrame> frame,
1455 CefRefPtr<CefRequest> request,
1456 CefRefPtr<CefCallback> callback) override {
1457 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
1458 // Ignore favicon requests.
1459 return RV_CANCEL;
1460 }
1461
1462 EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1463
1464 if (browser->IsPopup()) {
1465 EXPECT_EQ(TT_LINK, request->GetTransitionType());
1466 EXPECT_GT(browser->GetIdentifier(), 0);
1467 EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
1468 } else {
1469 EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
1470 EXPECT_GT(browser->GetIdentifier(), 0);
1471 EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
1472 }
1473
1474 return RV_CONTINUE;
1475 }
1476
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)1477 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
1478 bool isLoading,
1479 bool canGoBack,
1480 bool canGoForward) override {
1481 if (browser->IsPopup()) {
1482 state_popup_.OnLoadingStateChange(browser, isLoading, canGoBack,
1483 canGoForward);
1484 } else {
1485 state_main_.OnLoadingStateChange(browser, isLoading, canGoBack,
1486 canGoForward);
1487 }
1488
1489 if (!isLoading)
1490 ContinueIfReady(browser);
1491 }
1492
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)1493 void OnLoadStart(CefRefPtr<CefBrowser> browser,
1494 CefRefPtr<CefFrame> frame,
1495 TransitionType transition_type) override {
1496 if (browser->IsPopup()) {
1497 EXPECT_EQ(TT_LINK, transition_type);
1498 state_popup_.OnLoadStart(browser, frame);
1499 } else {
1500 EXPECT_EQ(kTransitionExplicitLoad, transition_type);
1501 state_main_.OnLoadStart(browser, frame);
1502 }
1503 }
1504
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1505 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1506 CefRefPtr<CefFrame> frame,
1507 int httpStatusCode) override {
1508 if (browser->IsPopup()) {
1509 state_popup_.OnLoadEnd(browser, frame, httpStatusCode);
1510 } else {
1511 state_main_.OnLoadEnd(browser, frame, httpStatusCode);
1512 }
1513
1514 ContinueIfReady(browser);
1515 }
1516
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)1517 void OnLoadError(CefRefPtr<CefBrowser> browser,
1518 CefRefPtr<CefFrame> frame,
1519 ErrorCode errorCode,
1520 const CefString& errorText,
1521 const CefString& failedUrl) override {
1522 ADD_FAILURE() << "browser OnLoadError url: " << failedUrl.ToString()
1523 << " error: " << errorCode;
1524 }
1525
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)1526 bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
1527 CefRefPtr<CefFrame> frame,
1528 CefProcessId source_process,
1529 CefRefPtr<CefProcessMessage> message) override {
1530 if (browser->IsPopup()) {
1531 EXPECT_GT(browser->GetIdentifier(), 0);
1532 EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
1533 } else {
1534 EXPECT_GT(browser->GetIdentifier(), 0);
1535 EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
1536 }
1537
1538 const std::string& msg_name = message->GetName();
1539 if (msg_name == kOrderNavMsg || msg_name == kOrderNavClosedMsg) {
1540 // Test that the renderer side succeeded.
1541 CefRefPtr<CefListValue> args = message->GetArgumentList();
1542 EXPECT_TRUE(args.get());
1543 EXPECT_TRUE(args->GetBool(0));
1544
1545 if (browser->IsPopup()) {
1546 EXPECT_EQ(browser_id_popup_, args->GetInt(1));
1547 } else {
1548 EXPECT_EQ(browser_id_main_, args->GetInt(1));
1549 }
1550
1551 if (msg_name == kOrderNavMsg) {
1552 // Continue with the test.
1553 got_message_ = true;
1554 ContinueIfReady(browser);
1555 } else {
1556 // Popup was closed. End the test.
1557 browser_popup_ = nullptr;
1558 DestroyTest();
1559 }
1560
1561 return true;
1562 }
1563
1564 // Message not handled.
1565 return false;
1566 }
1567
1568 protected:
DestroyTest()1569 void DestroyTest() override {
1570 // Verify test expectations.
1571 EXPECT_TRUE(got_before_browse_main_);
1572 EXPECT_TRUE(got_before_browse_popup_);
1573
1574 EXPECT_TRUE(state_main_.Verify(true, true, true, true));
1575 EXPECT_TRUE(state_popup_.Verify(true, true, true, true));
1576
1577 TestHandler::DestroyTest();
1578 }
1579
1580 int browser_id_main_;
1581 int browser_id_popup_;
1582 CefRefPtr<CefBrowser> browser_popup_;
1583
1584 TrackCallback got_before_browse_main_;
1585 TrackCallback got_before_browse_popup_;
1586
1587 OrderNavLoadState state_main_;
1588 OrderNavLoadState state_popup_;
1589
1590 bool got_message_;
1591
1592 IMPLEMENT_REFCOUNTING(OrderNavTestHandler);
1593 };
1594
1595 } // namespace
1596
1597 // Verify the order of navigation-related callbacks.
TEST(NavigationTest,Order)1598 TEST(NavigationTest, Order) {
1599 CefRefPtr<OrderNavTestHandler> handler = new OrderNavTestHandler();
1600 handler->ExecuteTest();
1601 ReleaseAndWaitForDestructor(handler);
1602 }
1603
1604 namespace {
1605
1606 const char kLoadNav1[] = "http://tests-conav1.com/nav1.html";
1607 const char kLoadNavSameOrigin2[] = "http://tests-conav1.com/nav2.html";
1608 const char kLoadNavCrossOrigin2[] = "http://tests-conav2.com/nav2.html";
1609 const char kLoadNavMsg[] = "NavigationTest.LoadNav";
1610 const char kLoadNavTestCmdKey[] = "nav-load-test";
1611
1612 // Renderer side.
1613 class LoadNavRendererTest : public ClientAppRenderer::Delegate,
1614 public CefLoadHandler {
1615 public:
LoadNavRendererTest()1616 LoadNavRendererTest() : run_test_(false), browser_id_(0), load_ct_(0) {}
~LoadNavRendererTest()1617 ~LoadNavRendererTest() override { EXPECT_EQ(0, browser_id_); }
1618
OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefDictionaryValue> extra_info)1619 void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
1620 CefRefPtr<CefBrowser> browser,
1621 CefRefPtr<CefDictionaryValue> extra_info) override {
1622 run_test_ = extra_info && extra_info->HasKey(kLoadNavTestCmdKey);
1623 if (!run_test_)
1624 return;
1625
1626 EXPECT_EQ(0, browser_id_);
1627 browser_id_ = browser->GetIdentifier();
1628 EXPECT_GT(browser_id_, 0);
1629 got_browser_created_.yes();
1630 }
1631
OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser)1632 void OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,
1633 CefRefPtr<CefBrowser> browser) override {
1634 if (!run_test_)
1635 return;
1636
1637 EXPECT_TRUE(got_browser_created_);
1638 EXPECT_TRUE(got_loading_state_end_);
1639
1640 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1641 browser_id_ = 0;
1642 }
1643
GetLoadHandler(CefRefPtr<ClientAppRenderer> app)1644 CefRefPtr<CefLoadHandler> GetLoadHandler(
1645 CefRefPtr<ClientAppRenderer> app) override {
1646 if (!run_test_)
1647 return nullptr;
1648
1649 return this;
1650 }
1651
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)1652 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
1653 bool isLoading,
1654 bool canGoBack,
1655 bool canGoForward) override {
1656 if (!isLoading) {
1657 EXPECT_TRUE(got_browser_created_);
1658
1659 got_loading_state_end_.yes();
1660
1661 EXPECT_EQ(browser_id_, browser->GetIdentifier());
1662
1663 load_ct_++;
1664 SendTestResults(browser, browser->GetMainFrame());
1665 }
1666 }
1667
1668 protected:
1669 // Send the test results.
SendTestResults(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)1670 void SendTestResults(CefRefPtr<CefBrowser> browser,
1671 CefRefPtr<CefFrame> frame) {
1672 // Check if the test has failed.
1673 bool result = !TestFailed();
1674
1675 // Return the result to the browser process.
1676 CefRefPtr<CefProcessMessage> return_msg =
1677 CefProcessMessage::Create(kLoadNavMsg);
1678 CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
1679 EXPECT_TRUE(args.get());
1680 EXPECT_TRUE(args->SetBool(0, result));
1681 EXPECT_TRUE(args->SetInt(1, browser->GetIdentifier()));
1682 EXPECT_TRUE(args->SetInt(2, load_ct_));
1683 frame->SendProcessMessage(PID_BROWSER, return_msg);
1684 }
1685
1686 bool run_test_;
1687
1688 int browser_id_;
1689 int load_ct_;
1690 TrackCallback got_browser_created_;
1691 TrackCallback got_loading_state_end_;
1692
1693 IMPLEMENT_REFCOUNTING(LoadNavRendererTest);
1694 };
1695
1696 // Browser side.
1697 class LoadNavTestHandler : public TestHandler {
1698 public:
1699 enum TestMode {
1700 LOAD,
1701 LEFT_CLICK,
1702 MIDDLE_CLICK,
1703 CTRL_LEFT_CLICK,
1704 };
1705
LoadNavTestHandler(TestMode mode,bool same_origin,bool cancel_in_open_url=false)1706 LoadNavTestHandler(TestMode mode,
1707 bool same_origin,
1708 bool cancel_in_open_url = false)
1709 : mode_(mode),
1710 same_origin_(same_origin),
1711 cancel_in_open_url_(cancel_in_open_url),
1712 browser_id_current_(0),
1713 renderer_load_ct_(0) {}
1714
GetURL2() const1715 std::string GetURL2() const {
1716 return same_origin_ ? kLoadNavSameOrigin2 : kLoadNavCrossOrigin2;
1717 }
1718
ExpectOpenURL() const1719 bool ExpectOpenURL() const {
1720 return mode_ == MIDDLE_CLICK || mode_ == CTRL_LEFT_CLICK;
1721 }
1722
RunTest()1723 void RunTest() override {
1724 const std::string& url2 = GetURL2();
1725 std::string link;
1726 if (mode_ != LOAD)
1727 link = "<a href=\"" + url2 + "\">CLICK ME</a>";
1728
1729 // Add the resources that we will navigate to/from.
1730 AddResource(kLoadNav1,
1731 "<html><body><h1>" + link + "Nav1</h1></body></html>",
1732 "text/html");
1733 AddResource(url2, "<html>Nav2</html>", "text/html");
1734
1735 CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
1736 extra_info->SetBool(kLoadNavTestCmdKey, true);
1737
1738 // Create the browser.
1739 CreateBrowser(kLoadNav1, nullptr, extra_info);
1740
1741 // Time out the test after a reasonable period of time.
1742 SetTestTimeout();
1743 }
1744
ContinueIfReady(CefRefPtr<CefBrowser> browser)1745 void ContinueIfReady(CefRefPtr<CefBrowser> browser) {
1746 if (!got_message_ || !got_load_end_)
1747 return;
1748
1749 std::string url = browser->GetMainFrame()->GetURL();
1750 if (url == kLoadNav1) {
1751 // Verify the behavior of the previous load.
1752 EXPECT_TRUE(got_before_browse_);
1753 EXPECT_TRUE(got_before_resource_load_);
1754 EXPECT_TRUE(got_load_start_);
1755 EXPECT_TRUE(got_load_end_);
1756 EXPECT_FALSE(got_open_url_from_tab_);
1757
1758 got_before_browse_.reset();
1759 got_before_resource_load_.reset();
1760 got_load_start_.reset();
1761 got_load_end_.reset();
1762 got_message_.reset();
1763
1764 EXPECT_EQ(1, renderer_load_ct_);
1765
1766 // Load the next url.
1767 if (mode_ == LOAD) {
1768 browser->GetMainFrame()->LoadURL(GetURL2());
1769 } else {
1770 // Navigate to the URL by clicking a link.
1771 CefMouseEvent mouse_event;
1772 mouse_event.x = 20;
1773 mouse_event.y = 20;
1774 #if defined(OS_MAC)
1775 // Use cmd instead of ctrl on OS X.
1776 mouse_event.modifiers =
1777 (mode_ == CTRL_LEFT_CLICK ? EVENTFLAG_COMMAND_DOWN : 0);
1778 #else
1779 mouse_event.modifiers =
1780 (mode_ == CTRL_LEFT_CLICK ? EVENTFLAG_CONTROL_DOWN : 0);
1781 #endif
1782
1783 cef_mouse_button_type_t button_type =
1784 (mode_ == MIDDLE_CLICK ? MBT_MIDDLE : MBT_LEFT);
1785 browser->GetHost()->SendMouseClickEvent(mouse_event, button_type, false,
1786 1);
1787 browser->GetHost()->SendMouseClickEvent(mouse_event, button_type, true,
1788 1);
1789 }
1790
1791 if (cancel_in_open_url_) {
1792 // The next navigation should not occur. Therefore call DestroyTest()
1793 // after a reasonable timeout.
1794 CefPostDelayedTask(
1795 TID_UI, base::BindOnce(&LoadNavTestHandler::DestroyTest, this),
1796 500);
1797 }
1798 } else {
1799 // Done with the test.
1800 DestroyTest();
1801 }
1802 }
1803
OnAfterCreated(CefRefPtr<CefBrowser> browser)1804 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
1805 TestHandler::OnAfterCreated(browser);
1806
1807 EXPECT_EQ(browser_id_current_, 0);
1808 browser_id_current_ = browser->GetIdentifier();
1809 EXPECT_GT(browser_id_current_, 0);
1810 }
1811
ExpectedOpenURLTransitionType() const1812 cef_transition_type_t ExpectedOpenURLTransitionType() const {
1813 if (mode_ != LEFT_CLICK && IsChromeRuntimeEnabled()) {
1814 // Because we triggered the navigation with LoadURL in OnOpenURLFromTab.
1815 return kTransitionExplicitLoad;
1816 }
1817 return TT_LINK;
1818 }
1819
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)1820 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
1821 CefRefPtr<CefFrame> frame,
1822 CefRefPtr<CefRequest> request,
1823 bool user_gesture,
1824 bool is_redirect) override {
1825 EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1826 if (mode_ == LOAD || request->GetURL() == kLoadNav1) {
1827 EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
1828 if (IsChromeRuntimeEnabled()) {
1829 // With the Chrome runtime this is true on initial navigation via
1830 // chrome::AddTabAt() and also true for clicked links.
1831 EXPECT_TRUE(user_gesture);
1832 } else {
1833 EXPECT_FALSE(user_gesture);
1834 }
1835 } else {
1836 EXPECT_EQ(ExpectedOpenURLTransitionType(), request->GetTransitionType());
1837
1838 if (mode_ == LEFT_CLICK || IsChromeRuntimeEnabled()) {
1839 EXPECT_TRUE(user_gesture);
1840 } else {
1841 EXPECT_FALSE(user_gesture);
1842 }
1843 }
1844
1845 EXPECT_GT(browser_id_current_, 0);
1846 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1847
1848 if (ExpectOpenURL() && request->GetURL() == GetURL2()) {
1849 // OnOpenURLFromTab should be called first for the file URL navigation.
1850 EXPECT_TRUE(got_open_url_from_tab_);
1851 } else {
1852 EXPECT_FALSE(got_open_url_from_tab_);
1853 }
1854
1855 got_before_browse_.yes();
1856
1857 return false;
1858 }
1859
OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & target_url,cef_window_open_disposition_t target_disposition,bool user_gesture)1860 bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
1861 CefRefPtr<CefFrame> frame,
1862 const CefString& target_url,
1863 cef_window_open_disposition_t target_disposition,
1864 bool user_gesture) override {
1865 EXPECT_TRUE(CefCurrentlyOn(TID_UI));
1866
1867 EXPECT_GT(browser_id_current_, 0);
1868 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1869
1870 // OnOpenURLFromTab should only be called for the file URL.
1871 EXPECT_STREQ(GetURL2().c_str(), target_url.ToString().c_str());
1872
1873 if (mode_ == LOAD)
1874 EXPECT_FALSE(user_gesture);
1875 else
1876 EXPECT_TRUE(user_gesture);
1877
1878 EXPECT_EQ(WOD_NEW_BACKGROUND_TAB, target_disposition);
1879
1880 // OnOpenURLFromTab should be called before OnBeforeBrowse for the file URL.
1881 EXPECT_FALSE(got_before_browse_);
1882
1883 got_open_url_from_tab_.yes();
1884
1885 if (!cancel_in_open_url_ && IsChromeRuntimeEnabled()) {
1886 // The chrome runtime may create a new popup window, which is not the
1887 // behavior that this test expects. Instead, match the alloy runtime
1888 // behavior by navigating in the current window.
1889 browser->GetMainFrame()->LoadURL(target_url);
1890 return true;
1891 }
1892
1893 return cancel_in_open_url_;
1894 }
1895
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefCallback> callback)1896 cef_return_value_t OnBeforeResourceLoad(
1897 CefRefPtr<CefBrowser> browser,
1898 CefRefPtr<CefFrame> frame,
1899 CefRefPtr<CefRequest> request,
1900 CefRefPtr<CefCallback> callback) override {
1901 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
1902 // Ignore favicon requests.
1903 return RV_CANCEL;
1904 }
1905
1906 EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1907
1908 const auto transition_type = request->GetTransitionType();
1909 if (mode_ == LOAD || request->GetURL() == kLoadNav1) {
1910 EXPECT_EQ(kTransitionExplicitLoad, transition_type);
1911 } else {
1912 EXPECT_EQ(ExpectedOpenURLTransitionType(), transition_type);
1913 }
1914
1915 EXPECT_GT(browser_id_current_, 0);
1916 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1917
1918 got_before_resource_load_.yes();
1919
1920 return RV_CONTINUE;
1921 }
1922
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)1923 void OnLoadStart(CefRefPtr<CefBrowser> browser,
1924 CefRefPtr<CefFrame> frame,
1925 TransitionType transition_type) override {
1926 EXPECT_GT(browser_id_current_, 0);
1927 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1928
1929 if (mode_ == LOAD || frame->GetURL() == kLoadNav1) {
1930 EXPECT_EQ(kTransitionExplicitLoad, transition_type);
1931 } else {
1932 EXPECT_EQ(ExpectedOpenURLTransitionType(), transition_type);
1933 }
1934
1935 got_load_start_.yes();
1936 }
1937
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1938 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1939 CefRefPtr<CefFrame> frame,
1940 int httpStatusCode) override {
1941 EXPECT_GT(browser_id_current_, 0);
1942 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1943
1944 got_load_end_.yes();
1945 ContinueIfReady(browser);
1946 }
1947
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)1948 bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
1949 CefRefPtr<CefFrame> frame,
1950 CefProcessId source_process,
1951 CefRefPtr<CefProcessMessage> message) override {
1952 EXPECT_GT(browser_id_current_, 0);
1953 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1954
1955 const std::string& msg_name = message->GetName();
1956 if (msg_name == kLoadNavMsg) {
1957 // Test that the renderer side succeeded.
1958 CefRefPtr<CefListValue> args = message->GetArgumentList();
1959 EXPECT_TRUE(args.get());
1960 EXPECT_TRUE(args->GetBool(0));
1961
1962 EXPECT_EQ(browser_id_current_, args->GetInt(1));
1963
1964 renderer_load_ct_ = args->GetInt(2);
1965 EXPECT_GE(renderer_load_ct_, 1);
1966
1967 // Continue with the test.
1968 got_message_.yes();
1969 ContinueIfReady(browser);
1970
1971 return true;
1972 }
1973
1974 // Message not handled.
1975 return false;
1976 }
1977
DestroyTest()1978 void DestroyTest() override {
1979 if (cancel_in_open_url_) {
1980 EXPECT_FALSE(got_before_browse_);
1981 EXPECT_FALSE(got_before_resource_load_);
1982 EXPECT_FALSE(got_load_start_);
1983 EXPECT_FALSE(got_load_end_);
1984 EXPECT_FALSE(got_message_);
1985
1986 // We should only navigate a single time if the 2nd load is canceled.
1987 EXPECT_EQ(1, renderer_load_ct_);
1988 } else {
1989 EXPECT_TRUE(got_before_browse_);
1990 EXPECT_TRUE(got_before_resource_load_);
1991 EXPECT_TRUE(got_load_start_);
1992 EXPECT_TRUE(got_load_end_);
1993 EXPECT_TRUE(got_message_);
1994
1995 if (same_origin_) {
1996 // The renderer process should always be reused.
1997 EXPECT_EQ(2, renderer_load_ct_);
1998 } else {
1999 // Each renderer process is only used for a single navigation.
2000 EXPECT_EQ(1, renderer_load_ct_);
2001 }
2002 }
2003
2004 if (ExpectOpenURL())
2005 EXPECT_TRUE(got_open_url_from_tab_);
2006 else
2007 EXPECT_FALSE(got_open_url_from_tab_);
2008
2009 TestHandler::DestroyTest();
2010 }
2011
2012 protected:
2013 const TestMode mode_;
2014 const bool same_origin_;
2015 const bool cancel_in_open_url_;
2016
2017 int browser_id_current_;
2018 int renderer_load_ct_;
2019
2020 TrackCallback got_before_browse_;
2021 TrackCallback got_open_url_from_tab_;
2022 TrackCallback got_before_resource_load_;
2023 TrackCallback got_load_start_;
2024 TrackCallback got_load_end_;
2025 TrackCallback got_message_;
2026
2027 IMPLEMENT_REFCOUNTING(LoadNavTestHandler);
2028 };
2029
2030 } // namespace
2031
2032 // Verify navigation-related callbacks when browsing same-origin via LoadURL().
TEST(NavigationTest,LoadSameOriginLoadURL)2033 TEST(NavigationTest, LoadSameOriginLoadURL) {
2034 CefRefPtr<LoadNavTestHandler> handler =
2035 new LoadNavTestHandler(LoadNavTestHandler::LOAD, true);
2036 handler->ExecuteTest();
2037 ReleaseAndWaitForDestructor(handler);
2038 }
2039
2040 // Verify navigation-related callbacks when browsing same-origin via left-click.
TEST(NavigationTest,LoadSameOriginLeftClick)2041 TEST(NavigationTest, LoadSameOriginLeftClick) {
2042 CefRefPtr<LoadNavTestHandler> handler =
2043 new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, true);
2044 handler->ExecuteTest();
2045 ReleaseAndWaitForDestructor(handler);
2046 }
2047
2048 // Verify navigation-related callbacks when browsing same-origin via middle-
2049 // click.
TEST(NavigationTest,LoadSameOriginMiddleClick)2050 TEST(NavigationTest, LoadSameOriginMiddleClick) {
2051 CefRefPtr<LoadNavTestHandler> handler =
2052 new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true);
2053 handler->ExecuteTest();
2054 ReleaseAndWaitForDestructor(handler);
2055 }
2056
2057 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadSameOriginMiddleClickCancel)2058 TEST(NavigationTest, LoadSameOriginMiddleClickCancel) {
2059 CefRefPtr<LoadNavTestHandler> handler =
2060 new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true, true);
2061 handler->ExecuteTest();
2062 ReleaseAndWaitForDestructor(handler);
2063 }
2064
2065 // Verify navigation-related callbacks when browsing same-origin via ctrl+left-
2066 // click.
TEST(NavigationTest,LoadSameOriginCtrlLeftClick)2067 TEST(NavigationTest, LoadSameOriginCtrlLeftClick) {
2068 CefRefPtr<LoadNavTestHandler> handler =
2069 new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true);
2070 handler->ExecuteTest();
2071 ReleaseAndWaitForDestructor(handler);
2072 }
2073
2074 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadSameOriginCtrlLeftClickCancel)2075 TEST(NavigationTest, LoadSameOriginCtrlLeftClickCancel) {
2076 CefRefPtr<LoadNavTestHandler> handler =
2077 new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true, true);
2078 handler->ExecuteTest();
2079 ReleaseAndWaitForDestructor(handler);
2080 }
2081
2082 // Verify navigation-related callbacks when browsing cross-origin via LoadURL().
TEST(NavigationTest,LoadCrossOriginLoadURL)2083 TEST(NavigationTest, LoadCrossOriginLoadURL) {
2084 CefRefPtr<LoadNavTestHandler> handler =
2085 new LoadNavTestHandler(LoadNavTestHandler::LOAD, false);
2086 handler->ExecuteTest();
2087 ReleaseAndWaitForDestructor(handler);
2088 }
2089
2090 // Verify navigation-related callbacks when browsing cross-origin via left-
2091 // click.
TEST(NavigationTest,LoadCrossOriginLeftClick)2092 TEST(NavigationTest, LoadCrossOriginLeftClick) {
2093 CefRefPtr<LoadNavTestHandler> handler =
2094 new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, false);
2095 handler->ExecuteTest();
2096 ReleaseAndWaitForDestructor(handler);
2097 }
2098
2099 // Verify navigation-related callbacks when browsing cross-origin via middle-
2100 // click.
TEST(NavigationTest,LoadCrossOriginMiddleClick)2101 TEST(NavigationTest, LoadCrossOriginMiddleClick) {
2102 CefRefPtr<LoadNavTestHandler> handler =
2103 new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false);
2104 handler->ExecuteTest();
2105 ReleaseAndWaitForDestructor(handler);
2106 }
2107
2108 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadCrossOriginMiddleClickCancel)2109 TEST(NavigationTest, LoadCrossOriginMiddleClickCancel) {
2110 CefRefPtr<LoadNavTestHandler> handler =
2111 new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false, true);
2112 handler->ExecuteTest();
2113 ReleaseAndWaitForDestructor(handler);
2114 }
2115
2116 // Verify navigation-related callbacks when browsing cross-origin via ctrl+left-
2117 // click.
TEST(NavigationTest,LoadCrossOriginCtrlLeftClick)2118 TEST(NavigationTest, LoadCrossOriginCtrlLeftClick) {
2119 CefRefPtr<LoadNavTestHandler> handler =
2120 new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false);
2121 handler->ExecuteTest();
2122 ReleaseAndWaitForDestructor(handler);
2123 }
2124
2125 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadCrossOriginCtrlLeftClickCancel)2126 TEST(NavigationTest, LoadCrossOriginCtrlLeftClickCancel) {
2127 CefRefPtr<LoadNavTestHandler> handler =
2128 new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false, true);
2129 handler->ExecuteTest();
2130 ReleaseAndWaitForDestructor(handler);
2131 }
2132
2133 namespace {
2134
2135 const char kSimultPopupMainUrl[] = "http://www.tests-sp.com/main.html";
2136 const char kSimultPopupPopupUrl[] = "http://www.tests-sp.com/popup";
2137 const size_t kSimultPopupCount = 5U;
2138
2139 // Test multiple popups simultaniously.
2140 class PopupSimultaneousTestHandler : public TestHandler {
2141 public:
PopupSimultaneousTestHandler(bool same_url)2142 explicit PopupSimultaneousTestHandler(bool same_url)
2143 : same_url_(same_url),
2144 before_popup_ct_(0U),
2145 after_created_ct_(0U),
2146 before_close_ct_(0U) {}
2147
RunTest()2148 void RunTest() override {
2149 std::string main_html = "<html><script>\n";
2150 for (size_t i = 0; i < kSimultPopupCount; ++i) {
2151 if (same_url_) {
2152 popup_url_[i] = std::string(kSimultPopupPopupUrl) + ".html";
2153 } else {
2154 std::stringstream ss;
2155 ss << kSimultPopupPopupUrl << i << ".html";
2156 popup_url_[i] = ss.str();
2157 }
2158 main_html += "window.open('" + popup_url_[i] + "');\n";
2159 AddResource(popup_url_[i], "<html>Popup " + popup_url_[i] + "</html>",
2160 "text/html");
2161 }
2162 main_html += "</script></html>";
2163
2164 AddResource(kSimultPopupMainUrl, main_html, "text/html");
2165
2166 // Create the browser.
2167 CreateBrowser(kSimultPopupMainUrl);
2168
2169 // Time out the test after a reasonable period of time.
2170 SetTestTimeout();
2171 }
2172
OnBeforePopup(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,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)2173 bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
2174 CefRefPtr<CefFrame> frame,
2175 const CefString& target_url,
2176 const CefString& target_frame_name,
2177 cef_window_open_disposition_t target_disposition,
2178 bool user_gesture,
2179 const CefPopupFeatures& popupFeatures,
2180 CefWindowInfo& windowInfo,
2181 CefRefPtr<CefClient>& client,
2182 CefBrowserSettings& settings,
2183 CefRefPtr<CefDictionaryValue>& extra_info,
2184 bool* no_javascript_access) override {
2185 const std::string& url = target_url;
2186 EXPECT_LT(before_popup_ct_, kSimultPopupCount);
2187 EXPECT_STREQ(popup_url_[before_popup_ct_].c_str(), url.c_str())
2188 << before_popup_ct_;
2189 before_popup_ct_++;
2190 return false;
2191 }
2192
OnAfterCreated(CefRefPtr<CefBrowser> browser)2193 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
2194 TestHandler::OnAfterCreated(browser);
2195
2196 if (browser->IsPopup()) {
2197 EXPECT_LT(after_created_ct_, kSimultPopupCount);
2198 browser_id_[after_created_ct_] = browser->GetIdentifier();
2199 after_created_ct_++;
2200 }
2201 }
2202
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2203 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2204 bool isLoading,
2205 bool canGoBack,
2206 bool canGoForward) override {
2207 if (isLoading)
2208 return;
2209
2210 if (browser->IsPopup()) {
2211 const std::string& url = browser->GetMainFrame()->GetURL();
2212 for (size_t i = 0; i < kSimultPopupCount; ++i) {
2213 if (browser->GetIdentifier() == browser_id_[i]) {
2214 EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
2215
2216 got_loading_state_change_[i].yes();
2217 CloseBrowser(browser, true);
2218 return;
2219 }
2220 }
2221 EXPECT_FALSE(true); // Not reached.
2222 }
2223 }
2224
OnBeforeClose(CefRefPtr<CefBrowser> browser)2225 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
2226 TestHandler::OnBeforeClose(browser);
2227
2228 if (browser->IsPopup()) {
2229 const std::string& url = browser->GetMainFrame()->GetURL();
2230 for (size_t i = 0; i < kSimultPopupCount; ++i) {
2231 if (browser->GetIdentifier() == browser_id_[i]) {
2232 EXPECT_TRUE(got_loading_state_change_[i]);
2233 EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
2234
2235 got_before_close_[i].yes();
2236
2237 if (++before_close_ct_ == kSimultPopupCount)
2238 DestroyTest();
2239 return;
2240 }
2241 }
2242 EXPECT_FALSE(true); // Not reached.
2243 }
2244 }
2245
2246 private:
DestroyTest()2247 void DestroyTest() override {
2248 EXPECT_EQ(kSimultPopupCount, before_popup_ct_);
2249 EXPECT_EQ(kSimultPopupCount, after_created_ct_);
2250 EXPECT_EQ(kSimultPopupCount, before_close_ct_);
2251
2252 for (size_t i = 0; i < kSimultPopupCount; ++i) {
2253 EXPECT_GT(browser_id_[i], 0) << i;
2254 EXPECT_TRUE(got_loading_state_change_[i]) << i;
2255 EXPECT_TRUE(got_before_close_[i]) << i;
2256 }
2257
2258 TestHandler::DestroyTest();
2259 }
2260
2261 const bool same_url_;
2262 std::string popup_url_[kSimultPopupCount];
2263 size_t before_popup_ct_;
2264 int browser_id_[kSimultPopupCount];
2265 size_t after_created_ct_;
2266 TrackCallback got_loading_state_change_[kSimultPopupCount];
2267 TrackCallback got_before_close_[kSimultPopupCount];
2268 size_t before_close_ct_;
2269
2270 IMPLEMENT_REFCOUNTING(PopupSimultaneousTestHandler);
2271 };
2272
2273 } // namespace
2274
2275 // Test simultaneous popups with different URLs.
TEST(NavigationTest,PopupSimultaneousDifferentUrl)2276 TEST(NavigationTest, PopupSimultaneousDifferentUrl) {
2277 CefRefPtr<PopupSimultaneousTestHandler> handler =
2278 new PopupSimultaneousTestHandler(false);
2279 handler->ExecuteTest();
2280 ReleaseAndWaitForDestructor(handler);
2281 }
2282
2283 // Test simultaneous popups with the same URL.
TEST(NavigationTest,PopupSimultaneousSameUrl)2284 TEST(NavigationTest, PopupSimultaneousSameUrl) {
2285 CefRefPtr<PopupSimultaneousTestHandler> handler =
2286 new PopupSimultaneousTestHandler(true);
2287 handler->ExecuteTest();
2288 ReleaseAndWaitForDestructor(handler);
2289 }
2290
2291 namespace {
2292
2293 const char kPopupJSOpenMainUrl[] = "http://www.tests-pjso.com/main.html";
2294 const char kPopupJSOpenPopupUrl[] = "http://www.tests-pjso.com/popup.html";
2295
2296 // Test a popup where the URL is a JavaScript URI that opens another popup.
2297 class PopupJSWindowOpenTestHandler : public TestHandler {
2298 public:
PopupJSWindowOpenTestHandler()2299 PopupJSWindowOpenTestHandler()
2300 : before_popup_ct_(0U),
2301 after_created_ct_(0U),
2302 load_end_ct_(0U),
2303 before_close_ct_(0U) {}
2304
RunTest()2305 void RunTest() override {
2306 AddResource(kPopupJSOpenMainUrl, "<html>Main</html>", "text/html");
2307 AddResource(kPopupJSOpenPopupUrl, "<html>Popup</html>", "text/html");
2308
2309 // Create the browser.
2310 CreateBrowser(kPopupJSOpenMainUrl);
2311
2312 // Time out the test after a reasonable period of time.
2313 SetTestTimeout();
2314 }
2315
OnBeforePopup(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,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)2316 bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
2317 CefRefPtr<CefFrame> frame,
2318 const CefString& target_url,
2319 const CefString& target_frame_name,
2320 cef_window_open_disposition_t target_disposition,
2321 bool user_gesture,
2322 const CefPopupFeatures& popupFeatures,
2323 CefWindowInfo& windowInfo,
2324 CefRefPtr<CefClient>& client,
2325 CefBrowserSettings& settings,
2326 CefRefPtr<CefDictionaryValue>& extra_info,
2327 bool* no_javascript_access) override {
2328 before_popup_ct_++;
2329 return false;
2330 }
2331
OnAfterCreated(CefRefPtr<CefBrowser> browser)2332 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
2333 TestHandler::OnAfterCreated(browser);
2334
2335 if (browser->IsPopup()) {
2336 after_created_ct_++;
2337 if (!popup1_)
2338 popup1_ = browser;
2339 else if (!popup2_)
2340 popup2_ = browser;
2341 else
2342 ADD_FAILURE();
2343 }
2344 }
2345
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2346 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2347 bool isLoading,
2348 bool canGoBack,
2349 bool canGoForward) override {
2350 if (isLoading)
2351 return;
2352
2353 if (browser->IsPopup()) {
2354 const std::string& url = browser->GetMainFrame()->GetURL();
2355 if (url == kPopupJSOpenPopupUrl) {
2356 EXPECT_TRUE(browser->IsSame(popup2_));
2357 popup2_ = nullptr;
2358
2359 // OnLoadingStateChange is not currently called for browser-side
2360 // navigations of empty popups. See https://crbug.com/789252.
2361 // Explicitly close the empty popup here as a workaround.
2362 CloseBrowser(popup1_, true);
2363 popup1_ = nullptr;
2364 } else {
2365 // Empty popup.
2366 EXPECT_TRUE(url.empty());
2367 EXPECT_TRUE(browser->IsSame(popup1_));
2368 popup1_ = nullptr;
2369 }
2370
2371 load_end_ct_++;
2372 CloseBrowser(browser, true);
2373 } else if (browser->GetMainFrame()->GetURL() == kPopupJSOpenMainUrl) {
2374 // Load the problematic JS URI.
2375 // This will result in 2 popups being created:
2376 // - An empty popup
2377 // - A popup that loads kPopupJSOpenPopupUrl
2378 browser->GetMainFrame()->LoadURL(
2379 "javascript:window.open(\"javascript:window.open('" +
2380 std::string(kPopupJSOpenPopupUrl) + "')\")");
2381 }
2382 }
2383
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2384 void OnLoadError(CefRefPtr<CefBrowser> browser,
2385 CefRefPtr<CefFrame> frame,
2386 ErrorCode errorCode,
2387 const CefString& errorText,
2388 const CefString& failedUrl) override {
2389 ADD_FAILURE() << "OnLoadError url: " << failedUrl.ToString()
2390 << " error: " << errorCode;
2391 }
2392
OnBeforeClose(CefRefPtr<CefBrowser> browser)2393 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
2394 TestHandler::OnBeforeClose(browser);
2395
2396 before_close_ct_++;
2397 if (before_close_ct_ == 2U)
2398 DestroyTest();
2399 }
2400
2401 private:
DestroyTest()2402 void DestroyTest() override {
2403 EXPECT_EQ(2U, before_popup_ct_);
2404 EXPECT_EQ(2U, after_created_ct_);
2405 EXPECT_EQ(2U, before_close_ct_);
2406
2407 // OnLoadingStateChange is not currently called for browser-side
2408 // navigations of empty popups. See https://crbug.com/789252.
2409 EXPECT_EQ(1U, load_end_ct_);
2410
2411 TestHandler::DestroyTest();
2412 }
2413
2414 CefRefPtr<CefBrowser> popup1_;
2415 CefRefPtr<CefBrowser> popup2_;
2416
2417 size_t before_popup_ct_;
2418 size_t after_created_ct_;
2419 size_t load_end_ct_;
2420 size_t before_close_ct_;
2421
2422 IMPLEMENT_REFCOUNTING(PopupJSWindowOpenTestHandler);
2423 };
2424
2425 } // namespace
2426
2427 // Test a popup where the URL is a JavaScript URI that opens another popup.
TEST(NavigationTest,PopupJSWindowOpen)2428 TEST(NavigationTest, PopupJSWindowOpen) {
2429 CefRefPtr<PopupJSWindowOpenTestHandler> handler =
2430 new PopupJSWindowOpenTestHandler();
2431 handler->ExecuteTest();
2432 ReleaseAndWaitForDestructor(handler);
2433 }
2434
2435 namespace {
2436
2437 const char kPopupJSEmptyMainUrl[] = "http://www.tests-pjse.com/main.html";
2438
2439 // Test creation of a popup where the URL is empty.
2440 class PopupJSWindowEmptyTestHandler : public TestHandler {
2441 public:
PopupJSWindowEmptyTestHandler()2442 PopupJSWindowEmptyTestHandler() {}
2443
RunTest()2444 void RunTest() override {
2445 AddResource(kPopupJSEmptyMainUrl, "<html>Main</html>", "text/html");
2446
2447 // Create the browser.
2448 CreateBrowser(kPopupJSEmptyMainUrl);
2449
2450 // Time out the test after a reasonable period of time.
2451 SetTestTimeout();
2452 }
2453
OnBeforePopup(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,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)2454 bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
2455 CefRefPtr<CefFrame> frame,
2456 const CefString& target_url,
2457 const CefString& target_frame_name,
2458 cef_window_open_disposition_t target_disposition,
2459 bool user_gesture,
2460 const CefPopupFeatures& popupFeatures,
2461 CefWindowInfo& windowInfo,
2462 CefRefPtr<CefClient>& client,
2463 CefBrowserSettings& settings,
2464 CefRefPtr<CefDictionaryValue>& extra_info,
2465 bool* no_javascript_access) override {
2466 got_before_popup_.yes();
2467 return false;
2468 }
2469
OnAfterCreated(CefRefPtr<CefBrowser> browser)2470 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
2471 TestHandler::OnAfterCreated(browser);
2472
2473 if (browser->IsPopup()) {
2474 got_after_created_popup_.yes();
2475 }
2476 }
2477
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2478 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2479 bool isLoading,
2480 bool canGoBack,
2481 bool canGoForward) override {
2482 if (isLoading)
2483 return;
2484
2485 if (browser->IsPopup()) {
2486 got_load_end_popup_.yes();
2487 CloseBrowser(browser, true);
2488 } else {
2489 browser->GetMainFrame()->LoadURL("javascript:window.open('')");
2490 }
2491 }
2492
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2493 void OnLoadError(CefRefPtr<CefBrowser> browser,
2494 CefRefPtr<CefFrame> frame,
2495 ErrorCode errorCode,
2496 const CefString& errorText,
2497 const CefString& failedUrl) override {
2498 ADD_FAILURE() << "OnLoadError url: " << failedUrl.ToString()
2499 << " error: " << errorCode;
2500 }
2501
OnBeforeClose(CefRefPtr<CefBrowser> browser)2502 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
2503 TestHandler::OnBeforeClose(browser);
2504
2505 if (browser->IsPopup()) {
2506 got_before_close_popup_.yes();
2507 DestroyTest();
2508 }
2509 }
2510
2511 private:
DestroyTest()2512 void DestroyTest() override {
2513 EXPECT_TRUE(got_before_popup_);
2514 EXPECT_TRUE(got_after_created_popup_);
2515 EXPECT_TRUE(got_load_end_popup_);
2516 EXPECT_TRUE(got_before_close_popup_);
2517
2518 TestHandler::DestroyTest();
2519 }
2520
2521 TrackCallback got_before_popup_;
2522 TrackCallback got_after_created_popup_;
2523 TrackCallback got_load_end_popup_;
2524 TrackCallback got_before_close_popup_;
2525
2526 IMPLEMENT_REFCOUNTING(PopupJSWindowEmptyTestHandler);
2527 };
2528
2529 } // namespace
2530
2531 // Test creation of a popup where the URL is empty.
TEST(NavigationTest,PopupJSWindowEmpty)2532 TEST(NavigationTest, PopupJSWindowEmpty) {
2533 CefRefPtr<PopupJSWindowEmptyTestHandler> handler =
2534 new PopupJSWindowEmptyTestHandler();
2535 handler->ExecuteTest();
2536 ReleaseAndWaitForDestructor(handler);
2537 }
2538
2539 namespace {
2540
2541 const char kBrowseNavPageUrl[] = "http://tests-browsenav/nav.html";
2542
2543 // Browser side.
2544 class BrowseNavTestHandler : public TestHandler {
2545 public:
BrowseNavTestHandler(bool allow)2546 BrowseNavTestHandler(bool allow) : allow_(allow), destroyed_(false) {}
2547
RunTest()2548 void RunTest() override {
2549 AddResource(kBrowseNavPageUrl, "<html>Test</html>", "text/html");
2550
2551 // Create the browser.
2552 CreateBrowser(kBrowseNavPageUrl);
2553
2554 // Time out the test after a reasonable period of time.
2555 SetTestTimeout();
2556 }
2557
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2558 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2559 CefRefPtr<CefFrame> frame,
2560 CefRefPtr<CefRequest> request,
2561 bool user_gesture,
2562 bool is_redirect) override {
2563 const std::string& url = request->GetURL();
2564 EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2565 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2566 EXPECT_TRUE(frame->IsMain());
2567
2568 got_before_browse_.yes();
2569
2570 return !allow_;
2571 }
2572
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)2573 void OnLoadStart(CefRefPtr<CefBrowser> browser,
2574 CefRefPtr<CefFrame> frame,
2575 TransitionType transition_type) override {
2576 const std::string& url = frame->GetURL();
2577 EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2578 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2579 EXPECT_TRUE(frame->IsMain());
2580
2581 got_load_start_.yes();
2582 }
2583
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2584 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2585 CefRefPtr<CefFrame> frame,
2586 int httpStatusCode) override {
2587 const std::string& url = frame->GetURL();
2588 EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2589 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2590 EXPECT_TRUE(frame->IsMain());
2591
2592 got_load_end_.yes();
2593 DestroyTestIfDone();
2594 }
2595
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2596 void OnLoadError(CefRefPtr<CefBrowser> browser,
2597 CefRefPtr<CefFrame> frame,
2598 ErrorCode errorCode,
2599 const CefString& errorText,
2600 const CefString& failedUrl) override {
2601 const std::string& url = frame->GetURL();
2602 EXPECT_STREQ("", url.c_str());
2603 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2604 EXPECT_TRUE(frame->IsMain());
2605
2606 EXPECT_EQ(ERR_ABORTED, errorCode);
2607 EXPECT_STREQ(kBrowseNavPageUrl, failedUrl.ToString().c_str());
2608
2609 got_load_error_.yes();
2610 DestroyTestIfDone();
2611 }
2612
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2613 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2614 bool isLoading,
2615 bool canGoBack,
2616 bool canGoForward) override {
2617 const std::string& url = browser->GetMainFrame()->GetURL();
2618 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2619
2620 if (isLoading) {
2621 EXPECT_STREQ("", url.c_str());
2622
2623 got_loading_state_changed_start_.yes();
2624 } else {
2625 if (allow_)
2626 EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2627 else
2628 EXPECT_STREQ("", url.c_str());
2629
2630 got_loading_state_changed_end_.yes();
2631 DestroyTestIfDone();
2632 }
2633 }
2634
2635 private:
DestroyTestIfDone()2636 void DestroyTestIfDone() {
2637 if (destroyed_)
2638 return;
2639
2640 if (got_loading_state_changed_end_) {
2641 if (allow_) {
2642 if (got_load_end_)
2643 DestroyTest();
2644 } else if (got_load_error_) {
2645 DestroyTest();
2646 }
2647 }
2648 }
2649
DestroyTest()2650 void DestroyTest() override {
2651 if (destroyed_)
2652 return;
2653 destroyed_ = true;
2654
2655 EXPECT_TRUE(got_before_browse_);
2656 EXPECT_TRUE(got_loading_state_changed_start_);
2657 EXPECT_TRUE(got_loading_state_changed_end_);
2658
2659 if (allow_) {
2660 EXPECT_TRUE(got_load_start_);
2661 EXPECT_TRUE(got_load_end_);
2662 EXPECT_FALSE(got_load_error_);
2663 } else {
2664 EXPECT_FALSE(got_load_start_);
2665 EXPECT_FALSE(got_load_end_);
2666 EXPECT_TRUE(got_load_error_);
2667 }
2668
2669 TestHandler::DestroyTest();
2670 }
2671
2672 bool allow_;
2673 bool destroyed_;
2674
2675 TrackCallback got_before_browse_;
2676 TrackCallback got_load_start_;
2677 TrackCallback got_load_end_;
2678 TrackCallback got_load_error_;
2679 TrackCallback got_loading_state_changed_start_;
2680 TrackCallback got_loading_state_changed_end_;
2681
2682 IMPLEMENT_REFCOUNTING(BrowseNavTestHandler);
2683 };
2684
2685 } // namespace
2686
2687 // Test allowing navigation.
TEST(NavigationTest,BrowseAllow)2688 TEST(NavigationTest, BrowseAllow) {
2689 CefRefPtr<BrowseNavTestHandler> handler = new BrowseNavTestHandler(true);
2690 handler->ExecuteTest();
2691 ReleaseAndWaitForDestructor(handler);
2692 }
2693
2694 // Test denying navigation.
TEST(NavigationTest,BrowseDeny)2695 TEST(NavigationTest, BrowseDeny) {
2696 CefRefPtr<BrowseNavTestHandler> handler = new BrowseNavTestHandler(false);
2697 handler->ExecuteTest();
2698 ReleaseAndWaitForDestructor(handler);
2699 }
2700
2701 namespace {
2702
2703 const char kSameNavPageUrl[] = "http://tests-samenav/nav.html";
2704
2705 // Browser side.
2706 class SameNavTestHandler : public TestHandler {
2707 public:
SameNavTestHandler()2708 SameNavTestHandler() : destroyed_(false), step_(0) {}
2709
RunTest()2710 void RunTest() override {
2711 AddResource(kSameNavPageUrl, "<html>Test</html>", "text/html");
2712
2713 // Create the browser.
2714 expected_url_ = kSameNavPageUrl;
2715 CreateBrowser(kSameNavPageUrl);
2716
2717 // Time out the test after a reasonable period of time.
2718 SetTestTimeout();
2719 }
2720
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2721 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2722 CefRefPtr<CefFrame> frame,
2723 CefRefPtr<CefRequest> request,
2724 bool user_gesture,
2725 bool is_redirect) override {
2726 const std::string& url = request->GetURL();
2727 EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2728 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2729 EXPECT_TRUE(frame->IsMain());
2730
2731 got_before_browse_.yes();
2732
2733 return false;
2734 }
2735
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)2736 void OnLoadStart(CefRefPtr<CefBrowser> browser,
2737 CefRefPtr<CefFrame> frame,
2738 TransitionType transition_type) override {
2739 const std::string& url = frame->GetURL();
2740 EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2741 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2742 EXPECT_TRUE(frame->IsMain());
2743
2744 got_load_start_.yes();
2745 }
2746
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2747 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2748 CefRefPtr<CefFrame> frame,
2749 int httpStatusCode) override {
2750 const std::string& url = frame->GetURL();
2751 EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2752 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2753 EXPECT_TRUE(frame->IsMain());
2754
2755 got_load_end_.yes();
2756 ContinueTestIfDone();
2757 }
2758
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2759 void OnLoadError(CefRefPtr<CefBrowser> browser,
2760 CefRefPtr<CefFrame> frame,
2761 ErrorCode errorCode,
2762 const CefString& errorText,
2763 const CefString& failedUrl) override {
2764 got_load_error_.yes();
2765 }
2766
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2767 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2768 bool isLoading,
2769 bool canGoBack,
2770 bool canGoForward) override {
2771 const std::string& url = browser->GetMainFrame()->GetURL();
2772 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2773
2774 if (isLoading) {
2775 // Verify the previous URL.
2776 if (step_ == 0)
2777 EXPECT_TRUE(url.empty());
2778 else
2779 EXPECT_STREQ(kSameNavPageUrl, url.c_str());
2780
2781 got_loading_state_changed_start_.yes();
2782 } else {
2783 EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2784
2785 got_loading_state_changed_end_.yes();
2786 ContinueTestIfDone();
2787 }
2788 }
2789
2790 private:
ContinueTestIfDone()2791 void ContinueTestIfDone() {
2792 if (step_ == 0) {
2793 // First navigation should trigger all callbacks except OnLoadError.
2794 if (got_loading_state_changed_end_ && got_load_end_) {
2795 EXPECT_TRUE(got_before_browse_);
2796 EXPECT_TRUE(got_loading_state_changed_start_);
2797 EXPECT_TRUE(got_load_start_);
2798 EXPECT_FALSE(got_load_error_);
2799
2800 got_before_browse_.reset();
2801 got_loading_state_changed_start_.reset();
2802 got_loading_state_changed_end_.reset();
2803 got_load_start_.reset();
2804 got_load_end_.reset();
2805
2806 step_++;
2807 expected_url_ = kSameNavPageUrl + std::string("#fragment");
2808 GetBrowser()->GetMainFrame()->LoadURL(expected_url_);
2809 }
2810 } else if (step_ == 1) {
2811 step_++;
2812 DestroyTest();
2813 } else {
2814 EXPECT_TRUE(false); // Not reached.
2815 }
2816 }
2817
DestroyTest()2818 void DestroyTest() override {
2819 if (destroyed_)
2820 return;
2821 destroyed_ = true;
2822
2823 EXPECT_EQ(2, step_);
2824
2825 // Second (fragment) navigation should only trigger OnLoadingStateChange.
2826 EXPECT_FALSE(got_before_browse_);
2827 EXPECT_TRUE(got_loading_state_changed_start_);
2828 EXPECT_TRUE(got_loading_state_changed_end_);
2829 EXPECT_FALSE(got_load_start_);
2830 EXPECT_FALSE(got_load_end_);
2831 EXPECT_FALSE(got_load_error_);
2832
2833 TestHandler::DestroyTest();
2834 }
2835
2836 bool destroyed_;
2837 int step_;
2838 std::string expected_url_;
2839
2840 TrackCallback got_before_browse_;
2841 TrackCallback got_load_start_;
2842 TrackCallback got_load_end_;
2843 TrackCallback got_load_error_;
2844 TrackCallback got_loading_state_changed_start_;
2845 TrackCallback got_loading_state_changed_end_;
2846
2847 IMPLEMENT_REFCOUNTING(SameNavTestHandler);
2848 };
2849
2850 } // namespace
2851
2852 // Test that same page navigation does not call OnLoadStart/OnLoadEnd.
TEST(NavigationTest,SamePage)2853 TEST(NavigationTest, SamePage) {
2854 CefRefPtr<SameNavTestHandler> handler = new SameNavTestHandler();
2855 handler->ExecuteTest();
2856 ReleaseAndWaitForDestructor(handler);
2857 }
2858
2859 namespace {
2860
2861 const char kCancelPageUrl[] = "http://tests-cancelnav/nav.html";
2862
2863 // A scheme handler that never starts sending data.
2864 class UnstartedSchemeHandler : public CefResourceHandler {
2865 public:
UnstartedSchemeHandler()2866 UnstartedSchemeHandler() {}
2867
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)2868 bool Open(CefRefPtr<CefRequest> request,
2869 bool& handle_request,
2870 CefRefPtr<CefCallback> callback) override {
2871 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
2872
2873 // Continue immediately.
2874 handle_request = true;
2875 return true;
2876 }
2877
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)2878 void GetResponseHeaders(CefRefPtr<CefResponse> response,
2879 int64& response_length,
2880 CefString& redirectUrl) override {
2881 response->SetStatus(200);
2882 response->SetMimeType("text/html");
2883 response_length = 100;
2884 }
2885
Cancel()2886 void Cancel() override { callback_ = nullptr; }
2887
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)2888 bool Read(void* data_out,
2889 int bytes_to_read,
2890 int& bytes_read,
2891 CefRefPtr<CefResourceReadCallback> callback) override {
2892 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
2893
2894 callback_ = callback;
2895
2896 // Pretend that we'll provide the data later.
2897 bytes_read = 0;
2898 return true;
2899 }
2900
2901 protected:
2902 CefRefPtr<CefResourceReadCallback> callback_;
2903
2904 IMPLEMENT_REFCOUNTING(UnstartedSchemeHandler);
2905 DISALLOW_COPY_AND_ASSIGN(UnstartedSchemeHandler);
2906 };
2907
2908 // Browser side.
2909 class CancelBeforeNavTestHandler : public TestHandler {
2910 public:
CancelBeforeNavTestHandler()2911 CancelBeforeNavTestHandler() : destroyed_(false) {}
2912
RunTest()2913 void RunTest() override {
2914 // Create the browser.
2915 CreateBrowser(kCancelPageUrl);
2916
2917 // Time out the test after a reasonable period of time.
2918 SetTestTimeout();
2919 }
2920
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2921 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2922 CefRefPtr<CefFrame> frame,
2923 CefRefPtr<CefRequest> request,
2924 bool user_gesture,
2925 bool is_redirect) override {
2926 EXPECT_TRUE(got_loading_state_changed_start_);
2927 EXPECT_FALSE(got_before_browse_);
2928 EXPECT_FALSE(got_get_resource_handler_);
2929 EXPECT_FALSE(got_load_start_);
2930 EXPECT_FALSE(got_cancel_load_);
2931 EXPECT_FALSE(got_load_error_);
2932 EXPECT_FALSE(got_load_end_);
2933 EXPECT_FALSE(got_loading_state_changed_end_);
2934
2935 const std::string& url = request->GetURL();
2936 EXPECT_STREQ(kCancelPageUrl, url.c_str());
2937 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2938 EXPECT_TRUE(frame->IsMain());
2939
2940 got_before_browse_.yes();
2941
2942 return false;
2943 }
2944
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)2945 CefRefPtr<CefResourceHandler> GetResourceHandler(
2946 CefRefPtr<CefBrowser> browser,
2947 CefRefPtr<CefFrame> frame,
2948 CefRefPtr<CefRequest> request) override {
2949 EXPECT_TRUE(got_loading_state_changed_start_);
2950 EXPECT_TRUE(got_before_browse_);
2951 EXPECT_FALSE(got_get_resource_handler_);
2952 EXPECT_FALSE(got_load_start_);
2953 EXPECT_FALSE(got_cancel_load_);
2954 EXPECT_FALSE(got_load_error_);
2955 EXPECT_FALSE(got_load_end_);
2956 EXPECT_FALSE(got_loading_state_changed_end_);
2957
2958 const std::string& url = request->GetURL();
2959 EXPECT_STREQ(kCancelPageUrl, url.c_str());
2960 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2961 EXPECT_TRUE(frame->IsMain());
2962
2963 got_get_resource_handler_.yes();
2964
2965 CefPostTask(TID_UI,
2966 base::BindOnce(&CancelBeforeNavTestHandler::CancelLoad, this));
2967
2968 return new UnstartedSchemeHandler();
2969 }
2970
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)2971 void OnLoadStart(CefRefPtr<CefBrowser> browser,
2972 CefRefPtr<CefFrame> frame,
2973 TransitionType transition_type) override {
2974 EXPECT_TRUE(false); // Not reached.
2975 got_load_start_.yes();
2976 }
2977
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2978 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2979 CefRefPtr<CefFrame> frame,
2980 int httpStatusCode) override {
2981 EXPECT_TRUE(false); // Not reached.
2982 got_load_end_.yes();
2983 }
2984
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2985 void OnLoadError(CefRefPtr<CefBrowser> browser,
2986 CefRefPtr<CefFrame> frame,
2987 ErrorCode errorCode,
2988 const CefString& errorText,
2989 const CefString& failedUrl) override {
2990 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2991 EXPECT_STREQ("", frame->GetURL().ToString().c_str());
2992 EXPECT_EQ(ERR_ABORTED, errorCode);
2993 EXPECT_STREQ(kCancelPageUrl, failedUrl.ToString().c_str());
2994 got_load_error_.yes();
2995 }
2996
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2997 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2998 bool isLoading,
2999 bool canGoBack,
3000 bool canGoForward) override {
3001 const std::string& url = browser->GetMainFrame()->GetURL();
3002 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3003 EXPECT_TRUE(url.empty());
3004
3005 if (isLoading) {
3006 EXPECT_FALSE(got_loading_state_changed_start_);
3007 EXPECT_FALSE(got_before_browse_);
3008 EXPECT_FALSE(got_get_resource_handler_);
3009 EXPECT_FALSE(got_load_start_);
3010 EXPECT_FALSE(got_cancel_load_);
3011 EXPECT_FALSE(got_load_error_);
3012 EXPECT_FALSE(got_load_end_);
3013 EXPECT_FALSE(got_loading_state_changed_end_);
3014
3015 got_loading_state_changed_start_.yes();
3016 } else {
3017 EXPECT_TRUE(got_loading_state_changed_start_);
3018 EXPECT_TRUE(got_before_browse_);
3019 EXPECT_TRUE(got_get_resource_handler_);
3020 EXPECT_FALSE(got_load_start_);
3021 EXPECT_TRUE(got_cancel_load_);
3022 EXPECT_TRUE(got_load_error_);
3023 EXPECT_FALSE(got_load_end_);
3024 EXPECT_FALSE(got_loading_state_changed_end_);
3025
3026 got_loading_state_changed_end_.yes();
3027
3028 DestroyTest();
3029 }
3030 }
3031
3032 private:
CancelLoad()3033 void CancelLoad() {
3034 got_cancel_load_.yes();
3035 GetBrowser()->StopLoad();
3036 }
3037
DestroyTest()3038 void DestroyTest() override {
3039 if (destroyed_)
3040 return;
3041 destroyed_ = true;
3042
3043 EXPECT_TRUE(got_loading_state_changed_start_);
3044 EXPECT_TRUE(got_before_browse_);
3045 EXPECT_TRUE(got_get_resource_handler_);
3046 EXPECT_FALSE(got_load_start_);
3047 EXPECT_TRUE(got_cancel_load_);
3048 EXPECT_TRUE(got_load_error_);
3049 EXPECT_FALSE(got_load_end_);
3050 EXPECT_TRUE(got_loading_state_changed_end_);
3051
3052 TestHandler::DestroyTest();
3053 }
3054
3055 bool destroyed_;
3056
3057 TrackCallback got_loading_state_changed_start_;
3058 TrackCallback got_before_browse_;
3059 TrackCallback got_get_resource_handler_;
3060 TrackCallback got_load_start_;
3061 TrackCallback got_cancel_load_;
3062 TrackCallback got_load_error_;
3063 TrackCallback got_load_end_;
3064 TrackCallback got_loading_state_changed_end_;
3065
3066 IMPLEMENT_REFCOUNTING(CancelBeforeNavTestHandler);
3067 };
3068
3069 } // namespace
3070
3071 // Test that navigation canceled before commit does not call
3072 // OnLoadStart/OnLoadEnd.
TEST(NavigationTest,CancelBeforeCommit)3073 TEST(NavigationTest, CancelBeforeCommit) {
3074 CefRefPtr<CancelBeforeNavTestHandler> handler =
3075 new CancelBeforeNavTestHandler();
3076 handler->ExecuteTest();
3077 ReleaseAndWaitForDestructor(handler);
3078 }
3079
3080 namespace {
3081
3082 // A scheme handler that stalls after writing some data.
3083 class StalledSchemeHandler : public CefResourceHandler {
3084 public:
StalledSchemeHandler()3085 StalledSchemeHandler() : offset_(0), write_size_(0) {}
3086
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)3087 bool Open(CefRefPtr<CefRequest> request,
3088 bool& handle_request,
3089 CefRefPtr<CefCallback> callback) override {
3090 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
3091
3092 // Continue immediately.
3093 handle_request = true;
3094 return true;
3095 }
3096
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)3097 void GetResponseHeaders(CefRefPtr<CefResponse> response,
3098 int64& response_length,
3099 CefString& redirectUrl) override {
3100 response->SetStatus(200);
3101 response->SetMimeType("text/html");
3102 content_ = "<html><body>Test</body></html>";
3103 // Write this number of bytes and then stall.
3104 write_size_ = content_.size() / 2U;
3105 response_length = content_.size();
3106 }
3107
Cancel()3108 void Cancel() override { callback_ = nullptr; }
3109
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)3110 bool Read(void* data_out,
3111 int bytes_to_read,
3112 int& bytes_read,
3113 CefRefPtr<CefResourceReadCallback> callback) override {
3114 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
3115
3116 bytes_read = 0;
3117
3118 size_t size = content_.size();
3119 if (offset_ >= write_size_) {
3120 // Now stall.
3121 callback_ = callback;
3122 return true;
3123 }
3124
3125 bool has_data = false;
3126
3127 if (offset_ < size) {
3128 // Write up to |write_size_| bytes.
3129 int transfer_size =
3130 std::min(bytes_to_read, std::min(static_cast<int>(write_size_),
3131 static_cast<int>(size - offset_)));
3132 memcpy(data_out, content_.c_str() + offset_, transfer_size);
3133 offset_ += transfer_size;
3134
3135 bytes_read = transfer_size;
3136 has_data = true;
3137 }
3138
3139 return has_data;
3140 }
3141
3142 protected:
3143 std::string content_;
3144 size_t offset_;
3145 size_t write_size_;
3146 CefRefPtr<CefResourceReadCallback> callback_;
3147
3148 IMPLEMENT_REFCOUNTING(StalledSchemeHandler);
3149 DISALLOW_COPY_AND_ASSIGN(StalledSchemeHandler);
3150 };
3151
3152 // Browser side.
3153 class CancelAfterNavTestHandler : public TestHandler {
3154 public:
CancelAfterNavTestHandler()3155 CancelAfterNavTestHandler() : destroyed_(false) {}
3156
RunTest()3157 void RunTest() override {
3158 // Create the browser.
3159 CreateBrowser(kCancelPageUrl);
3160
3161 // Time out the test after a reasonable period of time.
3162 SetTestTimeout();
3163 }
3164
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)3165 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
3166 CefRefPtr<CefFrame> frame,
3167 CefRefPtr<CefRequest> request,
3168 bool user_gesture,
3169 bool is_redirect) override {
3170 EXPECT_TRUE(got_loading_state_changed_start_);
3171 EXPECT_FALSE(got_before_browse_);
3172 EXPECT_FALSE(got_get_resource_handler_);
3173 EXPECT_FALSE(got_load_start_);
3174 EXPECT_FALSE(got_cancel_load_);
3175 EXPECT_FALSE(got_load_error_);
3176 EXPECT_FALSE(got_load_end_);
3177 EXPECT_FALSE(got_loading_state_changed_end_);
3178
3179 const std::string& url = request->GetURL();
3180 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3181 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3182 EXPECT_TRUE(frame->IsMain());
3183
3184 got_before_browse_.yes();
3185
3186 return false;
3187 }
3188
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)3189 CefRefPtr<CefResourceHandler> GetResourceHandler(
3190 CefRefPtr<CefBrowser> browser,
3191 CefRefPtr<CefFrame> frame,
3192 CefRefPtr<CefRequest> request) override {
3193 EXPECT_TRUE(got_loading_state_changed_start_);
3194 EXPECT_TRUE(got_before_browse_);
3195 EXPECT_FALSE(got_get_resource_handler_);
3196 EXPECT_FALSE(got_load_start_);
3197 EXPECT_FALSE(got_cancel_load_);
3198 EXPECT_FALSE(got_load_error_);
3199 EXPECT_FALSE(got_load_end_);
3200 EXPECT_FALSE(got_loading_state_changed_end_);
3201
3202 const std::string& url = request->GetURL();
3203 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3204 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3205 EXPECT_TRUE(frame->IsMain());
3206
3207 got_get_resource_handler_.yes();
3208
3209 // The required delay is longer when browser-side navigation is enabled.
3210 CefPostDelayedTask(
3211 TID_UI, base::BindOnce(&CancelAfterNavTestHandler::CancelLoad, this),
3212 1000);
3213
3214 return new StalledSchemeHandler();
3215 }
3216
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)3217 void OnLoadStart(CefRefPtr<CefBrowser> browser,
3218 CefRefPtr<CefFrame> frame,
3219 TransitionType transition_type) override {
3220 EXPECT_TRUE(got_loading_state_changed_start_);
3221 EXPECT_TRUE(got_before_browse_);
3222 EXPECT_TRUE(got_get_resource_handler_);
3223 EXPECT_FALSE(got_load_start_);
3224 EXPECT_FALSE(got_cancel_load_);
3225 EXPECT_FALSE(got_load_error_);
3226 EXPECT_FALSE(got_load_end_);
3227 EXPECT_FALSE(got_loading_state_changed_end_);
3228
3229 const std::string& url = frame->GetURL();
3230 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3231 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3232 EXPECT_TRUE(frame->IsMain());
3233
3234 got_load_start_.yes();
3235 }
3236
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)3237 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
3238 CefRefPtr<CefFrame> frame,
3239 int httpStatusCode) override {
3240 EXPECT_TRUE(got_loading_state_changed_start_);
3241 EXPECT_TRUE(got_before_browse_);
3242 EXPECT_TRUE(got_get_resource_handler_);
3243 EXPECT_TRUE(got_load_start_);
3244 EXPECT_TRUE(got_cancel_load_);
3245 EXPECT_TRUE(got_load_error_);
3246 EXPECT_FALSE(got_load_end_);
3247 EXPECT_FALSE(got_loading_state_changed_end_);
3248
3249 const std::string& url = frame->GetURL();
3250 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3251 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3252 EXPECT_TRUE(frame->IsMain());
3253
3254 got_load_end_.yes();
3255 DestroyTestIfDone();
3256 }
3257
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)3258 void OnLoadError(CefRefPtr<CefBrowser> browser,
3259 CefRefPtr<CefFrame> frame,
3260 ErrorCode errorCode,
3261 const CefString& errorText,
3262 const CefString& failedUrl) override {
3263 EXPECT_TRUE(got_loading_state_changed_start_);
3264 EXPECT_TRUE(got_before_browse_);
3265 EXPECT_TRUE(got_get_resource_handler_);
3266 EXPECT_TRUE(got_load_start_);
3267 EXPECT_TRUE(got_cancel_load_);
3268 EXPECT_FALSE(got_load_error_);
3269 EXPECT_FALSE(got_load_end_);
3270 EXPECT_FALSE(got_loading_state_changed_end_);
3271
3272 const std::string& url = failedUrl;
3273 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3274 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3275 EXPECT_TRUE(frame->IsMain());
3276
3277 got_load_error_.yes();
3278 }
3279
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)3280 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
3281 bool isLoading,
3282 bool canGoBack,
3283 bool canGoForward) override {
3284 const std::string& url = browser->GetMainFrame()->GetURL();
3285 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3286
3287 if (isLoading) {
3288 EXPECT_FALSE(got_loading_state_changed_start_);
3289 EXPECT_FALSE(got_before_browse_);
3290 EXPECT_FALSE(got_get_resource_handler_);
3291 EXPECT_FALSE(got_load_start_);
3292 EXPECT_FALSE(got_cancel_load_);
3293 EXPECT_FALSE(got_load_error_);
3294 EXPECT_FALSE(got_load_end_);
3295 EXPECT_FALSE(got_loading_state_changed_end_);
3296
3297 EXPECT_TRUE(url.empty());
3298
3299 got_loading_state_changed_start_.yes();
3300 } else {
3301 EXPECT_TRUE(got_loading_state_changed_start_);
3302 EXPECT_TRUE(got_before_browse_);
3303 EXPECT_TRUE(got_get_resource_handler_);
3304 EXPECT_TRUE(got_load_start_);
3305 EXPECT_TRUE(got_cancel_load_);
3306 EXPECT_TRUE(got_load_error_);
3307 EXPECT_TRUE(got_load_end_);
3308 EXPECT_FALSE(got_loading_state_changed_end_);
3309
3310 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3311
3312 got_loading_state_changed_end_.yes();
3313 DestroyTestIfDone();
3314 }
3315 }
3316
3317 private:
CancelLoad()3318 void CancelLoad() {
3319 got_cancel_load_.yes();
3320 GetBrowser()->StopLoad();
3321 }
3322
DestroyTestIfDone()3323 void DestroyTestIfDone() {
3324 if (got_loading_state_changed_end_ && got_load_end_)
3325 DestroyTest();
3326 }
3327
DestroyTest()3328 void DestroyTest() override {
3329 if (destroyed_)
3330 return;
3331 destroyed_ = true;
3332
3333 EXPECT_TRUE(got_loading_state_changed_start_);
3334 EXPECT_TRUE(got_before_browse_);
3335 EXPECT_TRUE(got_get_resource_handler_);
3336 EXPECT_TRUE(got_load_start_);
3337 EXPECT_TRUE(got_cancel_load_);
3338 EXPECT_TRUE(got_load_error_);
3339 EXPECT_TRUE(got_load_end_);
3340 EXPECT_TRUE(got_loading_state_changed_end_);
3341
3342 TestHandler::DestroyTest();
3343 }
3344
3345 bool destroyed_;
3346
3347 TrackCallback got_loading_state_changed_start_;
3348 TrackCallback got_before_browse_;
3349 TrackCallback got_get_resource_handler_;
3350 TrackCallback got_load_start_;
3351 TrackCallback got_cancel_load_;
3352 TrackCallback got_load_error_;
3353 TrackCallback got_load_end_;
3354 TrackCallback got_loading_state_changed_end_;
3355
3356 IMPLEMENT_REFCOUNTING(CancelAfterNavTestHandler);
3357 };
3358
3359 } // namespace
3360
3361 // Test that navigation canceled after commit calls everything.
TEST(NavigationTest,CancelAfterCommit)3362 TEST(NavigationTest, CancelAfterCommit) {
3363 CefRefPtr<CancelAfterNavTestHandler> handler =
3364 new CancelAfterNavTestHandler();
3365 handler->ExecuteTest();
3366 ReleaseAndWaitForDestructor(handler);
3367 }
3368
3369 namespace {
3370
3371 const char kExtraInfoUrl[] = "http://tests-extrainfonav.com/extra.html";
3372 const char kExtraInfoPopupUrl[] =
3373 "http://tests-extrainfonav.com/extra_popup.html";
3374 const char kExtraInfoNavMsg[] = "NavigationTest.ExtraInfoNav";
3375 const char kExtraInfoTestCmdKey[] = "nav-extra-info-test";
3376
SetBrowserExtraInfo(CefRefPtr<CefDictionaryValue> extra_info)3377 void SetBrowserExtraInfo(CefRefPtr<CefDictionaryValue> extra_info) {
3378 // Necessary for identifying the test case.
3379 extra_info->SetBool(kExtraInfoTestCmdKey, true);
3380
3381 // Arbitrary data for testing.
3382 extra_info->SetBool("bool", true);
3383 CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
3384 dict->SetInt("key1", 5);
3385 dict->SetString("key2", "test string");
3386 extra_info->SetDictionary("dictionary", dict);
3387 extra_info->SetDouble("double", 5.43322);
3388 extra_info->SetString("string", "some string");
3389 }
3390
3391 // Renderer side
3392 class ExtraInfoNavRendererTest : public ClientAppRenderer::Delegate {
3393 public:
ExtraInfoNavRendererTest()3394 ExtraInfoNavRendererTest() : run_test_(false) {}
3395
OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefDictionaryValue> extra_info)3396 void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
3397 CefRefPtr<CefBrowser> browser,
3398 CefRefPtr<CefDictionaryValue> extra_info) override {
3399 run_test_ = extra_info && extra_info->HasKey(kExtraInfoTestCmdKey);
3400 if (!run_test_)
3401 return;
3402
3403 CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
3404 SetBrowserExtraInfo(expected);
3405 TestDictionaryEqual(expected, extra_info);
3406
3407 SendTestResults(browser, browser->GetMainFrame());
3408 }
3409
3410 protected:
3411 // Send the test results.
SendTestResults(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)3412 void SendTestResults(CefRefPtr<CefBrowser> browser,
3413 CefRefPtr<CefFrame> frame) {
3414 // Check if the test has failed.
3415 bool result = !TestFailed();
3416
3417 CefRefPtr<CefProcessMessage> return_msg =
3418 CefProcessMessage::Create(kExtraInfoNavMsg);
3419 CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
3420 EXPECT_TRUE(args.get());
3421 EXPECT_TRUE(args->SetBool(0, result));
3422 EXPECT_TRUE(args->SetBool(1, browser->IsPopup()));
3423 frame->SendProcessMessage(PID_BROWSER, return_msg);
3424 }
3425
3426 bool run_test_;
3427
3428 IMPLEMENT_REFCOUNTING(ExtraInfoNavRendererTest);
3429 };
3430
3431 class ExtraInfoNavTestHandler : public TestHandler {
3432 public:
ExtraInfoNavTestHandler()3433 ExtraInfoNavTestHandler() : popup_opened_(false) {}
3434
RunTest()3435 void RunTest() override {
3436 AddResource(kExtraInfoUrl,
3437 "<html><head></head><body>ExtraInfo</body></html>",
3438 "text/html");
3439 AddResource(kExtraInfoPopupUrl, "<html>ExtraInfoPopup</html>", "text/html");
3440
3441 CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
3442 SetBrowserExtraInfo(extra_info);
3443
3444 // Create the browser.
3445 CreateBrowser(kExtraInfoUrl, nullptr, extra_info);
3446
3447 // Time out the test after a reasonable period of time.
3448 SetTestTimeout();
3449 }
3450
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)3451 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
3452 CefRefPtr<CefFrame> frame,
3453 int httpStatusCode) override {
3454 if (popup_opened_) {
3455 DestroyTest();
3456 } else {
3457 browser->GetMainFrame()->ExecuteJavaScript(
3458 "window.open('" + std::string(kExtraInfoPopupUrl) + "');",
3459 CefString(), 0);
3460 }
3461 }
3462
OnBeforePopup(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,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)3463 bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
3464 CefRefPtr<CefFrame> frame,
3465 const CefString& target_url,
3466 const CefString& target_frame_name,
3467 cef_window_open_disposition_t target_disposition,
3468 bool user_gesture,
3469 const CefPopupFeatures& popupFeatures,
3470 CefWindowInfo& windowInfo,
3471 CefRefPtr<CefClient>& client,
3472 CefBrowserSettings& settings,
3473 CefRefPtr<CefDictionaryValue>& extra_info,
3474 bool* no_javascript_access) override {
3475 const std::string& url = target_url;
3476 EXPECT_FALSE(popup_opened_);
3477 EXPECT_STREQ(kExtraInfoPopupUrl, url.c_str());
3478
3479 CefRefPtr<CefDictionaryValue> extra = CefDictionaryValue::Create();
3480 SetBrowserExtraInfo(extra);
3481
3482 extra_info = extra;
3483
3484 popup_opened_ = true;
3485 return false;
3486 }
3487
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)3488 bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
3489 CefRefPtr<CefFrame> frame,
3490 CefProcessId source_process,
3491 CefRefPtr<CefProcessMessage> message) override {
3492 if (message->GetName().ToString() == kExtraInfoNavMsg) {
3493 // Test that the renderer side succeeded.
3494 CefRefPtr<CefListValue> args = message->GetArgumentList();
3495 EXPECT_TRUE(args.get());
3496 EXPECT_TRUE(args->GetBool(0));
3497 if (popup_opened_) {
3498 EXPECT_TRUE(args->GetBool(1));
3499 got_process_message_popup_.yes();
3500 } else {
3501 EXPECT_FALSE(args->GetBool(1));
3502 got_process_message_main_.yes();
3503 }
3504 return true;
3505 }
3506
3507 // Message not handled.
3508 return false;
3509 }
3510
3511 protected:
3512 bool popup_opened_;
3513 TrackCallback got_process_message_main_;
3514 TrackCallback got_process_message_popup_;
3515
DestroyTest()3516 void DestroyTest() override {
3517 // Verify test expectations.
3518 EXPECT_TRUE(got_process_message_main_);
3519 EXPECT_TRUE(got_process_message_popup_);
3520
3521 TestHandler::DestroyTest();
3522 }
3523
3524 IMPLEMENT_REFCOUNTING(ExtraInfoNavTestHandler);
3525 };
3526
3527 } // namespace
3528
TEST(NavigationTest,ExtraInfo)3529 TEST(NavigationTest, ExtraInfo) {
3530 CefRefPtr<ExtraInfoNavTestHandler> handler = new ExtraInfoNavTestHandler();
3531 handler->ExecuteTest();
3532 ReleaseAndWaitForDestructor(handler);
3533 }
3534
3535 // Entry point for creating navigation renderer test objects.
3536 // Called from client_app_delegates.cc.
CreateNavigationRendererTests(ClientAppRenderer::DelegateSet & delegates)3537 void CreateNavigationRendererTests(ClientAppRenderer::DelegateSet& delegates) {
3538 delegates.insert(new HistoryNavRendererTest);
3539 delegates.insert(new OrderNavRendererTest);
3540 delegates.insert(new LoadNavRendererTest);
3541 delegates.insert(new ExtraInfoNavRendererTest);
3542 }
3543