1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stdint.h>
6 
7 #include <tuple>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/check.h"
13 #include "base/command_line.h"
14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/test/bind.h"
18 #include "base/test/scoped_feature_list.h"
19 #include "build/build_config.h"
20 #include "components/download/public/common/download_url_parameters.h"
21 #include "content/browser/child_process_security_policy_impl.h"
22 #include "content/browser/media/audio_stream_monitor.h"
23 #include "content/browser/media/media_web_contents_observer.h"
24 #include "content/browser/renderer_host/navigation_entry_impl.h"
25 #include "content/browser/renderer_host/navigator.h"
26 #include "content/browser/renderer_host/render_frame_host_impl.h"
27 #include "content/browser/renderer_host/render_frame_proxy_host.h"
28 #include "content/browser/renderer_host/render_view_host_impl.h"
29 #include "content/browser/site_instance_impl.h"
30 #include "content/browser/webui/content_web_ui_controller_factory.h"
31 #include "content/browser/webui/web_ui_controller_factory_registry.h"
32 #include "content/common/content_navigation_policy.h"
33 #include "content/common/frame.mojom.h"
34 #include "content/common/frame_messages.h"
35 #include "content/public/browser/child_process_security_policy.h"
36 #include "content/public/browser/content_browser_client.h"
37 #include "content/public/browser/context_menu_params.h"
38 #include "content/public/browser/global_request_id.h"
39 #include "content/public/browser/javascript_dialog_manager.h"
40 #include "content/public/browser/navigation_details.h"
41 #include "content/public/browser/notification_details.h"
42 #include "content/public/browser/notification_source.h"
43 #include "content/public/browser/render_widget_host_view.h"
44 #include "content/public/browser/ssl_host_state_delegate.h"
45 #include "content/public/browser/storage_partition.h"
46 #include "content/public/browser/web_contents_delegate.h"
47 #include "content/public/browser/web_contents_observer.h"
48 #include "content/public/browser/web_ui_controller.h"
49 #include "content/public/common/bindings_policy.h"
50 #include "content/public/common/content_constants.h"
51 #include "content/public/common/content_features.h"
52 #include "content/public/common/url_constants.h"
53 #include "content/public/common/url_utils.h"
54 #include "content/public/test/fake_local_frame.h"
55 #include "content/public/test/mock_render_process_host.h"
56 #include "content/public/test/navigation_simulator.h"
57 #include "content/public/test/test_browser_context.h"
58 #include "content/public/test/test_utils.h"
59 #include "content/test/navigation_simulator_impl.h"
60 #include "content/test/test_content_browser_client.h"
61 #include "content/test/test_content_client.h"
62 #include "content/test/test_render_frame_host.h"
63 #include "content/test/test_render_view_host.h"
64 #include "content/test/test_web_contents.h"
65 #include "net/test/cert_test_util.h"
66 #include "net/test/test_data_directory.h"
67 #include "services/network/public/cpp/web_sandbox_flags.h"
68 #include "skia/ext/skia_utils_base.h"
69 #include "testing/gmock/include/gmock/gmock.h"
70 #include "testing/gtest/include/gtest/gtest.h"
71 #include "third_party/blink/public/common/input/synthetic_web_input_event_builders.h"
72 #include "third_party/blink/public/common/security/protocol_handler_security_level.h"
73 #include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h"
74 #include "third_party/blink/public/mojom/frame/fullscreen.mojom.h"
75 #include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h"
76 #include "third_party/skia/include/core/SkColor.h"
77 #include "ui/gfx/skia_util.h"
78 #include "url/url_constants.h"
79 
80 namespace content {
81 namespace {
82 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
83  public:
WebContentsImplTestBrowserClient()84   WebContentsImplTestBrowserClient()
85       : original_browser_client_(SetBrowserClientForTesting(this)) {}
86 
~WebContentsImplTestBrowserClient()87   ~WebContentsImplTestBrowserClient() override {
88     SetBrowserClientForTesting(original_browser_client_);
89   }
90 
ShouldAssignSiteForURL(const GURL & url)91   bool ShouldAssignSiteForURL(const GURL& url) override {
92     if (site_assignment_for_url_.find(url) != site_assignment_for_url_.end()) {
93       return site_assignment_for_url_[url];
94     }
95 
96     return true;
97   }
98 
set_assign_site_for_url(bool assign,const GURL & url)99   void set_assign_site_for_url(bool assign, const GURL& url) {
100     DCHECK(url.is_valid());
101     site_assignment_for_url_[url] = assign;
102   }
103 
104  private:
105   std::map<GURL, bool> site_assignment_for_url_;
106   ContentBrowserClient* original_browser_client_;
107 };
108 
109 class WebContentsImplTest : public RenderViewHostImplTestHarness {
110  public:
SetUp()111   void SetUp() override {
112     RenderViewHostImplTestHarness::SetUp();
113     WebUIControllerFactory::RegisterFactory(
114         ContentWebUIControllerFactory::GetInstance());
115 
116     if (AreDefaultSiteInstancesEnabled()) {
117       // Isolate |isolated_cross_site_url()| so we can't get a default
118       // SiteInstance for it.
119       ChildProcessSecurityPolicyImpl::GetInstance()->AddIsolatedOrigins(
120           {url::Origin::Create(isolated_cross_site_url())},
121           ChildProcessSecurityPolicy::IsolatedOriginSource::TEST,
122           browser_context());
123 
124       // Reset the WebContents so the isolated origin will be honored by
125       // all BrowsingInstances used in the test.
126       SetContents(CreateTestWebContents());
127     }
128   }
129 
TearDown()130   void TearDown() override {
131     WebUIControllerFactory::UnregisterFactoryForTesting(
132         ContentWebUIControllerFactory::GetInstance());
133     RenderViewHostImplTestHarness::TearDown();
134   }
135 
has_audio_wake_lock()136   bool has_audio_wake_lock() {
137     return contents()
138         ->media_web_contents_observer()
139         ->has_audio_wake_lock_for_testing();
140   }
141 
isolated_cross_site_url() const142   GURL isolated_cross_site_url() const {
143     return GURL("http://isolated-cross-site.com");
144   }
145 };
146 
147 class TestWebContentsObserver : public WebContentsObserver {
148  public:
TestWebContentsObserver(WebContents * contents)149   explicit TestWebContentsObserver(WebContents* contents)
150       : WebContentsObserver(contents) {}
~TestWebContentsObserver()151   ~TestWebContentsObserver() override {}
152 
DidFinishLoad(RenderFrameHost * render_frame_host,const GURL & validated_url)153   void DidFinishLoad(RenderFrameHost* render_frame_host,
154                      const GURL& validated_url) override {
155     last_url_ = validated_url;
156   }
DidFailLoad(RenderFrameHost * render_frame_host,const GURL & validated_url,int error_code)157   void DidFailLoad(RenderFrameHost* render_frame_host,
158                    const GURL& validated_url,
159                    int error_code) override {
160     last_url_ = validated_url;
161   }
162 
DidFirstVisuallyNonEmptyPaint()163   void DidFirstVisuallyNonEmptyPaint() override {
164     observed_did_first_visually_non_empty_paint_ = true;
165     EXPECT_TRUE(web_contents()->CompletedFirstVisuallyNonEmptyPaint());
166   }
167 
DidChangeThemeColor()168   void DidChangeThemeColor() override { ++theme_color_change_calls_; }
169 
DidChangeVerticalScrollDirection(viz::VerticalScrollDirection scroll_direction)170   void DidChangeVerticalScrollDirection(
171       viz::VerticalScrollDirection scroll_direction) override {
172     last_vertical_scroll_direction_ = scroll_direction;
173   }
174 
OnIsConnectedToBluetoothDeviceChanged(bool is_connected_to_bluetooth_device)175   void OnIsConnectedToBluetoothDeviceChanged(
176       bool is_connected_to_bluetooth_device) override {
177     ++num_is_connected_to_bluetooth_device_changed_;
178     last_is_connected_to_bluetooth_device_ = is_connected_to_bluetooth_device;
179   }
180 
last_url() const181   const GURL& last_url() const { return last_url_; }
theme_color_change_calls() const182   int theme_color_change_calls() const { return theme_color_change_calls_; }
last_vertical_scroll_direction() const183   base::Optional<viz::VerticalScrollDirection> last_vertical_scroll_direction()
184       const {
185     return last_vertical_scroll_direction_;
186   }
observed_did_first_visually_non_empty_paint() const187   bool observed_did_first_visually_non_empty_paint() const {
188     return observed_did_first_visually_non_empty_paint_;
189   }
num_is_connected_to_bluetooth_device_changed() const190   int num_is_connected_to_bluetooth_device_changed() const {
191     return num_is_connected_to_bluetooth_device_changed_;
192   }
last_is_connected_to_bluetooth_device() const193   bool last_is_connected_to_bluetooth_device() const {
194     return last_is_connected_to_bluetooth_device_;
195   }
196 
197  private:
198   GURL last_url_;
199   int theme_color_change_calls_ = 0;
200   base::Optional<viz::VerticalScrollDirection> last_vertical_scroll_direction_;
201   bool observed_did_first_visually_non_empty_paint_ = false;
202   int num_is_connected_to_bluetooth_device_changed_ = 0;
203   bool last_is_connected_to_bluetooth_device_ = false;
204 
205   DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
206 };
207 
208 // Pretends to be a normal browser that receives toggles and transitions to/from
209 // a fullscreened state.
210 class FakeFullscreenDelegate : public WebContentsDelegate {
211  public:
FakeFullscreenDelegate()212   FakeFullscreenDelegate() : fullscreened_contents_(nullptr) {}
~FakeFullscreenDelegate()213   ~FakeFullscreenDelegate() override {}
214 
EnterFullscreenModeForTab(RenderFrameHost * requesting_frame,const blink::mojom::FullscreenOptions & options)215   void EnterFullscreenModeForTab(
216       RenderFrameHost* requesting_frame,
217       const blink::mojom::FullscreenOptions& options) override {
218     fullscreened_contents_ = WebContents::FromRenderFrameHost(requesting_frame);
219   }
220 
ExitFullscreenModeForTab(WebContents * web_contents)221   void ExitFullscreenModeForTab(WebContents* web_contents) override {
222     fullscreened_contents_ = nullptr;
223   }
224 
IsFullscreenForTabOrPending(const WebContents * web_contents)225   bool IsFullscreenForTabOrPending(const WebContents* web_contents) override {
226     return fullscreened_contents_ && web_contents == fullscreened_contents_;
227   }
228 
229  private:
230   WebContents* fullscreened_contents_;
231 
232   DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate);
233 };
234 
235 class FakeWebContentsDelegate : public WebContentsDelegate {
236  public:
FakeWebContentsDelegate()237   FakeWebContentsDelegate() : loading_state_changed_was_called_(false) {}
~FakeWebContentsDelegate()238   ~FakeWebContentsDelegate() override {}
239 
LoadingStateChanged(WebContents * source,bool to_different_document)240   void LoadingStateChanged(WebContents* source,
241                            bool to_different_document) override {
242     loading_state_changed_was_called_ = true;
243   }
244 
loading_state_changed_was_called() const245   bool loading_state_changed_was_called() const {
246     return loading_state_changed_was_called_;
247   }
248 
249  private:
250   bool loading_state_changed_was_called_;
251 
252   DISALLOW_COPY_AND_ASSIGN(FakeWebContentsDelegate);
253 };
254 
255 }  // namespace
256 
TEST_F(WebContentsImplTest,UpdateTitle)257 TEST_F(WebContentsImplTest, UpdateTitle) {
258   FakeWebContentsDelegate fake_delegate;
259   contents()->SetDelegate(&fake_delegate);
260 
261   NavigationControllerImpl& cont =
262       static_cast<NavigationControllerImpl&>(controller());
263   cont.LoadURL(GURL(url::kAboutBlankURL), Referrer(), ui::PAGE_TRANSITION_TYPED,
264                std::string());
265 
266   FrameHostMsg_DidCommitProvisionalLoad_Params params;
267   InitNavigateParams(&params, 0, true, GURL(url::kAboutBlankURL),
268                      ui::PAGE_TRANSITION_TYPED);
269 
270   main_test_rfh()->SendNavigateWithParams(&params,
271                                           false /* was_within_same_document */);
272 
273   contents()->UpdateTitle(main_test_rfh(),
274                           base::ASCIIToUTF16("    Lots O' Whitespace\n"),
275                           base::i18n::LEFT_TO_RIGHT);
276   // Make sure that title updates get stripped of whitespace.
277   EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
278   EXPECT_FALSE(contents()->IsWaitingForResponse());
279   EXPECT_TRUE(fake_delegate.loading_state_changed_was_called());
280 
281   contents()->SetDelegate(nullptr);
282 }
283 
TEST_F(WebContentsImplTest,DownloadInvalidImage)284 TEST_F(WebContentsImplTest, DownloadInvalidImage) {
285   TestWebContents* test_contents = contents();
286 
287   GURL url("about:blank");
288 
289   SkBitmap result_bitmap;
290   WebContents::ImageDownloadCallback cb = base::BindLambdaForTesting(
291       [&](int id, int http_status_code, const GURL& image_url,
292           const std::vector<SkBitmap>& bitmaps,
293           const std::vector<gfx::Size>& sizes) {
294         ASSERT_EQ(bitmaps.size(), 1u);
295         result_bitmap = bitmaps[0];
296       });
297 
298   // In production this would go to the renderer, but TestWebContents just
299   // waits for us to give a reply.
300   test_contents->DownloadImage(url,
301                                /*is_favicon=*/false,
302                                /*preferred_size=*/false,
303                                /*max_bitmap_size=*/0,
304                                /*bypass_cache=*/false, std::move(cb));
305 
306   SkBitmap badbitmap;
307   badbitmap.allocPixels(
308       SkImageInfo::Make(1, 1, kARGB_4444_SkColorType, kPremul_SkAlphaType));
309   badbitmap.eraseColor(SK_ColorGREEN);
310 
311   SkBitmap n32bitmap;
312   EXPECT_TRUE(skia::SkBitmapToN32OpaqueOrPremul(badbitmap, &n32bitmap));
313 
314   // The result from the renderer is not an N32 32bpp bitmap, so it should
315   // be converted before being given to the rest of the browser process.
316   test_contents->TestDidDownloadImage(url, 400, {badbitmap},
317                                       {gfx::Size(1000, 2000)});
318   EXPECT_TRUE(gfx::BitmapsAreEqual(result_bitmap, n32bitmap));
319 }
320 
TEST_F(WebContentsImplTest,UpdateTitleBeforeFirstNavigation)321 TEST_F(WebContentsImplTest, UpdateTitleBeforeFirstNavigation) {
322   ASSERT_TRUE(controller().IsInitialNavigation());
323   const base::string16 title = base::ASCIIToUTF16("Initial Entry Title");
324   contents()->UpdateTitle(main_test_rfh(), title, base::i18n::LEFT_TO_RIGHT);
325   EXPECT_EQ(title, contents()->GetTitle());
326 }
327 
TEST_F(WebContentsImplTest,SetMainFrameMimeType)328 TEST_F(WebContentsImplTest, SetMainFrameMimeType) {
329   ASSERT_TRUE(controller().IsInitialNavigation());
330   std::string mime = "text/html";
331   RenderViewHostImpl* rvh =
332       static_cast<RenderViewHostImpl*>(main_test_rfh()->GetRenderViewHost());
333   rvh->SetContentsMimeType(mime);
334   EXPECT_EQ(mime, contents()->GetContentsMimeType());
335 }
336 
TEST_F(WebContentsImplTest,DontUseTitleFromPendingEntry)337 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
338   const GURL kGURL(GetWebUIURL("blah"));
339   controller().LoadURL(
340       kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
341   EXPECT_EQ(base::string16(), contents()->GetTitle());
342 
343   // Also test setting title while the first navigation is still pending.
344   const base::string16 title = base::ASCIIToUTF16("Initial Entry Title");
345   contents()->UpdateTitle(main_test_rfh(), title, base::i18n::LEFT_TO_RIGHT);
346   EXPECT_EQ(title, contents()->GetTitle());
347 }
348 
TEST_F(WebContentsImplTest,UseTitleFromPendingEntryIfSet)349 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
350   const GURL kGURL(GetWebUIURL("blah"));
351   const base::string16 title = base::ASCIIToUTF16("My Title");
352   controller().LoadURL(
353       kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
354 
355   NavigationEntry* entry = controller().GetVisibleEntry();
356   ASSERT_EQ(kGURL, entry->GetURL());
357   entry->SetTitle(title);
358 
359   EXPECT_EQ(title, contents()->GetTitle());
360 }
361 
362 // Stub out local frame mojo binding. Intercepts calls to EnableViewSourceMode
363 // and marks the message as received. This class attaches to the first
364 // RenderFrameHostImpl created.
365 class EnableViewSourceLocalFrame : public content::FakeLocalFrame,
366                                    public WebContentsObserver {
367  public:
EnableViewSourceLocalFrame(WebContents * web_contents)368   explicit EnableViewSourceLocalFrame(WebContents* web_contents)
369       : WebContentsObserver(web_contents) {}
370 
RenderFrameCreated(RenderFrameHost * render_frame_host)371   void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
372     if (!initialized_) {
373       initialized_ = true;
374       Init(render_frame_host->GetRemoteAssociatedInterfaces());
375     }
376   }
377 
EnableViewSourceMode()378   void EnableViewSourceMode() final { enabled_view_source_ = true; }
379 
IsViewSourceModeEnabled() const380   bool IsViewSourceModeEnabled() const { return enabled_view_source_; }
381 
382  private:
383   bool enabled_view_source_ = false;
384   bool initialized_ = false;
385 };
386 
387 // Browser initiated navigations to view-source URLs of WebUI pages should work.
TEST_F(WebContentsImplTest,DirectNavigationToViewSourceWebUI)388 TEST_F(WebContentsImplTest, DirectNavigationToViewSourceWebUI) {
389   const GURL kGURL("view-source:" + GetWebUIURLString("blah/"));
390   // NavigationControllerImpl rewrites view-source URLs, simulating that here.
391   const GURL kRewrittenURL(GetWebUIURL("blah"));
392 
393   EnableViewSourceLocalFrame local_frame(contents());
394   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kGURL);
395 
396   // Did we get the expected message?
397   base::RunLoop().RunUntilIdle();
398   EXPECT_TRUE(local_frame.IsViewSourceModeEnabled());
399 
400   // This is the virtual URL.
401   EXPECT_EQ(
402       kGURL,
403       contents()->GetController().GetLastCommittedEntry()->GetVirtualURL());
404 
405   // The actual URL navigated to.
406   EXPECT_EQ(kRewrittenURL,
407             contents()->GetController().GetLastCommittedEntry()->GetURL());
408 }
409 
410 // Test simple same-SiteInstance navigation.
TEST_F(WebContentsImplTest,SimpleNavigation)411 TEST_F(WebContentsImplTest, SimpleNavigation) {
412   TestRenderFrameHost* orig_rfh = main_test_rfh();
413   SiteInstance* instance1 = contents()->GetSiteInstance();
414   EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
415 
416   // Navigate until ready to commit.
417   const GURL url("http://www.google.com");
418   auto navigation =
419       NavigationSimulator::CreateBrowserInitiated(url, contents());
420   navigation->ReadyToCommit();
421   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
422   EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
423   // Controller's pending entry will have a null site instance until we assign
424   // it in Commit.
425   EXPECT_EQ(
426       nullptr,
427       NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
428           site_instance());
429 
430   navigation->Commit();
431   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
432   EXPECT_EQ(orig_rfh, main_test_rfh());
433   EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
434   // Controller's entry should now have the SiteInstance, or else we won't be
435   // able to find it later.
436   EXPECT_EQ(
437       instance1,
438       NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
439           site_instance());
440 }
441 
442 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
TEST_F(WebContentsImplTest,NavigateToExcessivelyLongURL)443 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
444   // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
445   const GURL url(std::string("http://example.org/").append(
446       url::kMaxURLChars + 1, 'a'));
447 
448   controller().LoadURL(
449       url, Referrer(), ui::PAGE_TRANSITION_GENERATED, std::string());
450   EXPECT_EQ(nullptr, controller().GetPendingEntry());
451 }
452 
453 // Test that we reject NavigateToEntry if the url is invalid.
TEST_F(WebContentsImplTest,NavigateToInvalidURL)454 TEST_F(WebContentsImplTest, NavigateToInvalidURL) {
455   // Invalid URLs should not trigger a navigation.
456   const GURL invalid_url("view-source:http://example.org/%00");
457   controller().LoadURL(
458       invalid_url, Referrer(), ui::PAGE_TRANSITION_GENERATED, std::string());
459   EXPECT_EQ(nullptr, controller().GetPendingEntry());
460 
461   // Empty URLs are supported and should start a navigation.
462   controller().LoadURL(
463       GURL(), Referrer(), ui::PAGE_TRANSITION_GENERATED, std::string());
464   EXPECT_NE(nullptr, controller().GetPendingEntry());
465 }
466 
467 // Test that we reject NavigateToEntry if the url is a renderer debug URL
468 // inside a view-source: URL. This verifies that the navigation is not allowed
469 // to proceed after the view-source: URL rewriting logic has run.
TEST_F(WebContentsImplTest,NavigateToViewSourceRendererDebugURL)470 TEST_F(WebContentsImplTest, NavigateToViewSourceRendererDebugURL) {
471   const GURL renderer_debug_url(kChromeUIKillURL);
472   const GURL view_source_debug_url("view-source:" + renderer_debug_url.spec());
473   EXPECT_TRUE(IsRendererDebugURL(renderer_debug_url));
474   EXPECT_FALSE(IsRendererDebugURL(view_source_debug_url));
475   controller().LoadURL(view_source_debug_url, Referrer(),
476                        ui::PAGE_TRANSITION_GENERATED, std::string());
477   EXPECT_EQ(nullptr, controller().GetPendingEntry());
478 }
479 
480 // Test that navigating across a site boundary creates a new RenderViewHost
481 // with a new SiteInstance.  Going back should do the same.
TEST_F(WebContentsImplTest,CrossSiteBoundaries)482 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
483   // This test assumes no interaction with the back forward cache.
484   // Similar coverage when BFCache is on can be found in
485   // BackForwardCacheBrowserTest.NavigateBackForwardRepeatedly.
486   contents()->GetController().GetBackForwardCache().DisableForTesting(
487       BackForwardCache::TEST_ASSUMES_NO_CACHING);
488 
489   TestRenderFrameHost* orig_rfh = main_test_rfh();
490   int orig_rvh_delete_count = 0;
491   orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
492   SiteInstance* instance1 = contents()->GetSiteInstance();
493 
494   // Navigate to URL.  First URL should use first RenderViewHost.
495   const GURL url("http://www.google.com");
496   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
497 
498   // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
499   // that orig_rfh doesn't get deleted when it gets swapped out.
500   orig_rfh->GetSiteInstance()->IncrementActiveFrameCount();
501 
502   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
503   EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
504   EXPECT_EQ(url, contents()->GetLastCommittedURL());
505   EXPECT_EQ(url, contents()->GetVisibleURL());
506 
507   // Navigate to new site
508   const GURL url2("http://www.yahoo.com");
509   auto new_site_navigation =
510       NavigationSimulator::CreateBrowserInitiated(url2, contents());
511   new_site_navigation->ReadyToCommit();
512   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
513   EXPECT_EQ(url, contents()->GetLastCommittedURL());
514   EXPECT_EQ(url2, contents()->GetVisibleURL());
515   TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
516   EXPECT_TRUE(pending_rfh->GetLastCommittedURL().is_empty());
517   int pending_rvh_delete_count = 0;
518   pending_rfh->GetRenderViewHost()->set_delete_counter(
519       &pending_rvh_delete_count);
520 
521   // DidNavigate from the pending page.
522   new_site_navigation->Commit();
523   SiteInstance* instance2 = contents()->GetSiteInstance();
524 
525   // Keep the number of active frames in pending_rfh's SiteInstance
526   // non-zero so that orig_rfh doesn't get deleted when it gets
527   // swapped out.
528   pending_rfh->GetSiteInstance()->IncrementActiveFrameCount();
529 
530   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
531   EXPECT_EQ(pending_rfh, main_test_rfh());
532   EXPECT_EQ(url2, contents()->GetLastCommittedURL());
533   EXPECT_EQ(url2, contents()->GetVisibleURL());
534   EXPECT_NE(instance1, instance2);
535   EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
536   // We keep a proxy for the original RFH's SiteInstance.
537   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
538       instance1));
539   EXPECT_EQ(orig_rvh_delete_count, 0);
540 
541   // Going back should switch SiteInstances again.  The first SiteInstance is
542   // stored in the NavigationEntry, so it should be the same as at the start.
543   // We should use the same RFH as before, swapping it back in.
544   auto back_navigation =
545       NavigationSimulator::CreateHistoryNavigation(-1, contents());
546   back_navigation->ReadyToCommit();
547   TestRenderFrameHost* goback_rfh = contents()->GetPendingMainFrame();
548   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
549 
550   // DidNavigate from the back action.
551   back_navigation->Commit();
552   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
553   EXPECT_EQ(goback_rfh, main_test_rfh());
554   EXPECT_EQ(url, contents()->GetLastCommittedURL());
555   EXPECT_EQ(url, contents()->GetVisibleURL());
556   EXPECT_EQ(instance1, contents()->GetSiteInstance());
557   // There should be a proxy for the pending RFH SiteInstance.
558   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
559       instance2));
560   EXPECT_EQ(pending_rvh_delete_count, 0);
561 
562   // Close contents and ensure RVHs are deleted.
563   DeleteContents();
564   EXPECT_EQ(orig_rvh_delete_count, 1);
565   EXPECT_EQ(pending_rvh_delete_count, 1);
566 }
567 
568 // Test that navigating across a site boundary after a crash creates a new
569 // RFH without requiring a cross-site transition (i.e., PENDING state).
TEST_F(WebContentsImplTest,CrossSiteBoundariesAfterCrash)570 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
571   // Ensure that the cross-site transition will also be cross-process on
572   // Android.
573   IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
574 
575   TestRenderFrameHost* orig_rfh = main_test_rfh();
576 
577   int orig_rvh_delete_count = 0;
578   orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
579   SiteInstance* instance1 = contents()->GetSiteInstance();
580 
581   // Navigate to URL.  First URL should use first RenderViewHost.
582   const GURL url("http://www.google.com");
583   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
584   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
585   EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
586 
587   // Simulate a renderer crash.
588   EXPECT_TRUE(orig_rfh->IsRenderFrameLive());
589   orig_rfh->GetProcess()->SimulateCrash();
590   EXPECT_FALSE(orig_rfh->IsRenderFrameLive());
591 
592   // Start navigating to a new site. We should not go into PENDING.
593   const GURL url2("http://www.yahoo.com");
594   auto navigation_to_url2 =
595       NavigationSimulator::CreateBrowserInitiated(url2, contents());
596   navigation_to_url2->ReadyToCommit();
597 
598   TestRenderFrameHost* new_rfh = main_test_rfh();
599   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
600   EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
601   EXPECT_NE(orig_rfh, new_rfh);
602   EXPECT_EQ(orig_rvh_delete_count, 1);
603 
604   navigation_to_url2->Commit();
605   SiteInstance* instance2 = contents()->GetSiteInstance();
606 
607   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
608   EXPECT_EQ(new_rfh, main_rfh());
609   EXPECT_NE(instance1, instance2);
610   EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
611 
612   // Close contents and ensure RVHs are deleted.
613   DeleteContents();
614   EXPECT_EQ(orig_rvh_delete_count, 1);
615 }
616 
617 // Test that opening a new contents in the same SiteInstance and then navigating
618 // both contentses to a new site will place both contentses in a single
619 // SiteInstance.
TEST_F(WebContentsImplTest,NavigateTwoTabsCrossSite)620 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
621   SiteInstance* instance1 = contents()->GetSiteInstance();
622 
623   // Navigate to URL.  First URL should use first RenderViewHost.
624   const GURL url("http://www.google.com");
625   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
626 
627   // Open a new contents with the same SiteInstance, navigated to the same site.
628   std::unique_ptr<TestWebContents> contents2(
629       TestWebContents::Create(browser_context(), instance1));
630   NavigationSimulator::NavigateAndCommitFromBrowser(contents2.get(), url);
631   EXPECT_EQ(instance1, contents2->GetSiteInstance());
632 
633   // Navigate first contents to a new site.
634   const GURL url2a = isolated_cross_site_url();
635   auto navigation1 =
636       NavigationSimulator::CreateBrowserInitiated(url2a, contents());
637   navigation1->SetTransition(ui::PAGE_TRANSITION_LINK);
638   navigation1->ReadyToCommit();
639   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
640   navigation1->Commit();
641   SiteInstance* instance2a = contents()->GetSiteInstance();
642   EXPECT_NE(instance1, instance2a);
643 
644   // Navigate second contents to the same site as the first tab.
645   const GURL url2b = isolated_cross_site_url().Resolve("/foo");
646   auto navigation2 =
647       NavigationSimulator::CreateBrowserInitiated(url2b, contents2.get());
648   navigation2->SetTransition(ui::PAGE_TRANSITION_LINK);
649   navigation2->ReadyToCommit();
650   EXPECT_TRUE(contents2->CrossProcessNavigationPending());
651 
652   // NOTE(creis): We used to be in danger of showing a crash page here if the
653   // second contents hadn't navigated somewhere first (bug 1145430).  That case
654   // is now covered by the CrossSiteBoundariesAfterCrash test.
655   navigation2->Commit();
656   SiteInstance* instance2b = contents2->GetSiteInstance();
657   EXPECT_NE(instance1, instance2b);
658 
659   // Both contentses should now be in the same SiteInstance.
660   EXPECT_EQ(instance2a, instance2b);
661 }
662 
663 // The embedder can request sites for certain urls not be be assigned to the
664 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
665 // allowing to reuse the renderer backing certain chrome urls for subsequent
666 // navigation. The test verifies that the override is honored.
TEST_F(WebContentsImplTest,NavigateFromSitelessUrl)667 TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
668   WebContentsImplTestBrowserClient browser_client;
669   SetBrowserClientForTesting(&browser_client);
670 
671   TestRenderFrameHost* orig_rfh = main_test_rfh();
672   int orig_rvh_delete_count = 0;
673   orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
674   SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
675 
676   // Navigate to an URL that will not assign a new SiteInstance.
677   const GURL native_url("non-site-url://stuffandthings");
678   browser_client.set_assign_site_for_url(false, native_url);
679   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), native_url);
680 
681   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
682   EXPECT_EQ(orig_rfh, main_test_rfh());
683   EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
684   EXPECT_EQ(native_url, contents()->GetVisibleURL());
685   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
686   EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
687   EXPECT_FALSE(orig_instance->HasSite());
688 
689   // Navigate to new site (should keep same site instance).
690   const GURL url("http://www.google.com");
691   browser_client.set_assign_site_for_url(true, url);
692   auto navigation1 =
693       NavigationSimulator::CreateBrowserInitiated(url, contents());
694   navigation1->ReadyToCommit();
695   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
696   EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
697   EXPECT_EQ(url, contents()->GetVisibleURL());
698   EXPECT_FALSE(contents()->GetPendingMainFrame());
699   navigation1->Commit();
700 
701   // The first entry's SiteInstance should be reset to a new, related one. This
702   // prevents wrongly detecting a SiteInstance mismatch when returning to it
703   // later.
704   SiteInstanceImpl* prev_entry_instance = contents()
705                                               ->GetController()
706                                               .GetEntryAtIndex(0)
707                                               ->root_node()
708                                               ->frame_entry->site_instance();
709   EXPECT_NE(prev_entry_instance, orig_instance);
710   EXPECT_TRUE(orig_instance->IsRelatedSiteInstance(prev_entry_instance));
711   EXPECT_FALSE(prev_entry_instance->HasSite());
712 
713   SiteInstanceImpl* curr_entry_instance = contents()
714                                               ->GetController()
715                                               .GetEntryAtIndex(1)
716                                               ->root_node()
717                                               ->frame_entry->site_instance();
718   EXPECT_EQ(curr_entry_instance, orig_instance);
719   // Keep the number of active frames in orig_rfh's SiteInstance
720   // non-zero so that orig_rfh doesn't get deleted when it gets
721   // swapped out.
722   orig_rfh->GetSiteInstance()->IncrementActiveFrameCount();
723 
724   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
725   if (AreDefaultSiteInstancesEnabled()) {
726     // Verify that the empty SiteInstance gets converted into a default
727     // SiteInstance because |url| does not require a dedicated process.
728     EXPECT_TRUE(contents()->GetSiteInstance()->IsDefaultSiteInstance());
729   } else {
730     EXPECT_TRUE(
731         contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
732   }
733   EXPECT_EQ(url, contents()->GetLastCommittedURL());
734 
735   // Navigate to another new site (should create a new site instance).
736   const GURL url2 = isolated_cross_site_url();
737   auto navigation2 =
738       NavigationSimulator::CreateBrowserInitiated(url2, contents());
739   navigation2->ReadyToCommit();
740   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
741   EXPECT_EQ(url, contents()->GetLastCommittedURL());
742   EXPECT_EQ(url2, contents()->GetVisibleURL());
743   TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
744   int pending_rvh_delete_count = 0;
745   pending_rfh->GetRenderViewHost()->set_delete_counter(
746       &pending_rvh_delete_count);
747 
748   // DidNavigate from the pending page.
749   navigation2->Commit();
750   SiteInstance* new_instance = contents()->GetSiteInstance();
751 
752   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
753   EXPECT_EQ(pending_rfh, main_test_rfh());
754   EXPECT_EQ(url2, contents()->GetLastCommittedURL());
755   EXPECT_EQ(url2, contents()->GetVisibleURL());
756   EXPECT_NE(new_instance, orig_instance);
757   EXPECT_FALSE(contents()->GetPendingMainFrame());
758   EXPECT_EQ(orig_rvh_delete_count, 0);
759 
760   // Close contents and ensure RVHs are deleted.
761   DeleteContents();
762   EXPECT_EQ(orig_rvh_delete_count, 1);
763   EXPECT_EQ(pending_rvh_delete_count, 1);
764 }
765 
766 // Regression test for http://crbug.com/386542 - variation of
767 // NavigateFromSitelessUrl in which the original navigation is a session
768 // restore.
TEST_F(WebContentsImplTest,NavigateFromRestoredSitelessUrl)769 TEST_F(WebContentsImplTest, NavigateFromRestoredSitelessUrl) {
770   WebContentsImplTestBrowserClient browser_client;
771   SetBrowserClientForTesting(&browser_client);
772   SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
773   TestRenderFrameHost* orig_rfh = main_test_rfh();
774 
775   // Restore a navigation entry for URL that should not assign site to the
776   // SiteInstance.
777   const GURL native_url("non-site-url://stuffandthings");
778   browser_client.set_assign_site_for_url(false, native_url);
779   std::vector<std::unique_ptr<NavigationEntry>> entries;
780   std::unique_ptr<NavigationEntry> new_entry =
781       NavigationController::CreateNavigationEntry(
782           native_url, Referrer(), base::nullopt, ui::PAGE_TRANSITION_LINK,
783           false, std::string(), browser_context(),
784           nullptr /* blob_url_loader_factory */);
785   entries.push_back(std::move(new_entry));
786   controller().Restore(0, RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
787   ASSERT_EQ(0u, entries.size());
788   ASSERT_EQ(1, controller().GetEntryCount());
789 
790   EXPECT_TRUE(controller().NeedsReload());
791   controller().LoadIfNecessary();
792   NavigationEntry* entry = controller().GetPendingEntry();
793   orig_rfh->PrepareForCommit();
794   contents()->TestDidNavigate(orig_rfh, entry->GetUniqueID(), false,
795                               native_url, ui::PAGE_TRANSITION_RELOAD);
796   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
797   EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
798   EXPECT_FALSE(orig_instance->HasSite());
799 
800   // Navigate to a regular site and verify that the SiteInstance was kept.
801   const GURL url("http://www.google.com");
802   browser_client.set_assign_site_for_url(true, url);
803   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
804   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
805 
806   // Cleanup.
807   DeleteContents();
808 }
809 
810 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
811 // tab is restored, the SiteInstance will change upon navigation.
TEST_F(WebContentsImplTest,NavigateFromRestoredRegularUrl)812 TEST_F(WebContentsImplTest, NavigateFromRestoredRegularUrl) {
813   WebContentsImplTestBrowserClient browser_client;
814   SetBrowserClientForTesting(&browser_client);
815   SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
816   TestRenderFrameHost* orig_rfh = main_test_rfh();
817 
818   // Restore a navigation entry for a regular URL ensuring that the embedder
819   // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
820   const GURL regular_url("http://www.yahoo.com");
821   browser_client.set_assign_site_for_url(true, regular_url);
822   std::vector<std::unique_ptr<NavigationEntry>> entries;
823   std::unique_ptr<NavigationEntry> new_entry =
824       NavigationController::CreateNavigationEntry(
825           regular_url, Referrer(), base::nullopt, ui::PAGE_TRANSITION_LINK,
826           false, std::string(), browser_context(),
827           nullptr /* blob_url_loader_factory */);
828   entries.push_back(std::move(new_entry));
829   controller().Restore(0, RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
830   ASSERT_EQ(0u, entries.size());
831 
832   ASSERT_EQ(1, controller().GetEntryCount());
833   EXPECT_TRUE(controller().NeedsReload());
834   controller().LoadIfNecessary();
835   NavigationEntry* entry = controller().GetPendingEntry();
836   orig_rfh->PrepareForCommit();
837   contents()->TestDidNavigate(orig_rfh, entry->GetUniqueID(), false,
838                               regular_url, ui::PAGE_TRANSITION_RELOAD);
839   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
840   EXPECT_TRUE(orig_instance->HasSite());
841   EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
842             orig_instance->IsDefaultSiteInstance());
843 
844   // Navigate to another site and verify that a new SiteInstance was created.
845   const GURL url("http://www.google.com");
846   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
847   if (AreDefaultSiteInstancesEnabled()) {
848     // Verify this remains the default SiteInstance since |url| does
849     // not require a dedicated process.
850     EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
851 
852     // Navigate to a URL that does require a dedicated process and verify that
853     // the SiteInstance changes.
854     NavigationSimulator::NavigateAndCommitFromBrowser(
855         contents(), isolated_cross_site_url());
856     EXPECT_NE(orig_instance, contents()->GetSiteInstance());
857   } else {
858     EXPECT_NE(orig_instance, contents()->GetSiteInstance());
859   }
860 
861   // Cleanup.
862   DeleteContents();
863 }
864 
865 // Test that we can find an opener RVH even if it's pending.
866 // http://crbug.com/176252.
TEST_F(WebContentsImplTest,FindOpenerRVHWhenPending)867 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
868 
869   // Navigate to a URL.
870   const GURL url("http://www.google.com");
871   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
872 
873   // Start to navigate first tab to a new site, so that it has a pending RVH.
874   const GURL url2("http://www.yahoo.com");
875   auto navigation =
876       NavigationSimulator::CreateBrowserInitiated(url2, contents());
877   navigation->ReadyToCommit();
878   TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
879   SiteInstance* instance = pending_rfh->GetSiteInstance();
880 
881   // While it is still pending, simulate opening a new tab with the first tab
882   // as its opener.  This will call CreateOpenerProxies on the opener to ensure
883   // that an RVH exists.
884   std::unique_ptr<TestWebContents> popup(
885       TestWebContents::Create(browser_context(), instance));
886   popup->SetOpener(contents());
887   contents()->GetRenderManager()->CreateOpenerProxies(instance, nullptr);
888 
889   // If swapped out is forbidden, a new proxy should be created for the opener
890   // in |instance|, and we should ensure that its routing ID is returned here.
891   // Otherwise, we should find the pending RFH and not create a new proxy.
892   auto opener_frame_token =
893       popup->GetRenderManager()->GetOpenerFrameToken(instance);
894   RenderFrameProxyHost* proxy =
895       contents()->GetRenderManager()->GetRenderFrameProxyHost(instance);
896   EXPECT_TRUE(proxy);
897   EXPECT_EQ(*opener_frame_token, proxy->GetFrameToken());
898 
899   // Ensure that committing the navigation removes the proxy.
900   navigation->Commit();
901   EXPECT_FALSE(
902       contents()->GetRenderManager()->GetRenderFrameProxyHost(instance));
903 }
904 
905 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
906 // to determine whether a navigation is cross-site.
TEST_F(WebContentsImplTest,CrossSiteComparesAgainstCurrentPage)907 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
908   // The assumptions this test makes aren't valid with --site-per-process.  For
909   // example, a cross-site URL won't ever commit in the old RFH.  The test also
910   // assumes that default SiteInstances are enabled, and that aggressive
911   // BrowsingInstance swapping (even on renderer-initiated navigations) is
912   // disabled.
913   if (AreAllSitesIsolatedForTesting() || !AreDefaultSiteInstancesEnabled() ||
914       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
915     return;
916   }
917 
918   TestRenderFrameHost* orig_rfh = main_test_rfh();
919   SiteInstanceImpl* instance1 = contents()->GetSiteInstance();
920 
921   const GURL url("http://www.google.com");
922 
923   // Navigate to URL.
924   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
925 
926   // Open a related contents to a second site.
927   std::unique_ptr<TestWebContents> contents2(
928       TestWebContents::Create(browser_context(), instance1));
929   const GURL url2("http://www.yahoo.com");
930   auto navigation =
931       NavigationSimulator::CreateBrowserInitiated(url2, contents2.get());
932   navigation->ReadyToCommit();
933 
934   // The first RVH in contents2 isn't live yet, so we shortcut the cross site
935   // pending.
936   EXPECT_FALSE(contents2->CrossProcessNavigationPending());
937   navigation->Commit();
938   SiteInstance* instance2 = contents2->GetSiteInstance();
939   // With default SiteInstances, navigations in both tabs should
940   // share the same default SiteInstance, since neither requires a dedicated
941   // process.
942   EXPECT_EQ(instance1, instance2);
943   EXPECT_TRUE(instance1->IsDefaultSiteInstance());
944   EXPECT_FALSE(contents2->CrossProcessNavigationPending());
945 
946   // Simulate a link click in first contents to second site.  This doesn't
947   // switch SiteInstances and stays in the default SiteInstance.
948   NavigationSimulator::NavigateAndCommitFromDocument(url2, orig_rfh);
949   SiteInstance* instance3 = contents()->GetSiteInstance();
950   EXPECT_EQ(instance1, instance3);
951   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
952 
953   // Navigate same-site.  This also stays in the default SiteInstance.
954   const GURL url3("http://mail.yahoo.com");
955   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url3);
956   SiteInstance* instance4 = contents()->GetSiteInstance();
957   EXPECT_EQ(instance1, instance4);
958 }
959 
960 // Test that the onbeforeunload and onunload handlers run when navigating
961 // across site boundaries.
TEST_F(WebContentsImplTest,CrossSiteUnloadHandlers)962 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
963   TestRenderFrameHost* orig_rfh = main_test_rfh();
964   SiteInstance* instance1 = contents()->GetSiteInstance();
965 
966   // Navigate to URL.  First URL should use first RenderViewHost.
967   const GURL url("http://www.google.com");
968   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
969   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
970   EXPECT_EQ(orig_rfh, main_test_rfh());
971 
972   // Navigate to new site, but simulate an onbeforeunload denial.
973   const GURL url2("http://www.yahoo.com");
974   controller().LoadURL(
975       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
976   EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_completion());
977   orig_rfh->SimulateBeforeUnloadCompleted(false);
978   EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_completion());
979   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
980   EXPECT_EQ(orig_rfh, main_test_rfh());
981 
982   // Navigate again, but simulate an onbeforeunload approval.
983   controller().LoadURL(
984       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
985   EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_completion());
986   auto navigation = NavigationSimulator::CreateFromPending(contents());
987   navigation->ReadyToCommit();
988   EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_completion());
989   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
990   TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
991 
992   // DidNavigate from the pending page.
993   navigation->Commit();
994   SiteInstance* instance2 = contents()->GetSiteInstance();
995   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
996   EXPECT_EQ(pending_rfh, main_test_rfh());
997   EXPECT_NE(instance1, instance2);
998   EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
999 }
1000 
1001 // Test that during a slow cross-site navigation, the original renderer can
1002 // navigate to a different URL and have it displayed, canceling the slow
1003 // navigation.
TEST_F(WebContentsImplTest,CrossSiteNavigationPreempted)1004 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
1005   TestRenderFrameHost* orig_rfh = main_test_rfh();
1006   SiteInstance* instance1 = contents()->GetSiteInstance();
1007 
1008   // Navigate to URL.  First URL should use first RenderFrameHost.
1009   const GURL url("http://www.google.com");
1010   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
1011   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1012   EXPECT_EQ(orig_rfh, main_test_rfh());
1013 
1014   // Navigate to new site.
1015   const GURL url2("http://www.yahoo.com");
1016   controller().LoadURL(
1017       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1018   EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_completion());
1019   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1020 
1021   // Suppose the original renderer navigates before the new one is ready.
1022   const GURL url3("http://www.google.com/foo");
1023   NavigationSimulator::NavigateAndCommitFromDocument(url3, orig_rfh);
1024 
1025   // Verify that the pending navigation is cancelled.
1026   SiteInstance* instance2 = contents()->GetSiteInstance();
1027   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
1028     // If same-site ProactivelySwapBrowsingInstance or main-frame RenderDocument
1029     // is enabled, the RFH should change.
1030     EXPECT_NE(orig_rfh, main_test_rfh());
1031   } else {
1032     EXPECT_EQ(orig_rfh, main_test_rfh());
1033   }
1034   if (CanSameSiteMainFrameNavigationsChangeSiteInstances()) {
1035     // When ProactivelySwapBrowsingInstance is enabled on same-site navigations,
1036     // the SiteInstance will change.
1037     EXPECT_NE(instance1, instance2);
1038   } else {
1039     EXPECT_EQ(instance1, instance2);
1040   }
1041   EXPECT_FALSE(main_test_rfh()->is_waiting_for_beforeunload_completion());
1042   EXPECT_EQ(main_test_rfh()->GetLastCommittedURL(), url3);
1043   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1044   EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1045 }
1046 
1047 // Tests that if we go back twice (same-site then cross-site), and the same-site
1048 // RFH commits first, the cross-site RFH's navigation is canceled. If the
1049 // same-site navigation is a cross-RFH navigation, however, the same-site
1050 // navigation will get canceled instead and we are left with the newer
1051 // cross-site navigation.
1052 // TODO(avi,creis): Consider changing this behavior to better match the user's
1053 // intent.
TEST_F(WebContentsImplTest,CrossSiteNavigationBackPreempted)1054 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
1055   // Start with a web ui page, which gets a new RVH with WebUI bindings.
1056   GURL url1(std::string(kChromeUIScheme) + "://" +
1057             std::string(kChromeUIGpuHost));
1058   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url1);
1059   TestRenderFrameHost* webui_rfh = main_test_rfh();
1060   NavigationEntry* entry1 = controller().GetLastCommittedEntry();
1061   SiteInstance* instance1 = contents()->GetSiteInstance();
1062 
1063   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1064   EXPECT_EQ(url1, entry1->GetURL());
1065   EXPECT_EQ(instance1,
1066             NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1067   EXPECT_TRUE(webui_rfh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
1068 
1069   // Navigate to new site.
1070   const GURL url2("http://www.google.com");
1071   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url2);
1072   TestRenderFrameHost* google_rfh = main_test_rfh();
1073   NavigationEntry* entry2 = controller().GetLastCommittedEntry();
1074   SiteInstance* instance2 = contents()->GetSiteInstance();
1075 
1076   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1077   EXPECT_NE(instance1, instance2);
1078   EXPECT_FALSE(contents()->GetPendingMainFrame());
1079   EXPECT_EQ(url2, entry2->GetURL());
1080   EXPECT_EQ(instance2,
1081             NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1082   EXPECT_FALSE(google_rfh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
1083 
1084   // Navigate to third page on same site.
1085   const GURL url3("http://news.google.com");
1086   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url3);
1087   NavigationEntry* entry3 = controller().GetLastCommittedEntry();
1088   SiteInstance* instance3 = contents()->GetSiteInstance();
1089 
1090   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1091   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
1092     // If same-site ProactivelySwapBrowsingInstance or main-frame RenderDocument
1093     // is enabled, the RFH should change.
1094     EXPECT_NE(google_rfh, main_test_rfh());
1095   } else {
1096     EXPECT_EQ(google_rfh, main_test_rfh());
1097   }
1098   if (CanSameSiteMainFrameNavigationsChangeSiteInstances()) {
1099     // When ProactivelySwapBrowsingInstance is enabled on same-site navigations,
1100     // the SiteInstance will change.
1101     EXPECT_NE(instance2, instance3);
1102   } else {
1103     EXPECT_EQ(instance2, instance3);
1104   }
1105   EXPECT_FALSE(contents()->GetPendingMainFrame());
1106   EXPECT_EQ(url3, entry3->GetURL());
1107   EXPECT_EQ(instance3,
1108             NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1109 
1110   // Go back within the site.
1111   auto back_navigation1 =
1112       NavigationSimulatorImpl::CreateHistoryNavigation(-1, contents());
1113   back_navigation1->Start();
1114 
1115   auto* first_pending_rfh = contents()->GetPendingMainFrame();
1116   GlobalFrameRoutingId first_pending_rfh_id;
1117   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
1118     EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1119     EXPECT_TRUE(first_pending_rfh);
1120     first_pending_rfh_id = first_pending_rfh->GetGlobalFrameRoutingId();
1121   } else {
1122     EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1123     EXPECT_FALSE(first_pending_rfh);
1124   }
1125   EXPECT_EQ(entry2, controller().GetPendingEntry());
1126 
1127   // Before that commits, go back again.
1128   back_navigation1->ReadyToCommit();
1129   auto back_navigation2 =
1130       NavigationSimulatorImpl::CreateHistoryNavigation(-1, contents());
1131   back_navigation2->Start();
1132   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1133   EXPECT_TRUE(contents()->GetPendingMainFrame());
1134   EXPECT_EQ(entry1, controller().GetPendingEntry());
1135   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
1136     // When ProactivelySwapBrowsingInstance or RenderDocument is enabled on
1137     // same-site main frame navigation, the first back navigation will create a
1138     // speculative RFH even though it's a same-site navigation, and the
1139     // speculative RFH will be overwritten by the second back-navigation that
1140     // will also create a speculative RFH.
1141     EXPECT_NE(first_pending_rfh_id,
1142               contents()->GetPendingMainFrame()->GetGlobalFrameRoutingId());
1143     // Calling Commit() on the first back navigation below will cause a DCHECK
1144     // failure because we've already called DidFinishNavigaition on it, so we
1145     // will call it on the second back navigation instead.
1146     back_navigation2->Commit();
1147   } else {
1148     // DidNavigate from the first back. This aborts the second back's
1149     // speculative RFH.
1150     back_navigation1->Commit();
1151   }
1152 
1153   // We have committed this navigation and forgot about the second back if
1154   // CanSameSiteMainFrameNavigationsChangeRenderFrameHosts() is false, or the
1155   // first back if it's true.
1156   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1157   EXPECT_FALSE(controller().GetPendingEntry());
1158   EXPECT_EQ(google_rfh, main_test_rfh());
1159   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
1160     // We committed the second back navigation and landed on the first page.
1161     EXPECT_EQ(url1, controller().GetLastCommittedEntry()->GetURL());
1162   } else {
1163     // We committed the second back navigation and landed on the second page.
1164     EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
1165   }
1166 
1167   // We should not have corrupted the NTP entry.
1168   EXPECT_EQ(instance3,
1169             NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1170   EXPECT_EQ(instance2,
1171             NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1172   EXPECT_EQ(instance1,
1173             NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1174   EXPECT_EQ(url1, entry1->GetURL());
1175 }
1176 
1177 // Tests that if we go back twice (same-site then cross-site), and the cross-
1178 // site RFH commits first, we ignore the now-swapped-out RFH's commit.
TEST_F(WebContentsImplTest,CrossSiteNavigationBackOldNavigationIgnored)1179 TEST_F(WebContentsImplTest, CrossSiteNavigationBackOldNavigationIgnored) {
1180   // Start with a web ui page, which gets a new RFH with WebUI bindings.
1181   GURL url1(std::string(kChromeUIScheme) + "://" +
1182             std::string(kChromeUIGpuHost));
1183   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url1);
1184   TestRenderFrameHost* webui_rfh = main_test_rfh();
1185   NavigationEntry* entry1 = controller().GetLastCommittedEntry();
1186   SiteInstance* instance1 = contents()->GetSiteInstance();
1187 
1188   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1189   EXPECT_EQ(url1, entry1->GetURL());
1190   EXPECT_EQ(instance1,
1191             NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1192   EXPECT_TRUE(webui_rfh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
1193 
1194   // Navigate to new site.
1195   const GURL url2("http://www.google.com");
1196   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url2);
1197   TestRenderFrameHost* google_rfh = main_test_rfh();
1198   NavigationEntry* entry2 = controller().GetLastCommittedEntry();
1199   SiteInstance* instance2 = contents()->GetSiteInstance();
1200 
1201   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1202   EXPECT_NE(instance1, instance2);
1203   EXPECT_FALSE(contents()->GetPendingMainFrame());
1204   EXPECT_EQ(url2, entry2->GetURL());
1205   EXPECT_EQ(instance2,
1206             NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1207   EXPECT_FALSE(google_rfh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
1208 
1209   // Navigate to third page on same site.
1210   const GURL url3("http://google.com/foo");
1211   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url3);
1212   NavigationEntry* entry3 = controller().GetLastCommittedEntry();
1213   SiteInstance* instance3 = contents()->GetSiteInstance();
1214 
1215   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1216   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
1217     // If same-site ProactivelySwapBrowsingInstance or main-frame RenderDocument
1218     // is enabled, the RFH should change.
1219     EXPECT_NE(google_rfh, main_test_rfh());
1220     google_rfh = main_test_rfh();
1221   } else {
1222     EXPECT_EQ(google_rfh, main_test_rfh());
1223   }
1224   if (CanSameSiteMainFrameNavigationsChangeSiteInstances()) {
1225     // When ProactivelySwapBrowsingInstance is enabled on same-site navigations,
1226     // the SiteInstance will change.
1227     EXPECT_NE(instance2, instance3);
1228   } else {
1229     EXPECT_EQ(instance2, instance3);
1230   }
1231   EXPECT_FALSE(contents()->GetPendingMainFrame());
1232   EXPECT_EQ(url3, entry3->GetURL());
1233   EXPECT_EQ(instance3,
1234             NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1235 
1236   // Go back within the site.
1237   auto back_navigation1 =
1238       NavigationSimulator::CreateHistoryNavigation(-1, contents());
1239   back_navigation1->ReadyToCommit();
1240   if (CanSameSiteMainFrameNavigationsChangeSiteInstances()) {
1241     EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1242   } else {
1243     EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1244   }
1245   EXPECT_EQ(entry2, controller().GetPendingEntry());
1246 
1247   // Before that commits, go back again.
1248   auto back_navigation2 =
1249       NavigationSimulatorImpl::CreateHistoryNavigation(-1, contents());
1250   back_navigation2->set_drop_unload_ack(true);
1251   back_navigation2->ReadyToCommit();
1252   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1253   EXPECT_TRUE(contents()->GetPendingMainFrame());
1254   EXPECT_EQ(entry1, controller().GetPendingEntry());
1255   webui_rfh = contents()->GetPendingMainFrame();
1256 
1257   // DidNavigate from the second back.
1258   // Note that the process in instance1 is gone at this point, but we will still
1259   // use instance1 and entry1 because IsSuitableForURL will return true when
1260   // there is no process and the site URL matches.
1261   back_navigation2->Commit();
1262 
1263   // That should have landed us on the first entry.
1264   EXPECT_EQ(entry1, controller().GetLastCommittedEntry());
1265 
1266   // When the second back commits, it should be ignored.
1267   contents()->TestDidNavigate(google_rfh, entry2->GetUniqueID(), false, url2,
1268                               ui::PAGE_TRANSITION_TYPED);
1269   EXPECT_EQ(entry1, controller().GetLastCommittedEntry());
1270 
1271   // The newly created process for url1 should be locked to chrome://gpu.
1272   RenderProcessHost* new_process = contents()->GetMainFrame()->GetProcess();
1273   auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
1274   EXPECT_TRUE(policy->CanAccessDataForOrigin(new_process->GetID(), url1));
1275   EXPECT_FALSE(policy->CanAccessDataForOrigin(new_process->GetID(), url2));
1276 }
1277 
1278 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1279 // original renderer will not cancel the slow navigation (bug 42029).
TEST_F(WebContentsImplTest,CrossSiteNavigationNotPreemptedByFrame)1280 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
1281   TestRenderFrameHost* orig_rfh = main_test_rfh();
1282 
1283   // Navigate to URL.  First URL should use the original RenderFrameHost.
1284   const GURL url("http://www.google.com");
1285   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
1286   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1287   EXPECT_EQ(orig_rfh, main_test_rfh());
1288 
1289   // Start navigating to new site.
1290   const GURL url2("http://www.yahoo.com");
1291   controller().LoadURL(
1292       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1293 
1294   // Simulate a sub-frame navigation arriving and ensure the RVH is still
1295   // waiting for a before unload response.
1296   TestRenderFrameHost* child_rfh = orig_rfh->AppendChild("subframe");
1297   child_rfh->SendNavigateWithTransition(0, false,
1298                                         GURL("http://google.com/frame"),
1299                                         ui::PAGE_TRANSITION_AUTO_SUBFRAME);
1300   EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_completion());
1301 
1302   // Now simulate the onbeforeunload approval and verify the navigation is
1303   // not canceled.
1304   orig_rfh->PrepareForCommit();
1305   EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_completion());
1306   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1307 }
1308 
1309 // Test that a cross-site navigation is not preempted if the previous
1310 // renderer sends a FrameNavigate message just before being told to stop.
1311 // We should only preempt the cross-site navigation if the previous renderer
1312 // has started a new navigation. See http://crbug.com/79176.
TEST_F(WebContentsImplTest,CrossSiteNotPreemptedDuringBeforeUnload)1313 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1314   const GURL kUrl("http://foo");
1315   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kUrl);
1316 
1317   // First, make a non-user initiated same-site navigation.
1318   const GURL kSameSiteUrl("http://foo/1");
1319   TestRenderFrameHost* orig_rfh = main_test_rfh();
1320   // When ProactivelySwapBrowsingInstance or RenderDocument is enabled on
1321   // same-site main frame navigations, the same-site navigation below will
1322   // create a speculative RFH that will be overwritten when the cross-site
1323   // navigation starts, finishing the same-site navigation, so the scenario in
1324   // this test cannot be tested. We should disable same-site proactive
1325   // BrowsingInstance for |orig_rfh| before continuing.
1326   // Note: this will not disable RenderDocument.
1327   // TODO(crbug.com/936696): Skip this test when main-frame RenderDocument is
1328   // enabled.
1329   DisableProactiveBrowsingInstanceSwapFor(orig_rfh);
1330   auto same_site_navigation = NavigationSimulator::CreateRendererInitiated(
1331       kSameSiteUrl, main_test_rfh());
1332   same_site_navigation->SetHasUserGesture(false);
1333   same_site_navigation->ReadyToCommit();
1334   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1335 
1336   // Navigate to a new site, with the beforeunload request in flight.
1337   const GURL kCrossSiteUrl("http://www.yahoo.com");
1338   auto cross_site_navigation = NavigationSimulatorImpl::CreateBrowserInitiated(
1339       kCrossSiteUrl, contents());
1340   cross_site_navigation->set_block_invoking_before_unload_completed_callback(
1341       true);
1342   cross_site_navigation->Start();
1343   TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
1344   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1345   EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_completion());
1346   EXPECT_NE(orig_rfh, pending_rfh);
1347 
1348   // Suppose the first navigation tries to commit now, with a
1349   // blink::mojom::LocalFrame::StopLoading() in flight. This should not cancel
1350   // the pending navigation, but it should act as if the beforeunload completion
1351   // callback had been invoked.
1352   same_site_navigation->Commit();
1353   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1354   EXPECT_EQ(orig_rfh, main_test_rfh());
1355   EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_completion());
1356   // It should commit.
1357   ASSERT_EQ(2, controller().GetEntryCount());
1358   EXPECT_EQ(kSameSiteUrl, controller().GetLastCommittedEntry()->GetURL());
1359 
1360   // The pending navigation should be able to commit successfully.
1361   cross_site_navigation->Commit();
1362   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1363   EXPECT_EQ(pending_rfh, main_test_rfh());
1364   EXPECT_EQ(3, controller().GetEntryCount());
1365 }
1366 
1367 // Test that NavigationEntries have the correct page state after going
1368 // forward and back.  Prevents regression for bug 1116137.
TEST_F(WebContentsImplTest,NavigationEntryContentState)1369 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1370 
1371   // Navigate to URL.  There should be no committed entry yet.
1372   const GURL url("http://www.google.com");
1373   auto navigation =
1374       NavigationSimulator::CreateBrowserInitiated(url, contents());
1375   navigation->ReadyToCommit();
1376   NavigationEntry* entry = controller().GetLastCommittedEntry();
1377   EXPECT_EQ(nullptr, entry);
1378 
1379   // Committed entry should have page state.
1380   navigation->Commit();
1381   entry = controller().GetLastCommittedEntry();
1382   EXPECT_TRUE(entry->GetPageState().IsValid());
1383 
1384   // Navigate to same site.
1385   const GURL url2("http://images.google.com");
1386   auto navigation2 =
1387       NavigationSimulator::CreateBrowserInitiated(url2, contents());
1388   navigation2->ReadyToCommit();
1389   entry = controller().GetLastCommittedEntry();
1390   EXPECT_TRUE(entry->GetPageState().IsValid());
1391 
1392   // Committed entry should have page state.
1393   navigation2->Commit();
1394   entry = controller().GetLastCommittedEntry();
1395   EXPECT_TRUE(entry->GetPageState().IsValid());
1396 
1397   // Now go back.  Committed entry should still have page state.
1398   NavigationSimulator::GoBack(contents());
1399   entry = controller().GetLastCommittedEntry();
1400   EXPECT_TRUE(entry->GetPageState().IsValid());
1401 }
1402 
1403 // Test that NavigationEntries have the correct page state and SiteInstance
1404 // state after opening a new window to about:blank.  Prevents regression for
1405 // bugs b/1116137 and http://crbug.com/111975.
TEST_F(WebContentsImplTest,NavigationEntryContentStateNewWindow)1406 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1407   TestRenderFrameHost* orig_rfh = main_test_rfh();
1408 
1409   // Navigate to about:blank.
1410   const GURL url(url::kAboutBlankURL);
1411   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
1412 
1413   // Should have a page state here.
1414   NavigationEntry* entry = controller().GetLastCommittedEntry();
1415   EXPECT_TRUE(entry->GetPageState().IsValid());
1416 
1417   // The SiteInstance should be available for other navigations to use.
1418   NavigationEntryImpl* entry_impl =
1419       NavigationEntryImpl::FromNavigationEntry(entry);
1420   EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1421   int32_t site_instance_id = entry_impl->site_instance()->GetId();
1422 
1423   // Navigating to a normal page should not cause a process swap.
1424   const GURL new_url("http://www.google.com");
1425   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), new_url);
1426 
1427   EXPECT_EQ(orig_rfh, main_test_rfh());
1428   NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1429       controller().GetLastCommittedEntry());
1430   EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1431   EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1432 }
1433 
1434 namespace {
1435 
ExpectTrue(bool value)1436 void ExpectTrue(bool value) {
1437   DCHECK(value);
1438 }
1439 
ExpectFalse(bool value)1440 void ExpectFalse(bool value) {
1441   DCHECK(!value);
1442 }
1443 
1444 }  // namespace
1445 
1446 // Tests that fullscreen is exited throughout the object hierarchy when
1447 // navigating to a new page.
TEST_F(WebContentsImplTest,NavigationExitsFullscreen)1448 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
1449   FakeFullscreenDelegate fake_delegate;
1450   contents()->SetDelegate(&fake_delegate);
1451   TestRenderFrameHost* orig_rfh = main_test_rfh();
1452 
1453   // Navigate to a site.
1454   const GURL url("http://www.google.com");
1455   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
1456   EXPECT_EQ(orig_rfh, main_test_rfh());
1457 
1458   // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1459   EXPECT_FALSE(contents()->IsFullscreen());
1460   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1461   main_test_rfh()->frame_tree_node()->UpdateUserActivationState(
1462       blink::mojom::UserActivationUpdateType::kNotifyActivation,
1463       blink::mojom::UserActivationNotificationType::kTest);
1464   orig_rfh->EnterFullscreen(blink::mojom::FullscreenOptions::New(),
1465                             base::BindOnce(&ExpectTrue));
1466   EXPECT_TRUE(contents()->IsFullscreen());
1467   EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1468 
1469   // Navigate to a new site.
1470   const GURL url2("http://www.yahoo.com");
1471   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url2);
1472 
1473   // Confirm fullscreen has exited.
1474   EXPECT_FALSE(contents()->IsFullscreen());
1475   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1476 
1477   contents()->SetDelegate(nullptr);
1478 }
1479 
1480 // Tests that fullscreen is exited throughout the object hierarchy when
1481 // instructing NavigationController to GoBack() or GoForward().
TEST_F(WebContentsImplTest,HistoryNavigationExitsFullscreen)1482 TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
1483   FakeFullscreenDelegate fake_delegate;
1484   contents()->SetDelegate(&fake_delegate);
1485   TestRenderFrameHost* orig_rfh = main_test_rfh();
1486 
1487   // Navigate to a site.
1488   const GURL url("http://www.google.com");
1489   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
1490   EXPECT_EQ(orig_rfh, main_test_rfh());
1491 
1492   // Now, navigate to another page on the same site.
1493   const GURL url2("http://www.google.com/search?q=kittens");
1494   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url2);
1495   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
1496     // If ProactivelySwapBrowsingInstance is enabled on same-site navigations,
1497     // the same-site navigation above will use a new RFH.
1498     EXPECT_NE(orig_rfh, main_test_rfh());
1499   } else {
1500     EXPECT_EQ(orig_rfh, main_test_rfh());
1501   }
1502 
1503   // Sanity-check: Confirm we're not starting out in fullscreen mode.
1504   EXPECT_FALSE(contents()->IsFullscreen());
1505   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1506 
1507   for (int i = 0; i < 2; ++i) {
1508     // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1509     main_test_rfh()->frame_tree_node()->UpdateUserActivationState(
1510         blink::mojom::UserActivationUpdateType::kNotifyActivation,
1511         blink::mojom::UserActivationNotificationType::kTest);
1512     main_test_rfh()->EnterFullscreen(blink::mojom::FullscreenOptions::New(),
1513                                      base::BindOnce(&ExpectTrue));
1514     EXPECT_TRUE(contents()->IsFullscreen());
1515     EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1516 
1517     // Navigate backward (or forward).
1518     if (i == 0)
1519       NavigationSimulator::GoBack(contents());
1520     else
1521       NavigationSimulator::GoForward(contents());
1522 
1523     // Confirm fullscreen has exited.
1524     EXPECT_FALSE(contents()->IsFullscreen());
1525     EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1526   }
1527 
1528   contents()->SetDelegate(nullptr);
1529 }
1530 
1531 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1532 // crash.
TEST_F(WebContentsImplTest,CrashExitsFullscreen)1533 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
1534   FakeFullscreenDelegate fake_delegate;
1535   contents()->SetDelegate(&fake_delegate);
1536 
1537   // Navigate to a site.
1538   const GURL url("http://www.google.com");
1539   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
1540 
1541   // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1542   EXPECT_FALSE(contents()->IsFullscreen());
1543   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1544   main_test_rfh()->frame_tree_node()->UpdateUserActivationState(
1545       blink::mojom::UserActivationUpdateType::kNotifyActivation,
1546       blink::mojom::UserActivationNotificationType::kTest);
1547   main_test_rfh()->EnterFullscreen(blink::mojom::FullscreenOptions::New(),
1548                                    base::BindOnce(&ExpectTrue));
1549   EXPECT_TRUE(contents()->IsFullscreen());
1550   EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1551 
1552   // Crash the renderer.
1553   main_test_rfh()->GetProcess()->SimulateCrash();
1554 
1555   // Confirm fullscreen has exited.
1556   EXPECT_FALSE(contents()->IsFullscreen());
1557   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1558 
1559   contents()->SetDelegate(nullptr);
1560 }
1561 
TEST_F(WebContentsImplTest,FailEnterFullscreenWhenNoUserActivationNoOrientationChange)1562 TEST_F(WebContentsImplTest,
1563        FailEnterFullscreenWhenNoUserActivationNoOrientationChange) {
1564   FakeFullscreenDelegate fake_delegate;
1565   contents()->SetDelegate(&fake_delegate);
1566 
1567   // Navigate to a site.
1568   const GURL url("http://www.google.com");
1569   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), url);
1570 
1571   // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1572   EXPECT_FALSE(contents()->IsFullscreen());
1573   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1574 
1575   // When there is no user activation and no orientation change, entering
1576   // fullscreen will fail.
1577   main_test_rfh()->EnterFullscreen(blink::mojom::FullscreenOptions::New(),
1578                                    base::BindOnce(&ExpectFalse));
1579   EXPECT_FALSE(contents()->HasSeenRecentScreenOrientationChange());
1580   EXPECT_FALSE(
1581       main_test_rfh()->frame_tree_node()->HasTransientUserActivation());
1582   EXPECT_FALSE(contents()->IsFullscreen());
1583   EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1584 
1585   contents()->SetDelegate(nullptr);
1586 }
1587 
1588 // Regression test for http://crbug.com/168611 - the URLs passed by the
1589 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
TEST_F(WebContentsImplTest,FilterURLs)1590 TEST_F(WebContentsImplTest, FilterURLs) {
1591   TestWebContentsObserver observer(contents());
1592 
1593   // A navigation to about:whatever should always look like a navigation to
1594   // about:blank
1595   GURL url_normalized(url::kAboutBlankURL);
1596   GURL url_from_ipc("about:whatever");
1597   GURL url_blocked(kBlockedURL);
1598 
1599   // We navigate the test WebContents to about:blank, since NavigateAndCommit
1600   // will use the given URL to create the NavigationEntry as well, and that
1601   // entry should contain the filtered URL.
1602   contents()->NavigateAndCommit(url_normalized);
1603 
1604   // Check that an IPC with about:whatever is correctly normalized.
1605   contents()->TestDidFinishLoad(url_from_ipc);
1606 
1607   EXPECT_EQ(url_blocked, observer.last_url());
1608 
1609   // Create and navigate another WebContents.
1610   std::unique_ptr<TestWebContents> other_contents(
1611       static_cast<TestWebContents*>(CreateTestWebContents().release()));
1612   TestWebContentsObserver other_observer(other_contents.get());
1613   other_contents->NavigateAndCommit(url_normalized);
1614 
1615   // Check that an IPC with about:whatever is correctly normalized.
1616   other_contents->GetMainFrame()->DidFailLoadWithError(url_from_ipc, 1);
1617   EXPECT_EQ(url_blocked, other_observer.last_url());
1618 }
1619 
1620 // Test that if a pending contents is deleted before it is shown, we don't
1621 // crash.
TEST_F(WebContentsImplTest,PendingContentsDestroyed)1622 TEST_F(WebContentsImplTest, PendingContentsDestroyed) {
1623   auto other_contents = base::WrapUnique(
1624       static_cast<TestWebContents*>(CreateTestWebContents().release()));
1625   content::TestWebContents* test_web_contents = other_contents.get();
1626   contents()->AddPendingContents(std::move(other_contents), GURL());
1627   RenderWidgetHost* widget =
1628       test_web_contents->GetMainFrame()->GetRenderWidgetHost();
1629   int process_id = widget->GetProcess()->GetID();
1630   int widget_id = widget->GetRoutingID();
1631 
1632   // TODO(erikchen): Fix ownership semantics of WebContents. Nothing should be
1633   // able to delete it beside from the owner. https://crbug.com/832879.
1634   delete test_web_contents;
1635   EXPECT_FALSE(contents()->GetCreatedWindow(process_id, widget_id).has_value());
1636 }
1637 
TEST_F(WebContentsImplTest,PendingContentsShown)1638 TEST_F(WebContentsImplTest, PendingContentsShown) {
1639   GURL url("http://example.com");
1640   auto other_contents = base::WrapUnique(
1641       static_cast<TestWebContents*>(CreateTestWebContents().release()));
1642   content::TestWebContents* test_web_contents = other_contents.get();
1643   contents()->AddPendingContents(std::move(other_contents), url);
1644 
1645   RenderWidgetHost* widget =
1646       test_web_contents->GetMainFrame()->GetRenderWidgetHost();
1647   int process_id = widget->GetProcess()->GetID();
1648   int widget_id = widget->GetRoutingID();
1649 
1650   // The first call to GetCreatedWindow pops it off the pending list.
1651   base::Optional<CreatedWindow> created_window =
1652       contents()->GetCreatedWindow(process_id, widget_id);
1653   EXPECT_TRUE(created_window.has_value());
1654   EXPECT_EQ(test_web_contents, created_window->contents.get());
1655   // Validate target_url.
1656   EXPECT_EQ(url, created_window->target_url);
1657 
1658   // A second call should return nullopt, verifying that it's been forgotten.
1659   EXPECT_FALSE(contents()->GetCreatedWindow(process_id, widget_id).has_value());
1660 }
1661 
TEST_F(WebContentsImplTest,CapturerOverridesPreferredSize)1662 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
1663   const gfx::Size original_preferred_size(1024, 768);
1664   contents()->UpdatePreferredSize(original_preferred_size);
1665 
1666   // With no capturers, expect the preferred size to be the one propagated into
1667   // WebContentsImpl via the RenderViewHostDelegate interface.
1668   EXPECT_FALSE(contents()->IsBeingCaptured());
1669   EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
1670 
1671   // Increment capturer count, but without specifying a capture size.  Expect
1672   // a "not set" preferred size.
1673   contents()->IncrementCapturerCount(gfx::Size(), /* stay_hidden */ false);
1674   EXPECT_TRUE(contents()->IsBeingCaptured());
1675   EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
1676 
1677   // Increment capturer count again, but with an overriding capture size.
1678   // Expect preferred size to now be overridden to the capture size.
1679   const gfx::Size capture_size(1280, 720);
1680   contents()->IncrementCapturerCount(capture_size, /* stay_hidden */ false);
1681   EXPECT_TRUE(contents()->IsBeingCaptured());
1682   EXPECT_EQ(capture_size, contents()->GetPreferredSize());
1683 
1684   // Increment capturer count a third time, but the expect that the preferred
1685   // size is still the first capture size.
1686   const gfx::Size another_capture_size(720, 480);
1687   contents()->IncrementCapturerCount(another_capture_size,
1688                                      /* stay_hidden */ false);
1689   EXPECT_TRUE(contents()->IsBeingCaptured());
1690   EXPECT_EQ(capture_size, contents()->GetPreferredSize());
1691 
1692   // Decrement capturer count twice, but expect the preferred size to still be
1693   // overridden.
1694   contents()->DecrementCapturerCount(/* stay_hidden */ false);
1695   contents()->DecrementCapturerCount(/* stay_hidden */ false);
1696   EXPECT_TRUE(contents()->IsBeingCaptured());
1697   EXPECT_EQ(capture_size, contents()->GetPreferredSize());
1698 
1699   // Decrement capturer count, and since the count has dropped to zero, the
1700   // original preferred size should be restored.
1701   contents()->DecrementCapturerCount(/* stay_hidden */ false);
1702   EXPECT_FALSE(contents()->IsBeingCaptured());
1703   EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
1704 }
1705 
TEST_F(WebContentsImplTest,UpdateWebContentsVisibility)1706 TEST_F(WebContentsImplTest, UpdateWebContentsVisibility) {
1707   base::test::ScopedFeatureList scoped_feature_list;
1708   scoped_feature_list.InitAndEnableFeature(features::kWebContentsOcclusion);
1709 
1710   TestRenderWidgetHostView* view = static_cast<TestRenderWidgetHostView*>(
1711       main_test_rfh()->GetRenderViewHost()->GetWidget()->GetView());
1712   TestWebContentsObserver observer(contents());
1713 
1714   EXPECT_FALSE(view->is_showing());
1715   EXPECT_FALSE(view->is_occluded());
1716 
1717   // WebContents must be made visible once before it can be hidden.
1718   contents()->UpdateWebContentsVisibility(Visibility::HIDDEN);
1719   EXPECT_FALSE(view->is_showing());
1720   EXPECT_FALSE(view->is_occluded());
1721   EXPECT_EQ(Visibility::VISIBLE, contents()->GetVisibility());
1722 
1723   contents()->UpdateWebContentsVisibility(Visibility::VISIBLE);
1724   EXPECT_TRUE(view->is_showing());
1725   EXPECT_FALSE(view->is_occluded());
1726   EXPECT_EQ(Visibility::VISIBLE, contents()->GetVisibility());
1727 
1728   // Hiding/occluding/showing the WebContents should hide and show |view|.
1729   contents()->UpdateWebContentsVisibility(Visibility::HIDDEN);
1730   EXPECT_FALSE(view->is_showing());
1731   EXPECT_FALSE(view->is_occluded());
1732   EXPECT_EQ(Visibility::HIDDEN, contents()->GetVisibility());
1733 
1734   contents()->UpdateWebContentsVisibility(Visibility::VISIBLE);
1735   EXPECT_TRUE(view->is_showing());
1736   EXPECT_FALSE(view->is_occluded());
1737   EXPECT_EQ(Visibility::VISIBLE, contents()->GetVisibility());
1738 
1739   contents()->UpdateWebContentsVisibility(Visibility::OCCLUDED);
1740   EXPECT_TRUE(view->is_showing());
1741   EXPECT_TRUE(view->is_occluded());
1742   EXPECT_EQ(Visibility::OCCLUDED, contents()->GetVisibility());
1743 
1744   contents()->UpdateWebContentsVisibility(Visibility::VISIBLE);
1745   EXPECT_TRUE(view->is_showing());
1746   EXPECT_FALSE(view->is_occluded());
1747   EXPECT_EQ(Visibility::VISIBLE, contents()->GetVisibility());
1748 
1749   contents()->UpdateWebContentsVisibility(Visibility::OCCLUDED);
1750   EXPECT_TRUE(view->is_showing());
1751   EXPECT_TRUE(view->is_occluded());
1752   EXPECT_EQ(Visibility::OCCLUDED, contents()->GetVisibility());
1753 
1754   contents()->UpdateWebContentsVisibility(Visibility::HIDDEN);
1755   EXPECT_FALSE(view->is_showing());
1756   EXPECT_EQ(Visibility::HIDDEN, contents()->GetVisibility());
1757 }
1758 
1759 namespace {
1760 
HideOrOccludeWithCapturerTest(WebContentsImpl * contents,Visibility hidden_or_occluded)1761 void HideOrOccludeWithCapturerTest(WebContentsImpl* contents,
1762                                    Visibility hidden_or_occluded) {
1763   TestRenderWidgetHostView* view = static_cast<TestRenderWidgetHostView*>(
1764       contents->GetRenderWidgetHostView());
1765 
1766   EXPECT_FALSE(view->is_showing());
1767 
1768   // WebContents must be made visible once before it can be hidden.
1769   contents->UpdateWebContentsVisibility(Visibility::VISIBLE);
1770   EXPECT_TRUE(view->is_showing());
1771   EXPECT_FALSE(view->is_occluded());
1772   EXPECT_EQ(Visibility::VISIBLE, contents->GetVisibility());
1773 
1774   // Add a capturer when the contents is visible and then hide the contents.
1775   // |view| should remain visible.
1776   contents->IncrementCapturerCount(gfx::Size(), /* stay_hidden */ false);
1777   contents->UpdateWebContentsVisibility(hidden_or_occluded);
1778   EXPECT_TRUE(view->is_showing());
1779   EXPECT_FALSE(view->is_occluded());
1780   EXPECT_EQ(hidden_or_occluded, contents->GetVisibility());
1781 
1782   // Remove the capturer when the contents is hidden/occluded. |view| should be
1783   // hidden/occluded.
1784   contents->DecrementCapturerCount(/* stay_hidden */ false);
1785   if (hidden_or_occluded == Visibility::HIDDEN) {
1786     EXPECT_FALSE(view->is_showing());
1787   } else {
1788     EXPECT_TRUE(view->is_showing());
1789     EXPECT_TRUE(view->is_occluded());
1790   }
1791 
1792   // Add a capturer when the contents is hidden. |view| should be unoccluded.
1793   contents->IncrementCapturerCount(gfx::Size(), /* stay_hidden */ false);
1794   EXPECT_FALSE(view->is_occluded());
1795 
1796   // Show the contents. The view should be visible.
1797   contents->UpdateWebContentsVisibility(Visibility::VISIBLE);
1798   EXPECT_TRUE(view->is_showing());
1799   EXPECT_FALSE(view->is_occluded());
1800   EXPECT_EQ(Visibility::VISIBLE, contents->GetVisibility());
1801 
1802   // Remove the capturer when the contents is visible. The view should remain
1803   // visible.
1804   contents->DecrementCapturerCount(/* stay_hidden */ false);
1805   EXPECT_TRUE(view->is_showing());
1806   EXPECT_FALSE(view->is_occluded());
1807 }
1808 
1809 }  // namespace
1810 
TEST_F(WebContentsImplTest,HideWithCapturer)1811 TEST_F(WebContentsImplTest, HideWithCapturer) {
1812   HideOrOccludeWithCapturerTest(contents(), Visibility::HIDDEN);
1813 }
1814 
TEST_F(WebContentsImplTest,OccludeWithCapturer)1815 TEST_F(WebContentsImplTest, OccludeWithCapturer) {
1816   base::test::ScopedFeatureList scoped_feature_list;
1817   scoped_feature_list.InitAndEnableFeature(features::kWebContentsOcclusion);
1818   HideOrOccludeWithCapturerTest(contents(), Visibility::OCCLUDED);
1819 }
1820 
TEST_F(WebContentsImplTest,HiddenCapture)1821 TEST_F(WebContentsImplTest, HiddenCapture) {
1822   TestRenderWidgetHostView* rwhv = static_cast<TestRenderWidgetHostView*>(
1823       contents()->GetRenderWidgetHostView());
1824 
1825   contents()->UpdateWebContentsVisibility(Visibility::VISIBLE);
1826   contents()->UpdateWebContentsVisibility(Visibility::HIDDEN);
1827   EXPECT_EQ(Visibility::HIDDEN, contents()->GetVisibility());
1828 
1829   contents()->IncrementCapturerCount(gfx::Size(), /* stay_hidden */ true);
1830   EXPECT_TRUE(rwhv->is_showing());
1831 
1832   contents()->IncrementCapturerCount(gfx::Size(), /* stay_hidden */ false);
1833   EXPECT_TRUE(rwhv->is_showing());
1834 
1835   contents()->DecrementCapturerCount(/* stay_hidden */ true);
1836   EXPECT_TRUE(rwhv->is_showing());
1837 
1838   contents()->DecrementCapturerCount(/* stay_hidden */ false);
1839   EXPECT_FALSE(rwhv->is_showing());
1840 }
1841 
1842 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
1843 // on activity.
TEST_F(WebContentsImplTest,GetLastActiveTime)1844 TEST_F(WebContentsImplTest, GetLastActiveTime) {
1845   // The WebContents starts with a valid creation time.
1846   EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
1847 
1848   // Reset the last active time to a known-bad value.
1849   contents()->last_active_time_ = base::TimeTicks();
1850   ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
1851 
1852   // Simulate activating the WebContents. The active time should update.
1853   contents()->WasShown();
1854   EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
1855 }
1856 
1857 class ContentsZoomChangedDelegate : public WebContentsDelegate {
1858  public:
ContentsZoomChangedDelegate()1859   ContentsZoomChangedDelegate() :
1860     contents_zoom_changed_call_count_(0),
1861     last_zoom_in_(false) {
1862   }
1863 
GetAndResetContentsZoomChangedCallCount()1864   int GetAndResetContentsZoomChangedCallCount() {
1865     int count = contents_zoom_changed_call_count_;
1866     contents_zoom_changed_call_count_ = 0;
1867     return count;
1868   }
1869 
last_zoom_in() const1870   bool last_zoom_in() const {
1871     return last_zoom_in_;
1872   }
1873 
1874   // WebContentsDelegate:
ContentsZoomChange(bool zoom_in)1875   void ContentsZoomChange(bool zoom_in) override {
1876     contents_zoom_changed_call_count_++;
1877     last_zoom_in_ = zoom_in;
1878   }
1879 
1880  private:
1881   int contents_zoom_changed_call_count_;
1882   bool last_zoom_in_;
1883 
1884   DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
1885 };
1886 
1887 // Tests that some mouseehweel events get turned into browser zoom requests.
TEST_F(WebContentsImplTest,HandleWheelEvent)1888 TEST_F(WebContentsImplTest, HandleWheelEvent) {
1889   using blink::WebInputEvent;
1890 
1891   std::unique_ptr<ContentsZoomChangedDelegate> delegate(
1892       new ContentsZoomChangedDelegate());
1893   contents()->SetDelegate(delegate.get());
1894 
1895   int modifiers = 0;
1896   // Verify that normal mouse wheel events do nothing to change the zoom level.
1897   blink::WebMouseWheelEvent event =
1898       blink::SyntheticWebMouseWheelEventBuilder::Build(
1899           0, 0, 0, 1, modifiers, ui::ScrollGranularity::kScrollByPixel);
1900   EXPECT_FALSE(contents()->HandleWheelEvent(event));
1901   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
1902 
1903   // But whenever the ctrl modifier is applied zoom can be increased or
1904   // decreased. Except on MacOS where we never want to adjust zoom
1905   // with mousewheel.
1906   modifiers = WebInputEvent::kControlKey;
1907   event = blink::SyntheticWebMouseWheelEventBuilder::Build(
1908       0, 0, 0, 1, modifiers, ui::ScrollGranularity::kScrollByPixel);
1909   bool handled = contents()->HandleWheelEvent(event);
1910 #if defined(USE_AURA)
1911   EXPECT_TRUE(handled);
1912   EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
1913   EXPECT_TRUE(delegate->last_zoom_in());
1914 #else
1915   EXPECT_FALSE(handled);
1916   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
1917 #endif
1918 
1919   modifiers = WebInputEvent::kControlKey | WebInputEvent::kShiftKey |
1920               WebInputEvent::kAltKey;
1921   event = blink::SyntheticWebMouseWheelEventBuilder::Build(
1922       0, 0, 2, -5, modifiers, ui::ScrollGranularity::kScrollByPixel);
1923   handled = contents()->HandleWheelEvent(event);
1924 #if defined(USE_AURA)
1925   EXPECT_TRUE(handled);
1926   EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
1927   EXPECT_FALSE(delegate->last_zoom_in());
1928 #else
1929   EXPECT_FALSE(handled);
1930   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
1931 #endif
1932 
1933   // Unless there is no vertical movement.
1934   event = blink::SyntheticWebMouseWheelEventBuilder::Build(
1935       0, 0, 2, 0, modifiers, ui::ScrollGranularity::kScrollByPixel);
1936   EXPECT_FALSE(contents()->HandleWheelEvent(event));
1937   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
1938 
1939   // Events containing precise scrolling deltas also shouldn't result in the
1940   // zoom being adjusted, to avoid accidental adjustments caused by
1941   // two-finger-scrolling on a touchpad.
1942   modifiers = WebInputEvent::kControlKey;
1943   event = blink::SyntheticWebMouseWheelEventBuilder::Build(
1944       0, 0, 0, 5, modifiers, ui::ScrollGranularity::kScrollByPrecisePixel);
1945   EXPECT_FALSE(contents()->HandleWheelEvent(event));
1946   EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
1947 
1948   // Ensure pointers to the delegate aren't kept beyond its lifetime.
1949   contents()->SetDelegate(nullptr);
1950 }
1951 
1952 // Tests that GetRelatedActiveContentsCount is shared between related
1953 // SiteInstances and includes WebContents that have not navigated yet.
TEST_F(WebContentsImplTest,ActiveContentsCountBasic)1954 TEST_F(WebContentsImplTest, ActiveContentsCountBasic) {
1955   scoped_refptr<SiteInstance> instance1(
1956       SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
1957   scoped_refptr<SiteInstance> instance2(
1958       instance1->GetRelatedSiteInstance(GURL("http://b.com")));
1959 
1960   EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
1961   EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
1962 
1963   std::unique_ptr<TestWebContents> contents1(
1964       TestWebContents::Create(browser_context(), instance1.get()));
1965   EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
1966   EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
1967 
1968   std::unique_ptr<TestWebContents> contents2(
1969       TestWebContents::Create(browser_context(), instance1.get()));
1970   EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount());
1971   EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount());
1972 
1973   contents1.reset();
1974   EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
1975   EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
1976 
1977   contents2.reset();
1978   EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
1979   EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
1980 }
1981 
1982 // Tests that GetRelatedActiveContentsCount is preserved correctly across
1983 // same-site and cross-site navigations.
TEST_F(WebContentsImplTest,ActiveContentsCountNavigate)1984 TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
1985   scoped_refptr<SiteInstance> instance(
1986       SiteInstance::Create(browser_context()));
1987 
1988   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
1989 
1990   std::unique_ptr<TestWebContents> contents(
1991       TestWebContents::Create(browser_context(), instance.get()));
1992   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
1993 
1994   // Navigate to a URL.
1995   auto navigation1 = NavigationSimulator::CreateBrowserInitiated(
1996       GURL("http://a.com/1"), contents.get());
1997   navigation1->Start();
1998   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
1999   navigation1->Commit();
2000   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2001 
2002   // Navigate to a URL in the same site.
2003   auto navigation2 = NavigationSimulator::CreateBrowserInitiated(
2004       GURL("http://a.com/2"), contents.get());
2005   navigation2->Start();
2006   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2007   navigation2->Commit();
2008   if (CanSameSiteMainFrameNavigationsChangeSiteInstances()) {
2009     // When ProactivelySwapBrowsingInstance turned on for same-site navigations,
2010     // the BrowsingInstance will change on same-site navigations.
2011     EXPECT_NE(instance, contents->GetSiteInstance());
2012     // Check the previous instance's count.
2013     EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2014     // Update the current instance.
2015     instance = contents->GetSiteInstance();
2016     EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2017   }
2018 
2019   // Navigate to a URL in a different site in the same BrowsingInstance.
2020   const GURL kUrl2("http://b.com");
2021   auto navigation3 = NavigationSimulator::CreateRendererInitiated(
2022       kUrl2, contents->GetMainFrame());
2023   navigation3->ReadyToCommit();
2024   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2025   if (AreAllSitesIsolatedForTesting() ||
2026       CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
2027     EXPECT_TRUE(contents->CrossProcessNavigationPending());
2028   } else {
2029     EXPECT_FALSE(contents->CrossProcessNavigationPending());
2030   }
2031   navigation3->Commit();
2032   if (CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
2033     // When ProactivelySwapBrowsingInstance turned on, the BrowsingInstance will
2034     // change on cross-site navigations.
2035     EXPECT_NE(instance, contents->GetSiteInstance());
2036     EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2037     // Update the current instance.
2038     instance = contents->GetSiteInstance();
2039   }
2040   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2041 
2042   // Navigate to a URL in a different site and different BrowsingInstance, by
2043   // using a TYPED page transition instead of LINK.
2044   const GURL kUrl3("http://c.com");
2045   auto navigation4 =
2046       NavigationSimulator::CreateBrowserInitiated(kUrl3, contents.get());
2047   navigation4->SetTransition(ui::PAGE_TRANSITION_TYPED);
2048   navigation4->ReadyToCommit();
2049   EXPECT_TRUE(contents->CrossProcessNavigationPending());
2050   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2051   scoped_refptr<SiteInstance> new_instance =
2052       contents->GetPendingMainFrame()->GetSiteInstance();
2053   navigation4->Commit();
2054   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2055   EXPECT_EQ(1u, new_instance->GetRelatedActiveContentsCount());
2056   EXPECT_FALSE(new_instance->IsRelatedSiteInstance(instance.get()));
2057 
2058   contents.reset();
2059   EXPECT_EQ(0u, new_instance->GetRelatedActiveContentsCount());
2060 }
2061 
2062 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2063 // from WebUI.
TEST_F(WebContentsImplTest,ActiveContentsCountChangeBrowsingInstance)2064 TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
2065   scoped_refptr<SiteInstance> instance(
2066       SiteInstance::Create(browser_context()));
2067 
2068   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2069 
2070   std::unique_ptr<TestWebContents> contents(
2071       TestWebContents::Create(browser_context(), instance.get()));
2072   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2073 
2074   // Navigate to a URL.
2075   contents->NavigateAndCommit(GURL("http://a.com"));
2076   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2077 
2078   // Navigate to a URL which sort of looks like a chrome:// url.
2079   contents->NavigateAndCommit(GURL("http://gpu"));
2080   if (CanCrossSiteNavigationsProactivelySwapBrowsingInstances()) {
2081     // The navigation from "a.com" to "gpu" is using a new BrowsingInstance.
2082     EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2083     // The rest of the test expects |instance| to match the one in the main
2084     // frame.
2085     instance = contents->GetMainFrame()->GetSiteInstance();
2086   }
2087   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2088 
2089   // Navigate to a URL with WebUI. This will change BrowsingInstances.
2090   const GURL kWebUIUrl = GURL(GetWebUIURL(kChromeUIGpuHost));
2091   auto web_ui_navigation =
2092       NavigationSimulator::CreateBrowserInitiated(kWebUIUrl, contents.get());
2093   web_ui_navigation->Start();
2094   EXPECT_TRUE(contents->CrossProcessNavigationPending());
2095   scoped_refptr<SiteInstance> instance_webui(
2096       contents->GetPendingMainFrame()->GetSiteInstance());
2097   EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
2098 
2099   // At this point, contents still counts for the old BrowsingInstance.
2100   EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2101   EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2102 
2103   // Commit and contents counts for the new one.
2104   web_ui_navigation->Commit();
2105   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2106   EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount());
2107 
2108   contents.reset();
2109   EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2110   EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2111 }
2112 
2113 class LoadingWebContentsObserver : public WebContentsObserver {
2114  public:
LoadingWebContentsObserver(WebContents * contents)2115   explicit LoadingWebContentsObserver(WebContents* contents)
2116       : WebContentsObserver(contents),
2117         is_loading_(false),
2118         did_receive_response_(false) {}
~LoadingWebContentsObserver()2119   ~LoadingWebContentsObserver() override {}
2120 
2121   // The assertions on these messages ensure that they are received in order.
DidStartLoading()2122   void DidStartLoading() override {
2123     ASSERT_FALSE(did_receive_response_);
2124     ASSERT_FALSE(is_loading_);
2125     is_loading_ = true;
2126   }
DidReceiveResponse()2127   void DidReceiveResponse() override {
2128     ASSERT_TRUE(is_loading_);
2129     did_receive_response_ = true;
2130   }
DidStopLoading()2131   void DidStopLoading() override {
2132     ASSERT_TRUE(is_loading_);
2133     is_loading_ = false;
2134     did_receive_response_ = false;
2135   }
2136 
is_loading() const2137   bool is_loading() const { return is_loading_; }
did_receive_response() const2138   bool did_receive_response() const { return did_receive_response_; }
2139 
2140  private:
2141   bool is_loading_;
2142   bool did_receive_response_;
2143 
2144   DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver);
2145 };
2146 
2147 // Subclass of WebContentsImplTest for cases that need out-of-process iframes.
2148 class WebContentsImplTestWithSiteIsolation : public WebContentsImplTest {
2149  public:
WebContentsImplTestWithSiteIsolation()2150   WebContentsImplTestWithSiteIsolation() {
2151     IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
2152   }
2153 };
2154 
2155 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2156 // interleaving cross-process navigations in multiple subframes.
2157 // See https://crbug.com/448601 for details of the underlying issue. The
2158 // sequence of events that reproduce it are as follows:
2159 // * Navigate top-level frame with one subframe.
2160 // * Subframe navigates more than once before the top-level frame has had a
2161 //   chance to complete the load.
2162 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2163 // to 0, while the loading_progresses_ map is not reset.
TEST_F(WebContentsImplTestWithSiteIsolation,StartStopEventsBalance)2164 TEST_F(WebContentsImplTestWithSiteIsolation, StartStopEventsBalance) {
2165   // The bug manifests itself in regular mode as well, but browser-initiated
2166   // navigation of subframes is only possible in --site-per-process mode within
2167   // unit tests.
2168   const GURL initial_url("about:blank");
2169   const GURL main_url("http://www.chromium.org");
2170   const GURL foo_url("http://foo.chromium.org");
2171   const GURL bar_url("http://bar.chromium.org");
2172   TestRenderFrameHost* orig_rfh = main_test_rfh();
2173 
2174   // Use a WebContentsObserver to observe the behavior of the tab's spinner.
2175   LoadingWebContentsObserver observer(contents());
2176 
2177   // Navigate the main RenderFrame and commit. The frame should still be
2178   // loading.
2179   auto main_frame_navigation =
2180       NavigationSimulatorImpl::CreateBrowserInitiated(main_url, contents());
2181   main_frame_navigation->SetKeepLoading(true);
2182   main_frame_navigation->Commit();
2183   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2184   EXPECT_EQ(orig_rfh, main_test_rfh());
2185   EXPECT_TRUE(contents()->IsLoading());
2186 
2187   // The Observer callback implementations contain assertions to ensure that the
2188   // events arrive in the correct order.
2189   EXPECT_TRUE(observer.is_loading());
2190   EXPECT_TRUE(observer.did_receive_response());
2191 
2192   // Create a child frame to navigate multiple times.
2193   TestRenderFrameHost* subframe = orig_rfh->AppendChild("subframe");
2194 
2195   // Navigate the child frame to about:blank, which will send DidStopLoading
2196   // message.
2197   NavigationSimulator::NavigateAndCommitFromDocument(initial_url, subframe);
2198 
2199   // Navigate the frame to another URL, which will send again
2200   // DidStartLoading and DidStopLoading messages.
2201   NavigationSimulator::NavigateAndCommitFromDocument(foo_url, subframe);
2202 
2203   // Since the main frame hasn't sent any DidStopLoading messages, it is
2204   // expected that the WebContents is still in loading state.
2205   EXPECT_TRUE(contents()->IsLoading());
2206   EXPECT_TRUE(observer.is_loading());
2207   EXPECT_TRUE(observer.did_receive_response());
2208 
2209   // After navigation, the RenderFrameHost may change.
2210   subframe = static_cast<TestRenderFrameHost*>(
2211       contents()->GetFrameTree()->root()->child_at(0)->current_frame_host());
2212   // Navigate the frame again, this time using LoadURLWithParams. This causes
2213   // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2214   // the spinner.
2215   {
2216     auto navigation =
2217         NavigationSimulatorImpl::CreateBrowserInitiated(bar_url, contents());
2218 
2219     NavigationController::LoadURLParams load_params(bar_url);
2220     load_params.referrer = Referrer(GURL("http://referrer"),
2221                                     network::mojom::ReferrerPolicy::kDefault);
2222     load_params.transition_type = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
2223     load_params.extra_headers = "content-type: text/plain";
2224     load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT;
2225     load_params.is_renderer_initiated = false;
2226     load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
2227     load_params.frame_tree_node_id =
2228         subframe->frame_tree_node()->frame_tree_node_id();
2229     navigation->SetLoadURLParams(&load_params);
2230 
2231     navigation->Commit();
2232     subframe = static_cast<TestRenderFrameHost*>(
2233         navigation->GetFinalRenderFrameHost());
2234   }
2235 
2236   // At this point the status should still be loading, since the main frame
2237   // hasn't sent the DidstopLoading message yet.
2238   EXPECT_TRUE(contents()->IsLoading());
2239   EXPECT_TRUE(observer.is_loading());
2240   EXPECT_TRUE(observer.did_receive_response());
2241 
2242   // Send the DidStopLoading for the main frame and ensure it isn't loading
2243   // anymore.
2244   main_frame_navigation->StopLoading();
2245   EXPECT_FALSE(contents()->IsLoading());
2246   EXPECT_FALSE(observer.is_loading());
2247   EXPECT_FALSE(observer.did_receive_response());
2248 }
2249 
2250 // Tests that WebContentsImpl::IsLoadingToDifferentDocument only reports main
2251 // frame loads. Browser-initiated navigation of subframes is only possible in
2252 // --site-per-process mode within unit tests.
TEST_F(WebContentsImplTestWithSiteIsolation,IsLoadingToDifferentDocument)2253 TEST_F(WebContentsImplTestWithSiteIsolation, IsLoadingToDifferentDocument) {
2254   const GURL main_url("http://www.chromium.org");
2255   TestRenderFrameHost* orig_rfh = main_test_rfh();
2256 
2257   // Navigate the main RenderFrame and commit. The frame should still be
2258   // loading.
2259   auto navigation =
2260       NavigationSimulatorImpl::CreateBrowserInitiated(main_url, contents());
2261   navigation->SetKeepLoading(true);
2262   navigation->Commit();
2263   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2264   EXPECT_EQ(orig_rfh, main_test_rfh());
2265   EXPECT_TRUE(contents()->IsLoading());
2266   EXPECT_TRUE(contents()->IsLoadingToDifferentDocument());
2267 
2268   // Send the DidStopLoading for the main frame and ensure it isn't loading
2269   // anymore.
2270   navigation->StopLoading();
2271   EXPECT_FALSE(contents()->IsLoading());
2272   EXPECT_FALSE(contents()->IsLoadingToDifferentDocument());
2273 
2274   // Create a child frame to navigate.
2275   TestRenderFrameHost* subframe = orig_rfh->AppendChild("subframe");
2276 
2277   // Navigate the child frame to about:blank, make sure the web contents is
2278   // marked as "loading" but not "loading to different document".
2279   subframe->SendNavigateWithTransition(0, false, GURL("about:blank"),
2280                                        ui::PAGE_TRANSITION_AUTO_SUBFRAME);
2281   EXPECT_TRUE(contents()->IsLoading());
2282   EXPECT_FALSE(contents()->IsLoadingToDifferentDocument());
2283   static_cast<mojom::FrameHost*>(subframe)->DidStopLoading();
2284   EXPECT_FALSE(contents()->IsLoading());
2285 }
2286 
2287 // Ensure that WebContentsImpl does not stop loading too early when there still
2288 // is a pending renderer. This can happen if a same-process non user-initiated
2289 // navigation completes while there is an ongoing cross-process navigation.
2290 // TODO(clamy): Rewrite that test when the renderer-initiated non-user-initiated
2291 // navigation no longer kills the speculative RenderFrameHost. See
2292 // https://crbug.com/889039.
TEST_F(WebContentsImplTest,DISABLED_NoEarlyStop)2293 TEST_F(WebContentsImplTest, DISABLED_NoEarlyStop) {
2294   const GURL kUrl1("http://www.chromium.org");
2295   const GURL kUrl2("http://www.google.com");
2296   const GURL kUrl3("http://www.chromium.org/foo");
2297 
2298   contents()->NavigateAndCommit(kUrl1);
2299 
2300   TestRenderFrameHost* current_rfh = main_test_rfh();
2301 
2302   // Start a browser-initiated cross-process navigation to |kUrl2|. The
2303   // WebContents should be loading.
2304   auto cross_process_navigation =
2305       NavigationSimulator::CreateBrowserInitiated(kUrl2, contents());
2306   cross_process_navigation->ReadyToCommit();
2307   TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
2308   EXPECT_TRUE(contents()->IsLoading());
2309 
2310   // The current RenderFrameHost starts a non user-initiated render-initiated
2311   // navigation. The WebContents should still be loading.
2312   auto same_process_navigation =
2313       NavigationSimulator::CreateRendererInitiated(kUrl3, current_rfh);
2314   same_process_navigation->SetHasUserGesture(false);
2315   same_process_navigation->Start();
2316   EXPECT_TRUE(contents()->IsLoading());
2317 
2318   // Simulate the commit and DidStopLoading from the renderer-initiated
2319   // navigation in the current RenderFrameHost. There should still be a pending
2320   // RenderFrameHost and the WebContents should still be loading.
2321   same_process_navigation->Commit();
2322   static_cast<mojom::FrameHost*>(current_rfh)->DidStopLoading();
2323   EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh);
2324   EXPECT_TRUE(contents()->IsLoading());
2325 
2326   // The same-process navigation should have committed.
2327   ASSERT_EQ(2, controller().GetEntryCount());
2328   EXPECT_EQ(kUrl3, controller().GetLastCommittedEntry()->GetURL());
2329 
2330   // Commit the cross-process navigation. The formerly pending RenderFrameHost
2331   // should now be the current RenderFrameHost and the WebContents should still
2332   // be loading.
2333   cross_process_navigation->Commit();
2334   EXPECT_FALSE(contents()->GetPendingMainFrame());
2335   TestRenderFrameHost* new_current_rfh = main_test_rfh();
2336   EXPECT_EQ(new_current_rfh, pending_rfh);
2337   EXPECT_TRUE(contents()->IsLoading());
2338   EXPECT_EQ(3, controller().GetEntryCount());
2339 
2340   // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
2341   // should now have stopped loading.
2342   static_cast<mojom::FrameHost*>(new_current_rfh)->DidStopLoading();
2343   EXPECT_EQ(main_test_rfh(), new_current_rfh);
2344   EXPECT_FALSE(contents()->IsLoading());
2345 }
2346 
TEST_F(WebContentsImplTest,MediaWakeLock)2347 TEST_F(WebContentsImplTest, MediaWakeLock) {
2348   EXPECT_FALSE(has_audio_wake_lock());
2349 
2350   AudioStreamMonitor* monitor = contents()->audio_stream_monitor();
2351 
2352   // Ensure RenderFrame is initialized before simulating events coming from it.
2353   main_test_rfh()->InitializeRenderFrameIfNeeded();
2354 
2355   // Send a fake audio stream monitor notification.  The audio wake lock
2356   // should be created.
2357   monitor->set_was_recently_audible_for_testing(true);
2358   contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_AUDIO);
2359   EXPECT_TRUE(has_audio_wake_lock());
2360 
2361   // Send another fake notification, this time when WasRecentlyAudible() will
2362   // be false.  The wake lock should be released.
2363   monitor->set_was_recently_audible_for_testing(false);
2364   contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_AUDIO);
2365   EXPECT_FALSE(has_audio_wake_lock());
2366 
2367   main_test_rfh()->GetProcess()->SimulateCrash();
2368 
2369   // Verify that all the wake locks have been released.
2370   EXPECT_FALSE(has_audio_wake_lock());
2371 }
2372 
TEST_F(WebContentsImplTest,ThemeColorChangeDependingOnFirstVisiblePaint)2373 TEST_F(WebContentsImplTest, ThemeColorChangeDependingOnFirstVisiblePaint) {
2374   TestWebContentsObserver observer(contents());
2375   TestRenderFrameHost* rfh = main_test_rfh();
2376   rfh->InitializeRenderFrameIfNeeded();
2377 
2378   EXPECT_EQ(base::nullopt, contents()->GetThemeColor());
2379   EXPECT_EQ(0, observer.theme_color_change_calls());
2380 
2381   // Theme color changes should not propagate past the WebContentsImpl before
2382   // the first visually non-empty paint has occurred.
2383   rfh->DidChangeThemeColor(SK_ColorRED);
2384 
2385   EXPECT_EQ(SK_ColorRED, contents()->GetThemeColor());
2386   EXPECT_EQ(0, observer.theme_color_change_calls());
2387 
2388   // Simulate that the first visually non-empty paint has occurred. This will
2389   // propagate the current theme color to the delegates.
2390   RenderViewHostTester::SimulateFirstPaint(test_rvh());
2391 
2392   EXPECT_EQ(SK_ColorRED, contents()->GetThemeColor());
2393   EXPECT_EQ(1, observer.theme_color_change_calls());
2394 
2395   // Additional changes made by the web contents should propagate as well.
2396   rfh->DidChangeThemeColor(SK_ColorGREEN);
2397 
2398   EXPECT_EQ(SK_ColorGREEN, contents()->GetThemeColor());
2399   EXPECT_EQ(2, observer.theme_color_change_calls());
2400 }
2401 
TEST_F(WebContentsImplTest,ParseDownloadHeaders)2402 TEST_F(WebContentsImplTest, ParseDownloadHeaders) {
2403   download::DownloadUrlParameters::RequestHeadersType request_headers =
2404       WebContentsImpl::ParseDownloadHeaders("A: 1\r\nB: 2\r\nC: 3\r\n\r\n");
2405   ASSERT_EQ(3u, request_headers.size());
2406   EXPECT_EQ("A", request_headers[0].first);
2407   EXPECT_EQ("1", request_headers[0].second);
2408   EXPECT_EQ("B", request_headers[1].first);
2409   EXPECT_EQ("2", request_headers[1].second);
2410   EXPECT_EQ("C", request_headers[2].first);
2411   EXPECT_EQ("3", request_headers[2].second);
2412 
2413   request_headers = WebContentsImpl::ParseDownloadHeaders("A:1\r\nA:2\r\n");
2414   ASSERT_EQ(2u, request_headers.size());
2415   EXPECT_EQ("A", request_headers[0].first);
2416   EXPECT_EQ("1", request_headers[0].second);
2417   EXPECT_EQ("A", request_headers[1].first);
2418   EXPECT_EQ("2", request_headers[1].second);
2419 
2420   request_headers = WebContentsImpl::ParseDownloadHeaders("A 1\r\nA: 2");
2421   ASSERT_EQ(1u, request_headers.size());
2422   EXPECT_EQ("A", request_headers[0].first);
2423   EXPECT_EQ("2", request_headers[0].second);
2424 
2425   request_headers = WebContentsImpl::ParseDownloadHeaders("A: 1");
2426   ASSERT_EQ(1u, request_headers.size());
2427   EXPECT_EQ("A", request_headers[0].first);
2428   EXPECT_EQ("1", request_headers[0].second);
2429 
2430   request_headers = WebContentsImpl::ParseDownloadHeaders("A 1");
2431   ASSERT_EQ(0u, request_headers.size());
2432 }
2433 
2434 namespace {
2435 
2436 class TestJavaScriptDialogManager : public JavaScriptDialogManager {
2437  public:
TestJavaScriptDialogManager()2438   TestJavaScriptDialogManager() {}
~TestJavaScriptDialogManager()2439   ~TestJavaScriptDialogManager() override {}
2440 
reset_count()2441   size_t reset_count() { return reset_count_; }
2442 
2443   // JavaScriptDialogManager
2444 
RunJavaScriptDialog(WebContents * web_contents,RenderFrameHost * render_frame_host,JavaScriptDialogType dialog_type,const base::string16 & message_text,const base::string16 & default_prompt_text,DialogClosedCallback callback,bool * did_suppress_message)2445   void RunJavaScriptDialog(WebContents* web_contents,
2446                            RenderFrameHost* render_frame_host,
2447                            JavaScriptDialogType dialog_type,
2448                            const base::string16& message_text,
2449                            const base::string16& default_prompt_text,
2450                            DialogClosedCallback callback,
2451                            bool* did_suppress_message) override {
2452     *did_suppress_message = true;
2453   }
2454 
RunBeforeUnloadDialog(WebContents * web_contents,RenderFrameHost * render_frame_host,bool is_reload,DialogClosedCallback callback)2455   void RunBeforeUnloadDialog(WebContents* web_contents,
2456                              RenderFrameHost* render_frame_host,
2457                              bool is_reload,
2458                              DialogClosedCallback callback) override {}
2459 
HandleJavaScriptDialog(WebContents * web_contents,bool accept,const base::string16 * prompt_override)2460   bool HandleJavaScriptDialog(WebContents* web_contents,
2461                               bool accept,
2462                               const base::string16* prompt_override) override {
2463     return true;
2464   }
2465 
CancelDialogs(WebContents * web_contents,bool reset_state)2466   void CancelDialogs(WebContents* web_contents,
2467                      bool reset_state) override {
2468     if (reset_state)
2469       ++reset_count_;
2470   }
2471 
2472  private:
2473   size_t reset_count_ = 0;
2474 
2475   DISALLOW_COPY_AND_ASSIGN(TestJavaScriptDialogManager);
2476 };
2477 
2478 }  // namespace
2479 
TEST_F(WebContentsImplTest,ResetJavaScriptDialogOnUserNavigate)2480 TEST_F(WebContentsImplTest, ResetJavaScriptDialogOnUserNavigate) {
2481   const GURL kUrl("http://www.google.com");
2482   const GURL kUrl2("http://www.google.com/sub");
2483   TestJavaScriptDialogManager dialog_manager;
2484   contents()->SetJavaScriptDialogManagerForTesting(&dialog_manager);
2485 
2486   // A user-initiated navigation.
2487   NavigationSimulator::NavigateAndCommitFromBrowser(contents(), kUrl);
2488   EXPECT_EQ(1u, dialog_manager.reset_count());
2489 
2490   // An automatic navigation.
2491   auto navigation =
2492       NavigationSimulator::CreateRendererInitiated(kUrl2, main_test_rfh());
2493   navigation->SetHasUserGesture(false);
2494   navigation->Commit();
2495   if (CanSameSiteMainFrameNavigationsChangeRenderFrameHosts()) {
2496     // If we changed RenderFrameHost on a renderer-initiated navigation above,
2497     // we would trigger RenderFrameHostManager::UnloadOldFrame, similar to the
2498     // first (user/browser-initiated) navigation, which will trigger dialog
2499     // cancellations and increment the reset_count to 2.
2500     EXPECT_EQ(2u, dialog_manager.reset_count());
2501   } else {
2502     EXPECT_EQ(1u, dialog_manager.reset_count());
2503   }
2504 
2505   contents()->SetJavaScriptDialogManagerForTesting(nullptr);
2506 }
2507 
TEST_F(WebContentsImplTest,StartingSandboxFlags)2508 TEST_F(WebContentsImplTest, StartingSandboxFlags) {
2509   WebContents::CreateParams params(browser_context());
2510   network::mojom::WebSandboxFlags expected_flags =
2511       network::mojom::WebSandboxFlags::kPopups |
2512       network::mojom::WebSandboxFlags::kModals |
2513       network::mojom::WebSandboxFlags::kTopNavigation;
2514   params.starting_sandbox_flags = expected_flags;
2515   std::unique_ptr<WebContentsImpl> new_contents(
2516       WebContentsImpl::CreateWithOpener(params, nullptr));
2517   FrameTreeNode* root = new_contents->GetFrameTree()->root();
2518   network::mojom::WebSandboxFlags pending_flags =
2519       root->pending_frame_policy().sandbox_flags;
2520   EXPECT_EQ(pending_flags, expected_flags);
2521   network::mojom::WebSandboxFlags effective_flags =
2522       root->effective_frame_policy().sandbox_flags;
2523   EXPECT_EQ(effective_flags, expected_flags);
2524 }
2525 
TEST_F(WebContentsImplTest,DidFirstVisuallyNonEmptyPaint)2526 TEST_F(WebContentsImplTest, DidFirstVisuallyNonEmptyPaint) {
2527   TestWebContentsObserver observer(contents());
2528 
2529   RenderWidgetHostOwnerDelegate* rwhod = test_rvh();
2530   rwhod->RenderWidgetDidFirstVisuallyNonEmptyPaint();
2531 
2532   EXPECT_TRUE(observer.observed_did_first_visually_non_empty_paint());
2533 }
2534 
TEST_F(WebContentsImplTest,DidChangeVerticalScrollDirection)2535 TEST_F(WebContentsImplTest, DidChangeVerticalScrollDirection) {
2536   TestWebContentsObserver observer(contents());
2537 
2538   EXPECT_FALSE(observer.last_vertical_scroll_direction().has_value());
2539 
2540   contents()->OnVerticalScrollDirectionChanged(
2541       viz::VerticalScrollDirection::kUp);
2542 
2543   EXPECT_EQ(viz::VerticalScrollDirection::kUp,
2544             observer.last_vertical_scroll_direction().value());
2545 }
2546 
2547 namespace {
2548 
2549 class MockWebContentsDelegate : public WebContentsDelegate {
2550  public:
MockWebContentsDelegate(blink::ProtocolHandlerSecurityLevel security_level=blink::ProtocolHandlerSecurityLevel::kStrict)2551   explicit MockWebContentsDelegate(
2552       blink::ProtocolHandlerSecurityLevel security_level =
2553           blink::ProtocolHandlerSecurityLevel::kStrict)
2554       : security_level_(security_level) {}
2555   MOCK_METHOD2(HandleContextMenu,
2556                bool(RenderFrameHost*, const ContextMenuParams&));
2557   MOCK_METHOD4(RegisterProtocolHandler,
2558                void(RenderFrameHost*, const std::string&, const GURL&, bool));
2559 
GetProtocolHandlerSecurityLevel(RenderFrameHost *)2560   blink::ProtocolHandlerSecurityLevel GetProtocolHandlerSecurityLevel(
2561       RenderFrameHost*) override {
2562     return security_level_;
2563   }
2564 
2565  private:
2566   blink::ProtocolHandlerSecurityLevel security_level_;
2567 };
2568 
2569 }  // namespace
2570 
TEST_F(WebContentsImplTest,HandleContextMenuDelegate)2571 TEST_F(WebContentsImplTest, HandleContextMenuDelegate) {
2572   MockWebContentsDelegate delegate;
2573   contents()->SetDelegate(&delegate);
2574 
2575   RenderFrameHost* rfh = main_test_rfh();
2576   EXPECT_CALL(delegate, HandleContextMenu(rfh, ::testing::_))
2577       .WillOnce(::testing::Return(true));
2578 
2579   ContextMenuParams params;
2580   contents()->ShowContextMenu(rfh, params);
2581 
2582   contents()->SetDelegate(nullptr);
2583 }
2584 
TEST_F(WebContentsImplTest,RegisterProtocolHandlerDifferentOrigin)2585 TEST_F(WebContentsImplTest, RegisterProtocolHandlerDifferentOrigin) {
2586   MockWebContentsDelegate delegate;
2587   contents()->SetDelegate(&delegate);
2588 
2589   GURL url("https://www.google.com");
2590   GURL handler_url1("https://www.google.com/handler/%s");
2591   GURL handler_url2("https://www.example.com/handler/%s");
2592 
2593   contents()->NavigateAndCommit(url);
2594 
2595   // Only the first call to RegisterProtocolHandler should register because the
2596   // other call has a handler from a different origin.
2597   EXPECT_CALL(delegate, RegisterProtocolHandler(main_test_rfh(), "mailto",
2598                                                 handler_url1, true))
2599       .Times(1);
2600   EXPECT_CALL(delegate, RegisterProtocolHandler(main_test_rfh(), "mailto",
2601                                                 handler_url2, true))
2602       .Times(0);
2603 
2604   {
2605     contents()->RegisterProtocolHandler(main_test_rfh(), "mailto", handler_url1,
2606                                         /*user_gesture=*/true);
2607   }
2608 
2609   {
2610     contents()->RegisterProtocolHandler(main_test_rfh(), "mailto", handler_url2,
2611                                         /*user_gesture=*/true);
2612   }
2613 
2614   // Check behavior for RegisterProtocolHandler::kUntrustedOrigins.
2615   MockWebContentsDelegate unrestrictive_delegate(
2616       blink::ProtocolHandlerSecurityLevel::kUntrustedOrigins);
2617   contents()->SetDelegate(&unrestrictive_delegate);
2618   EXPECT_CALL(
2619       unrestrictive_delegate,
2620       RegisterProtocolHandler(main_test_rfh(), "mailto", handler_url1, true))
2621       .Times(1);
2622   EXPECT_CALL(
2623       unrestrictive_delegate,
2624       RegisterProtocolHandler(main_test_rfh(), "mailto", handler_url2, true))
2625       .Times(1);
2626 
2627   {
2628     contents()->RegisterProtocolHandler(main_test_rfh(), "mailto", handler_url1,
2629                                         /*user_gesture=*/true);
2630   }
2631 
2632   {
2633     contents()->RegisterProtocolHandler(main_test_rfh(), "mailto", handler_url2,
2634                                         /*user_gesture=*/true);
2635   }
2636 
2637   contents()->SetDelegate(nullptr);
2638 }
2639 
TEST_F(WebContentsImplTest,RegisterProtocolHandlerDataURL)2640 TEST_F(WebContentsImplTest, RegisterProtocolHandlerDataURL) {
2641   MockWebContentsDelegate delegate;
2642   contents()->SetDelegate(&delegate);
2643 
2644   GURL data("data:text/html,<html><body><b>hello world</b></body></html>");
2645   GURL data_handler(data.spec() + "%s");
2646 
2647   contents()->NavigateAndCommit(data);
2648 
2649   // Data URLs should fail.
2650   EXPECT_CALL(delegate, RegisterProtocolHandler(contents()->GetMainFrame(),
2651                                                 "mailto", data_handler, true))
2652       .Times(0);
2653 
2654   {
2655     contents()->RegisterProtocolHandler(main_test_rfh(), "mailto", data_handler,
2656                                         /*user_gesture=*/true);
2657   }
2658 
2659   contents()->SetDelegate(nullptr);
2660 }
2661 
TEST_F(WebContentsImplTest,Bluetooth)2662 TEST_F(WebContentsImplTest, Bluetooth) {
2663   TestWebContentsObserver observer(contents());
2664   EXPECT_EQ(observer.num_is_connected_to_bluetooth_device_changed(), 0);
2665   EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice());
2666 
2667   contents()->TestIncrementBluetoothConnectedDeviceCount();
2668   EXPECT_EQ(observer.num_is_connected_to_bluetooth_device_changed(), 1);
2669   EXPECT_TRUE(observer.last_is_connected_to_bluetooth_device());
2670   EXPECT_TRUE(contents()->IsConnectedToBluetoothDevice());
2671 
2672   contents()->TestDecrementBluetoothConnectedDeviceCount();
2673   EXPECT_EQ(observer.num_is_connected_to_bluetooth_device_changed(), 2);
2674   EXPECT_FALSE(observer.last_is_connected_to_bluetooth_device());
2675   EXPECT_FALSE(contents()->IsConnectedToBluetoothDevice());
2676 }
2677 
TEST_F(WebContentsImplTest,FaviconURLsSet)2678 TEST_F(WebContentsImplTest, FaviconURLsSet) {
2679   std::vector<blink::mojom::FaviconURLPtr> favicon_urls;
2680   const auto kFavicon =
2681       blink::mojom::FaviconURL(GURL("https://example.com/favicon.ico"),
2682                                blink::mojom::FaviconIconType::kFavicon, {});
2683 
2684   contents()->NavigateAndCommit(GURL("https://example.com"));
2685   EXPECT_EQ(0u, contents()->GetFaviconURLs().size());
2686 
2687   favicon_urls.push_back(blink::mojom::FaviconURL::New(kFavicon));
2688   contents()->UpdateFaviconURL(contents()->GetMainFrame(),
2689                                std::move(favicon_urls));
2690   EXPECT_EQ(1u, contents()->GetFaviconURLs().size());
2691 
2692   favicon_urls.push_back(blink::mojom::FaviconURL::New(kFavicon));
2693   favicon_urls.push_back(blink::mojom::FaviconURL::New(kFavicon));
2694   contents()->UpdateFaviconURL(contents()->GetMainFrame(),
2695                                std::move(favicon_urls));
2696   EXPECT_EQ(2u, contents()->GetFaviconURLs().size());
2697 
2698   favicon_urls.push_back(blink::mojom::FaviconURL::New(kFavicon));
2699   contents()->UpdateFaviconURL(contents()->GetMainFrame(),
2700                                std::move(favicon_urls));
2701   EXPECT_EQ(1u, contents()->GetFaviconURLs().size());
2702 }
2703 
TEST_F(WebContentsImplTest,FaviconURLsResetWithNavigation)2704 TEST_F(WebContentsImplTest, FaviconURLsResetWithNavigation) {
2705   std::vector<blink::mojom::FaviconURLPtr> favicon_urls;
2706   favicon_urls.push_back(blink::mojom::FaviconURL::New(
2707       GURL("https://example.com/favicon.ico"),
2708       blink::mojom::FaviconIconType::kFavicon, std::vector<gfx::Size>()));
2709 
2710   contents()->NavigateAndCommit(GURL("https://example.com"));
2711   EXPECT_EQ(0u, contents()->GetFaviconURLs().size());
2712 
2713   contents()->UpdateFaviconURL(contents()->GetMainFrame(),
2714                                std::move(favicon_urls));
2715   EXPECT_EQ(1u, contents()->GetFaviconURLs().size());
2716 
2717   contents()->NavigateAndCommit(GURL("https://example.com/navigation.html"));
2718   EXPECT_EQ(0u, contents()->GetFaviconURLs().size());
2719 }
2720 
2721 }  // namespace content
2722