• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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