web_contents_impl_browsertest.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright 2013 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 "base/values.h" 6#include "content/browser/frame_host/navigation_entry_impl.h" 7#include "content/browser/web_contents/web_contents_impl.h" 8#include "content/public/browser/load_notification_details.h" 9#include "content/public/browser/navigation_controller.h" 10#include "content/public/browser/notification_details.h" 11#include "content/public/browser/notification_observer.h" 12#include "content/public/browser/notification_types.h" 13#include "content/public/browser/render_view_host.h" 14#include "content/public/browser/render_widget_host_view.h" 15#include "content/public/browser/web_contents_observer.h" 16#include "content/public/browser/web_contents_view.h" 17#include "content/public/common/content_paths.h" 18#include "content/public/test/browser_test_utils.h" 19#include "content/public/test/test_utils.h" 20#include "content/shell/browser/shell.h" 21#include "content/test/content_browser_test.h" 22#include "content/test/content_browser_test_utils.h" 23#include "net/test/embedded_test_server/embedded_test_server.h" 24 25namespace content { 26 27void ResizeWebContentsView(Shell* shell, const gfx::Size& size, 28 bool set_start_page) { 29 // Shell::SizeTo is not implemented on Aura; WebContentsView::SizeContents 30 // works on Win and ChromeOS but not Linux - we need to resize the shell 31 // window on Linux because if we don't, the next layout of the unchanged shell 32 // window will resize WebContentsView back to the previous size. 33 // The cleaner and shorter SizeContents is preferred as more platforms convert 34 // to Aura. 35#if defined(TOOLKIT_GTK) || defined(OS_MACOSX) 36 shell->SizeTo(size); 37 // If |set_start_page| is true, start with blank page to make sure resize 38 // takes effect. 39 if (set_start_page) 40 NavigateToURL(shell, GURL("about://blank")); 41#else 42 shell->web_contents()->GetView()->SizeContents(size); 43#endif // defined(TOOLKIT_GTK) || defined(OS_MACOSX) 44} 45 46class WebContentsImplBrowserTest : public ContentBrowserTest { 47 public: 48 WebContentsImplBrowserTest() {} 49 50 private: 51 DISALLOW_COPY_AND_ASSIGN(WebContentsImplBrowserTest); 52}; 53 54// Keeps track of data from LoadNotificationDetails so we can later verify that 55// they are correct, after the LoadNotificationDetails object is deleted. 56class LoadStopNotificationObserver : public WindowedNotificationObserver { 57 public: 58 LoadStopNotificationObserver(NavigationController* controller) 59 : WindowedNotificationObserver(NOTIFICATION_LOAD_STOP, 60 Source<NavigationController>(controller)), 61 session_index_(-1), 62 controller_(NULL) { 63 } 64 virtual void Observe(int type, 65 const NotificationSource& source, 66 const NotificationDetails& details) OVERRIDE { 67 if (type == NOTIFICATION_LOAD_STOP) { 68 const Details<LoadNotificationDetails> load_details(details); 69 url_ = load_details->url; 70 session_index_ = load_details->session_index; 71 controller_ = load_details->controller; 72 } 73 WindowedNotificationObserver::Observe(type, source, details); 74 } 75 76 GURL url_; 77 int session_index_; 78 NavigationController* controller_; 79}; 80 81// Starts a new navigation as soon as the current one commits, but does not 82// wait for it to complete. This allows us to observe DidStopLoading while 83// a pending entry is present. 84class NavigateOnCommitObserver : public WebContentsObserver { 85 public: 86 NavigateOnCommitObserver(Shell* shell, GURL url) 87 : WebContentsObserver(shell->web_contents()), 88 shell_(shell), 89 url_(url), 90 done_(false) { 91 } 92 93 // WebContentsObserver: 94 virtual void NavigationEntryCommitted( 95 const LoadCommittedDetails& load_details) OVERRIDE { 96 if (!done_) { 97 done_ = true; 98 shell_->LoadURL(url_); 99 } 100 } 101 102 Shell* shell_; 103 GURL url_; 104 bool done_; 105}; 106 107class RenderViewSizeDelegate : public WebContentsDelegate { 108 public: 109 void set_size_insets(const gfx::Size& size_insets) { 110 size_insets_ = size_insets; 111 } 112 113 // WebContentsDelegate: 114 virtual gfx::Size GetSizeForNewRenderView( 115 const WebContents* web_contents) const OVERRIDE { 116 gfx::Size size(web_contents->GetView()->GetContainerSize()); 117 size.Enlarge(size_insets_.width(), size_insets_.height()); 118 return size; 119 } 120 121 private: 122 gfx::Size size_insets_; 123}; 124 125class RenderViewSizeObserver : public WebContentsObserver { 126 public: 127 RenderViewSizeObserver(Shell* shell, const gfx::Size& wcv_new_size) 128 : WebContentsObserver(shell->web_contents()), 129 shell_(shell), 130 wcv_new_size_(wcv_new_size) { 131 } 132 133 // WebContentsObserver: 134 virtual void RenderViewCreated(RenderViewHost* rvh) OVERRIDE { 135 rwhv_create_size_ = rvh->GetView()->GetViewBounds().size(); 136 } 137 138 virtual void DidStartNavigationToPendingEntry( 139 const GURL& url, 140 NavigationController::ReloadType reload_type) OVERRIDE { 141 ResizeWebContentsView(shell_, wcv_new_size_, false); 142 } 143 144 gfx::Size rwhv_create_size() const { return rwhv_create_size_; } 145 146 private: 147 Shell* shell_; // Weak ptr. 148 gfx::Size wcv_new_size_; 149 gfx::Size rwhv_create_size_; 150}; 151 152// See: http://crbug.com/298193 153#if defined(OS_WIN) 154#define MAYBE_DidStopLoadingDetails DISABLED_DidStopLoadingDetails 155#else 156#define MAYBE_DidStopLoadingDetails DidStopLoadingDetails 157#endif 158 159// Test that DidStopLoading includes the correct URL in the details. 160IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, 161 MAYBE_DidStopLoadingDetails) { 162 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 163 164 LoadStopNotificationObserver load_observer( 165 &shell()->web_contents()->GetController()); 166 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); 167 load_observer.Wait(); 168 169 EXPECT_EQ("/title1.html", load_observer.url_.path()); 170 EXPECT_EQ(0, load_observer.session_index_); 171 EXPECT_EQ(&shell()->web_contents()->GetController(), 172 load_observer.controller_); 173} 174 175// See: http://crbug.com/298193 176#if defined(OS_WIN) 177#define MAYBE_DidStopLoadingDetailsWithPending \ 178 DISABLED_DidStopLoadingDetailsWithPending 179#else 180#define MAYBE_DidStopLoadingDetailsWithPending DidStopLoadingDetailsWithPending 181#endif 182 183// Test that DidStopLoading includes the correct URL in the details when a 184// pending entry is present. 185IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, 186 MAYBE_DidStopLoadingDetailsWithPending) { 187 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 188 189 // Listen for the first load to stop. 190 LoadStopNotificationObserver load_observer( 191 &shell()->web_contents()->GetController()); 192 // Start a new pending navigation as soon as the first load commits. 193 // We will hear a DidStopLoading from the first load as the new load 194 // is started. 195 NavigateOnCommitObserver commit_observer( 196 shell(), embedded_test_server()->GetURL("/title2.html")); 197 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); 198 load_observer.Wait(); 199 200 EXPECT_EQ("/title1.html", load_observer.url_.path()); 201 EXPECT_EQ(0, load_observer.session_index_); 202 EXPECT_EQ(&shell()->web_contents()->GetController(), 203 load_observer.controller_); 204} 205// Test that a renderer-initiated navigation to an invalid URL does not leave 206// around a pending entry that could be used in a URL spoof. We test this in 207// a browser test because our unit test framework incorrectly calls 208// DidStartProvisionalLoadForFrame for in-page navigations. 209// See http://crbug.com/280512. 210IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, 211 ClearNonVisiblePendingOnFail) { 212 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 213 214 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); 215 216 // Navigate to an invalid URL and make sure it doesn't leave a pending entry. 217 LoadStopNotificationObserver load_observer1( 218 &shell()->web_contents()->GetController()); 219 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), 220 "window.location.href=\"nonexistent:12121\";")); 221 load_observer1.Wait(); 222 EXPECT_FALSE(shell()->web_contents()->GetController().GetPendingEntry()); 223 224 LoadStopNotificationObserver load_observer2( 225 &shell()->web_contents()->GetController()); 226 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), 227 "window.location.href=\"#foo\";")); 228 load_observer2.Wait(); 229 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html#foo"), 230 shell()->web_contents()->GetVisibleURL()); 231} 232 233// TODO(sail): enable this for MAC when auto resizing of WebContentsViewCocoa is 234// fixed. 235// TODO(shrikant): enable this for Windows when issue with 236// force-compositing-mode is resolved (http://crbug.com/281726). 237#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_ANDROID) 238#define MAYBE_GetSizeForNewRenderView DISABLED_GetSizeForNewRenderView 239#else 240#define MAYBE_GetSizeForNewRenderView GetSizeForNewRenderView 241#endif 242// Test that RenderViewHost is created and updated at the size specified by 243// WebContentsDelegate::GetSizeForNewRenderView(). 244IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, 245 MAYBE_GetSizeForNewRenderView) { 246 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 247 // Create a new server with a different site. 248 net::SpawnedTestServer https_server( 249 net::SpawnedTestServer::TYPE_HTTPS, 250 net::SpawnedTestServer::kLocalhost, 251 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); 252 ASSERT_TRUE(https_server.Start()); 253 254 scoped_ptr<RenderViewSizeDelegate> delegate(new RenderViewSizeDelegate()); 255 shell()->web_contents()->SetDelegate(delegate.get()); 256 ASSERT_TRUE(shell()->web_contents()->GetDelegate() == delegate.get()); 257 258 // When no size is set, RenderWidgetHostView adopts the size of 259 // WebContenntsView. 260 NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html")); 261 EXPECT_EQ(shell()->web_contents()->GetView()->GetContainerSize(), 262 shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds(). 263 size()); 264 265 // When a size is set, RenderWidgetHostView and WebContentsView honor this 266 // size. 267 gfx::Size size(300, 300); 268 gfx::Size size_insets(-10, -15); 269 ResizeWebContentsView(shell(), size, true); 270 delegate->set_size_insets(size_insets); 271 NavigateToURL(shell(), https_server.GetURL("/")); 272 size.Enlarge(size_insets.width(), size_insets.height()); 273 EXPECT_EQ(size, 274 shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds(). 275 size()); 276 EXPECT_EQ(size, shell()->web_contents()->GetView()->GetContainerSize()); 277 278 // If WebContentsView is resized after RenderWidgetHostView is created but 279 // before pending navigation entry is committed, both RenderWidgetHostView and 280 // WebContentsView use the new size of WebContentsView. 281 gfx::Size init_size(200, 200); 282 gfx::Size new_size(100, 100); 283 size_insets = gfx::Size(-20, -30); 284 ResizeWebContentsView(shell(), init_size, true); 285 delegate->set_size_insets(size_insets); 286 RenderViewSizeObserver observer(shell(), new_size); 287 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); 288 // RenderWidgetHostView is created at specified size. 289 init_size.Enlarge(size_insets.width(), size_insets.height()); 290 EXPECT_EQ(init_size, observer.rwhv_create_size()); 291 // RenderViewSizeObserver resizes WebContentsView in 292 // DidStartNavigationToPendingEntry, so both WebContentsView and 293 // RenderWidgetHostView adopt this new size. 294 new_size.Enlarge(size_insets.width(), size_insets.height()); 295 EXPECT_EQ(new_size, 296 shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds(). 297 size()); 298 EXPECT_EQ(new_size, shell()->web_contents()->GetView()->GetContainerSize()); 299} 300 301IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, OpenURLSubframe) { 302 303 // Navigate with source_frame_id 3, FrameTreeNode ID 4. 304 const GURL url("http://foo"); 305 OpenURLParams params(url, Referrer(), 3, 4, CURRENT_TAB, PAGE_TRANSITION_LINK, 306 true); 307 shell()->web_contents()->OpenURL(params); 308 309 // Make sure the NavigationEntry ends up with the FrameTreeNode ID. 310 NavigationController* controller = &shell()->web_contents()->GetController(); 311 EXPECT_TRUE(controller->GetPendingEntry()); 312 EXPECT_EQ(4, NavigationEntryImpl::FromNavigationEntry( 313 controller->GetPendingEntry())->frame_tree_node_id()); 314} 315 316 317} // namespace content 318