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