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_bind.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->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<CefRequestCallback> callback)387 cef_return_value_t OnBeforeResourceLoad(
388 CefRefPtr<CefBrowser> browser,
389 CefRefPtr<CefFrame> frame,
390 CefRefPtr<CefRequest> request,
391 CefRefPtr<CefRequestCallback> 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<CefRequestCallback> callback)840 cef_return_value_t OnBeforeResourceLoad(
841 CefRefPtr<CefBrowser> browser,
842 CefRefPtr<CefFrame> frame,
843 CefRefPtr<CefRequest> request,
844 CefRefPtr<CefRequestCallback> 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->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<CefRequestCallback> callback)1452 cef_return_value_t OnBeforeResourceLoad(
1453 CefRefPtr<CefBrowser> browser,
1454 CefRefPtr<CefFrame> frame,
1455 CefRefPtr<CefRequest> request,
1456 CefRefPtr<CefRequestCallback> 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->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::Bind(&LoadNavTestHandler::DestroyTest, this), 500);
1796 }
1797 } else {
1798 // Done with the test.
1799 DestroyTest();
1800 }
1801 }
1802
OnAfterCreated(CefRefPtr<CefBrowser> browser)1803 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
1804 TestHandler::OnAfterCreated(browser);
1805
1806 EXPECT_EQ(browser_id_current_, 0);
1807 browser_id_current_ = browser->GetIdentifier();
1808 EXPECT_GT(browser_id_current_, 0);
1809 }
1810
ExpectedOpenURLTransitionType() const1811 cef_transition_type_t ExpectedOpenURLTransitionType() const {
1812 if (mode_ != LEFT_CLICK && IsChromeRuntimeEnabled()) {
1813 // Because we triggered the navigation with LoadURL in OnOpenURLFromTab.
1814 return kTransitionExplicitLoad;
1815 }
1816 return TT_LINK;
1817 }
1818
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)1819 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
1820 CefRefPtr<CefFrame> frame,
1821 CefRefPtr<CefRequest> request,
1822 bool user_gesture,
1823 bool is_redirect) override {
1824 EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1825 if (mode_ == LOAD || request->GetURL() == kLoadNav1) {
1826 EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
1827 if (IsChromeRuntimeEnabled()) {
1828 // With the Chrome runtime this is true on initial navigation via
1829 // chrome::AddTabAt() and also true for clicked links.
1830 EXPECT_TRUE(user_gesture);
1831 } else {
1832 EXPECT_FALSE(user_gesture);
1833 }
1834 } else {
1835 EXPECT_EQ(ExpectedOpenURLTransitionType(), request->GetTransitionType());
1836
1837 if (mode_ == LEFT_CLICK || IsChromeRuntimeEnabled()) {
1838 EXPECT_TRUE(user_gesture);
1839 } else {
1840 EXPECT_FALSE(user_gesture);
1841 }
1842 }
1843
1844 EXPECT_GT(browser_id_current_, 0);
1845 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1846
1847 if (ExpectOpenURL() && request->GetURL() == GetURL2()) {
1848 // OnOpenURLFromTab should be called first for the file URL navigation.
1849 EXPECT_TRUE(got_open_url_from_tab_);
1850 } else {
1851 EXPECT_FALSE(got_open_url_from_tab_);
1852 }
1853
1854 got_before_browse_.yes();
1855
1856 return false;
1857 }
1858
OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString & target_url,cef_window_open_disposition_t target_disposition,bool user_gesture)1859 bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
1860 CefRefPtr<CefFrame> frame,
1861 const CefString& target_url,
1862 cef_window_open_disposition_t target_disposition,
1863 bool user_gesture) override {
1864 EXPECT_TRUE(CefCurrentlyOn(TID_UI));
1865
1866 EXPECT_GT(browser_id_current_, 0);
1867 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1868
1869 // OnOpenURLFromTab should only be called for the file URL.
1870 EXPECT_STREQ(GetURL2().c_str(), target_url.ToString().c_str());
1871
1872 if (mode_ == LOAD)
1873 EXPECT_FALSE(user_gesture);
1874 else
1875 EXPECT_TRUE(user_gesture);
1876
1877 EXPECT_EQ(WOD_NEW_BACKGROUND_TAB, target_disposition);
1878
1879 // OnOpenURLFromTab should be called before OnBeforeBrowse for the file URL.
1880 EXPECT_FALSE(got_before_browse_);
1881
1882 got_open_url_from_tab_.yes();
1883
1884 if (!cancel_in_open_url_ && IsChromeRuntimeEnabled()) {
1885 // The chrome runtime may create a new popup window, which is not the
1886 // behavior that this test expects. Instead, match the alloy runtime
1887 // behavior by navigating in the current window.
1888 browser->GetMainFrame()->LoadURL(target_url);
1889 return true;
1890 }
1891
1892 return cancel_in_open_url_;
1893 }
1894
OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefRequestCallback> callback)1895 cef_return_value_t OnBeforeResourceLoad(
1896 CefRefPtr<CefBrowser> browser,
1897 CefRefPtr<CefFrame> frame,
1898 CefRefPtr<CefRequest> request,
1899 CefRefPtr<CefRequestCallback> callback) override {
1900 if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
1901 // Ignore favicon requests.
1902 return RV_CANCEL;
1903 }
1904
1905 EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
1906
1907 const auto transition_type = request->GetTransitionType();
1908 if (mode_ == LOAD || request->GetURL() == kLoadNav1) {
1909 EXPECT_EQ(kTransitionExplicitLoad, transition_type);
1910 } else {
1911 EXPECT_EQ(ExpectedOpenURLTransitionType(), transition_type);
1912 }
1913
1914 EXPECT_GT(browser_id_current_, 0);
1915 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1916
1917 got_before_resource_load_.yes();
1918
1919 return RV_CONTINUE;
1920 }
1921
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)1922 void OnLoadStart(CefRefPtr<CefBrowser> browser,
1923 CefRefPtr<CefFrame> frame,
1924 TransitionType transition_type) override {
1925 EXPECT_GT(browser_id_current_, 0);
1926 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1927
1928 if (mode_ == LOAD || frame->GetURL() == kLoadNav1) {
1929 EXPECT_EQ(kTransitionExplicitLoad, transition_type);
1930 } else {
1931 EXPECT_EQ(ExpectedOpenURLTransitionType(), transition_type);
1932 }
1933
1934 got_load_start_.yes();
1935 }
1936
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)1937 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
1938 CefRefPtr<CefFrame> frame,
1939 int httpStatusCode) override {
1940 EXPECT_GT(browser_id_current_, 0);
1941 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1942
1943 got_load_end_.yes();
1944 ContinueIfReady(browser);
1945 }
1946
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)1947 bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
1948 CefRefPtr<CefFrame> frame,
1949 CefProcessId source_process,
1950 CefRefPtr<CefProcessMessage> message) override {
1951 EXPECT_GT(browser_id_current_, 0);
1952 EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
1953
1954 const std::string& msg_name = message->GetName();
1955 if (msg_name == kLoadNavMsg) {
1956 // Test that the renderer side succeeded.
1957 CefRefPtr<CefListValue> args = message->GetArgumentList();
1958 EXPECT_TRUE(args.get());
1959 EXPECT_TRUE(args->GetBool(0));
1960
1961 EXPECT_EQ(browser_id_current_, args->GetInt(1));
1962
1963 renderer_load_ct_ = args->GetInt(2);
1964 EXPECT_GE(renderer_load_ct_, 1);
1965
1966 // Continue with the test.
1967 got_message_.yes();
1968 ContinueIfReady(browser);
1969
1970 return true;
1971 }
1972
1973 // Message not handled.
1974 return false;
1975 }
1976
DestroyTest()1977 void DestroyTest() override {
1978 if (cancel_in_open_url_) {
1979 EXPECT_FALSE(got_before_browse_);
1980 EXPECT_FALSE(got_before_resource_load_);
1981 EXPECT_FALSE(got_load_start_);
1982 EXPECT_FALSE(got_load_end_);
1983 EXPECT_FALSE(got_message_);
1984
1985 // We should only navigate a single time if the 2nd load is canceled.
1986 EXPECT_EQ(1, renderer_load_ct_);
1987 } else {
1988 EXPECT_TRUE(got_before_browse_);
1989 EXPECT_TRUE(got_before_resource_load_);
1990 EXPECT_TRUE(got_load_start_);
1991 EXPECT_TRUE(got_load_end_);
1992 EXPECT_TRUE(got_message_);
1993
1994 if (same_origin_) {
1995 // The renderer process should always be reused.
1996 EXPECT_EQ(2, renderer_load_ct_);
1997 } else {
1998 // Each renderer process is only used for a single navigation.
1999 EXPECT_EQ(1, renderer_load_ct_);
2000 }
2001 }
2002
2003 if (ExpectOpenURL())
2004 EXPECT_TRUE(got_open_url_from_tab_);
2005 else
2006 EXPECT_FALSE(got_open_url_from_tab_);
2007
2008 TestHandler::DestroyTest();
2009 }
2010
2011 protected:
2012 const TestMode mode_;
2013 const bool same_origin_;
2014 const bool cancel_in_open_url_;
2015
2016 int browser_id_current_;
2017 int renderer_load_ct_;
2018
2019 TrackCallback got_before_browse_;
2020 TrackCallback got_open_url_from_tab_;
2021 TrackCallback got_before_resource_load_;
2022 TrackCallback got_load_start_;
2023 TrackCallback got_load_end_;
2024 TrackCallback got_message_;
2025
2026 IMPLEMENT_REFCOUNTING(LoadNavTestHandler);
2027 };
2028
2029 } // namespace
2030
2031 // Verify navigation-related callbacks when browsing same-origin via LoadURL().
TEST(NavigationTest,LoadSameOriginLoadURL)2032 TEST(NavigationTest, LoadSameOriginLoadURL) {
2033 CefRefPtr<LoadNavTestHandler> handler =
2034 new LoadNavTestHandler(LoadNavTestHandler::LOAD, true);
2035 handler->ExecuteTest();
2036 ReleaseAndWaitForDestructor(handler);
2037 }
2038
2039 // Verify navigation-related callbacks when browsing same-origin via left-click.
TEST(NavigationTest,LoadSameOriginLeftClick)2040 TEST(NavigationTest, LoadSameOriginLeftClick) {
2041 CefRefPtr<LoadNavTestHandler> handler =
2042 new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, true);
2043 handler->ExecuteTest();
2044 ReleaseAndWaitForDestructor(handler);
2045 }
2046
2047 // Verify navigation-related callbacks when browsing same-origin via middle-
2048 // click.
TEST(NavigationTest,LoadSameOriginMiddleClick)2049 TEST(NavigationTest, LoadSameOriginMiddleClick) {
2050 CefRefPtr<LoadNavTestHandler> handler =
2051 new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true);
2052 handler->ExecuteTest();
2053 ReleaseAndWaitForDestructor(handler);
2054 }
2055
2056 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadSameOriginMiddleClickCancel)2057 TEST(NavigationTest, LoadSameOriginMiddleClickCancel) {
2058 CefRefPtr<LoadNavTestHandler> handler =
2059 new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true, true);
2060 handler->ExecuteTest();
2061 ReleaseAndWaitForDestructor(handler);
2062 }
2063
2064 // Verify navigation-related callbacks when browsing same-origin via ctrl+left-
2065 // click.
TEST(NavigationTest,LoadSameOriginCtrlLeftClick)2066 TEST(NavigationTest, LoadSameOriginCtrlLeftClick) {
2067 CefRefPtr<LoadNavTestHandler> handler =
2068 new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true);
2069 handler->ExecuteTest();
2070 ReleaseAndWaitForDestructor(handler);
2071 }
2072
2073 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadSameOriginCtrlLeftClickCancel)2074 TEST(NavigationTest, LoadSameOriginCtrlLeftClickCancel) {
2075 CefRefPtr<LoadNavTestHandler> handler =
2076 new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true, true);
2077 handler->ExecuteTest();
2078 ReleaseAndWaitForDestructor(handler);
2079 }
2080
2081 // Verify navigation-related callbacks when browsing cross-origin via LoadURL().
TEST(NavigationTest,LoadCrossOriginLoadURL)2082 TEST(NavigationTest, LoadCrossOriginLoadURL) {
2083 CefRefPtr<LoadNavTestHandler> handler =
2084 new LoadNavTestHandler(LoadNavTestHandler::LOAD, false);
2085 handler->ExecuteTest();
2086 ReleaseAndWaitForDestructor(handler);
2087 }
2088
2089 // Verify navigation-related callbacks when browsing cross-origin via left-
2090 // click.
TEST(NavigationTest,LoadCrossOriginLeftClick)2091 TEST(NavigationTest, LoadCrossOriginLeftClick) {
2092 CefRefPtr<LoadNavTestHandler> handler =
2093 new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, false);
2094 handler->ExecuteTest();
2095 ReleaseAndWaitForDestructor(handler);
2096 }
2097
2098 // Verify navigation-related callbacks when browsing cross-origin via middle-
2099 // click.
TEST(NavigationTest,LoadCrossOriginMiddleClick)2100 TEST(NavigationTest, LoadCrossOriginMiddleClick) {
2101 CefRefPtr<LoadNavTestHandler> handler =
2102 new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false);
2103 handler->ExecuteTest();
2104 ReleaseAndWaitForDestructor(handler);
2105 }
2106
2107 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadCrossOriginMiddleClickCancel)2108 TEST(NavigationTest, LoadCrossOriginMiddleClickCancel) {
2109 CefRefPtr<LoadNavTestHandler> handler =
2110 new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false, true);
2111 handler->ExecuteTest();
2112 ReleaseAndWaitForDestructor(handler);
2113 }
2114
2115 // Verify navigation-related callbacks when browsing cross-origin via ctrl+left-
2116 // click.
TEST(NavigationTest,LoadCrossOriginCtrlLeftClick)2117 TEST(NavigationTest, LoadCrossOriginCtrlLeftClick) {
2118 CefRefPtr<LoadNavTestHandler> handler =
2119 new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false);
2120 handler->ExecuteTest();
2121 ReleaseAndWaitForDestructor(handler);
2122 }
2123
2124 // Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
TEST(NavigationTest,LoadCrossOriginCtrlLeftClickCancel)2125 TEST(NavigationTest, LoadCrossOriginCtrlLeftClickCancel) {
2126 CefRefPtr<LoadNavTestHandler> handler =
2127 new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false, true);
2128 handler->ExecuteTest();
2129 ReleaseAndWaitForDestructor(handler);
2130 }
2131
2132 namespace {
2133
2134 const char kSimultPopupMainUrl[] = "http://www.tests-sp.com/main.html";
2135 const char kSimultPopupPopupUrl[] = "http://www.tests-sp.com/popup";
2136 const size_t kSimultPopupCount = 5U;
2137
2138 // Test multiple popups simultaniously.
2139 class PopupSimultaneousTestHandler : public TestHandler {
2140 public:
PopupSimultaneousTestHandler(bool same_url)2141 explicit PopupSimultaneousTestHandler(bool same_url)
2142 : same_url_(same_url),
2143 before_popup_ct_(0U),
2144 after_created_ct_(0U),
2145 before_close_ct_(0U) {}
2146
RunTest()2147 void RunTest() override {
2148 std::string main_html = "<html><script>\n";
2149 for (size_t i = 0; i < kSimultPopupCount; ++i) {
2150 if (same_url_) {
2151 popup_url_[i] = std::string(kSimultPopupPopupUrl) + ".html";
2152 } else {
2153 std::stringstream ss;
2154 ss << kSimultPopupPopupUrl << i << ".html";
2155 popup_url_[i] = ss.str();
2156 }
2157 main_html += "window.open('" + popup_url_[i] + "');\n";
2158 AddResource(popup_url_[i], "<html>Popup " + popup_url_[i] + "</html>",
2159 "text/html");
2160 }
2161 main_html += "</script></html>";
2162
2163 AddResource(kSimultPopupMainUrl, main_html, "text/html");
2164
2165 // Create the browser.
2166 CreateBrowser(kSimultPopupMainUrl);
2167
2168 // Time out the test after a reasonable period of time.
2169 SetTestTimeout();
2170 }
2171
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)2172 bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
2173 CefRefPtr<CefFrame> frame,
2174 const CefString& target_url,
2175 const CefString& target_frame_name,
2176 cef_window_open_disposition_t target_disposition,
2177 bool user_gesture,
2178 const CefPopupFeatures& popupFeatures,
2179 CefWindowInfo& windowInfo,
2180 CefRefPtr<CefClient>& client,
2181 CefBrowserSettings& settings,
2182 CefRefPtr<CefDictionaryValue>& extra_info,
2183 bool* no_javascript_access) override {
2184 const std::string& url = target_url;
2185 EXPECT_LT(before_popup_ct_, kSimultPopupCount);
2186 EXPECT_STREQ(popup_url_[before_popup_ct_].c_str(), url.c_str())
2187 << before_popup_ct_;
2188 before_popup_ct_++;
2189 return false;
2190 }
2191
OnAfterCreated(CefRefPtr<CefBrowser> browser)2192 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
2193 TestHandler::OnAfterCreated(browser);
2194
2195 if (browser->IsPopup()) {
2196 EXPECT_LT(after_created_ct_, kSimultPopupCount);
2197 browser_id_[after_created_ct_] = browser->GetIdentifier();
2198 after_created_ct_++;
2199 }
2200 }
2201
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2202 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2203 bool isLoading,
2204 bool canGoBack,
2205 bool canGoForward) override {
2206 if (isLoading)
2207 return;
2208
2209 if (browser->IsPopup()) {
2210 const std::string& url = browser->GetMainFrame()->GetURL();
2211 for (size_t i = 0; i < kSimultPopupCount; ++i) {
2212 if (browser->GetIdentifier() == browser_id_[i]) {
2213 EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
2214
2215 got_loading_state_change_[i].yes();
2216 CloseBrowser(browser, true);
2217 return;
2218 }
2219 }
2220 EXPECT_FALSE(true); // Not reached.
2221 }
2222 }
2223
OnBeforeClose(CefRefPtr<CefBrowser> browser)2224 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
2225 TestHandler::OnBeforeClose(browser);
2226
2227 if (browser->IsPopup()) {
2228 const std::string& url = browser->GetMainFrame()->GetURL();
2229 for (size_t i = 0; i < kSimultPopupCount; ++i) {
2230 if (browser->GetIdentifier() == browser_id_[i]) {
2231 EXPECT_TRUE(got_loading_state_change_[i]);
2232 EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
2233
2234 got_before_close_[i].yes();
2235
2236 if (++before_close_ct_ == kSimultPopupCount)
2237 DestroyTest();
2238 return;
2239 }
2240 }
2241 EXPECT_FALSE(true); // Not reached.
2242 }
2243 }
2244
2245 private:
DestroyTest()2246 void DestroyTest() override {
2247 EXPECT_EQ(kSimultPopupCount, before_popup_ct_);
2248 EXPECT_EQ(kSimultPopupCount, after_created_ct_);
2249 EXPECT_EQ(kSimultPopupCount, before_close_ct_);
2250
2251 for (size_t i = 0; i < kSimultPopupCount; ++i) {
2252 EXPECT_GT(browser_id_[i], 0) << i;
2253 EXPECT_TRUE(got_loading_state_change_[i]) << i;
2254 EXPECT_TRUE(got_before_close_[i]) << i;
2255 }
2256
2257 TestHandler::DestroyTest();
2258 }
2259
2260 const bool same_url_;
2261 std::string popup_url_[kSimultPopupCount];
2262 size_t before_popup_ct_;
2263 int browser_id_[kSimultPopupCount];
2264 size_t after_created_ct_;
2265 TrackCallback got_loading_state_change_[kSimultPopupCount];
2266 TrackCallback got_before_close_[kSimultPopupCount];
2267 size_t before_close_ct_;
2268
2269 IMPLEMENT_REFCOUNTING(PopupSimultaneousTestHandler);
2270 };
2271
2272 } // namespace
2273
2274 // Test simultaneous popups with different URLs.
TEST(NavigationTest,PopupSimultaneousDifferentUrl)2275 TEST(NavigationTest, PopupSimultaneousDifferentUrl) {
2276 CefRefPtr<PopupSimultaneousTestHandler> handler =
2277 new PopupSimultaneousTestHandler(false);
2278 handler->ExecuteTest();
2279 ReleaseAndWaitForDestructor(handler);
2280 }
2281
2282 // Test simultaneous popups with the same URL.
TEST(NavigationTest,PopupSimultaneousSameUrl)2283 TEST(NavigationTest, PopupSimultaneousSameUrl) {
2284 CefRefPtr<PopupSimultaneousTestHandler> handler =
2285 new PopupSimultaneousTestHandler(true);
2286 handler->ExecuteTest();
2287 ReleaseAndWaitForDestructor(handler);
2288 }
2289
2290 namespace {
2291
2292 const char kPopupJSOpenMainUrl[] = "http://www.tests-pjso.com/main.html";
2293 const char kPopupJSOpenPopupUrl[] = "http://www.tests-pjso.com/popup.html";
2294
2295 // Test a popup where the URL is a JavaScript URI that opens another popup.
2296 class PopupJSWindowOpenTestHandler : public TestHandler {
2297 public:
PopupJSWindowOpenTestHandler()2298 PopupJSWindowOpenTestHandler()
2299 : before_popup_ct_(0U),
2300 after_created_ct_(0U),
2301 load_end_ct_(0U),
2302 before_close_ct_(0U) {}
2303
RunTest()2304 void RunTest() override {
2305 AddResource(kPopupJSOpenMainUrl, "<html>Main</html>", "text/html");
2306 AddResource(kPopupJSOpenPopupUrl, "<html>Popup</html>", "text/html");
2307
2308 // Create the browser.
2309 CreateBrowser(kPopupJSOpenMainUrl);
2310
2311 // Time out the test after a reasonable period of time.
2312 SetTestTimeout();
2313 }
2314
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)2315 bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
2316 CefRefPtr<CefFrame> frame,
2317 const CefString& target_url,
2318 const CefString& target_frame_name,
2319 cef_window_open_disposition_t target_disposition,
2320 bool user_gesture,
2321 const CefPopupFeatures& popupFeatures,
2322 CefWindowInfo& windowInfo,
2323 CefRefPtr<CefClient>& client,
2324 CefBrowserSettings& settings,
2325 CefRefPtr<CefDictionaryValue>& extra_info,
2326 bool* no_javascript_access) override {
2327 before_popup_ct_++;
2328 return false;
2329 }
2330
OnAfterCreated(CefRefPtr<CefBrowser> browser)2331 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
2332 TestHandler::OnAfterCreated(browser);
2333
2334 if (browser->IsPopup()) {
2335 after_created_ct_++;
2336 if (!popup1_)
2337 popup1_ = browser;
2338 else if (!popup2_)
2339 popup2_ = browser;
2340 else
2341 ADD_FAILURE();
2342 }
2343 }
2344
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2345 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2346 bool isLoading,
2347 bool canGoBack,
2348 bool canGoForward) override {
2349 if (isLoading)
2350 return;
2351
2352 if (browser->IsPopup()) {
2353 const std::string& url = browser->GetMainFrame()->GetURL();
2354 if (url == kPopupJSOpenPopupUrl) {
2355 EXPECT_TRUE(browser->IsSame(popup2_));
2356 popup2_ = nullptr;
2357
2358 // OnLoadingStateChange is not currently called for browser-side
2359 // navigations of empty popups. See https://crbug.com/789252.
2360 // Explicitly close the empty popup here as a workaround.
2361 CloseBrowser(popup1_, true);
2362 popup1_ = nullptr;
2363 } else {
2364 // Empty popup.
2365 EXPECT_TRUE(url.empty());
2366 EXPECT_TRUE(browser->IsSame(popup1_));
2367 popup1_ = nullptr;
2368 }
2369
2370 load_end_ct_++;
2371 CloseBrowser(browser, true);
2372 } else if (browser->GetMainFrame()->GetURL() == kPopupJSOpenMainUrl) {
2373 // Load the problematic JS URI.
2374 // This will result in 2 popups being created:
2375 // - An empty popup
2376 // - A popup that loads kPopupJSOpenPopupUrl
2377 browser->GetMainFrame()->LoadURL(
2378 "javascript:window.open(\"javascript:window.open('" +
2379 std::string(kPopupJSOpenPopupUrl) + "')\")");
2380 }
2381 }
2382
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2383 void OnLoadError(CefRefPtr<CefBrowser> browser,
2384 CefRefPtr<CefFrame> frame,
2385 ErrorCode errorCode,
2386 const CefString& errorText,
2387 const CefString& failedUrl) override {
2388 ADD_FAILURE() << "OnLoadError url: " << failedUrl.ToString()
2389 << " error: " << errorCode;
2390 }
2391
OnBeforeClose(CefRefPtr<CefBrowser> browser)2392 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
2393 TestHandler::OnBeforeClose(browser);
2394
2395 before_close_ct_++;
2396 if (before_close_ct_ == 2U)
2397 DestroyTest();
2398 }
2399
2400 private:
DestroyTest()2401 void DestroyTest() override {
2402 EXPECT_EQ(2U, before_popup_ct_);
2403 EXPECT_EQ(2U, after_created_ct_);
2404 EXPECT_EQ(2U, before_close_ct_);
2405
2406 // OnLoadingStateChange is not currently called for browser-side
2407 // navigations of empty popups. See https://crbug.com/789252.
2408 EXPECT_EQ(1U, load_end_ct_);
2409
2410 TestHandler::DestroyTest();
2411 }
2412
2413 CefRefPtr<CefBrowser> popup1_;
2414 CefRefPtr<CefBrowser> popup2_;
2415
2416 size_t before_popup_ct_;
2417 size_t after_created_ct_;
2418 size_t load_end_ct_;
2419 size_t before_close_ct_;
2420
2421 IMPLEMENT_REFCOUNTING(PopupJSWindowOpenTestHandler);
2422 };
2423
2424 } // namespace
2425
2426 // Test a popup where the URL is a JavaScript URI that opens another popup.
TEST(NavigationTest,PopupJSWindowOpen)2427 TEST(NavigationTest, PopupJSWindowOpen) {
2428 CefRefPtr<PopupJSWindowOpenTestHandler> handler =
2429 new PopupJSWindowOpenTestHandler();
2430 handler->ExecuteTest();
2431 ReleaseAndWaitForDestructor(handler);
2432 }
2433
2434 namespace {
2435
2436 const char kPopupJSEmptyMainUrl[] = "http://www.tests-pjse.com/main.html";
2437
2438 // Test creation of a popup where the URL is empty.
2439 class PopupJSWindowEmptyTestHandler : public TestHandler {
2440 public:
PopupJSWindowEmptyTestHandler()2441 PopupJSWindowEmptyTestHandler() {}
2442
RunTest()2443 void RunTest() override {
2444 AddResource(kPopupJSEmptyMainUrl, "<html>Main</html>", "text/html");
2445
2446 // Create the browser.
2447 CreateBrowser(kPopupJSEmptyMainUrl);
2448
2449 // Time out the test after a reasonable period of time.
2450 SetTestTimeout();
2451 }
2452
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)2453 bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
2454 CefRefPtr<CefFrame> frame,
2455 const CefString& target_url,
2456 const CefString& target_frame_name,
2457 cef_window_open_disposition_t target_disposition,
2458 bool user_gesture,
2459 const CefPopupFeatures& popupFeatures,
2460 CefWindowInfo& windowInfo,
2461 CefRefPtr<CefClient>& client,
2462 CefBrowserSettings& settings,
2463 CefRefPtr<CefDictionaryValue>& extra_info,
2464 bool* no_javascript_access) override {
2465 got_before_popup_.yes();
2466 return false;
2467 }
2468
OnAfterCreated(CefRefPtr<CefBrowser> browser)2469 void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
2470 TestHandler::OnAfterCreated(browser);
2471
2472 if (browser->IsPopup()) {
2473 got_after_created_popup_.yes();
2474 }
2475 }
2476
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2477 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2478 bool isLoading,
2479 bool canGoBack,
2480 bool canGoForward) override {
2481 if (isLoading)
2482 return;
2483
2484 if (browser->IsPopup()) {
2485 got_load_end_popup_.yes();
2486 CloseBrowser(browser, true);
2487 } else {
2488 browser->GetMainFrame()->LoadURL("javascript:window.open('')");
2489 }
2490 }
2491
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2492 void OnLoadError(CefRefPtr<CefBrowser> browser,
2493 CefRefPtr<CefFrame> frame,
2494 ErrorCode errorCode,
2495 const CefString& errorText,
2496 const CefString& failedUrl) override {
2497 ADD_FAILURE() << "OnLoadError url: " << failedUrl.ToString()
2498 << " error: " << errorCode;
2499 }
2500
OnBeforeClose(CefRefPtr<CefBrowser> browser)2501 void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
2502 TestHandler::OnBeforeClose(browser);
2503
2504 if (browser->IsPopup()) {
2505 got_before_close_popup_.yes();
2506 DestroyTest();
2507 }
2508 }
2509
2510 private:
DestroyTest()2511 void DestroyTest() override {
2512 EXPECT_TRUE(got_before_popup_);
2513 EXPECT_TRUE(got_after_created_popup_);
2514 EXPECT_TRUE(got_load_end_popup_);
2515 EXPECT_TRUE(got_before_close_popup_);
2516
2517 TestHandler::DestroyTest();
2518 }
2519
2520 TrackCallback got_before_popup_;
2521 TrackCallback got_after_created_popup_;
2522 TrackCallback got_load_end_popup_;
2523 TrackCallback got_before_close_popup_;
2524
2525 IMPLEMENT_REFCOUNTING(PopupJSWindowEmptyTestHandler);
2526 };
2527
2528 } // namespace
2529
2530 // Test creation of a popup where the URL is empty.
TEST(NavigationTest,PopupJSWindowEmpty)2531 TEST(NavigationTest, PopupJSWindowEmpty) {
2532 CefRefPtr<PopupJSWindowEmptyTestHandler> handler =
2533 new PopupJSWindowEmptyTestHandler();
2534 handler->ExecuteTest();
2535 ReleaseAndWaitForDestructor(handler);
2536 }
2537
2538 namespace {
2539
2540 const char kBrowseNavPageUrl[] = "http://tests-browsenav/nav.html";
2541
2542 // Browser side.
2543 class BrowseNavTestHandler : public TestHandler {
2544 public:
BrowseNavTestHandler(bool allow)2545 BrowseNavTestHandler(bool allow) : allow_(allow), destroyed_(false) {}
2546
RunTest()2547 void RunTest() override {
2548 AddResource(kBrowseNavPageUrl, "<html>Test</html>", "text/html");
2549
2550 // Create the browser.
2551 CreateBrowser(kBrowseNavPageUrl);
2552
2553 // Time out the test after a reasonable period of time.
2554 SetTestTimeout();
2555 }
2556
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2557 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2558 CefRefPtr<CefFrame> frame,
2559 CefRefPtr<CefRequest> request,
2560 bool user_gesture,
2561 bool is_redirect) override {
2562 const std::string& url = request->GetURL();
2563 EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2564 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2565 EXPECT_TRUE(frame->IsMain());
2566
2567 got_before_browse_.yes();
2568
2569 return !allow_;
2570 }
2571
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)2572 void OnLoadStart(CefRefPtr<CefBrowser> browser,
2573 CefRefPtr<CefFrame> frame,
2574 TransitionType transition_type) override {
2575 const std::string& url = frame->GetURL();
2576 EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2577 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2578 EXPECT_TRUE(frame->IsMain());
2579
2580 got_load_start_.yes();
2581 }
2582
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2583 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2584 CefRefPtr<CefFrame> frame,
2585 int httpStatusCode) override {
2586 const std::string& url = frame->GetURL();
2587 EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2588 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2589 EXPECT_TRUE(frame->IsMain());
2590
2591 got_load_end_.yes();
2592 DestroyTestIfDone();
2593 }
2594
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2595 void OnLoadError(CefRefPtr<CefBrowser> browser,
2596 CefRefPtr<CefFrame> frame,
2597 ErrorCode errorCode,
2598 const CefString& errorText,
2599 const CefString& failedUrl) override {
2600 const std::string& url = frame->GetURL();
2601 EXPECT_STREQ("", url.c_str());
2602 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2603 EXPECT_TRUE(frame->IsMain());
2604
2605 EXPECT_EQ(ERR_ABORTED, errorCode);
2606 EXPECT_STREQ(kBrowseNavPageUrl, failedUrl.ToString().c_str());
2607
2608 got_load_error_.yes();
2609 DestroyTestIfDone();
2610 }
2611
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2612 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2613 bool isLoading,
2614 bool canGoBack,
2615 bool canGoForward) override {
2616 const std::string& url = browser->GetMainFrame()->GetURL();
2617 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2618
2619 if (isLoading) {
2620 EXPECT_STREQ("", url.c_str());
2621
2622 got_loading_state_changed_start_.yes();
2623 } else {
2624 if (allow_)
2625 EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
2626 else
2627 EXPECT_STREQ("", url.c_str());
2628
2629 got_loading_state_changed_end_.yes();
2630 DestroyTestIfDone();
2631 }
2632 }
2633
2634 private:
DestroyTestIfDone()2635 void DestroyTestIfDone() {
2636 if (destroyed_)
2637 return;
2638
2639 if (got_loading_state_changed_end_) {
2640 if (allow_) {
2641 if (got_load_end_)
2642 DestroyTest();
2643 } else if (got_load_error_) {
2644 DestroyTest();
2645 }
2646 }
2647 }
2648
DestroyTest()2649 void DestroyTest() override {
2650 if (destroyed_)
2651 return;
2652 destroyed_ = true;
2653
2654 EXPECT_TRUE(got_before_browse_);
2655 EXPECT_TRUE(got_loading_state_changed_start_);
2656 EXPECT_TRUE(got_loading_state_changed_end_);
2657
2658 if (allow_) {
2659 EXPECT_TRUE(got_load_start_);
2660 EXPECT_TRUE(got_load_end_);
2661 EXPECT_FALSE(got_load_error_);
2662 } else {
2663 EXPECT_FALSE(got_load_start_);
2664 EXPECT_FALSE(got_load_end_);
2665 EXPECT_TRUE(got_load_error_);
2666 }
2667
2668 TestHandler::DestroyTest();
2669 }
2670
2671 bool allow_;
2672 bool destroyed_;
2673
2674 TrackCallback got_before_browse_;
2675 TrackCallback got_load_start_;
2676 TrackCallback got_load_end_;
2677 TrackCallback got_load_error_;
2678 TrackCallback got_loading_state_changed_start_;
2679 TrackCallback got_loading_state_changed_end_;
2680
2681 IMPLEMENT_REFCOUNTING(BrowseNavTestHandler);
2682 };
2683
2684 } // namespace
2685
2686 // Test allowing navigation.
TEST(NavigationTest,BrowseAllow)2687 TEST(NavigationTest, BrowseAllow) {
2688 CefRefPtr<BrowseNavTestHandler> handler = new BrowseNavTestHandler(true);
2689 handler->ExecuteTest();
2690 ReleaseAndWaitForDestructor(handler);
2691 }
2692
2693 // Test denying navigation.
TEST(NavigationTest,BrowseDeny)2694 TEST(NavigationTest, BrowseDeny) {
2695 CefRefPtr<BrowseNavTestHandler> handler = new BrowseNavTestHandler(false);
2696 handler->ExecuteTest();
2697 ReleaseAndWaitForDestructor(handler);
2698 }
2699
2700 namespace {
2701
2702 const char kSameNavPageUrl[] = "http://tests-samenav/nav.html";
2703
2704 // Browser side.
2705 class SameNavTestHandler : public TestHandler {
2706 public:
SameNavTestHandler()2707 SameNavTestHandler() : destroyed_(false), step_(0) {}
2708
RunTest()2709 void RunTest() override {
2710 AddResource(kSameNavPageUrl, "<html>Test</html>", "text/html");
2711
2712 // Create the browser.
2713 expected_url_ = kSameNavPageUrl;
2714 CreateBrowser(kSameNavPageUrl);
2715
2716 // Time out the test after a reasonable period of time.
2717 SetTestTimeout();
2718 }
2719
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2720 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2721 CefRefPtr<CefFrame> frame,
2722 CefRefPtr<CefRequest> request,
2723 bool user_gesture,
2724 bool is_redirect) override {
2725 const std::string& url = request->GetURL();
2726 EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2727 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2728 EXPECT_TRUE(frame->IsMain());
2729
2730 got_before_browse_.yes();
2731
2732 return false;
2733 }
2734
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)2735 void OnLoadStart(CefRefPtr<CefBrowser> browser,
2736 CefRefPtr<CefFrame> frame,
2737 TransitionType transition_type) override {
2738 const std::string& url = frame->GetURL();
2739 EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2740 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2741 EXPECT_TRUE(frame->IsMain());
2742
2743 got_load_start_.yes();
2744 }
2745
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2746 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2747 CefRefPtr<CefFrame> frame,
2748 int httpStatusCode) override {
2749 const std::string& url = frame->GetURL();
2750 EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2751 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2752 EXPECT_TRUE(frame->IsMain());
2753
2754 got_load_end_.yes();
2755 ContinueTestIfDone();
2756 }
2757
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2758 void OnLoadError(CefRefPtr<CefBrowser> browser,
2759 CefRefPtr<CefFrame> frame,
2760 ErrorCode errorCode,
2761 const CefString& errorText,
2762 const CefString& failedUrl) override {
2763 got_load_error_.yes();
2764 }
2765
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2766 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2767 bool isLoading,
2768 bool canGoBack,
2769 bool canGoForward) override {
2770 const std::string& url = browser->GetMainFrame()->GetURL();
2771 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2772
2773 if (isLoading) {
2774 // Verify the previous URL.
2775 if (step_ == 0)
2776 EXPECT_TRUE(url.empty());
2777 else
2778 EXPECT_STREQ(kSameNavPageUrl, url.c_str());
2779
2780 got_loading_state_changed_start_.yes();
2781 } else {
2782 EXPECT_STREQ(expected_url_.c_str(), url.c_str());
2783
2784 got_loading_state_changed_end_.yes();
2785 ContinueTestIfDone();
2786 }
2787 }
2788
2789 private:
ContinueTestIfDone()2790 void ContinueTestIfDone() {
2791 if (step_ == 0) {
2792 // First navigation should trigger all callbacks except OnLoadError.
2793 if (got_loading_state_changed_end_ && got_load_end_) {
2794 EXPECT_TRUE(got_before_browse_);
2795 EXPECT_TRUE(got_loading_state_changed_start_);
2796 EXPECT_TRUE(got_load_start_);
2797 EXPECT_FALSE(got_load_error_);
2798
2799 got_before_browse_.reset();
2800 got_loading_state_changed_start_.reset();
2801 got_loading_state_changed_end_.reset();
2802 got_load_start_.reset();
2803 got_load_end_.reset();
2804
2805 step_++;
2806 expected_url_ = kSameNavPageUrl + std::string("#fragment");
2807 GetBrowser()->GetMainFrame()->LoadURL(expected_url_);
2808 }
2809 } else if (step_ == 1) {
2810 step_++;
2811 DestroyTest();
2812 } else {
2813 EXPECT_TRUE(false); // Not reached.
2814 }
2815 }
2816
DestroyTest()2817 void DestroyTest() override {
2818 if (destroyed_)
2819 return;
2820 destroyed_ = true;
2821
2822 EXPECT_EQ(2, step_);
2823
2824 // Second (fragment) navigation should only trigger OnLoadingStateChange.
2825 EXPECT_FALSE(got_before_browse_);
2826 EXPECT_TRUE(got_loading_state_changed_start_);
2827 EXPECT_TRUE(got_loading_state_changed_end_);
2828 EXPECT_FALSE(got_load_start_);
2829 EXPECT_FALSE(got_load_end_);
2830 EXPECT_FALSE(got_load_error_);
2831
2832 TestHandler::DestroyTest();
2833 }
2834
2835 bool destroyed_;
2836 int step_;
2837 std::string expected_url_;
2838
2839 TrackCallback got_before_browse_;
2840 TrackCallback got_load_start_;
2841 TrackCallback got_load_end_;
2842 TrackCallback got_load_error_;
2843 TrackCallback got_loading_state_changed_start_;
2844 TrackCallback got_loading_state_changed_end_;
2845
2846 IMPLEMENT_REFCOUNTING(SameNavTestHandler);
2847 };
2848
2849 } // namespace
2850
2851 // Test that same page navigation does not call OnLoadStart/OnLoadEnd.
TEST(NavigationTest,SamePage)2852 TEST(NavigationTest, SamePage) {
2853 CefRefPtr<SameNavTestHandler> handler = new SameNavTestHandler();
2854 handler->ExecuteTest();
2855 ReleaseAndWaitForDestructor(handler);
2856 }
2857
2858 namespace {
2859
2860 const char kCancelPageUrl[] = "http://tests-cancelnav/nav.html";
2861
2862 // A scheme handler that never starts sending data.
2863 class UnstartedSchemeHandler : public CefResourceHandler {
2864 public:
UnstartedSchemeHandler()2865 UnstartedSchemeHandler() {}
2866
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)2867 bool Open(CefRefPtr<CefRequest> request,
2868 bool& handle_request,
2869 CefRefPtr<CefCallback> callback) override {
2870 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
2871
2872 // Continue immediately.
2873 handle_request = true;
2874 return true;
2875 }
2876
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)2877 void GetResponseHeaders(CefRefPtr<CefResponse> response,
2878 int64& response_length,
2879 CefString& redirectUrl) override {
2880 response->SetStatus(200);
2881 response->SetMimeType("text/html");
2882 response_length = 100;
2883 }
2884
Cancel()2885 void Cancel() override { callback_ = nullptr; }
2886
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)2887 bool Read(void* data_out,
2888 int bytes_to_read,
2889 int& bytes_read,
2890 CefRefPtr<CefResourceReadCallback> callback) override {
2891 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
2892
2893 callback_ = callback;
2894
2895 // Pretend that we'll provide the data later.
2896 bytes_read = 0;
2897 return true;
2898 }
2899
2900 protected:
2901 CefRefPtr<CefResourceReadCallback> callback_;
2902
2903 IMPLEMENT_REFCOUNTING(UnstartedSchemeHandler);
2904 DISALLOW_COPY_AND_ASSIGN(UnstartedSchemeHandler);
2905 };
2906
2907 // Browser side.
2908 class CancelBeforeNavTestHandler : public TestHandler {
2909 public:
CancelBeforeNavTestHandler()2910 CancelBeforeNavTestHandler() : destroyed_(false) {}
2911
RunTest()2912 void RunTest() override {
2913 // Create the browser.
2914 CreateBrowser(kCancelPageUrl);
2915
2916 // Time out the test after a reasonable period of time.
2917 SetTestTimeout();
2918 }
2919
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)2920 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
2921 CefRefPtr<CefFrame> frame,
2922 CefRefPtr<CefRequest> request,
2923 bool user_gesture,
2924 bool is_redirect) override {
2925 EXPECT_TRUE(got_loading_state_changed_start_);
2926 EXPECT_FALSE(got_before_browse_);
2927 EXPECT_FALSE(got_get_resource_handler_);
2928 EXPECT_FALSE(got_load_start_);
2929 EXPECT_FALSE(got_cancel_load_);
2930 EXPECT_FALSE(got_load_error_);
2931 EXPECT_FALSE(got_load_end_);
2932 EXPECT_FALSE(got_loading_state_changed_end_);
2933
2934 const std::string& url = request->GetURL();
2935 EXPECT_STREQ(kCancelPageUrl, url.c_str());
2936 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2937 EXPECT_TRUE(frame->IsMain());
2938
2939 got_before_browse_.yes();
2940
2941 return false;
2942 }
2943
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)2944 CefRefPtr<CefResourceHandler> GetResourceHandler(
2945 CefRefPtr<CefBrowser> browser,
2946 CefRefPtr<CefFrame> frame,
2947 CefRefPtr<CefRequest> request) override {
2948 EXPECT_TRUE(got_loading_state_changed_start_);
2949 EXPECT_TRUE(got_before_browse_);
2950 EXPECT_FALSE(got_get_resource_handler_);
2951 EXPECT_FALSE(got_load_start_);
2952 EXPECT_FALSE(got_cancel_load_);
2953 EXPECT_FALSE(got_load_error_);
2954 EXPECT_FALSE(got_load_end_);
2955 EXPECT_FALSE(got_loading_state_changed_end_);
2956
2957 const std::string& url = request->GetURL();
2958 EXPECT_STREQ(kCancelPageUrl, url.c_str());
2959 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2960 EXPECT_TRUE(frame->IsMain());
2961
2962 got_get_resource_handler_.yes();
2963
2964 CefPostTask(TID_UI,
2965 base::Bind(&CancelBeforeNavTestHandler::CancelLoad, this));
2966
2967 return new UnstartedSchemeHandler();
2968 }
2969
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)2970 void OnLoadStart(CefRefPtr<CefBrowser> browser,
2971 CefRefPtr<CefFrame> frame,
2972 TransitionType transition_type) override {
2973 EXPECT_TRUE(false); // Not reached.
2974 got_load_start_.yes();
2975 }
2976
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)2977 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
2978 CefRefPtr<CefFrame> frame,
2979 int httpStatusCode) override {
2980 EXPECT_TRUE(false); // Not reached.
2981 got_load_end_.yes();
2982 }
2983
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)2984 void OnLoadError(CefRefPtr<CefBrowser> browser,
2985 CefRefPtr<CefFrame> frame,
2986 ErrorCode errorCode,
2987 const CefString& errorText,
2988 const CefString& failedUrl) override {
2989 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
2990 EXPECT_STREQ("", frame->GetURL().ToString().c_str());
2991 EXPECT_EQ(ERR_ABORTED, errorCode);
2992 EXPECT_STREQ(kCancelPageUrl, failedUrl.ToString().c_str());
2993 got_load_error_.yes();
2994 }
2995
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)2996 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
2997 bool isLoading,
2998 bool canGoBack,
2999 bool canGoForward) override {
3000 const std::string& url = browser->GetMainFrame()->GetURL();
3001 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3002 EXPECT_TRUE(url.empty());
3003
3004 if (isLoading) {
3005 EXPECT_FALSE(got_loading_state_changed_start_);
3006 EXPECT_FALSE(got_before_browse_);
3007 EXPECT_FALSE(got_get_resource_handler_);
3008 EXPECT_FALSE(got_load_start_);
3009 EXPECT_FALSE(got_cancel_load_);
3010 EXPECT_FALSE(got_load_error_);
3011 EXPECT_FALSE(got_load_end_);
3012 EXPECT_FALSE(got_loading_state_changed_end_);
3013
3014 got_loading_state_changed_start_.yes();
3015 } else {
3016 EXPECT_TRUE(got_loading_state_changed_start_);
3017 EXPECT_TRUE(got_before_browse_);
3018 EXPECT_TRUE(got_get_resource_handler_);
3019 EXPECT_FALSE(got_load_start_);
3020 EXPECT_TRUE(got_cancel_load_);
3021 EXPECT_TRUE(got_load_error_);
3022 EXPECT_FALSE(got_load_end_);
3023 EXPECT_FALSE(got_loading_state_changed_end_);
3024
3025 got_loading_state_changed_end_.yes();
3026
3027 DestroyTest();
3028 }
3029 }
3030
3031 private:
CancelLoad()3032 void CancelLoad() {
3033 got_cancel_load_.yes();
3034 GetBrowser()->StopLoad();
3035 }
3036
DestroyTest()3037 void DestroyTest() override {
3038 if (destroyed_)
3039 return;
3040 destroyed_ = true;
3041
3042 EXPECT_TRUE(got_loading_state_changed_start_);
3043 EXPECT_TRUE(got_before_browse_);
3044 EXPECT_TRUE(got_get_resource_handler_);
3045 EXPECT_FALSE(got_load_start_);
3046 EXPECT_TRUE(got_cancel_load_);
3047 EXPECT_TRUE(got_load_error_);
3048 EXPECT_FALSE(got_load_end_);
3049 EXPECT_TRUE(got_loading_state_changed_end_);
3050
3051 TestHandler::DestroyTest();
3052 }
3053
3054 bool destroyed_;
3055
3056 TrackCallback got_loading_state_changed_start_;
3057 TrackCallback got_before_browse_;
3058 TrackCallback got_get_resource_handler_;
3059 TrackCallback got_load_start_;
3060 TrackCallback got_cancel_load_;
3061 TrackCallback got_load_error_;
3062 TrackCallback got_load_end_;
3063 TrackCallback got_loading_state_changed_end_;
3064
3065 IMPLEMENT_REFCOUNTING(CancelBeforeNavTestHandler);
3066 };
3067
3068 } // namespace
3069
3070 // Test that navigation canceled before commit does not call
3071 // OnLoadStart/OnLoadEnd.
TEST(NavigationTest,CancelBeforeCommit)3072 TEST(NavigationTest, CancelBeforeCommit) {
3073 CefRefPtr<CancelBeforeNavTestHandler> handler =
3074 new CancelBeforeNavTestHandler();
3075 handler->ExecuteTest();
3076 ReleaseAndWaitForDestructor(handler);
3077 }
3078
3079 namespace {
3080
3081 // A scheme handler that stalls after writing some data.
3082 class StalledSchemeHandler : public CefResourceHandler {
3083 public:
StalledSchemeHandler()3084 StalledSchemeHandler() : offset_(0), write_size_(0) {}
3085
Open(CefRefPtr<CefRequest> request,bool & handle_request,CefRefPtr<CefCallback> callback)3086 bool Open(CefRefPtr<CefRequest> request,
3087 bool& handle_request,
3088 CefRefPtr<CefCallback> callback) override {
3089 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
3090
3091 // Continue immediately.
3092 handle_request = true;
3093 return true;
3094 }
3095
GetResponseHeaders(CefRefPtr<CefResponse> response,int64 & response_length,CefString & redirectUrl)3096 void GetResponseHeaders(CefRefPtr<CefResponse> response,
3097 int64& response_length,
3098 CefString& redirectUrl) override {
3099 response->SetStatus(200);
3100 response->SetMimeType("text/html");
3101 content_ = "<html><body>Test</body></html>";
3102 // Write this number of bytes and then stall.
3103 write_size_ = content_.size() / 2U;
3104 response_length = content_.size();
3105 }
3106
Cancel()3107 void Cancel() override { callback_ = nullptr; }
3108
Read(void * data_out,int bytes_to_read,int & bytes_read,CefRefPtr<CefResourceReadCallback> callback)3109 bool Read(void* data_out,
3110 int bytes_to_read,
3111 int& bytes_read,
3112 CefRefPtr<CefResourceReadCallback> callback) override {
3113 EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
3114
3115 bytes_read = 0;
3116
3117 size_t size = content_.size();
3118 if (offset_ >= write_size_) {
3119 // Now stall.
3120 callback_ = callback;
3121 return true;
3122 }
3123
3124 bool has_data = false;
3125
3126 if (offset_ < size) {
3127 // Write up to |write_size_| bytes.
3128 int transfer_size =
3129 std::min(bytes_to_read, std::min(static_cast<int>(write_size_),
3130 static_cast<int>(size - offset_)));
3131 memcpy(data_out, content_.c_str() + offset_, transfer_size);
3132 offset_ += transfer_size;
3133
3134 bytes_read = transfer_size;
3135 has_data = true;
3136 }
3137
3138 return has_data;
3139 }
3140
3141 protected:
3142 std::string content_;
3143 size_t offset_;
3144 size_t write_size_;
3145 CefRefPtr<CefResourceReadCallback> callback_;
3146
3147 IMPLEMENT_REFCOUNTING(StalledSchemeHandler);
3148 DISALLOW_COPY_AND_ASSIGN(StalledSchemeHandler);
3149 };
3150
3151 // Browser side.
3152 class CancelAfterNavTestHandler : public TestHandler {
3153 public:
CancelAfterNavTestHandler()3154 CancelAfterNavTestHandler() : destroyed_(false) {}
3155
RunTest()3156 void RunTest() override {
3157 // Create the browser.
3158 CreateBrowser(kCancelPageUrl);
3159
3160 // Time out the test after a reasonable period of time.
3161 SetTestTimeout();
3162 }
3163
OnBeforeBrowse(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,bool user_gesture,bool is_redirect)3164 bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
3165 CefRefPtr<CefFrame> frame,
3166 CefRefPtr<CefRequest> request,
3167 bool user_gesture,
3168 bool is_redirect) override {
3169 EXPECT_TRUE(got_loading_state_changed_start_);
3170 EXPECT_FALSE(got_before_browse_);
3171 EXPECT_FALSE(got_get_resource_handler_);
3172 EXPECT_FALSE(got_load_start_);
3173 EXPECT_FALSE(got_cancel_load_);
3174 EXPECT_FALSE(got_load_error_);
3175 EXPECT_FALSE(got_load_end_);
3176 EXPECT_FALSE(got_loading_state_changed_end_);
3177
3178 const std::string& url = request->GetURL();
3179 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3180 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3181 EXPECT_TRUE(frame->IsMain());
3182
3183 got_before_browse_.yes();
3184
3185 return false;
3186 }
3187
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)3188 CefRefPtr<CefResourceHandler> GetResourceHandler(
3189 CefRefPtr<CefBrowser> browser,
3190 CefRefPtr<CefFrame> frame,
3191 CefRefPtr<CefRequest> request) override {
3192 EXPECT_TRUE(got_loading_state_changed_start_);
3193 EXPECT_TRUE(got_before_browse_);
3194 EXPECT_FALSE(got_get_resource_handler_);
3195 EXPECT_FALSE(got_load_start_);
3196 EXPECT_FALSE(got_cancel_load_);
3197 EXPECT_FALSE(got_load_error_);
3198 EXPECT_FALSE(got_load_end_);
3199 EXPECT_FALSE(got_loading_state_changed_end_);
3200
3201 const std::string& url = request->GetURL();
3202 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3203 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3204 EXPECT_TRUE(frame->IsMain());
3205
3206 got_get_resource_handler_.yes();
3207
3208 // The required delay is longer when browser-side navigation is enabled.
3209 CefPostDelayedTask(
3210 TID_UI, base::Bind(&CancelAfterNavTestHandler::CancelLoad, this), 1000);
3211
3212 return new StalledSchemeHandler();
3213 }
3214
OnLoadStart(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,TransitionType transition_type)3215 void OnLoadStart(CefRefPtr<CefBrowser> browser,
3216 CefRefPtr<CefFrame> frame,
3217 TransitionType transition_type) override {
3218 EXPECT_TRUE(got_loading_state_changed_start_);
3219 EXPECT_TRUE(got_before_browse_);
3220 EXPECT_TRUE(got_get_resource_handler_);
3221 EXPECT_FALSE(got_load_start_);
3222 EXPECT_FALSE(got_cancel_load_);
3223 EXPECT_FALSE(got_load_error_);
3224 EXPECT_FALSE(got_load_end_);
3225 EXPECT_FALSE(got_loading_state_changed_end_);
3226
3227 const std::string& url = frame->GetURL();
3228 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3229 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3230 EXPECT_TRUE(frame->IsMain());
3231
3232 got_load_start_.yes();
3233 }
3234
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)3235 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
3236 CefRefPtr<CefFrame> frame,
3237 int httpStatusCode) override {
3238 EXPECT_TRUE(got_loading_state_changed_start_);
3239 EXPECT_TRUE(got_before_browse_);
3240 EXPECT_TRUE(got_get_resource_handler_);
3241 EXPECT_TRUE(got_load_start_);
3242 EXPECT_TRUE(got_cancel_load_);
3243 EXPECT_TRUE(got_load_error_);
3244 EXPECT_FALSE(got_load_end_);
3245 EXPECT_FALSE(got_loading_state_changed_end_);
3246
3247 const std::string& url = frame->GetURL();
3248 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3249 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3250 EXPECT_TRUE(frame->IsMain());
3251
3252 got_load_end_.yes();
3253 DestroyTestIfDone();
3254 }
3255
OnLoadError(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,ErrorCode errorCode,const CefString & errorText,const CefString & failedUrl)3256 void OnLoadError(CefRefPtr<CefBrowser> browser,
3257 CefRefPtr<CefFrame> frame,
3258 ErrorCode errorCode,
3259 const CefString& errorText,
3260 const CefString& failedUrl) override {
3261 EXPECT_TRUE(got_loading_state_changed_start_);
3262 EXPECT_TRUE(got_before_browse_);
3263 EXPECT_TRUE(got_get_resource_handler_);
3264 EXPECT_TRUE(got_load_start_);
3265 EXPECT_TRUE(got_cancel_load_);
3266 EXPECT_FALSE(got_load_error_);
3267 EXPECT_FALSE(got_load_end_);
3268 EXPECT_FALSE(got_loading_state_changed_end_);
3269
3270 const std::string& url = failedUrl;
3271 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3272 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3273 EXPECT_TRUE(frame->IsMain());
3274
3275 got_load_error_.yes();
3276 }
3277
OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward)3278 void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
3279 bool isLoading,
3280 bool canGoBack,
3281 bool canGoForward) override {
3282 const std::string& url = browser->GetMainFrame()->GetURL();
3283 EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
3284
3285 if (isLoading) {
3286 EXPECT_FALSE(got_loading_state_changed_start_);
3287 EXPECT_FALSE(got_before_browse_);
3288 EXPECT_FALSE(got_get_resource_handler_);
3289 EXPECT_FALSE(got_load_start_);
3290 EXPECT_FALSE(got_cancel_load_);
3291 EXPECT_FALSE(got_load_error_);
3292 EXPECT_FALSE(got_load_end_);
3293 EXPECT_FALSE(got_loading_state_changed_end_);
3294
3295 EXPECT_TRUE(url.empty());
3296
3297 got_loading_state_changed_start_.yes();
3298 } else {
3299 EXPECT_TRUE(got_loading_state_changed_start_);
3300 EXPECT_TRUE(got_before_browse_);
3301 EXPECT_TRUE(got_get_resource_handler_);
3302 EXPECT_TRUE(got_load_start_);
3303 EXPECT_TRUE(got_cancel_load_);
3304 EXPECT_TRUE(got_load_error_);
3305 EXPECT_TRUE(got_load_end_);
3306 EXPECT_FALSE(got_loading_state_changed_end_);
3307
3308 EXPECT_STREQ(kCancelPageUrl, url.c_str());
3309
3310 got_loading_state_changed_end_.yes();
3311 DestroyTestIfDone();
3312 }
3313 }
3314
3315 private:
CancelLoad()3316 void CancelLoad() {
3317 got_cancel_load_.yes();
3318 GetBrowser()->StopLoad();
3319 }
3320
DestroyTestIfDone()3321 void DestroyTestIfDone() {
3322 if (got_loading_state_changed_end_ && got_load_end_)
3323 DestroyTest();
3324 }
3325
DestroyTest()3326 void DestroyTest() override {
3327 if (destroyed_)
3328 return;
3329 destroyed_ = true;
3330
3331 EXPECT_TRUE(got_loading_state_changed_start_);
3332 EXPECT_TRUE(got_before_browse_);
3333 EXPECT_TRUE(got_get_resource_handler_);
3334 EXPECT_TRUE(got_load_start_);
3335 EXPECT_TRUE(got_cancel_load_);
3336 EXPECT_TRUE(got_load_error_);
3337 EXPECT_TRUE(got_load_end_);
3338 EXPECT_TRUE(got_loading_state_changed_end_);
3339
3340 TestHandler::DestroyTest();
3341 }
3342
3343 bool destroyed_;
3344
3345 TrackCallback got_loading_state_changed_start_;
3346 TrackCallback got_before_browse_;
3347 TrackCallback got_get_resource_handler_;
3348 TrackCallback got_load_start_;
3349 TrackCallback got_cancel_load_;
3350 TrackCallback got_load_error_;
3351 TrackCallback got_load_end_;
3352 TrackCallback got_loading_state_changed_end_;
3353
3354 IMPLEMENT_REFCOUNTING(CancelAfterNavTestHandler);
3355 };
3356
3357 } // namespace
3358
3359 // Test that navigation canceled after commit calls everything.
TEST(NavigationTest,CancelAfterCommit)3360 TEST(NavigationTest, CancelAfterCommit) {
3361 CefRefPtr<CancelAfterNavTestHandler> handler =
3362 new CancelAfterNavTestHandler();
3363 handler->ExecuteTest();
3364 ReleaseAndWaitForDestructor(handler);
3365 }
3366
3367 namespace {
3368
3369 const char kExtraInfoUrl[] = "http://tests-extrainfonav.com/extra.html";
3370 const char kExtraInfoPopupUrl[] =
3371 "http://tests-extrainfonav.com/extra_popup.html";
3372 const char kExtraInfoNavMsg[] = "NavigationTest.ExtraInfoNav";
3373 const char kExtraInfoTestCmdKey[] = "nav-extra-info-test";
3374
SetBrowserExtraInfo(CefRefPtr<CefDictionaryValue> extra_info)3375 void SetBrowserExtraInfo(CefRefPtr<CefDictionaryValue> extra_info) {
3376 // Necessary for identifying the test case.
3377 extra_info->SetBool(kExtraInfoTestCmdKey, true);
3378
3379 // Arbitrary data for testing.
3380 extra_info->SetBool("bool", true);
3381 CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
3382 dict->SetInt("key1", 5);
3383 dict->SetString("key2", "test string");
3384 extra_info->SetDictionary("dictionary", dict);
3385 extra_info->SetDouble("double", 5.43322);
3386 extra_info->SetString("string", "some string");
3387 }
3388
3389 // Renderer side
3390 class ExtraInfoNavRendererTest : public ClientAppRenderer::Delegate {
3391 public:
ExtraInfoNavRendererTest()3392 ExtraInfoNavRendererTest() : run_test_(false) {}
3393
OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefDictionaryValue> extra_info)3394 void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
3395 CefRefPtr<CefBrowser> browser,
3396 CefRefPtr<CefDictionaryValue> extra_info) override {
3397 run_test_ = extra_info->HasKey(kExtraInfoTestCmdKey);
3398 if (!run_test_)
3399 return;
3400
3401 CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
3402 SetBrowserExtraInfo(expected);
3403 TestDictionaryEqual(expected, extra_info);
3404
3405 SendTestResults(browser, browser->GetMainFrame());
3406 }
3407
3408 protected:
3409 // Send the test results.
SendTestResults(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)3410 void SendTestResults(CefRefPtr<CefBrowser> browser,
3411 CefRefPtr<CefFrame> frame) {
3412 // Check if the test has failed.
3413 bool result = !TestFailed();
3414
3415 CefRefPtr<CefProcessMessage> return_msg =
3416 CefProcessMessage::Create(kExtraInfoNavMsg);
3417 CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
3418 EXPECT_TRUE(args.get());
3419 EXPECT_TRUE(args->SetBool(0, result));
3420 EXPECT_TRUE(args->SetBool(1, browser->IsPopup()));
3421 frame->SendProcessMessage(PID_BROWSER, return_msg);
3422 }
3423
3424 bool run_test_;
3425
3426 IMPLEMENT_REFCOUNTING(ExtraInfoNavRendererTest);
3427 };
3428
3429 class ExtraInfoNavTestHandler : public TestHandler {
3430 public:
ExtraInfoNavTestHandler()3431 ExtraInfoNavTestHandler() : popup_opened_(false) {}
3432
RunTest()3433 void RunTest() override {
3434 AddResource(kExtraInfoUrl,
3435 "<html><head></head><body>ExtraInfo</body></html>",
3436 "text/html");
3437 AddResource(kExtraInfoPopupUrl, "<html>ExtraInfoPopup</html>", "text/html");
3438
3439 CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
3440 SetBrowserExtraInfo(extra_info);
3441
3442 // Create the browser.
3443 CreateBrowser(kExtraInfoUrl, nullptr, extra_info);
3444
3445 // Time out the test after a reasonable period of time.
3446 SetTestTimeout();
3447 }
3448
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)3449 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
3450 CefRefPtr<CefFrame> frame,
3451 int httpStatusCode) override {
3452 if (popup_opened_) {
3453 DestroyTest();
3454 } else {
3455 browser->GetMainFrame()->ExecuteJavaScript(
3456 "window.open('" + std::string(kExtraInfoPopupUrl) + "');",
3457 CefString(), 0);
3458 }
3459 }
3460
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)3461 bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
3462 CefRefPtr<CefFrame> frame,
3463 const CefString& target_url,
3464 const CefString& target_frame_name,
3465 cef_window_open_disposition_t target_disposition,
3466 bool user_gesture,
3467 const CefPopupFeatures& popupFeatures,
3468 CefWindowInfo& windowInfo,
3469 CefRefPtr<CefClient>& client,
3470 CefBrowserSettings& settings,
3471 CefRefPtr<CefDictionaryValue>& extra_info,
3472 bool* no_javascript_access) override {
3473 const std::string& url = target_url;
3474 EXPECT_FALSE(popup_opened_);
3475 EXPECT_STREQ(kExtraInfoPopupUrl, url.c_str());
3476
3477 CefRefPtr<CefDictionaryValue> extra = CefDictionaryValue::Create();
3478 SetBrowserExtraInfo(extra);
3479
3480 extra_info = extra;
3481
3482 popup_opened_ = true;
3483 return false;
3484 }
3485
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)3486 bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
3487 CefRefPtr<CefFrame> frame,
3488 CefProcessId source_process,
3489 CefRefPtr<CefProcessMessage> message) override {
3490 if (message->GetName().ToString() == kExtraInfoNavMsg) {
3491 // Test that the renderer side succeeded.
3492 CefRefPtr<CefListValue> args = message->GetArgumentList();
3493 EXPECT_TRUE(args.get());
3494 EXPECT_TRUE(args->GetBool(0));
3495 if (popup_opened_) {
3496 EXPECT_TRUE(args->GetBool(1));
3497 got_process_message_popup_.yes();
3498 } else {
3499 EXPECT_FALSE(args->GetBool(1));
3500 got_process_message_main_.yes();
3501 }
3502 return true;
3503 }
3504
3505 // Message not handled.
3506 return false;
3507 }
3508
3509 protected:
3510 bool popup_opened_;
3511 TrackCallback got_process_message_main_;
3512 TrackCallback got_process_message_popup_;
3513
DestroyTest()3514 void DestroyTest() override {
3515 // Verify test expectations.
3516 EXPECT_TRUE(got_process_message_main_);
3517 EXPECT_TRUE(got_process_message_popup_);
3518
3519 TestHandler::DestroyTest();
3520 }
3521
3522 IMPLEMENT_REFCOUNTING(ExtraInfoNavTestHandler);
3523 };
3524
3525 } // namespace
3526
TEST(NavigationTest,ExtraInfo)3527 TEST(NavigationTest, ExtraInfo) {
3528 CefRefPtr<ExtraInfoNavTestHandler> handler = new ExtraInfoNavTestHandler();
3529 handler->ExecuteTest();
3530 ReleaseAndWaitForDestructor(handler);
3531 }
3532
3533 // Entry point for creating navigation renderer test objects.
3534 // Called from client_app_delegates.cc.
CreateNavigationRendererTests(ClientAppRenderer::DelegateSet & delegates)3535 void CreateNavigationRendererTests(ClientAppRenderer::DelegateSet& delegates) {
3536 delegates.insert(new HistoryNavRendererTest);
3537 delegates.insert(new OrderNavRendererTest);
3538 delegates.insert(new LoadNavRendererTest);
3539 delegates.insert(new ExtraInfoNavRendererTest);
3540 }
3541