[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 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 | |
dmazzoni | 0b5d248 | 2014-09-10 19:45:57 | [diff] [blame] | 5 | #include "content/browser/site_per_process_browsertest.h" |
| 6 | |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | #include <stdint.h> |
| 9 | |
nick | 59dcb16 | 2015-04-09 20:29:01 | [diff] [blame] | 10 | #include <algorithm> |
| 11 | #include <vector> |
| 12 | |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 13 | #include "base/command_line.h" |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 14 | #include "base/location.h" |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 15 | #include "base/macros.h" |
nasko | 39e3eb7 | 2016-06-24 23:15:44 | [diff] [blame] | 16 | #include "base/path_service.h" |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 17 | #include "base/single_thread_task_runner.h" |
brettw | d97eede | 2015-07-06 22:09:00 | [diff] [blame] | 18 | #include "base/strings/pattern.h" |
[email protected] | 348fbaac | 2013-06-11 06:31:51 | [diff] [blame] | 19 | #include "base/strings/stringprintf.h" |
lfg | 9ef7d2d | 2014-12-15 22:32:30 | [diff] [blame] | 20 | #include "base/strings/utf_string_conversions.h" |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 21 | #include "base/test/test_timeouts.h" |
gab | 30f26df | 2016-05-11 19:37:55 | [diff] [blame] | 22 | #include "base/threading/thread_task_runner_handle.h" |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 23 | #include "build/build_config.h" |
bnc | 210d6f3 | 2016-05-24 07:40:47 | [diff] [blame] | 24 | #include "components/network_session_configurator/switches.h" |
[email protected] | 9a1abe7 | 2014-06-19 23:49:02 | [diff] [blame] | 25 | #include "content/browser/frame_host/cross_process_frame_connector.h" |
[email protected] | d4a8ca48 | 2013-10-30 21:06:40 | [diff] [blame] | 26 | #include "content/browser/frame_host/frame_tree.h" |
csharrison | 264bca64 | 2016-05-06 19:27:09 | [diff] [blame] | 27 | #include "content/browser/frame_host/interstitial_page_impl.h" |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 28 | #include "content/browser/frame_host/navigator.h" |
[email protected] | 9a1abe7 | 2014-06-19 23:49:02 | [diff] [blame] | 29 | #include "content/browser/frame_host/render_frame_proxy_host.h" |
| 30 | #include "content/browser/frame_host/render_widget_host_view_child_frame.h" |
kenrb | 2a565f8 | 2015-09-02 20:24:59 | [diff] [blame] | 31 | #include "content/browser/gpu/compositor_util.h" |
estark | 693d128 | 2016-03-15 22:41:29 | [diff] [blame] | 32 | #include "content/browser/loader/resource_dispatcher_host_impl.h" |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 33 | #include "content/browser/renderer_host/input/synthetic_tap_gesture.h" |
[email protected] | 9b159a5 | 2013-10-03 17:24:55 | [diff] [blame] | 34 | #include "content/browser/renderer_host/render_view_host_impl.h" |
kenrb | 2a565f8 | 2015-09-02 20:24:59 | [diff] [blame] | 35 | #include "content/browser/renderer_host/render_widget_host_input_event_router.h" |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 36 | #include "content/browser/renderer_host/render_widget_host_view_aura.h" |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 37 | #include "content/common/child_process_messages.h" |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 38 | #include "content/common/frame_messages.h" |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 39 | #include "content/common/input/synthetic_tap_gesture_params.h" |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 40 | #include "content/common/input_messages.h" |
kenrb | 77db507 | 2015-10-15 19:21:25 | [diff] [blame] | 41 | #include "content/common/view_messages.h" |
estark | 693d128 | 2016-03-15 22:41:29 | [diff] [blame] | 42 | #include "content/public/browser/cert_store.h" |
csharrison | 264bca64 | 2016-05-06 19:27:09 | [diff] [blame] | 43 | #include "content/public/browser/interstitial_page_delegate.h" |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 44 | #include "content/public/browser/notification_observer.h" |
| 45 | #include "content/public/browser/notification_service.h" |
| 46 | #include "content/public/browser/notification_types.h" |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 47 | #include "content/public/browser/resource_dispatcher_host.h" |
carlosk | d80262f5 | 2015-12-16 14:40:35 | [diff] [blame] | 48 | #include "content/public/common/browser_side_navigation_policy.h" |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 49 | #include "content/public/common/content_switches.h" |
alexmos | 5b50b674 | 2016-03-17 20:38:05 | [diff] [blame] | 50 | #include "content/public/common/url_constants.h" |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 51 | #include "content/public/test/browser_test_utils.h" |
[email protected] | 6e9def1 | 2014-03-27 20:23:28 | [diff] [blame] | 52 | #include "content/public/test/content_browser_test_utils.h" |
nasko | 3e8c20e | 2014-12-18 06:54:56 | [diff] [blame] | 53 | #include "content/public/test/test_navigation_observer.h" |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 54 | #include "content/public/test/test_utils.h" |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 55 | #include "content/test/content_browser_test_utils_internal.h" |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 56 | #include "content/test/test_frame_navigation_observer.h" |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 57 | #include "ipc/ipc_security_test_util.h" |
[email protected] | 9b159a5 | 2013-10-03 17:24:55 | [diff] [blame] | 58 | #include "net/dns/mock_host_resolver.h" |
nasko | cbce0e6 | 2014-10-07 14:04:26 | [diff] [blame] | 59 | #include "net/test/embedded_test_server/embedded_test_server.h" |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 60 | #include "testing/gtest/include/gtest/gtest.h" |
mkwst | f672e7ef | 2016-06-09 20:51:07 | [diff] [blame] | 61 | #include "third_party/WebKit/public/platform/WebInsecureRequestPolicy.h" |
kenrb | 2a565f8 | 2015-09-02 20:24:59 | [diff] [blame] | 62 | #include "third_party/WebKit/public/web/WebInputEvent.h" |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 63 | #include "third_party/WebKit/public/web/WebSandboxFlags.h" |
oshima | 06b3960 | 2016-05-11 02:40:10 | [diff] [blame] | 64 | #include "ui/display/display_switches.h" |
wjmaclean | fab616a | 2016-03-02 18:40:39 | [diff] [blame] | 65 | #include "ui/events/event.h" |
| 66 | #include "ui/events/event_utils.h" |
| 67 | #include "ui/gfx/geometry/point.h" |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 68 | |
wjmaclean | fab616a | 2016-03-02 18:40:39 | [diff] [blame] | 69 | #if defined(USE_AURA) |
| 70 | #include "content/browser/renderer_host/render_widget_host_view_aura.h" |
| 71 | #endif |
| 72 | |
ahest | 1d019b7 | 2016-02-02 07:24:42 | [diff] [blame] | 73 | #if defined(OS_MACOSX) |
spqchan | 83534ab0 | 2016-02-23 19:28:27 | [diff] [blame] | 74 | #include "ui/base/test/scoped_preferred_scroller_style_mac.h" |
ahest | 1d019b7 | 2016-02-02 07:24:42 | [diff] [blame] | 75 | #endif |
| 76 | |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 77 | namespace content { |
| 78 | |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 79 | namespace { |
| 80 | |
| 81 | // Helper function to send a postMessage and wait for a reply message. The |
| 82 | // |post_message_script| is executed on the |sender_ftn| frame, and the sender |
| 83 | // frame is expected to post |reply_status| from the DOMAutomationController |
| 84 | // when it receives a reply. |
| 85 | void PostMessageAndWaitForReply(FrameTreeNode* sender_ftn, |
| 86 | const std::string& post_message_script, |
| 87 | const std::string& reply_status) { |
alexmos | 17e5753 | 2015-08-15 02:54:36 | [diff] [blame] | 88 | // Subtle: msg_queue needs to be declared before the ExecuteScript below, or |
| 89 | // else it might miss the message of interest. See https://crbug.com/518729. |
| 90 | DOMMessageQueue msg_queue; |
| 91 | |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 92 | bool success = false; |
| 93 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 94 | sender_ftn, |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 95 | "window.domAutomationController.send(" + post_message_script + ");", |
| 96 | &success)); |
| 97 | EXPECT_TRUE(success); |
| 98 | |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 99 | std::string status; |
| 100 | while (msg_queue.WaitForMessage(&status)) { |
| 101 | if (status == reply_status) |
| 102 | break; |
| 103 | } |
| 104 | } |
| 105 | |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 106 | // Helper function to extract and return "window.receivedMessages" from the |
| 107 | // |sender_ftn| frame. This variable is used in post_message.html to count the |
| 108 | // number of messages received via postMessage by the current window. |
| 109 | int GetReceivedMessages(FrameTreeNode* ftn) { |
| 110 | int received_messages = 0; |
| 111 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 112 | ftn, "window.domAutomationController.send(window.receivedMessages);", |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 113 | &received_messages)); |
| 114 | return received_messages; |
| 115 | } |
| 116 | |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 117 | // Helper function to perform a window.open from the |caller_frame| targeting a |
| 118 | // frame with the specified name. |
| 119 | void NavigateNamedFrame(const ToRenderFrameHost& caller_frame, |
| 120 | const GURL& url, |
| 121 | const std::string& name) { |
| 122 | bool success = false; |
| 123 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
| 124 | caller_frame, |
| 125 | "window.domAutomationController.send(" |
| 126 | " !!window.open('" + url.spec() + "', '" + name + "'));", |
| 127 | &success)); |
| 128 | EXPECT_TRUE(success); |
| 129 | } |
| 130 | |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 131 | // Helper function to generate a click on the given RenderWidgetHost. The |
| 132 | // mouse event is forwarded directly to the RenderWidgetHost without any |
| 133 | // hit-testing. |
| 134 | void SimulateMouseClick(RenderWidgetHost* rwh, int x, int y) { |
| 135 | blink::WebMouseEvent mouse_event; |
| 136 | mouse_event.type = blink::WebInputEvent::MouseDown; |
| 137 | mouse_event.button = blink::WebPointerProperties::ButtonLeft; |
| 138 | mouse_event.x = x; |
| 139 | mouse_event.y = y; |
| 140 | rwh->ForwardMouseEvent(mouse_event); |
| 141 | } |
| 142 | |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 143 | // Retrieve document.origin for the frame |ftn|. |
| 144 | std::string GetDocumentOrigin(FrameTreeNode* ftn) { |
| 145 | std::string origin; |
| 146 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 147 | ftn, "domAutomationController.send(document.origin)", &origin)); |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 148 | return origin; |
| 149 | } |
| 150 | |
lfg | 52bac907 | 2015-11-06 17:27:52 | [diff] [blame] | 151 | class RenderWidgetHostMouseEventMonitor { |
| 152 | public: |
| 153 | explicit RenderWidgetHostMouseEventMonitor(RenderWidgetHost* host) |
| 154 | : host_(host), event_received_(false) { |
| 155 | host_->AddMouseEventCallback( |
| 156 | base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback, |
| 157 | base::Unretained(this))); |
| 158 | } |
| 159 | ~RenderWidgetHostMouseEventMonitor() { |
| 160 | host_->RemoveMouseEventCallback( |
| 161 | base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback, |
| 162 | base::Unretained(this))); |
| 163 | } |
| 164 | bool EventWasReceived() const { return event_received_; } |
| 165 | void ResetEventReceived() { event_received_ = false; } |
| 166 | const blink::WebMouseEvent& event() const { return event_; } |
| 167 | |
| 168 | private: |
| 169 | bool MouseEventCallback(const blink::WebMouseEvent& event) { |
| 170 | event_received_ = true; |
| 171 | event_ = event; |
| 172 | return false; |
| 173 | } |
| 174 | RenderWidgetHost* host_; |
| 175 | bool event_received_; |
| 176 | blink::WebMouseEvent event_; |
| 177 | |
| 178 | DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostMouseEventMonitor); |
| 179 | }; |
| 180 | |
kenrb | 0b67820 | 2016-06-23 19:07:35 | [diff] [blame] | 181 | class TestInputEventObserver : public RenderWidgetHost::InputEventObserver { |
| 182 | public: |
| 183 | explicit TestInputEventObserver(RenderWidgetHost* host) |
| 184 | : host_(host), |
| 185 | event_received_(false), |
| 186 | last_event_type_(blink::WebInputEvent::Undefined) { |
| 187 | host_->AddInputEventObserver(this); |
| 188 | } |
| 189 | |
| 190 | ~TestInputEventObserver() override { host_->RemoveInputEventObserver(this); } |
| 191 | |
| 192 | bool EventWasReceived() const { return event_received_; } |
| 193 | void ResetEventReceived() { event_received_ = false; } |
| 194 | blink::WebInputEvent::Type EventType() const { return last_event_type_; } |
| 195 | |
| 196 | void OnInputEvent(const blink::WebInputEvent& event) override { |
| 197 | event_received_ = true; |
| 198 | last_event_type_ = event.type; |
| 199 | }; |
| 200 | |
| 201 | RenderWidgetHost* host_; |
| 202 | bool event_received_; |
| 203 | blink::WebInputEvent::Type last_event_type_; |
| 204 | |
| 205 | DISALLOW_COPY_AND_ASSIGN(TestInputEventObserver); |
| 206 | }; |
| 207 | |
lfg | 52bac907 | 2015-11-06 17:27:52 | [diff] [blame] | 208 | // Helper function that performs a surface hittest. |
| 209 | void SurfaceHitTestTestHelper( |
| 210 | Shell* shell, |
| 211 | net::test_server::EmbeddedTestServer* embedded_test_server) { |
lfg | 52bac907 | 2015-11-06 17:27:52 | [diff] [blame] | 212 | GURL main_url(embedded_test_server->GetURL( |
| 213 | "/frame_tree/page_with_positioned_frame.html")); |
| 214 | NavigateToURL(shell, main_url); |
| 215 | |
| 216 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
| 217 | FrameTreeNode* root = static_cast<WebContentsImpl*>(shell->web_contents()) |
| 218 | ->GetFrameTree() |
| 219 | ->root(); |
| 220 | ASSERT_EQ(1U, root->child_count()); |
| 221 | |
| 222 | FrameTreeNode* child_node = root->child_at(0); |
| 223 | GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html")); |
| 224 | EXPECT_EQ(site_url, child_node->current_url()); |
| 225 | EXPECT_NE(shell->web_contents()->GetSiteInstance(), |
| 226 | child_node->current_frame_host()->GetSiteInstance()); |
| 227 | |
| 228 | // Create listeners for mouse events. |
| 229 | RenderWidgetHostMouseEventMonitor main_frame_monitor( |
| 230 | root->current_frame_host()->GetRenderWidgetHost()); |
| 231 | RenderWidgetHostMouseEventMonitor child_frame_monitor( |
| 232 | child_node->current_frame_host()->GetRenderWidgetHost()); |
| 233 | |
| 234 | RenderWidgetHostInputEventRouter* router = |
| 235 | static_cast<WebContentsImpl*>(shell->web_contents()) |
| 236 | ->GetInputEventRouter(); |
| 237 | |
| 238 | RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>( |
| 239 | root->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 240 | RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>( |
| 241 | child_node->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 242 | |
kenrb | e975655 | 2016-02-27 00:53:50 | [diff] [blame] | 243 | SurfaceHitTestReadyNotifier notifier( |
| 244 | static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child)); |
| 245 | notifier.WaitForSurfaceReady(); |
lfg | 52bac907 | 2015-11-06 17:27:52 | [diff] [blame] | 246 | |
| 247 | // Target input event to child frame. |
| 248 | blink::WebMouseEvent child_event; |
| 249 | child_event.type = blink::WebInputEvent::MouseDown; |
| 250 | child_event.button = blink::WebPointerProperties::ButtonLeft; |
| 251 | child_event.x = 75; |
| 252 | child_event.y = 75; |
| 253 | child_event.clickCount = 1; |
| 254 | main_frame_monitor.ResetEventReceived(); |
| 255 | child_frame_monitor.ResetEventReceived(); |
| 256 | router->RouteMouseEvent(root_view, &child_event); |
| 257 | |
lfg | 52bac907 | 2015-11-06 17:27:52 | [diff] [blame] | 258 | EXPECT_TRUE(child_frame_monitor.EventWasReceived()); |
| 259 | EXPECT_EQ(23, child_frame_monitor.event().x); |
| 260 | EXPECT_EQ(23, child_frame_monitor.event().y); |
| 261 | EXPECT_FALSE(main_frame_monitor.EventWasReceived()); |
| 262 | |
| 263 | child_frame_monitor.ResetEventReceived(); |
| 264 | main_frame_monitor.ResetEventReceived(); |
| 265 | |
| 266 | // Target input event to main frame. |
| 267 | blink::WebMouseEvent main_event; |
| 268 | main_event.type = blink::WebInputEvent::MouseDown; |
| 269 | main_event.button = blink::WebPointerProperties::ButtonLeft; |
| 270 | main_event.x = 1; |
| 271 | main_event.y = 1; |
| 272 | main_event.clickCount = 1; |
| 273 | // Ladies and gentlemen, THIS is the main_event! |
| 274 | router->RouteMouseEvent(root_view, &main_event); |
| 275 | |
| 276 | EXPECT_FALSE(child_frame_monitor.EventWasReceived()); |
| 277 | EXPECT_TRUE(main_frame_monitor.EventWasReceived()); |
| 278 | EXPECT_EQ(1, main_frame_monitor.event().x); |
| 279 | EXPECT_EQ(1, main_frame_monitor.event().y); |
| 280 | } |
| 281 | |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 282 | class RedirectNotificationObserver : public NotificationObserver { |
| 283 | public: |
| 284 | // Register to listen for notifications of the given type from either a |
| 285 | // specific source, or from all sources if |source| is |
| 286 | // NotificationService::AllSources(). |
| 287 | RedirectNotificationObserver(int notification_type, |
| 288 | const NotificationSource& source); |
dcheng | c2282aa | 2014-10-21 12:07:58 | [diff] [blame] | 289 | ~RedirectNotificationObserver() override; |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 290 | |
| 291 | // Wait until the specified notification occurs. If the notification was |
| 292 | // emitted between the construction of this object and this call then it |
| 293 | // returns immediately. |
| 294 | void Wait(); |
| 295 | |
| 296 | // Returns NotificationService::AllSources() if we haven't observed a |
| 297 | // notification yet. |
| 298 | const NotificationSource& source() const { |
| 299 | return source_; |
| 300 | } |
| 301 | |
| 302 | const NotificationDetails& details() const { |
| 303 | return details_; |
| 304 | } |
| 305 | |
| 306 | // NotificationObserver: |
dcheng | c2282aa | 2014-10-21 12:07:58 | [diff] [blame] | 307 | void Observe(int type, |
| 308 | const NotificationSource& source, |
| 309 | const NotificationDetails& details) override; |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 310 | |
| 311 | private: |
| 312 | bool seen_; |
| 313 | bool seen_twice_; |
| 314 | bool running_; |
| 315 | NotificationRegistrar registrar_; |
| 316 | |
| 317 | NotificationSource source_; |
| 318 | NotificationDetails details_; |
| 319 | scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 320 | |
| 321 | DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver); |
| 322 | }; |
| 323 | |
| 324 | RedirectNotificationObserver::RedirectNotificationObserver( |
| 325 | int notification_type, |
| 326 | const NotificationSource& source) |
| 327 | : seen_(false), |
| 328 | running_(false), |
| 329 | source_(NotificationService::AllSources()) { |
| 330 | registrar_.Add(this, notification_type, source); |
| 331 | } |
| 332 | |
| 333 | RedirectNotificationObserver::~RedirectNotificationObserver() {} |
| 334 | |
| 335 | void RedirectNotificationObserver::Wait() { |
| 336 | if (seen_ && seen_twice_) |
| 337 | return; |
| 338 | |
| 339 | running_ = true; |
| 340 | message_loop_runner_ = new MessageLoopRunner; |
| 341 | message_loop_runner_->Run(); |
| 342 | EXPECT_TRUE(seen_); |
| 343 | } |
| 344 | |
| 345 | void RedirectNotificationObserver::Observe( |
| 346 | int type, |
| 347 | const NotificationSource& source, |
| 348 | const NotificationDetails& details) { |
| 349 | source_ = source; |
| 350 | details_ = details; |
| 351 | seen_twice_ = seen_; |
| 352 | seen_ = true; |
| 353 | if (!running_) |
| 354 | return; |
| 355 | |
| 356 | message_loop_runner_->Quit(); |
| 357 | running_ = false; |
| 358 | } |
| 359 | |
alexmos | 35d7b93 | 2014-12-05 03:55:23 | [diff] [blame] | 360 | // This observer keeps track of the number of created RenderFrameHosts. Tests |
| 361 | // can use this to ensure that a certain number of child frames has been |
| 362 | // created after navigating. |
| 363 | class RenderFrameHostCreatedObserver : public WebContentsObserver { |
| 364 | public: |
| 365 | RenderFrameHostCreatedObserver(WebContents* web_contents, |
| 366 | int expected_frame_count) |
| 367 | : WebContentsObserver(web_contents), |
| 368 | expected_frame_count_(expected_frame_count), |
| 369 | frames_created_(0), |
| 370 | message_loop_runner_(new MessageLoopRunner) {} |
| 371 | |
| 372 | ~RenderFrameHostCreatedObserver() override; |
| 373 | |
| 374 | // Runs a nested message loop and blocks until the expected number of |
| 375 | // RenderFrameHosts is created. |
| 376 | void Wait(); |
| 377 | |
| 378 | private: |
| 379 | // WebContentsObserver |
| 380 | void RenderFrameCreated(RenderFrameHost* render_frame_host) override; |
| 381 | |
| 382 | // The number of RenderFrameHosts to wait for. |
| 383 | int expected_frame_count_; |
| 384 | |
| 385 | // The number of RenderFrameHosts that have been created. |
| 386 | int frames_created_; |
| 387 | |
| 388 | // The MessageLoopRunner used to spin the message loop. |
| 389 | scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 390 | |
| 391 | DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver); |
| 392 | }; |
| 393 | |
| 394 | RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() { |
| 395 | } |
| 396 | |
| 397 | void RenderFrameHostCreatedObserver::Wait() { |
| 398 | message_loop_runner_->Run(); |
| 399 | } |
| 400 | |
| 401 | void RenderFrameHostCreatedObserver::RenderFrameCreated( |
| 402 | RenderFrameHost* render_frame_host) { |
| 403 | frames_created_++; |
| 404 | if (frames_created_ == expected_frame_count_) { |
| 405 | message_loop_runner_->Quit(); |
| 406 | } |
| 407 | } |
| 408 | |
kenrb | 1922185 | 2016-04-29 17:21:40 | [diff] [blame] | 409 | // This observer detects when WebContents receives notification of a user |
| 410 | // gesture having occurred, following a user input event targeted to |
| 411 | // a RenderWidgetHost under that WebContents. |
| 412 | class UserInteractionObserver : public WebContentsObserver { |
| 413 | public: |
| 414 | explicit UserInteractionObserver(WebContents* web_contents) |
| 415 | : WebContentsObserver(web_contents), user_interaction_received_(false) {} |
| 416 | |
| 417 | ~UserInteractionObserver() override {} |
| 418 | |
| 419 | // Retrieve the flag. There is no need to wait on a loop since |
| 420 | // DidGetUserInteraction() should be called synchronously with the input |
| 421 | // event processing in the browser process. |
| 422 | bool WasUserInteractionReceived() { return user_interaction_received_; } |
| 423 | |
| 424 | void Reset() { user_interaction_received_ = false; } |
| 425 | |
| 426 | private: |
| 427 | // WebContentsObserver |
| 428 | void DidGetUserInteraction(const blink::WebInputEvent::Type type) override { |
| 429 | user_interaction_received_ = true; |
| 430 | } |
| 431 | |
| 432 | bool user_interaction_received_; |
| 433 | |
| 434 | DISALLOW_COPY_AND_ASSIGN(UserInteractionObserver); |
| 435 | }; |
| 436 | |
alexmos | 21acae5 | 2015-11-07 01:04:43 | [diff] [blame] | 437 | // This observer is used to wait for its owner FrameTreeNode to become focused. |
| 438 | class FrameFocusedObserver : public FrameTreeNode::Observer { |
| 439 | public: |
| 440 | FrameFocusedObserver(FrameTreeNode* owner) |
| 441 | : owner_(owner), message_loop_runner_(new MessageLoopRunner) { |
| 442 | owner->AddObserver(this); |
| 443 | } |
| 444 | |
| 445 | ~FrameFocusedObserver() override { owner_->RemoveObserver(this); } |
| 446 | |
| 447 | void Wait() { message_loop_runner_->Run(); } |
| 448 | |
| 449 | private: |
| 450 | // FrameTreeNode::Observer |
| 451 | void OnFrameTreeNodeFocused(FrameTreeNode* node) override { |
| 452 | if (node == owner_) |
| 453 | message_loop_runner_->Quit(); |
| 454 | } |
| 455 | |
| 456 | FrameTreeNode* owner_; |
| 457 | scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 458 | |
| 459 | DISALLOW_COPY_AND_ASSIGN(FrameFocusedObserver); |
| 460 | }; |
| 461 | |
alexmos | ba1fb715 | 2015-12-12 07:20:30 | [diff] [blame] | 462 | // This observer is used to wait for its owner FrameTreeNode to become deleted. |
| 463 | class FrameDeletedObserver : public FrameTreeNode::Observer { |
| 464 | public: |
| 465 | FrameDeletedObserver(FrameTreeNode* owner) |
| 466 | : owner_(owner), message_loop_runner_(new MessageLoopRunner) { |
| 467 | owner->AddObserver(this); |
| 468 | } |
| 469 | |
| 470 | void Wait() { message_loop_runner_->Run(); } |
| 471 | |
| 472 | private: |
| 473 | // FrameTreeNode::Observer |
| 474 | void OnFrameTreeNodeDestroyed(FrameTreeNode* node) override { |
| 475 | if (node == owner_) |
| 476 | message_loop_runner_->Quit(); |
| 477 | } |
| 478 | |
| 479 | FrameTreeNode* owner_; |
| 480 | scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 481 | |
| 482 | DISALLOW_COPY_AND_ASSIGN(FrameDeletedObserver); |
| 483 | }; |
| 484 | |
alexmos | 21acae5 | 2015-11-07 01:04:43 | [diff] [blame] | 485 | // Helper function to focus a frame by sending it a mouse click and then |
| 486 | // waiting for it to become focused. |
| 487 | void FocusFrame(FrameTreeNode* frame) { |
| 488 | FrameFocusedObserver focus_observer(frame); |
| 489 | SimulateMouseClick(frame->current_frame_host()->GetRenderWidgetHost(), 1, 1); |
| 490 | focus_observer.Wait(); |
| 491 | } |
| 492 | |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 493 | // A BrowserMessageFilter that drops SwapOut ACK messages. |
| 494 | class SwapoutACKMessageFilter : public BrowserMessageFilter { |
| 495 | public: |
| 496 | SwapoutACKMessageFilter() : BrowserMessageFilter(FrameMsgStart) {} |
| 497 | |
| 498 | protected: |
| 499 | ~SwapoutACKMessageFilter() override {} |
| 500 | |
| 501 | private: |
| 502 | // BrowserMessageFilter: |
| 503 | bool OnMessageReceived(const IPC::Message& message) override { |
| 504 | return message.type() == FrameHostMsg_SwapOut_ACK::ID; |
| 505 | } |
| 506 | |
| 507 | DISALLOW_COPY_AND_ASSIGN(SwapoutACKMessageFilter); |
| 508 | }; |
| 509 | |
ekaramad | babb9bf | 2016-01-12 15:17:02 | [diff] [blame] | 510 | class RenderWidgetHostVisibilityObserver : public NotificationObserver { |
| 511 | public: |
| 512 | explicit RenderWidgetHostVisibilityObserver(RenderWidgetHostImpl* rwhi, |
| 513 | bool expected_visibility_state) |
| 514 | : expected_visibility_state_(expected_visibility_state), |
| 515 | was_observed_(false), |
| 516 | did_fail_(false), |
| 517 | source_(rwhi) { |
| 518 | registrar_.Add(this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, |
| 519 | source_); |
| 520 | message_loop_runner_ = new MessageLoopRunner; |
| 521 | } |
| 522 | |
| 523 | bool WaitUntilSatisfied() { |
| 524 | if (!was_observed_) |
| 525 | message_loop_runner_->Run(); |
| 526 | registrar_.Remove(this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, |
| 527 | source_); |
| 528 | return !did_fail_; |
| 529 | } |
| 530 | |
| 531 | private: |
| 532 | void Observe(int type, |
| 533 | const NotificationSource& source, |
| 534 | const NotificationDetails& details) override { |
| 535 | was_observed_ = true; |
| 536 | did_fail_ = expected_visibility_state_ != |
| 537 | (*static_cast<const Details<bool>&>(details).ptr()); |
| 538 | if (message_loop_runner_->loop_running()) |
| 539 | message_loop_runner_->Quit(); |
| 540 | } |
| 541 | |
ekaramad | babb9bf | 2016-01-12 15:17:02 | [diff] [blame] | 542 | bool expected_visibility_state_; |
| 543 | scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 544 | NotificationRegistrar registrar_; |
| 545 | bool was_observed_; |
| 546 | bool did_fail_; |
| 547 | Source<RenderWidgetHost> source_; |
| 548 | |
| 549 | DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostVisibilityObserver); |
| 550 | }; |
| 551 | |
estark | 693d128 | 2016-03-15 22:41:29 | [diff] [blame] | 552 | // A mock CertStore that always assigns the render process host id as |
| 553 | // the certificate id. Certificates are never removed. |
| 554 | class MockCertStore : public CertStore { |
| 555 | public: |
| 556 | MockCertStore() {} |
| 557 | ~MockCertStore() override {} |
| 558 | |
| 559 | int StoreCert(net::X509Certificate* cert, |
| 560 | int render_process_host_id) override { |
| 561 | certs_[render_process_host_id] = cert; |
| 562 | return render_process_host_id; |
| 563 | } |
| 564 | |
| 565 | bool RetrieveCert(int cert_id, |
| 566 | scoped_refptr<net::X509Certificate>* cert) override { |
| 567 | if (certs_.find(cert_id) == certs_.end()) |
| 568 | return false; |
| 569 | *cert = certs_[cert_id]; |
| 570 | return true; |
| 571 | } |
| 572 | |
| 573 | private: |
| 574 | std::map<int, scoped_refptr<net::X509Certificate>> certs_; |
| 575 | |
| 576 | DISALLOW_COPY_AND_ASSIGN(MockCertStore); |
| 577 | }; |
| 578 | |
csharrison | 264bca64 | 2016-05-06 19:27:09 | [diff] [blame] | 579 | class TestInterstitialDelegate : public InterstitialPageDelegate { |
| 580 | private: |
| 581 | // InterstitialPageDelegate: |
| 582 | std::string GetHTMLContents() override { return "<p>Interstitial</p>"; } |
| 583 | }; |
| 584 | |
nick | 5f3d7607 | 2015-06-09 00:24:00 | [diff] [blame] | 585 | } // namespace |
| 586 | |
dmazzoni | 0b5d248 | 2014-09-10 19:45:57 | [diff] [blame] | 587 | // |
| 588 | // SitePerProcessBrowserTest |
| 589 | // |
[email protected] | c96e970 | 2014-02-15 08:29:50 | [diff] [blame] | 590 | |
dmazzoni | 0b5d248 | 2014-09-10 19:45:57 | [diff] [blame] | 591 | SitePerProcessBrowserTest::SitePerProcessBrowserTest() { |
| 592 | }; |
| 593 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 594 | std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) { |
| 595 | return visualizer_.DepictFrameTree(node); |
nick | 59dcb16 | 2015-04-09 20:29:01 | [diff] [blame] | 596 | } |
| 597 | |
avi | 83883c8 | 2014-12-23 00:08:49 | [diff] [blame] | 598 | void SitePerProcessBrowserTest::SetUpCommandLine( |
| 599 | base::CommandLine* command_line) { |
nick | d30fd96 | 2015-07-27 21:51:08 | [diff] [blame] | 600 | IsolateAllSitesForTesting(command_line); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 601 | }; |
| 602 | |
nasko | cbce0e6 | 2014-10-07 14:04:26 | [diff] [blame] | 603 | void SitePerProcessBrowserTest::SetUpOnMainThread() { |
| 604 | host_resolver()->AddRule("*", "127.0.0.1"); |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 605 | ASSERT_TRUE(embedded_test_server()->Start()); |
nasko | cbce0e6 | 2014-10-07 14:04:26 | [diff] [blame] | 606 | SetupCrossSiteRedirector(embedded_test_server()); |
nasko | cbce0e6 | 2014-10-07 14:04:26 | [diff] [blame] | 607 | } |
| 608 | |
lfg | 52bac907 | 2015-11-06 17:27:52 | [diff] [blame] | 609 | // |
| 610 | // SitePerProcessHighDPIBrowserTest |
| 611 | // |
| 612 | |
| 613 | |
| 614 | class SitePerProcessHighDPIBrowserTest : public SitePerProcessBrowserTest { |
| 615 | public: |
| 616 | SitePerProcessHighDPIBrowserTest() {} |
| 617 | |
| 618 | protected: |
| 619 | void SetUpCommandLine(base::CommandLine* command_line) override { |
| 620 | SitePerProcessBrowserTest::SetUpCommandLine(command_line); |
| 621 | command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, |
| 622 | base::StringPrintf("2")); |
| 623 | } |
| 624 | }; |
| 625 | |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 626 | // SitePerProcessIgnoreCertErrorsBrowserTest |
| 627 | |
| 628 | class SitePerProcessIgnoreCertErrorsBrowserTest |
| 629 | : public SitePerProcessBrowserTest { |
| 630 | public: |
| 631 | SitePerProcessIgnoreCertErrorsBrowserTest() {} |
| 632 | |
| 633 | protected: |
| 634 | void SetUpCommandLine(base::CommandLine* command_line) override { |
| 635 | SitePerProcessBrowserTest::SetUpCommandLine(command_line); |
| 636 | command_line->AppendSwitch(switches::kIgnoreCertificateErrors); |
| 637 | } |
| 638 | }; |
| 639 | |
nasko | 983ea9c | 2014-10-25 00:27:53 | [diff] [blame] | 640 | // Ensure that navigating subframes in --site-per-process mode works and the |
| 641 | // correct documents are committed. |
| 642 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) { |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 643 | GURL main_url(embedded_test_server()->GetURL( |
| 644 | "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))")); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 645 | NavigateToURL(shell(), main_url); |
| 646 | |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 647 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 648 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
[email protected] | 8d613aa | 2014-02-12 20:37:20 | [diff] [blame] | 649 | |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 650 | TestNavigationObserver observer(shell()->web_contents()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 651 | |
[email protected] | a1b9926 | 2013-12-27 21:56:22 | [diff] [blame] | 652 | // Load same-site page into iframe. |
[email protected] | 9a1abe7 | 2014-06-19 23:49:02 | [diff] [blame] | 653 | FrameTreeNode* child = root->child_at(0); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 654 | GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
[email protected] | 9a1abe7 | 2014-06-19 23:49:02 | [diff] [blame] | 655 | NavigateFrameToURL(child, http_url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 656 | EXPECT_EQ(http_url, observer.last_navigation_url()); |
| 657 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
[email protected] | de3c5d8 | 2014-05-28 22:12:59 | [diff] [blame] | 658 | { |
| 659 | // There should be only one RenderWidgetHost when there are no |
| 660 | // cross-process iframes. |
[email protected] | 948481d | 2014-06-11 18:32:22 | [diff] [blame] | 661 | std::set<RenderWidgetHostView*> views_set = |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 662 | web_contents()->GetRenderWidgetHostViewsInTree(); |
[email protected] | 948481d | 2014-06-11 18:32:22 | [diff] [blame] | 663 | EXPECT_EQ(1U, views_set.size()); |
[email protected] | de3c5d8 | 2014-05-28 22:12:59 | [diff] [blame] | 664 | } |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 665 | |
| 666 | EXPECT_EQ( |
| 667 | " Site A\n" |
| 668 | " |--Site A\n" |
| 669 | " +--Site A\n" |
| 670 | " |--Site A\n" |
| 671 | " +--Site A\n" |
| 672 | " +--Site A\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 673 | "Where A = http://a.com/", |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 674 | DepictFrameTree(root)); |
[email protected] | a1b9926 | 2013-12-27 21:56:22 | [diff] [blame] | 675 | |
| 676 | // Load cross-site page into iframe. |
nasko | 30374c7 | 2014-10-30 19:18:37 | [diff] [blame] | 677 | GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html"); |
| 678 | NavigateFrameToURL(root->child_at(0), url); |
nasko | cbce0e6 | 2014-10-07 14:04:26 | [diff] [blame] | 679 | // Verify that the navigation succeeded and the expected URL was loaded. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 680 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 681 | EXPECT_EQ(url, observer.last_navigation_url()); |
[email protected] | a1b9926 | 2013-12-27 21:56:22 | [diff] [blame] | 682 | |
| 683 | // Ensure that we have created a new process for the subframe. |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 684 | ASSERT_EQ(2U, root->child_count()); |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 685 | SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance(); |
| 686 | RenderViewHost* rvh = child->current_frame_host()->render_view_host(); |
| 687 | RenderProcessHost* rph = child->current_frame_host()->GetProcess(); |
| 688 | EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh); |
| 689 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance); |
| 690 | EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph); |
[email protected] | de3c5d8 | 2014-05-28 22:12:59 | [diff] [blame] | 691 | { |
| 692 | // There should be now two RenderWidgetHosts, one for each process |
| 693 | // rendering a frame. |
[email protected] | 948481d | 2014-06-11 18:32:22 | [diff] [blame] | 694 | std::set<RenderWidgetHostView*> views_set = |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 695 | web_contents()->GetRenderWidgetHostViewsInTree(); |
[email protected] | 948481d | 2014-06-11 18:32:22 | [diff] [blame] | 696 | EXPECT_EQ(2U, views_set.size()); |
[email protected] | de3c5d8 | 2014-05-28 22:12:59 | [diff] [blame] | 697 | } |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 698 | RenderFrameProxyHost* proxy_to_parent = |
| 699 | child->render_manager()->GetProxyToParent(); |
[email protected] | 9a1abe7 | 2014-06-19 23:49:02 | [diff] [blame] | 700 | EXPECT_TRUE(proxy_to_parent); |
| 701 | EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector()); |
kenrb | a719983 | 2015-01-22 23:44:59 | [diff] [blame] | 702 | // The out-of-process iframe should have its own RenderWidgetHost, |
| 703 | // independent of any RenderViewHost. |
| 704 | EXPECT_NE( |
avi | f9ab5d94 | 2015-10-15 14:05:44 | [diff] [blame] | 705 | rvh->GetWidget()->GetView(), |
[email protected] | 9a1abe7 | 2014-06-19 23:49:02 | [diff] [blame] | 706 | proxy_to_parent->cross_process_frame_connector()->get_view_for_testing()); |
kenrb | a719983 | 2015-01-22 23:44:59 | [diff] [blame] | 707 | EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost()); |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 708 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 709 | EXPECT_EQ( |
| 710 | " Site A ------------ proxies for B\n" |
| 711 | " |--Site B ------- proxies for A\n" |
| 712 | " +--Site A ------- proxies for B\n" |
| 713 | " |--Site A -- proxies for B\n" |
| 714 | " +--Site A -- proxies for B\n" |
| 715 | " +--Site A -- proxies for B\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 716 | "Where A = http://a.com/\n" |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 717 | " B = http://foo.com/", |
| 718 | DepictFrameTree(root)); |
| 719 | |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 720 | // Load another cross-site page into the same iframe. |
nasko | 30374c7 | 2014-10-30 19:18:37 | [diff] [blame] | 721 | url = embedded_test_server()->GetURL("bar.com", "/title3.html"); |
| 722 | NavigateFrameToURL(root->child_at(0), url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 723 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 724 | EXPECT_EQ(url, observer.last_navigation_url()); |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 725 | |
| 726 | // Check again that a new process is created and is different from the |
| 727 | // top level one and the previous one. |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 728 | ASSERT_EQ(2U, root->child_count()); |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 729 | child = root->child_at(0); |
[email protected] | a1b9926 | 2013-12-27 21:56:22 | [diff] [blame] | 730 | EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), |
| 731 | child->current_frame_host()->render_view_host()); |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 732 | EXPECT_NE(rvh, child->current_frame_host()->render_view_host()); |
[email protected] | a1b9926 | 2013-12-27 21:56:22 | [diff] [blame] | 733 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 734 | child->current_frame_host()->GetSiteInstance()); |
| 735 | EXPECT_NE(site_instance, |
| 736 | child->current_frame_host()->GetSiteInstance()); |
[email protected] | a1b9926 | 2013-12-27 21:56:22 | [diff] [blame] | 737 | EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), |
| 738 | child->current_frame_host()->GetProcess()); |
[email protected] | 893558b | 2014-04-25 23:01:06 | [diff] [blame] | 739 | EXPECT_NE(rph, child->current_frame_host()->GetProcess()); |
[email protected] | de3c5d8 | 2014-05-28 22:12:59 | [diff] [blame] | 740 | { |
[email protected] | 948481d | 2014-06-11 18:32:22 | [diff] [blame] | 741 | std::set<RenderWidgetHostView*> views_set = |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 742 | web_contents()->GetRenderWidgetHostViewsInTree(); |
[email protected] | 948481d | 2014-06-11 18:32:22 | [diff] [blame] | 743 | EXPECT_EQ(2U, views_set.size()); |
[email protected] | de3c5d8 | 2014-05-28 22:12:59 | [diff] [blame] | 744 | } |
[email protected] | 9a1abe7 | 2014-06-19 23:49:02 | [diff] [blame] | 745 | EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent()); |
| 746 | EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector()); |
kenrb | a719983 | 2015-01-22 23:44:59 | [diff] [blame] | 747 | EXPECT_NE( |
avi | 3627ecac | 2015-10-16 17:40:43 | [diff] [blame] | 748 | child->current_frame_host()->render_view_host()->GetWidget()->GetView(), |
[email protected] | 9a1abe7 | 2014-06-19 23:49:02 | [diff] [blame] | 749 | proxy_to_parent->cross_process_frame_connector()->get_view_for_testing()); |
kenrb | a719983 | 2015-01-22 23:44:59 | [diff] [blame] | 750 | EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost()); |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 751 | |
| 752 | EXPECT_EQ( |
| 753 | " Site A ------------ proxies for C\n" |
| 754 | " |--Site C ------- proxies for A\n" |
| 755 | " +--Site A ------- proxies for C\n" |
| 756 | " |--Site A -- proxies for C\n" |
| 757 | " +--Site A -- proxies for C\n" |
| 758 | " +--Site A -- proxies for C\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 759 | "Where A = http://a.com/\n" |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 760 | " C = http://bar.com/", |
| 761 | DepictFrameTree(root)); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 762 | } |
| 763 | |
creis | 0bfe528 | 2016-06-02 06:46:20 | [diff] [blame] | 764 | // Ensure that title updates affect the correct NavigationEntry after a new |
| 765 | // subframe navigation with an out-of-process iframe. https://crbug.com/616609. |
| 766 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, TitleAfterCrossSiteIframe) { |
| 767 | // Start at an initial page. |
| 768 | GURL initial_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 769 | EXPECT_TRUE(NavigateToURL(shell(), initial_url)); |
| 770 | |
| 771 | // Navigate to a same-site page with a same-site iframe. |
| 772 | GURL main_url(embedded_test_server()->GetURL( |
| 773 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 774 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 775 | |
| 776 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 777 | |
| 778 | // Make the main frame update its title after the subframe loads. |
| 779 | EXPECT_TRUE(ExecuteScript(shell()->web_contents(), |
| 780 | "document.querySelector('iframe').onload = " |
| 781 | " function() { document.title = 'loaded'; };")); |
| 782 | EXPECT_TRUE( |
| 783 | ExecuteScript(shell()->web_contents(), "document.title = 'not loaded';")); |
| 784 | base::string16 expected_title(base::UTF8ToUTF16("loaded")); |
| 785 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| 786 | |
| 787 | // Navigate the iframe cross-site. |
| 788 | TestNavigationObserver load_observer(shell()->web_contents()); |
| 789 | GURL frame_url = embedded_test_server()->GetURL("b.com", "/title2.html"); |
| 790 | EXPECT_TRUE( |
| 791 | ExecuteScript(root->child_at(0)->current_frame_host(), |
| 792 | "window.location.href = '" + frame_url.spec() + "';")); |
| 793 | load_observer.Wait(); |
| 794 | |
| 795 | // Wait for the title to update and ensure it affects the right NavEntry. |
| 796 | EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 797 | NavigationEntry* entry = |
| 798 | shell()->web_contents()->GetController().GetLastCommittedEntry(); |
| 799 | EXPECT_EQ(expected_title, entry->GetTitle()); |
| 800 | } |
| 801 | |
kenrb | 1b1ab8e | 2016-04-13 17:27:44 | [diff] [blame] | 802 | // Class to sniff incoming IPCs for FrameHostMsg_FrameRectChanged messages. |
| 803 | class FrameRectChangedMessageFilter : public content::BrowserMessageFilter { |
| 804 | public: |
| 805 | FrameRectChangedMessageFilter() |
| 806 | : content::BrowserMessageFilter(FrameMsgStart), |
| 807 | message_loop_runner_(new content::MessageLoopRunner), |
| 808 | frame_rect_received_(false) {} |
| 809 | |
| 810 | bool OnMessageReceived(const IPC::Message& message) override { |
| 811 | IPC_BEGIN_MESSAGE_MAP(FrameRectChangedMessageFilter, message) |
| 812 | IPC_MESSAGE_HANDLER(FrameHostMsg_FrameRectChanged, OnFrameRectChanged) |
| 813 | IPC_END_MESSAGE_MAP() |
| 814 | return false; |
| 815 | } |
| 816 | |
| 817 | gfx::Rect last_rect() const { return last_rect_; } |
| 818 | |
| 819 | void Wait() { |
kenrb | 1b1ab8e | 2016-04-13 17:27:44 | [diff] [blame] | 820 | message_loop_runner_->Run(); |
| 821 | } |
| 822 | |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 823 | void Reset() { |
| 824 | last_rect_ = gfx::Rect(); |
| 825 | message_loop_runner_ = new content::MessageLoopRunner; |
| 826 | frame_rect_received_ = false; |
| 827 | } |
| 828 | |
kenrb | 1b1ab8e | 2016-04-13 17:27:44 | [diff] [blame] | 829 | private: |
| 830 | ~FrameRectChangedMessageFilter() override {} |
| 831 | |
| 832 | void OnFrameRectChanged(const gfx::Rect& rect) { |
| 833 | content::BrowserThread::PostTask( |
| 834 | content::BrowserThread::UI, FROM_HERE, |
| 835 | base::Bind(&FrameRectChangedMessageFilter::OnFrameRectChangedOnUI, this, |
| 836 | rect)); |
| 837 | } |
| 838 | |
| 839 | void OnFrameRectChangedOnUI(const gfx::Rect& rect) { |
| 840 | last_rect_ = rect; |
| 841 | if (!frame_rect_received_) { |
| 842 | frame_rect_received_ = true; |
| 843 | message_loop_runner_->Quit(); |
| 844 | } |
| 845 | } |
| 846 | |
| 847 | scoped_refptr<content::MessageLoopRunner> message_loop_runner_; |
| 848 | bool frame_rect_received_; |
| 849 | gfx::Rect last_rect_; |
| 850 | |
| 851 | DISALLOW_COPY_AND_ASSIGN(FrameRectChangedMessageFilter); |
| 852 | }; |
| 853 | |
| 854 | // Test that the view bounds for an out-of-process iframe are set and updated |
| 855 | // correctly, including accounting for local frame offsets in the parent and |
| 856 | // scroll positions. |
| 857 | #if defined(OS_ANDROID) |
| 858 | // Browser process hit testing is not implemented on Android. |
| 859 | // https://crbug.com/491334 |
| 860 | #define MAYBE_ViewBoundsInNestedFrameTest DISABLED_ViewBoundsInNestedFrameTest |
| 861 | #else |
| 862 | #define MAYBE_ViewBoundsInNestedFrameTest ViewBoundsInNestedFrameTest |
| 863 | #endif |
| 864 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 865 | MAYBE_ViewBoundsInNestedFrameTest) { |
| 866 | GURL main_url(embedded_test_server()->GetURL( |
| 867 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 868 | NavigateToURL(shell(), main_url); |
| 869 | |
| 870 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
| 871 | FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| 872 | ->GetFrameTree() |
| 873 | ->root(); |
| 874 | RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>( |
| 875 | root->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 876 | ASSERT_EQ(1U, root->child_count()); |
| 877 | |
| 878 | FrameTreeNode* parent_iframe_node = root->child_at(0); |
| 879 | GURL site_url(embedded_test_server()->GetURL( |
| 880 | "a.com", "/frame_tree/page_with_positioned_frame.html")); |
| 881 | NavigateFrameToURL(parent_iframe_node, site_url); |
| 882 | |
| 883 | EXPECT_EQ( |
| 884 | " Site A ------------ proxies for B\n" |
| 885 | " +--Site A ------- proxies for B\n" |
| 886 | " +--Site B -- proxies for A\n" |
| 887 | "Where A = http://a.com/\n" |
| 888 | " B = http://baz.com/", |
| 889 | DepictFrameTree(root)); |
| 890 | |
| 891 | FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0); |
| 892 | RenderWidgetHostViewBase* rwhv_nested = |
| 893 | static_cast<RenderWidgetHostViewBase*>( |
| 894 | nested_iframe_node->current_frame_host() |
| 895 | ->GetRenderWidgetHost() |
| 896 | ->GetView()); |
| 897 | |
| 898 | SurfaceHitTestReadyNotifier notifier( |
| 899 | static_cast<RenderWidgetHostViewChildFrame*>(rwhv_nested)); |
| 900 | notifier.WaitForSurfaceReady(); |
| 901 | |
| 902 | // Verify the view bounds of the nested iframe, which should account for the |
| 903 | // relative offset of its direct parent within the root frame. |
| 904 | gfx::Rect bounds = rwhv_nested->GetViewBounds(); |
| 905 | EXPECT_EQ(bounds.x() - rwhv_root->GetViewBounds().x(), 397); |
| 906 | EXPECT_EQ(bounds.y() - rwhv_root->GetViewBounds().y(), 112); |
| 907 | |
| 908 | scoped_refptr<FrameRectChangedMessageFilter> filter = |
| 909 | new FrameRectChangedMessageFilter(); |
| 910 | root->current_frame_host()->GetProcess()->AddFilter(filter.get()); |
| 911 | |
| 912 | // Scroll the parent frame downward to verify that the child rect gets updated |
| 913 | // correctly. |
| 914 | blink::WebMouseWheelEvent scroll_event; |
| 915 | scroll_event.type = blink::WebInputEvent::MouseWheel; |
| 916 | scroll_event.x = 387; |
| 917 | scroll_event.y = 110; |
| 918 | scroll_event.deltaX = 0.0f; |
| 919 | scroll_event.deltaY = -30.0f; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 920 | rwhv_root->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); |
kenrb | 1b1ab8e | 2016-04-13 17:27:44 | [diff] [blame] | 921 | |
| 922 | filter->Wait(); |
| 923 | |
| 924 | // The precise amount of scroll for the first view position update is not |
| 925 | // deterministic, so this simply verifies that the OOPIF moved from its |
| 926 | // earlier position. |
| 927 | gfx::Rect update_rect = filter->last_rect(); |
| 928 | EXPECT_LT(update_rect.y(), bounds.y() - rwhv_root->GetViewBounds().y()); |
| 929 | } |
| 930 | |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 931 | // Test that scrolling a nested out-of-process iframe bubbles unused scroll |
| 932 | // delta to a parent frame. |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 933 | // Browser process hit testing is not implemented on Android. |
| 934 | // https://crbug.com/491334 |
lfg | 0d3213a | 2016-07-12 13:48:30 | [diff] [blame] | 935 | // Flaky https://crbug.com/627238. |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 936 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
lfg | 0d3213a | 2016-07-12 13:48:30 | [diff] [blame] | 937 | DISABLED_ScrollBubblingFromOOPIFTest) { |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 938 | GURL main_url(embedded_test_server()->GetURL( |
| 939 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 940 | NavigateToURL(shell(), main_url); |
| 941 | |
| 942 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
| 943 | FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| 944 | ->GetFrameTree() |
| 945 | ->root(); |
| 946 | ASSERT_EQ(1U, root->child_count()); |
| 947 | |
| 948 | FrameTreeNode* parent_iframe_node = root->child_at(0); |
| 949 | |
| 950 | // This test uses the position of the nested iframe within the parent iframe |
| 951 | // to infer the scroll position of the parent. FrameRectChangedMessageFilter |
| 952 | // catches updates to the position in order to avoid busy waiting. |
kenrb | 3bdfea5 | 2016-07-08 21:50:30 | [diff] [blame] | 953 | // It gets created early to catch the initial rects from the navigation. |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 954 | scoped_refptr<FrameRectChangedMessageFilter> filter = |
| 955 | new FrameRectChangedMessageFilter(); |
| 956 | parent_iframe_node->current_frame_host()->GetProcess()->AddFilter( |
| 957 | filter.get()); |
| 958 | |
| 959 | GURL site_url(embedded_test_server()->GetURL( |
| 960 | "b.com", "/frame_tree/page_with_positioned_frame.html")); |
| 961 | NavigateFrameToURL(parent_iframe_node, site_url); |
| 962 | |
kenrb | 3bdfea5 | 2016-07-08 21:50:30 | [diff] [blame] | 963 | // Navigate the nested frame to a page large enough to have scrollbars. |
| 964 | FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0); |
| 965 | GURL nested_site_url(embedded_test_server()->GetURL( |
| 966 | "baz.com", "/tall_page.html")); |
| 967 | NavigateFrameToURL(nested_iframe_node, nested_site_url); |
| 968 | |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 969 | EXPECT_EQ( |
| 970 | " Site A ------------ proxies for B C\n" |
| 971 | " +--Site B ------- proxies for A C\n" |
| 972 | " +--Site C -- proxies for A B\n" |
| 973 | "Where A = http://a.com/\n" |
| 974 | " B = http://b.com/\n" |
| 975 | " C = http://baz.com/", |
| 976 | DepictFrameTree(root)); |
| 977 | |
| 978 | RenderWidgetHostViewBase* rwhv_parent = |
| 979 | static_cast<RenderWidgetHostViewBase*>( |
| 980 | parent_iframe_node->current_frame_host() |
| 981 | ->GetRenderWidgetHost() |
| 982 | ->GetView()); |
| 983 | |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 984 | RenderWidgetHostViewBase* rwhv_nested = |
| 985 | static_cast<RenderWidgetHostViewBase*>( |
| 986 | nested_iframe_node->current_frame_host() |
| 987 | ->GetRenderWidgetHost() |
| 988 | ->GetView()); |
| 989 | |
| 990 | SurfaceHitTestReadyNotifier notifier( |
| 991 | static_cast<RenderWidgetHostViewChildFrame*>(rwhv_nested)); |
| 992 | notifier.WaitForSurfaceReady(); |
| 993 | |
| 994 | // Save the original offset as a point of reference. |
| 995 | filter->Wait(); |
| 996 | gfx::Rect update_rect = filter->last_rect(); |
| 997 | int initial_y = update_rect.y(); |
| 998 | filter->Reset(); |
| 999 | |
| 1000 | // Scroll the parent frame downward. |
| 1001 | blink::WebMouseWheelEvent scroll_event; |
| 1002 | scroll_event.type = blink::WebInputEvent::MouseWheel; |
| 1003 | scroll_event.x = 1; |
| 1004 | scroll_event.y = 1; |
| 1005 | scroll_event.deltaX = 0.0f; |
| 1006 | scroll_event.deltaY = -5.0f; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 1007 | rwhv_parent->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 1008 | |
| 1009 | // Ensure that the view position is propagated to the child properly. |
| 1010 | filter->Wait(); |
| 1011 | update_rect = filter->last_rect(); |
| 1012 | EXPECT_LT(update_rect.y(), initial_y); |
| 1013 | filter->Reset(); |
| 1014 | |
| 1015 | // Now scroll the nested frame upward, which should bubble to the parent. |
| 1016 | // The upscroll exceeds the amount that the frame was initially scrolled |
| 1017 | // down to account for rounding. |
| 1018 | scroll_event.deltaY = 6.0f; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 1019 | rwhv_nested->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 1020 | |
| 1021 | filter->Wait(); |
| 1022 | // This loop isn't great, but it accounts for the possibility of multiple |
| 1023 | // incremental updates happening as a result of the scroll animation. |
| 1024 | // A failure condition of this test is that the loop might not terminate |
| 1025 | // due to bubbling not working properly. If the overscroll bubbles to the |
| 1026 | // parent iframe then the nested frame's y coord will return to its |
| 1027 | // initial position. |
| 1028 | update_rect = filter->last_rect(); |
| 1029 | while (update_rect.y() > initial_y) { |
| 1030 | base::RunLoop run_loop; |
| 1031 | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 1032 | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); |
| 1033 | run_loop.Run(); |
| 1034 | update_rect = filter->last_rect(); |
| 1035 | } |
| 1036 | |
| 1037 | filter->Reset(); |
| 1038 | |
| 1039 | // Scroll the parent down again in order to test scroll bubbling from |
| 1040 | // gestures. |
| 1041 | scroll_event.deltaY = -5.0f; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 1042 | rwhv_parent->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 1043 | |
| 1044 | // Ensure ensuing offset change is received, and then reset the filter. |
| 1045 | filter->Wait(); |
| 1046 | filter->Reset(); |
| 1047 | |
| 1048 | // Scroll down the nested iframe via gesture. This requires 3 separate input |
| 1049 | // events. |
| 1050 | blink::WebGestureEvent gesture_event; |
| 1051 | gesture_event.type = blink::WebGestureEvent::GestureScrollBegin; |
| 1052 | gesture_event.sourceDevice = blink::WebGestureDeviceTouchpad; |
| 1053 | gesture_event.x = 1; |
| 1054 | gesture_event.y = 1; |
| 1055 | rwhv_nested->GetRenderWidgetHost()->ForwardGestureEvent(gesture_event); |
| 1056 | |
| 1057 | gesture_event.type = blink::WebGestureEvent::GestureScrollUpdate; |
| 1058 | gesture_event.data.scrollUpdate.deltaX = 0.0f; |
| 1059 | gesture_event.data.scrollUpdate.deltaY = 6.0f; |
| 1060 | gesture_event.data.scrollUpdate.velocityX = 0; |
| 1061 | gesture_event.data.scrollUpdate.velocityY = 0; |
| 1062 | rwhv_nested->GetRenderWidgetHost()->ForwardGestureEvent(gesture_event); |
| 1063 | |
| 1064 | gesture_event.type = blink::WebGestureEvent::GestureScrollEnd; |
| 1065 | rwhv_nested->GetRenderWidgetHost()->ForwardGestureEvent(gesture_event); |
| 1066 | |
| 1067 | filter->Wait(); |
| 1068 | update_rect = filter->last_rect(); |
| 1069 | // As above, if this loop does not terminate then it indicates an issue |
| 1070 | // with scroll bubbling. |
| 1071 | while (update_rect.y() > initial_y) { |
| 1072 | base::RunLoop run_loop; |
| 1073 | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 1074 | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); |
| 1075 | run_loop.Run(); |
| 1076 | update_rect = filter->last_rect(); |
| 1077 | } |
kenrb | 3bdfea5 | 2016-07-08 21:50:30 | [diff] [blame] | 1078 | |
| 1079 | // Test that when the child frame absorbs all of the scroll delta, it does |
| 1080 | // not propagate to the parent (see https://crbug.com/621624). |
| 1081 | filter->Reset(); |
| 1082 | scroll_event.deltaY = -5.0f; |
| 1083 | rwhv_nested->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo()); |
| 1084 | // It isn't possible to busy loop waiting on the renderer here because we |
| 1085 | // are explicitly testing that something does *not* happen. This creates a |
| 1086 | // small chance of false positives but shouldn't result in false negatives, |
| 1087 | // so flakiness implies this test is failing. |
| 1088 | { |
| 1089 | base::RunLoop run_loop; |
| 1090 | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 1091 | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::action_timeout()); |
| 1092 | run_loop.Run(); |
| 1093 | } |
| 1094 | DCHECK_EQ(filter->last_rect().x(), 0); |
| 1095 | DCHECK_EQ(filter->last_rect().y(), 0); |
kenrb | 42ba7e8 | 2016-05-16 18:54:18 | [diff] [blame] | 1096 | } |
| 1097 | |
kenrb | 0b67820 | 2016-06-23 19:07:35 | [diff] [blame] | 1098 | // Test that an ET_SCROLL event sent to an out-of-process iframe correctly |
| 1099 | // results in a scroll. This is only handled by RenderWidgetHostViewAura |
| 1100 | // and is needed for trackpad scrolling on Chromebooks. |
| 1101 | #if !defined(USE_AURA) |
| 1102 | #define MAYBE_ScrollEventToOOPIF DISABLED_ScrollEventToOOPIF |
| 1103 | #else |
| 1104 | #define MAYBE_ScrollEventToOOPIF ScrollEventToOOPIF |
| 1105 | #endif |
| 1106 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_ScrollEventToOOPIF) { |
| 1107 | GURL main_url(embedded_test_server()->GetURL( |
| 1108 | "/frame_tree/page_with_positioned_frame.html")); |
| 1109 | NavigateToURL(shell(), main_url); |
| 1110 | |
| 1111 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
| 1112 | FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| 1113 | ->GetFrameTree() |
| 1114 | ->root(); |
| 1115 | ASSERT_EQ(1U, root->child_count()); |
| 1116 | |
| 1117 | FrameTreeNode* child_node = root->child_at(0); |
| 1118 | GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html")); |
| 1119 | EXPECT_EQ(site_url, child_node->current_url()); |
| 1120 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 1121 | child_node->current_frame_host()->GetSiteInstance()); |
| 1122 | |
| 1123 | RenderWidgetHostViewAura* rwhv_parent = |
| 1124 | static_cast<RenderWidgetHostViewAura*>( |
| 1125 | root->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 1126 | |
| 1127 | RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>( |
| 1128 | child_node->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 1129 | |
| 1130 | SurfaceHitTestReadyNotifier notifier( |
| 1131 | static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child)); |
| 1132 | notifier.WaitForSurfaceReady(); |
| 1133 | |
| 1134 | // Create listener for input events. |
| 1135 | TestInputEventObserver child_frame_monitor( |
| 1136 | child_node->current_frame_host()->GetRenderWidgetHost()); |
| 1137 | |
| 1138 | // Send a ui::ScrollEvent that will hit test to the child frame. |
| 1139 | ui::ScrollEvent scroll_event(ui::ET_SCROLL, gfx::Point(75, 75), |
| 1140 | ui::EventTimeForNow(), ui::EF_NONE, |
| 1141 | 0, 10, // Offsets |
| 1142 | 0, 10, // Offset ordinals |
| 1143 | 2); |
| 1144 | rwhv_parent->OnScrollEvent(&scroll_event); |
| 1145 | |
| 1146 | // Verify that this a mouse wheel event was sent to the child frame renderer. |
| 1147 | EXPECT_TRUE(child_frame_monitor.EventWasReceived()); |
| 1148 | EXPECT_EQ(child_frame_monitor.EventType(), blink::WebInputEvent::MouseWheel); |
| 1149 | } |
| 1150 | |
kenrb | 2a565f8 | 2015-09-02 20:24:59 | [diff] [blame] | 1151 | // Test that mouse events are being routed to the correct RenderWidgetHostView |
| 1152 | // based on coordinates. |
oshima | cc0f3ba | 2016-03-02 19:16:34 | [diff] [blame] | 1153 | #if defined(OS_ANDROID) || defined(THREAD_SANITIZER) |
kenrb | 2a565f8 | 2015-09-02 20:24:59 | [diff] [blame] | 1154 | // Browser process hit testing is not implemented on Android. |
| 1155 | // https://crbug.com/491334 |
oshima | cc0f3ba | 2016-03-02 19:16:34 | [diff] [blame] | 1156 | // The test times out often on TSAN bot. |
| 1157 | // https://crbug.com/591170. |
kenrb | 2a565f8 | 2015-09-02 20:24:59 | [diff] [blame] | 1158 | #define MAYBE_SurfaceHitTestTest DISABLED_SurfaceHitTestTest |
| 1159 | #else |
| 1160 | #define MAYBE_SurfaceHitTestTest SurfaceHitTestTest |
| 1161 | #endif |
| 1162 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_SurfaceHitTestTest) { |
lfg | 52bac907 | 2015-11-06 17:27:52 | [diff] [blame] | 1163 | SurfaceHitTestTestHelper(shell(), embedded_test_server()); |
| 1164 | } |
kenrb | 2a565f8 | 2015-09-02 20:24:59 | [diff] [blame] | 1165 | |
lfg | 52bac907 | 2015-11-06 17:27:52 | [diff] [blame] | 1166 | // Same test as above, but runs in high-dpi mode. |
| 1167 | #if defined(OS_ANDROID) || defined(OS_WIN) |
| 1168 | // Browser process hit testing is not implemented on Android. |
| 1169 | // https://crbug.com/491334 |
| 1170 | // Windows is disabled because of https://crbug.com/545547. |
| 1171 | #define MAYBE_HighDPISurfaceHitTestTest DISABLED_SurfaceHitTestTest |
| 1172 | #else |
| 1173 | #define MAYBE_HighDPISurfaceHitTestTest SurfaceHitTestTest |
| 1174 | #endif |
| 1175 | IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest, |
| 1176 | MAYBE_HighDPISurfaceHitTestTest) { |
| 1177 | SurfaceHitTestTestHelper(shell(), embedded_test_server()); |
kenrb | 2a565f8 | 2015-09-02 20:24:59 | [diff] [blame] | 1178 | } |
| 1179 | |
kenrb | 9d8b832 | 2016-03-01 18:53:24 | [diff] [blame] | 1180 | // Test that mouse events are being routed to the correct RenderWidgetHostView |
| 1181 | // when there are nested out-of-process iframes. |
| 1182 | #if defined(OS_ANDROID) |
| 1183 | // Browser process hit testing is not implemented on Android. |
| 1184 | // https://crbug.com/491334 |
| 1185 | #define MAYBE_NestedSurfaceHitTestTest DISABLED_NestedSurfaceHitTestTest |
| 1186 | #else |
| 1187 | #define MAYBE_NestedSurfaceHitTestTest NestedSurfaceHitTestTest |
| 1188 | #endif |
| 1189 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 1190 | MAYBE_NestedSurfaceHitTestTest) { |
| 1191 | GURL main_url(embedded_test_server()->GetURL( |
| 1192 | "/frame_tree/page_with_positioned_nested_frames.html")); |
| 1193 | NavigateToURL(shell(), main_url); |
| 1194 | |
| 1195 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1196 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
kenrb | 9d8b832 | 2016-03-01 18:53:24 | [diff] [blame] | 1197 | ASSERT_EQ(1U, root->child_count()); |
| 1198 | |
| 1199 | FrameTreeNode* parent_iframe_node = root->child_at(0); |
| 1200 | GURL site_url(embedded_test_server()->GetURL( |
| 1201 | "a.com", "/frame_tree/page_with_positioned_frame.html")); |
| 1202 | EXPECT_EQ(site_url, parent_iframe_node->current_url()); |
| 1203 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 1204 | parent_iframe_node->current_frame_host()->GetSiteInstance()); |
| 1205 | |
| 1206 | FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0); |
| 1207 | GURL nested_site_url( |
| 1208 | embedded_test_server()->GetURL("baz.com", "/title1.html")); |
| 1209 | EXPECT_EQ(nested_site_url, nested_iframe_node->current_url()); |
| 1210 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 1211 | nested_iframe_node->current_frame_host()->GetSiteInstance()); |
| 1212 | EXPECT_NE(parent_iframe_node->current_frame_host()->GetSiteInstance(), |
| 1213 | nested_iframe_node->current_frame_host()->GetSiteInstance()); |
| 1214 | |
| 1215 | // Create listeners for mouse events. |
| 1216 | RenderWidgetHostMouseEventMonitor main_frame_monitor( |
| 1217 | root->current_frame_host()->GetRenderWidgetHost()); |
| 1218 | RenderWidgetHostMouseEventMonitor nested_frame_monitor( |
| 1219 | nested_iframe_node->current_frame_host()->GetRenderWidgetHost()); |
| 1220 | |
| 1221 | RenderWidgetHostInputEventRouter* router = |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1222 | web_contents()->GetInputEventRouter(); |
kenrb | 9d8b832 | 2016-03-01 18:53:24 | [diff] [blame] | 1223 | |
| 1224 | RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>( |
| 1225 | root->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 1226 | RenderWidgetHostViewBase* rwhv_nested = |
| 1227 | static_cast<RenderWidgetHostViewBase*>( |
| 1228 | nested_iframe_node->current_frame_host() |
| 1229 | ->GetRenderWidgetHost() |
| 1230 | ->GetView()); |
| 1231 | |
| 1232 | SurfaceHitTestReadyNotifier notifier( |
| 1233 | static_cast<RenderWidgetHostViewChildFrame*>(rwhv_nested)); |
| 1234 | notifier.WaitForSurfaceReady(); |
| 1235 | |
| 1236 | // Target input event to nested frame. |
| 1237 | blink::WebMouseEvent nested_event; |
| 1238 | nested_event.type = blink::WebInputEvent::MouseDown; |
| 1239 | nested_event.button = blink::WebPointerProperties::ButtonLeft; |
| 1240 | nested_event.x = 125; |
| 1241 | nested_event.y = 125; |
| 1242 | nested_event.clickCount = 1; |
| 1243 | nested_frame_monitor.ResetEventReceived(); |
| 1244 | main_frame_monitor.ResetEventReceived(); |
| 1245 | router->RouteMouseEvent(root_view, &nested_event); |
| 1246 | |
| 1247 | EXPECT_TRUE(nested_frame_monitor.EventWasReceived()); |
| 1248 | EXPECT_EQ(21, nested_frame_monitor.event().x); |
| 1249 | EXPECT_EQ(21, nested_frame_monitor.event().y); |
| 1250 | EXPECT_FALSE(main_frame_monitor.EventWasReceived()); |
| 1251 | } |
| 1252 | |
lfg | e6119aac | 2016-01-27 02:14:31 | [diff] [blame] | 1253 | // This test tests that browser process hittesting ignores frames with |
| 1254 | // pointer-events: none. |
| 1255 | #if defined(OS_ANDROID) |
| 1256 | // Browser process hit testing is not implemented on Android. |
| 1257 | // https://crbug.com/491334 |
| 1258 | #define MAYBE_SurfaceHitTestPointerEventsNone \ |
| 1259 | DISABLED_SurfaceHitTestPointerEventsNone |
thestig | e45d56d3 | 2016-01-29 00:58:47 | [diff] [blame] | 1260 | #elif defined(THREAD_SANITIZER) |
| 1261 | // Flaky on TSAN. https://crbug.com/582277 |
| 1262 | #define MAYBE_SurfaceHitTestPointerEventsNone \ |
| 1263 | DISABLED_SurfaceHitTestPointerEventsNone |
lfg | e6119aac | 2016-01-27 02:14:31 | [diff] [blame] | 1264 | #else |
| 1265 | #define MAYBE_SurfaceHitTestPointerEventsNone SurfaceHitTestPointerEventsNone |
| 1266 | #endif |
| 1267 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 1268 | MAYBE_SurfaceHitTestPointerEventsNone) { |
| 1269 | GURL main_url(embedded_test_server()->GetURL( |
| 1270 | "/frame_tree/page_with_positioned_frame_pointer-events_none.html")); |
| 1271 | NavigateToURL(shell(), main_url); |
| 1272 | |
| 1273 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1274 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
lfg | e6119aac | 2016-01-27 02:14:31 | [diff] [blame] | 1275 | ASSERT_EQ(1U, root->child_count()); |
| 1276 | |
| 1277 | FrameTreeNode* child_node = root->child_at(0); |
| 1278 | GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html")); |
| 1279 | EXPECT_EQ(site_url, child_node->current_url()); |
| 1280 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 1281 | child_node->current_frame_host()->GetSiteInstance()); |
| 1282 | |
| 1283 | // Create listeners for mouse events. |
| 1284 | RenderWidgetHostMouseEventMonitor main_frame_monitor( |
| 1285 | root->current_frame_host()->GetRenderWidgetHost()); |
| 1286 | RenderWidgetHostMouseEventMonitor child_frame_monitor( |
| 1287 | child_node->current_frame_host()->GetRenderWidgetHost()); |
| 1288 | |
| 1289 | RenderWidgetHostInputEventRouter* router = |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1290 | web_contents()->GetInputEventRouter(); |
lfg | e6119aac | 2016-01-27 02:14:31 | [diff] [blame] | 1291 | |
| 1292 | RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>( |
| 1293 | root->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 1294 | RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>( |
| 1295 | child_node->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 1296 | |
kenrb | e975655 | 2016-02-27 00:53:50 | [diff] [blame] | 1297 | SurfaceHitTestReadyNotifier notifier( |
| 1298 | static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child)); |
| 1299 | notifier.WaitForSurfaceReady(); |
lfg | e6119aac | 2016-01-27 02:14:31 | [diff] [blame] | 1300 | |
| 1301 | // Target input event to child frame. |
| 1302 | blink::WebMouseEvent child_event; |
| 1303 | child_event.type = blink::WebInputEvent::MouseDown; |
| 1304 | child_event.button = blink::WebPointerProperties::ButtonLeft; |
| 1305 | child_event.x = 75; |
| 1306 | child_event.y = 75; |
| 1307 | child_event.clickCount = 1; |
| 1308 | main_frame_monitor.ResetEventReceived(); |
| 1309 | child_frame_monitor.ResetEventReceived(); |
| 1310 | router->RouteMouseEvent(root_view, &child_event); |
| 1311 | |
| 1312 | EXPECT_TRUE(main_frame_monitor.EventWasReceived()); |
| 1313 | EXPECT_EQ(75, main_frame_monitor.event().x); |
| 1314 | EXPECT_EQ(75, main_frame_monitor.event().y); |
| 1315 | EXPECT_FALSE(child_frame_monitor.EventWasReceived()); |
| 1316 | } |
| 1317 | |
lazyboy | 2f1a9d1 | 2015-04-03 05:16:15 | [diff] [blame] | 1318 | // Tests OOPIF rendering by checking that the RWH of the iframe generates |
| 1319 | // OnSwapCompositorFrame message. |
| 1320 | #if defined(OS_ANDROID) |
| 1321 | // http://crbug.com/471850 |
| 1322 | #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped |
| 1323 | #else |
| 1324 | #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped |
| 1325 | #endif |
| 1326 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 1327 | MAYBE_CompositorFrameSwapped) { |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1328 | GURL main_url(embedded_test_server()->GetURL( |
| 1329 | "a.com", "/cross_site_iframe_factory.html?a(baz)")); |
lazyboy | 2f1a9d1 | 2015-04-03 05:16:15 | [diff] [blame] | 1330 | NavigateToURL(shell(), main_url); |
| 1331 | |
| 1332 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1333 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
lazyboy | 2f1a9d1 | 2015-04-03 05:16:15 | [diff] [blame] | 1334 | ASSERT_EQ(1U, root->child_count()); |
| 1335 | |
| 1336 | FrameTreeNode* child_node = root->child_at(0); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1337 | GURL site_url(embedded_test_server()->GetURL( |
| 1338 | "baz.com", "/cross_site_iframe_factory.html?baz()")); |
lazyboy | 2f1a9d1 | 2015-04-03 05:16:15 | [diff] [blame] | 1339 | EXPECT_EQ(site_url, child_node->current_url()); |
| 1340 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 1341 | child_node->current_frame_host()->GetSiteInstance()); |
| 1342 | RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>( |
| 1343 | child_node->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 1344 | |
| 1345 | // Wait for OnSwapCompositorFrame message. |
| 1346 | while (rwhv_base->RendererFrameNumber() <= 0) { |
| 1347 | // TODO(lazyboy): Find a better way to avoid sleeping like this. See |
| 1348 | // http://crbug.com/405282 for details. |
| 1349 | base::RunLoop run_loop; |
skyostil | 95082a6 | 2015-06-05 19:53:07 | [diff] [blame] | 1350 | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
lazyboy | 2f1a9d1 | 2015-04-03 05:16:15 | [diff] [blame] | 1351 | FROM_HERE, run_loop.QuitClosure(), |
| 1352 | base::TimeDelta::FromMilliseconds(10)); |
| 1353 | run_loop.Run(); |
| 1354 | } |
| 1355 | } |
| 1356 | |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1357 | // Ensure that OOPIFs are deleted after navigating to a new main frame. |
| 1358 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) { |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1359 | GURL main_url(embedded_test_server()->GetURL( |
| 1360 | "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))")); |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1361 | NavigateToURL(shell(), main_url); |
| 1362 | |
| 1363 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1364 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1365 | |
| 1366 | TestNavigationObserver observer(shell()->web_contents()); |
| 1367 | |
| 1368 | // Load a cross-site page into both iframes. |
| 1369 | GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html"); |
| 1370 | NavigateFrameToURL(root->child_at(0), foo_url); |
| 1371 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1372 | EXPECT_EQ(foo_url, observer.last_navigation_url()); |
| 1373 | NavigateFrameToURL(root->child_at(1), foo_url); |
| 1374 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1375 | EXPECT_EQ(foo_url, observer.last_navigation_url()); |
| 1376 | |
| 1377 | // Ensure that we have created a new process for the subframes. |
nasko | f95ab0e | 2015-05-23 02:27:24 | [diff] [blame] | 1378 | EXPECT_EQ( |
| 1379 | " Site A ------------ proxies for B\n" |
| 1380 | " |--Site B ------- proxies for A\n" |
| 1381 | " +--Site B ------- proxies for A\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1382 | "Where A = http://a.com/\n" |
nasko | f95ab0e | 2015-05-23 02:27:24 | [diff] [blame] | 1383 | " B = http://foo.com/", |
| 1384 | DepictFrameTree(root)); |
| 1385 | |
| 1386 | int subframe_process_id = root->child_at(0) |
| 1387 | ->current_frame_host() |
| 1388 | ->GetSiteInstance() |
| 1389 | ->GetProcess() |
| 1390 | ->GetID(); |
| 1391 | int subframe_rvh_id = root->child_at(0) |
| 1392 | ->current_frame_host() |
| 1393 | ->render_view_host() |
| 1394 | ->GetRoutingID(); |
| 1395 | EXPECT_TRUE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id)); |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1396 | |
| 1397 | // Use Javascript in the parent to remove one of the frames and ensure that |
| 1398 | // the subframe goes away. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 1399 | EXPECT_TRUE(ExecuteScript(shell(), |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1400 | "document.body.removeChild(" |
| 1401 | "document.querySelectorAll('iframe')[0])")); |
| 1402 | ASSERT_EQ(1U, root->child_count()); |
| 1403 | |
| 1404 | // Load a new same-site page in the top-level frame and ensure the other |
| 1405 | // subframe goes away. |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1406 | GURL new_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1407 | NavigateToURL(shell(), new_url); |
| 1408 | ASSERT_EQ(0U, root->child_count()); |
nasko | f95ab0e | 2015-05-23 02:27:24 | [diff] [blame] | 1409 | |
| 1410 | // Ensure the RVH for the subframe gets cleaned up when the frame goes away. |
| 1411 | EXPECT_FALSE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id)); |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1412 | } |
| 1413 | |
| 1414 | // Ensure that root frames cannot be detached. |
| 1415 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) { |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1416 | GURL main_url(embedded_test_server()->GetURL( |
| 1417 | "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))")); |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1418 | NavigateToURL(shell(), main_url); |
| 1419 | |
| 1420 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1421 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1422 | |
| 1423 | TestNavigationObserver observer(shell()->web_contents()); |
| 1424 | |
| 1425 | // Load cross-site pages into both iframes. |
| 1426 | GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html"); |
| 1427 | NavigateFrameToURL(root->child_at(0), foo_url); |
| 1428 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1429 | EXPECT_EQ(foo_url, observer.last_navigation_url()); |
| 1430 | GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html"); |
| 1431 | NavigateFrameToURL(root->child_at(1), bar_url); |
| 1432 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1433 | EXPECT_EQ(bar_url, observer.last_navigation_url()); |
| 1434 | |
| 1435 | // Ensure that we have created new processes for the subframes. |
| 1436 | ASSERT_EQ(2U, root->child_count()); |
| 1437 | FrameTreeNode* foo_child = root->child_at(0); |
| 1438 | SiteInstance* foo_site_instance = |
| 1439 | foo_child->current_frame_host()->GetSiteInstance(); |
| 1440 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance); |
| 1441 | FrameTreeNode* bar_child = root->child_at(1); |
| 1442 | SiteInstance* bar_site_instance = |
| 1443 | bar_child->current_frame_host()->GetSiteInstance(); |
| 1444 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance); |
| 1445 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1446 | EXPECT_EQ( |
| 1447 | " Site A ------------ proxies for B C\n" |
| 1448 | " |--Site B ------- proxies for A C\n" |
| 1449 | " +--Site C ------- proxies for A B\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1450 | "Where A = http://a.com/\n" |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1451 | " B = http://foo.com/\n" |
| 1452 | " C = http://bar.com/", |
| 1453 | DepictFrameTree(root)); |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1454 | |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1455 | // Simulate an attempt to detach the root frame from foo_site_instance. This |
| 1456 | // should kill foo_site_instance's process. |
| 1457 | RenderFrameProxyHost* foo_mainframe_rfph = |
| 1458 | root->render_manager()->GetRenderFrameProxyHost(foo_site_instance); |
| 1459 | content::RenderProcessHostWatcher foo_terminated( |
| 1460 | foo_mainframe_rfph->GetProcess(), |
| 1461 | content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 1462 | FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID()); |
| 1463 | IPC::IpcSecurityTestUtil::PwnMessageReceived( |
| 1464 | foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2); |
| 1465 | foo_terminated.Wait(); |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1466 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1467 | EXPECT_EQ( |
| 1468 | " Site A ------------ proxies for B C\n" |
| 1469 | " |--Site B ------- proxies for A C\n" |
| 1470 | " +--Site C ------- proxies for A B\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1471 | "Where A = http://a.com/\n" |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1472 | " B = http://foo.com/ (no process)\n" |
| 1473 | " C = http://bar.com/", |
| 1474 | DepictFrameTree(root)); |
creis | 0f6edddc | 2015-04-08 00:20:52 | [diff] [blame] | 1475 | } |
| 1476 | |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1477 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrame) { |
| 1478 | GURL main_url(embedded_test_server()->GetURL( |
| 1479 | "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))")); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1480 | NavigateToURL(shell(), main_url); |
| 1481 | |
| 1482 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1483 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1484 | |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 1485 | TestNavigationObserver observer(shell()->web_contents()); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1486 | |
| 1487 | // Load same-site page into iframe. |
| 1488 | FrameTreeNode* child = root->child_at(0); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1489 | GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1490 | NavigateFrameToURL(child, http_url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 1491 | EXPECT_EQ(http_url, observer.last_navigation_url()); |
| 1492 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1493 | |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1494 | // Load cross-site page into iframe. |
nasko | 30374c7 | 2014-10-30 19:18:37 | [diff] [blame] | 1495 | GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html"); |
| 1496 | NavigateFrameToURL(root->child_at(0), url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 1497 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1498 | EXPECT_EQ(url, observer.last_navigation_url()); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1499 | |
| 1500 | // Ensure that we have created a new process for the subframe. |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1501 | EXPECT_EQ( |
| 1502 | " Site A ------------ proxies for B\n" |
| 1503 | " |--Site B ------- proxies for A\n" |
| 1504 | " +--Site A ------- proxies for B\n" |
| 1505 | " |--Site A -- proxies for B\n" |
| 1506 | " +--Site A -- proxies for B\n" |
| 1507 | " +--Site A -- proxies for B\n" |
| 1508 | "Where A = http://a.com/\n" |
| 1509 | " B = http://foo.com/", |
| 1510 | DepictFrameTree(root)); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1511 | SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance(); |
| 1512 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance); |
| 1513 | |
| 1514 | // Emulate the main frame changing the src of the iframe such that it |
| 1515 | // navigates cross-site. |
nasko | 30374c7 | 2014-10-30 19:18:37 | [diff] [blame] | 1516 | url = embedded_test_server()->GetURL("bar.com", "/title3.html"); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1517 | NavigateIframeToURL(shell()->web_contents(), "child-0", url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 1518 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1519 | EXPECT_EQ(url, observer.last_navigation_url()); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1520 | |
| 1521 | // Check again that a new process is created and is different from the |
| 1522 | // top level one and the previous one. |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1523 | EXPECT_EQ( |
| 1524 | " Site A ------------ proxies for C\n" |
| 1525 | " |--Site C ------- proxies for A\n" |
| 1526 | " +--Site A ------- proxies for C\n" |
| 1527 | " |--Site A -- proxies for C\n" |
| 1528 | " +--Site A -- proxies for C\n" |
| 1529 | " +--Site A -- proxies for C\n" |
| 1530 | "Where A = http://a.com/\n" |
| 1531 | " C = http://bar.com/", |
| 1532 | DepictFrameTree(root)); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1533 | |
japhet | e6adf14 | 2014-10-31 00:01:49 | [diff] [blame] | 1534 | // Navigate back to the parent's origin and ensure we return to the |
| 1535 | // parent's process. |
| 1536 | NavigateFrameToURL(child, http_url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 1537 | EXPECT_EQ(http_url, observer.last_navigation_url()); |
| 1538 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
japhet | e6adf14 | 2014-10-31 00:01:49 | [diff] [blame] | 1539 | EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), |
| 1540 | child->current_frame_host()->GetSiteInstance()); |
japhet | 70ea134 | 2014-09-30 21:56:39 | [diff] [blame] | 1541 | } |
| 1542 | |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1543 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1544 | NavigateRemoteFrameToBlankAndDataURLs) { |
| 1545 | GURL main_url(embedded_test_server()->GetURL( |
| 1546 | "a.com", "/cross_site_iframe_factory.html?a(a,a(a))")); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1547 | NavigateToURL(shell(), main_url); |
| 1548 | |
| 1549 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1550 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1551 | |
| 1552 | TestNavigationObserver observer(shell()->web_contents()); |
| 1553 | |
| 1554 | // Load same-site page into iframe. |
| 1555 | FrameTreeNode* child = root->child_at(0); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1556 | GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1557 | NavigateFrameToURL(child, http_url); |
| 1558 | EXPECT_EQ(http_url, observer.last_navigation_url()); |
| 1559 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1560 | EXPECT_EQ( |
| 1561 | " Site A\n" |
| 1562 | " |--Site A\n" |
| 1563 | " +--Site A\n" |
| 1564 | " +--Site A\n" |
| 1565 | "Where A = http://a.com/", |
| 1566 | DepictFrameTree(root)); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1567 | |
| 1568 | // Load cross-site page into iframe. |
| 1569 | GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html"); |
nasko | d948aa86 | 2016-04-26 19:58:52 | [diff] [blame] | 1570 | NavigateFrameToURL(child, url); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1571 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1572 | EXPECT_EQ(url, observer.last_navigation_url()); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1573 | EXPECT_EQ( |
| 1574 | " Site A ------------ proxies for B\n" |
| 1575 | " |--Site B ------- proxies for A\n" |
| 1576 | " +--Site A ------- proxies for B\n" |
| 1577 | " +--Site A -- proxies for B\n" |
| 1578 | "Where A = http://a.com/\n" |
| 1579 | " B = http://foo.com/", |
| 1580 | DepictFrameTree(root)); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1581 | |
| 1582 | // Navigate iframe to a data URL. The navigation happens from a script in the |
| 1583 | // parent frame, so the data URL should be committed in the same SiteInstance |
| 1584 | // as the parent frame. |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 1585 | RenderFrameDeletedObserver deleted_observer1( |
| 1586 | root->child_at(0)->current_frame_host()); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1587 | GURL data_url("data:text/html,dataurl"); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1588 | NavigateIframeToURL(shell()->web_contents(), "child-0", data_url); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1589 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1590 | EXPECT_EQ(data_url, observer.last_navigation_url()); |
| 1591 | |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 1592 | // Wait for the old process to exit, to verify that the proxies go away. |
| 1593 | deleted_observer1.WaitUntilDeleted(); |
| 1594 | |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1595 | // Ensure that we have navigated using the top level process. |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1596 | EXPECT_EQ( |
| 1597 | " Site A\n" |
| 1598 | " |--Site A\n" |
| 1599 | " +--Site A\n" |
| 1600 | " +--Site A\n" |
| 1601 | "Where A = http://a.com/", |
| 1602 | DepictFrameTree(root)); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1603 | |
| 1604 | // Load cross-site page into iframe. |
| 1605 | url = embedded_test_server()->GetURL("bar.com", "/title2.html"); |
nasko | d948aa86 | 2016-04-26 19:58:52 | [diff] [blame] | 1606 | NavigateFrameToURL(child, url); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1607 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1608 | EXPECT_EQ(url, observer.last_navigation_url()); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1609 | EXPECT_EQ( |
| 1610 | " Site A ------------ proxies for C\n" |
| 1611 | " |--Site C ------- proxies for A\n" |
| 1612 | " +--Site A ------- proxies for C\n" |
| 1613 | " +--Site A -- proxies for C\n" |
| 1614 | "Where A = http://a.com/\n" |
| 1615 | " C = http://bar.com/", |
| 1616 | DepictFrameTree(root)); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1617 | |
| 1618 | // Navigate iframe to about:blank. The navigation happens from a script in the |
| 1619 | // parent frame, so it should be committed in the same SiteInstance as the |
| 1620 | // parent frame. |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 1621 | RenderFrameDeletedObserver deleted_observer2( |
| 1622 | root->child_at(0)->current_frame_host()); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1623 | GURL about_blank_url("about:blank"); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1624 | NavigateIframeToURL(shell()->web_contents(), "child-0", about_blank_url); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1625 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1626 | EXPECT_EQ(about_blank_url, observer.last_navigation_url()); |
| 1627 | |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 1628 | // Wait for the old process to exit, to verify that the proxies go away. |
| 1629 | deleted_observer2.WaitUntilDeleted(); |
| 1630 | |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1631 | // Ensure that we have navigated using the top level process. |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1632 | EXPECT_EQ( |
| 1633 | " Site A\n" |
| 1634 | " |--Site A\n" |
| 1635 | " +--Site A\n" |
| 1636 | " +--Site A\n" |
| 1637 | "Where A = http://a.com/", |
| 1638 | DepictFrameTree(root)); |
nasko | d948aa86 | 2016-04-26 19:58:52 | [diff] [blame] | 1639 | |
| 1640 | // Load cross-site page into iframe again. |
| 1641 | url = embedded_test_server()->GetURL("f00.com", "/title3.html"); |
| 1642 | NavigateFrameToURL(child, url); |
| 1643 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1644 | EXPECT_EQ(url, observer.last_navigation_url()); |
| 1645 | EXPECT_EQ( |
| 1646 | " Site A ------------ proxies for D\n" |
| 1647 | " |--Site D ------- proxies for A\n" |
| 1648 | " +--Site A ------- proxies for D\n" |
| 1649 | " +--Site A -- proxies for D\n" |
| 1650 | "Where A = http://a.com/\n" |
| 1651 | " D = http://f00.com/", |
| 1652 | DepictFrameTree(root)); |
| 1653 | |
| 1654 | // Navigate the iframe itself to about:blank using a script executing in its |
| 1655 | // own context. It should stay in the same SiteInstance as before, not the |
| 1656 | // parent one. |
| 1657 | std::string script( |
| 1658 | "window.domAutomationController.send(" |
| 1659 | "window.location.href = 'about:blank');"); |
| 1660 | TestFrameNavigationObserver frame_observer(child); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 1661 | EXPECT_TRUE(ExecuteScript(child, script)); |
nasko | d948aa86 | 2016-04-26 19:58:52 | [diff] [blame] | 1662 | frame_observer.Wait(); |
| 1663 | EXPECT_EQ(about_blank_url, child->current_url()); |
| 1664 | |
| 1665 | // Ensure that we have navigated using the top level process. |
| 1666 | EXPECT_EQ( |
| 1667 | " Site A ------------ proxies for D\n" |
| 1668 | " |--Site D ------- proxies for A\n" |
| 1669 | " +--Site A ------- proxies for D\n" |
| 1670 | " +--Site A -- proxies for D\n" |
| 1671 | "Where A = http://a.com/\n" |
| 1672 | " D = http://f00.com/", |
| 1673 | DepictFrameTree(root)); |
lfg | f52ea14 | 2015-03-07 23:03:33 | [diff] [blame] | 1674 | } |
| 1675 | |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1676 | // This test checks that killing a renderer process of a remote frame |
| 1677 | // and then navigating some other frame to the same SiteInstance of the killed |
| 1678 | // process works properly. |
| 1679 | // This can be illustrated as follows, |
| 1680 | // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed |
| 1681 | // B process: |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 1682 | // |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1683 | // 1 A A A |
| 1684 | // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ . |
| 1685 | // 2 3 B A B* A B* B |
| 1686 | // |
| 1687 | // Initially, node1.proxy_hosts_ = {B} |
| 1688 | // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate |
| 1689 | // 3 to B and we expect that to complete normally. |
| 1690 | // See http://crbug.com/432107. |
| 1691 | // |
| 1692 | // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to |
| 1693 | // site B and stays in not rendered state. |
| 1694 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 1695 | NavigateRemoteFrameToKilledProcess) { |
| 1696 | GURL main_url(embedded_test_server()->GetURL( |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1697 | "foo.com", "/cross_site_iframe_factory.html?foo.com(bar.com, foo.com)")); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1698 | NavigateToURL(shell(), main_url); |
| 1699 | |
| 1700 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1701 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1702 | |
| 1703 | TestNavigationObserver observer(shell()->web_contents()); |
| 1704 | ASSERT_EQ(2U, root->child_count()); |
| 1705 | |
| 1706 | // Make sure node2 points to the correct cross-site page. |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1707 | GURL site_b_url = embedded_test_server()->GetURL( |
| 1708 | "bar.com", "/cross_site_iframe_factory.html?bar.com()"); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1709 | FrameTreeNode* node2 = root->child_at(0); |
| 1710 | EXPECT_EQ(site_b_url, node2->current_url()); |
| 1711 | |
| 1712 | // Kill that cross-site renderer. |
| 1713 | RenderProcessHost* child_process = |
| 1714 | node2->current_frame_host()->GetProcess(); |
| 1715 | RenderProcessHostWatcher crash_observer( |
| 1716 | child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 1717 | child_process->Shutdown(0, false); |
| 1718 | crash_observer.Wait(); |
| 1719 | |
| 1720 | // Now navigate the second iframe (node3) to the same site as the node2. |
| 1721 | FrameTreeNode* node3 = root->child_at(1); |
| 1722 | NavigateFrameToURL(node3, site_b_url); |
| 1723 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1724 | EXPECT_EQ(site_b_url, observer.last_navigation_url()); |
| 1725 | } |
| 1726 | |
| 1727 | // This test is similar to |
| 1728 | // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with |
| 1729 | // addition that node2 also has a cross-origin frame to site C. |
| 1730 | // |
| 1731 | // 1 A A A |
| 1732 | // / \ / \ / \ / \ . |
| 1733 | // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 1734 | // / / |
| 1735 | // 4 C |
| 1736 | // |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1737 | // Initially, node1.proxy_hosts_ = {B, C} |
| 1738 | // After we kill B, we make sure B stays in node1.proxy_hosts_, but |
| 1739 | // C gets cleared from node1.proxy_hosts_. |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 1740 | // |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1741 | // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to |
| 1742 | // site B and stays in not rendered state. |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 1743 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1744 | NavigateRemoteFrameToKilledProcessWithSubtree) { |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1745 | GURL main_url(embedded_test_server()->GetURL( |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1746 | "a.com", "/cross_site_iframe_factory.html?a(bar(baz), a)")); |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 1747 | NavigateToURL(shell(), main_url); |
| 1748 | |
| 1749 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1750 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 1751 | TestNavigationObserver observer(shell()->web_contents()); |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 1752 | |
| 1753 | ASSERT_EQ(2U, root->child_count()); |
| 1754 | |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1755 | GURL site_b_url(embedded_test_server()->GetURL( |
| 1756 | "bar.com", "/cross_site_iframe_factory.html?bar(baz())")); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 1757 | // We can't use a TestNavigationObserver to verify the URL here, |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 1758 | // since the frame has children that may have clobbered it in the observer. |
| 1759 | EXPECT_EQ(site_b_url, root->child_at(0)->current_url()); |
| 1760 | |
| 1761 | // Ensure that a new process is created for node2. |
| 1762 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 1763 | root->child_at(0)->current_frame_host()->GetSiteInstance()); |
| 1764 | // Ensure that a new process is *not* created for node3. |
| 1765 | EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), |
| 1766 | root->child_at(1)->current_frame_host()->GetSiteInstance()); |
| 1767 | |
| 1768 | ASSERT_EQ(1U, root->child_at(0)->child_count()); |
| 1769 | |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1770 | // Make sure node4 points to the correct cross-site page. |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 1771 | FrameTreeNode* node4 = root->child_at(0)->child_at(0); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 1772 | GURL site_c_url(embedded_test_server()->GetURL( |
| 1773 | "baz.com", "/cross_site_iframe_factory.html?baz()")); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1774 | EXPECT_EQ(site_c_url, node4->current_url()); |
| 1775 | |
| 1776 | // |site_instance_c| is expected to go away once we kill |child_process_b| |
| 1777 | // below, so create a local scope so we can extend the lifetime of |
| 1778 | // |site_instance_c| with a refptr. |
| 1779 | { |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1780 | // Initially each frame has proxies for the other sites. |
| 1781 | EXPECT_EQ( |
| 1782 | " Site A ------------ proxies for B C\n" |
| 1783 | " |--Site B ------- proxies for A C\n" |
| 1784 | " | +--Site C -- proxies for A B\n" |
| 1785 | " +--Site A ------- proxies for B C\n" |
| 1786 | "Where A = http://a.com/\n" |
| 1787 | " B = http://bar.com/\n" |
| 1788 | " C = http://baz.com/", |
| 1789 | DepictFrameTree(root)); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1790 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1791 | // Kill the render process for Site B. |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1792 | RenderProcessHost* child_process_b = |
| 1793 | root->child_at(0)->current_frame_host()->GetProcess(); |
| 1794 | RenderProcessHostWatcher crash_observer( |
| 1795 | child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 1796 | child_process_b->Shutdown(0, false); |
| 1797 | crash_observer.Wait(); |
| 1798 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1799 | // The Site C frame (a child of the crashed Site B frame) should go away, |
| 1800 | // and there should be no remaining proxies for site C anywhere. |
| 1801 | EXPECT_EQ( |
| 1802 | " Site A ------------ proxies for B\n" |
| 1803 | " |--Site B ------- proxies for A\n" |
| 1804 | " +--Site A ------- proxies for B\n" |
| 1805 | "Where A = http://a.com/\n" |
| 1806 | " B = http://bar.com/ (no process)", |
| 1807 | DepictFrameTree(root)); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1808 | } |
| 1809 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1810 | // Now navigate the second iframe (node3) to Site B also. |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1811 | FrameTreeNode* node3 = root->child_at(1); |
| 1812 | GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html"); |
| 1813 | NavigateFrameToURL(node3, url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 1814 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1815 | EXPECT_EQ(url, observer.last_navigation_url()); |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 1816 | |
| 1817 | EXPECT_EQ( |
| 1818 | " Site A ------------ proxies for B\n" |
| 1819 | " |--Site B ------- proxies for A\n" |
| 1820 | " +--Site B ------- proxies for A\n" |
| 1821 | "Where A = http://a.com/\n" |
| 1822 | " B = http://bar.com/", |
| 1823 | DepictFrameTree(root)); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 1824 | } |
| 1825 | |
creis | 9321868 | 2016-01-28 04:34:10 | [diff] [blame] | 1826 | // Ensure that the renderer process doesn't crash when the main frame navigates |
| 1827 | // a remote child to a page that results in a network error. |
| 1828 | // See https://crbug.com/558016. |
| 1829 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteAfterError) { |
| 1830 | GURL main_url(embedded_test_server()->GetURL( |
| 1831 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 1832 | NavigateToURL(shell(), main_url); |
| 1833 | |
| 1834 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1835 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
creis | 9321868 | 2016-01-28 04:34:10 | [diff] [blame] | 1836 | |
creis | 9321868 | 2016-01-28 04:34:10 | [diff] [blame] | 1837 | // Load same-site page into iframe. |
clamy | 7531fd26 | 2016-02-26 12:37:15 | [diff] [blame] | 1838 | { |
| 1839 | TestNavigationObserver observer(shell()->web_contents()); |
| 1840 | FrameTreeNode* child = root->child_at(0); |
| 1841 | GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 1842 | NavigateFrameToURL(child, http_url); |
| 1843 | EXPECT_EQ(http_url, observer.last_navigation_url()); |
| 1844 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1845 | observer.Wait(); |
| 1846 | } |
creis | 9321868 | 2016-01-28 04:34:10 | [diff] [blame] | 1847 | |
| 1848 | // Load cross-site page into iframe. |
clamy | 7531fd26 | 2016-02-26 12:37:15 | [diff] [blame] | 1849 | { |
| 1850 | TestNavigationObserver observer(shell()->web_contents()); |
| 1851 | FrameTreeNode* child = root->child_at(0); |
| 1852 | GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html"); |
| 1853 | NavigateFrameToURL(root->child_at(0), url); |
| 1854 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1855 | EXPECT_EQ(url, observer.last_navigation_url()); |
| 1856 | observer.Wait(); |
creis | 9321868 | 2016-01-28 04:34:10 | [diff] [blame] | 1857 | |
clamy | 7531fd26 | 2016-02-26 12:37:15 | [diff] [blame] | 1858 | // Ensure that we have created a new process for the subframe. |
| 1859 | EXPECT_EQ( |
| 1860 | " Site A ------------ proxies for B\n" |
| 1861 | " +--Site B ------- proxies for A\n" |
| 1862 | "Where A = http://a.com/\n" |
| 1863 | " B = http://foo.com/", |
| 1864 | DepictFrameTree(root)); |
| 1865 | SiteInstance* site_instance = |
| 1866 | child->current_frame_host()->GetSiteInstance(); |
| 1867 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance); |
| 1868 | } |
creis | 9321868 | 2016-01-28 04:34:10 | [diff] [blame] | 1869 | |
| 1870 | // Stop the test server and try to navigate the remote frame. |
clamy | 7531fd26 | 2016-02-26 12:37:15 | [diff] [blame] | 1871 | { |
| 1872 | GURL url = embedded_test_server()->GetURL("bar.com", "/title3.html"); |
| 1873 | EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete()); |
| 1874 | NavigateIframeToURL(shell()->web_contents(), "child-0", url); |
| 1875 | } |
creis | 9321868 | 2016-01-28 04:34:10 | [diff] [blame] | 1876 | } |
| 1877 | |
creis | 1857908a | 2016-02-25 20:31:52 | [diff] [blame] | 1878 | // Ensure that a cross-site page ends up in the correct process when it |
| 1879 | // successfully loads after earlier encountering a network error for it. |
| 1880 | // See https://crbug.com/560511. |
| 1881 | // TODO(creis): Make the net error page show in the correct process as well, |
| 1882 | // per https://crbug.com/588314. |
| 1883 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ProcessTransferAfterError) { |
| 1884 | GURL main_url(embedded_test_server()->GetURL( |
| 1885 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 1886 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 1887 | |
| 1888 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1889 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
creis | 1857908a | 2016-02-25 20:31:52 | [diff] [blame] | 1890 | FrameTreeNode* child = root->child_at(0); |
| 1891 | GURL url_a = child->current_url(); |
| 1892 | |
| 1893 | // Disable host resolution in the test server and try to navigate the subframe |
| 1894 | // cross-site, which will lead to a committed net error (which looks like |
| 1895 | // success to the TestNavigationObserver). |
| 1896 | GURL url_b = embedded_test_server()->GetURL("b.com", "/title3.html"); |
| 1897 | host_resolver()->ClearRules(); |
| 1898 | TestNavigationObserver observer(shell()->web_contents()); |
| 1899 | NavigateIframeToURL(shell()->web_contents(), "child-0", url_b); |
| 1900 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1901 | EXPECT_EQ(url_b, observer.last_navigation_url()); |
clamy | 6e0ee03e | 2016-03-02 15:15:52 | [diff] [blame] | 1902 | EXPECT_EQ(2, shell()->web_contents()->GetController().GetEntryCount()); |
| 1903 | |
| 1904 | // PlzNavigate: Ensure that we have created a new process for the subframe. |
| 1905 | if (IsBrowserSideNavigationEnabled()) { |
| 1906 | EXPECT_EQ( |
| 1907 | " Site A ------------ proxies for B\n" |
| 1908 | " +--Site B ------- proxies for A\n" |
| 1909 | "Where A = http://a.com/\n" |
| 1910 | " B = http://b.com/", |
| 1911 | DepictFrameTree(root)); |
| 1912 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 1913 | child->current_frame_host()->GetSiteInstance()); |
| 1914 | } |
creis | 1857908a | 2016-02-25 20:31:52 | [diff] [blame] | 1915 | |
| 1916 | // The FrameTreeNode should update its URL (so that we don't affect other uses |
| 1917 | // of the API), but the frame's last_successful_url shouldn't change and the |
| 1918 | // origin should be empty. |
clamy | 6e0ee03e | 2016-03-02 15:15:52 | [diff] [blame] | 1919 | // PlzNavigate: We have switched RenderFrameHosts for the subframe, so the |
| 1920 | // last succesful url should be empty (since the frame only loaded an error |
| 1921 | // page). |
| 1922 | if (IsBrowserSideNavigationEnabled()) |
| 1923 | EXPECT_EQ(GURL(), child->current_frame_host()->last_successful_url()); |
| 1924 | else |
| 1925 | EXPECT_EQ(url_a, child->current_frame_host()->last_successful_url()); |
creis | 1857908a | 2016-02-25 20:31:52 | [diff] [blame] | 1926 | EXPECT_EQ(url_b, child->current_url()); |
| 1927 | EXPECT_EQ("null", child->current_origin().Serialize()); |
| 1928 | |
| 1929 | // Try again after re-enabling host resolution. |
| 1930 | host_resolver()->AddRule("*", "127.0.0.1"); |
| 1931 | NavigateIframeToURL(shell()->web_contents(), "child-0", url_b); |
| 1932 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 1933 | EXPECT_EQ(url_b, observer.last_navigation_url()); |
| 1934 | |
| 1935 | // The FrameTreeNode should have updated its URL and origin. |
| 1936 | EXPECT_EQ(url_b, child->current_frame_host()->last_successful_url()); |
| 1937 | EXPECT_EQ(url_b, child->current_url()); |
| 1938 | EXPECT_EQ(url_b.GetOrigin().spec(), |
| 1939 | child->current_origin().Serialize() + '/'); |
| 1940 | |
| 1941 | // Ensure that we have created a new process for the subframe. |
clamy | 6e0ee03e | 2016-03-02 15:15:52 | [diff] [blame] | 1942 | // PlzNavigate: the subframe should still be in its separate process. |
creis | 1857908a | 2016-02-25 20:31:52 | [diff] [blame] | 1943 | EXPECT_EQ( |
| 1944 | " Site A ------------ proxies for B\n" |
| 1945 | " +--Site B ------- proxies for A\n" |
| 1946 | "Where A = http://a.com/\n" |
| 1947 | " B = http://b.com/", |
| 1948 | DepictFrameTree(root)); |
| 1949 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 1950 | child->current_frame_host()->GetSiteInstance()); |
| 1951 | |
| 1952 | // Make sure that the navigation replaced the error page and that going back |
| 1953 | // ends up on the original site. |
| 1954 | EXPECT_EQ(2, shell()->web_contents()->GetController().GetEntryCount()); |
| 1955 | { |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 1956 | RenderFrameDeletedObserver deleted_observer(child->current_frame_host()); |
creis | 1857908a | 2016-02-25 20:31:52 | [diff] [blame] | 1957 | TestNavigationObserver back_load_observer(shell()->web_contents()); |
| 1958 | shell()->web_contents()->GetController().GoBack(); |
| 1959 | back_load_observer.Wait(); |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 1960 | |
| 1961 | // Wait for the old process to exit, to verify that the proxies go away. |
| 1962 | deleted_observer.WaitUntilDeleted(); |
creis | 1857908a | 2016-02-25 20:31:52 | [diff] [blame] | 1963 | } |
| 1964 | EXPECT_EQ( |
| 1965 | " Site A\n" |
| 1966 | " +--Site A\n" |
| 1967 | "Where A = http://a.com/", |
| 1968 | DepictFrameTree(root)); |
| 1969 | EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), |
| 1970 | child->current_frame_host()->GetSiteInstance()); |
| 1971 | EXPECT_EQ(url_a, child->current_frame_host()->last_successful_url()); |
| 1972 | EXPECT_EQ(url_a, child->current_url()); |
| 1973 | EXPECT_EQ(url_a.GetOrigin().spec(), |
| 1974 | child->current_origin().Serialize() + '/'); |
| 1975 | } |
| 1976 | |
alexmos | dcbe3fb4 | 2015-04-29 23:10:37 | [diff] [blame] | 1977 | // Verify that killing a cross-site frame's process B and then navigating a |
| 1978 | // frame to B correctly recreates all proxies in B. |
| 1979 | // |
| 1980 | // 1 A A A |
| 1981 | // / | \ / | \ / | \ / | \ . |
| 1982 | // 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A |
| 1983 | // |
| 1984 | // After the last step, the test sends a postMessage from node 3 to node 4, |
| 1985 | // verifying that a proxy for node 4 has been recreated in process B. This |
| 1986 | // verifies the fix for https://crbug.com/478892. |
| 1987 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 1988 | NavigatingToKilledProcessRestoresAllProxies) { |
| 1989 | // Navigate to a page with three frames: one cross-site and two same-site. |
| 1990 | GURL main_url(embedded_test_server()->GetURL( |
| 1991 | "a.com", "/frame_tree/page_with_three_frames.html")); |
| 1992 | NavigateToURL(shell(), main_url); |
| 1993 | |
| 1994 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 1995 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | dcbe3fb4 | 2015-04-29 23:10:37 | [diff] [blame] | 1996 | TestNavigationObserver observer(shell()->web_contents()); |
| 1997 | |
| 1998 | EXPECT_EQ( |
| 1999 | " Site A ------------ proxies for B\n" |
| 2000 | " |--Site B ------- proxies for A\n" |
| 2001 | " |--Site A ------- proxies for B\n" |
| 2002 | " +--Site A ------- proxies for B\n" |
| 2003 | "Where A = http://a.com/\n" |
| 2004 | " B = http://b.com/", |
| 2005 | DepictFrameTree(root)); |
| 2006 | |
| 2007 | // Kill the first subframe's b.com renderer. |
| 2008 | RenderProcessHost* child_process = |
| 2009 | root->child_at(0)->current_frame_host()->GetProcess(); |
| 2010 | RenderProcessHostWatcher crash_observer( |
| 2011 | child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 2012 | child_process->Shutdown(0, false); |
| 2013 | crash_observer.Wait(); |
| 2014 | |
| 2015 | // Navigate the second subframe to b.com to recreate the b.com process. |
| 2016 | GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html"); |
| 2017 | NavigateFrameToURL(root->child_at(1), b_url); |
alexmos | dcbe3fb4 | 2015-04-29 23:10:37 | [diff] [blame] | 2018 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 2019 | EXPECT_EQ(b_url, observer.last_navigation_url()); |
| 2020 | EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive()); |
| 2021 | |
| 2022 | EXPECT_EQ( |
| 2023 | " Site A ------------ proxies for B\n" |
| 2024 | " |--Site B ------- proxies for A\n" |
| 2025 | " |--Site B ------- proxies for A\n" |
| 2026 | " +--Site A ------- proxies for B\n" |
| 2027 | "Where A = http://a.com/\n" |
| 2028 | " B = http://b.com/", |
| 2029 | DepictFrameTree(root)); |
| 2030 | |
| 2031 | // Check that third subframe's proxy is available in the b.com process by |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 2032 | // sending it a postMessage from second subframe, and waiting for a reply. |
| 2033 | PostMessageAndWaitForReply(root->child_at(1), |
| 2034 | "postToSibling('subframe-msg','frame3')", |
| 2035 | "\"done-frame2\""); |
alexmos | dcbe3fb4 | 2015-04-29 23:10:37 | [diff] [blame] | 2036 | } |
| 2037 | |
alexmos | a398899 | 2015-05-14 23:26:21 | [diff] [blame] | 2038 | // Verify that proxy creation doesn't recreate a crashed process if no frame |
| 2039 | // will be created in it. |
| 2040 | // |
| 2041 | // 1 A A A |
| 2042 | // / | \ / | \ / | \ / | \ . |
| 2043 | // 2 3 4 -> B A A -> Kill B -> B* A A -> B* A A |
| 2044 | // \ . |
| 2045 | // A |
| 2046 | // |
| 2047 | // The test kills process B (node 2), creates a child frame of node 4 in |
| 2048 | // process A, and then checks that process B isn't resurrected to create a |
| 2049 | // proxy for the new child frame. See https://crbug.com/476846. |
| 2050 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 2051 | CreateChildFrameAfterKillingProcess) { |
| 2052 | // Navigate to a page with three frames: one cross-site and two same-site. |
| 2053 | GURL main_url(embedded_test_server()->GetURL( |
| 2054 | "a.com", "/frame_tree/page_with_three_frames.html")); |
| 2055 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 2056 | |
| 2057 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2058 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | a398899 | 2015-05-14 23:26:21 | [diff] [blame] | 2059 | |
| 2060 | EXPECT_EQ( |
| 2061 | " Site A ------------ proxies for B\n" |
| 2062 | " |--Site B ------- proxies for A\n" |
| 2063 | " |--Site A ------- proxies for B\n" |
| 2064 | " +--Site A ------- proxies for B\n" |
| 2065 | "Where A = http://a.com/\n" |
| 2066 | " B = http://b.com/", |
| 2067 | DepictFrameTree(root)); |
| 2068 | SiteInstance* b_site_instance = |
| 2069 | root->child_at(0)->current_frame_host()->GetSiteInstance(); |
| 2070 | |
| 2071 | // Kill the first subframe's renderer (B). |
| 2072 | RenderProcessHost* child_process = |
| 2073 | root->child_at(0)->current_frame_host()->GetProcess(); |
| 2074 | RenderProcessHostWatcher crash_observer( |
| 2075 | child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 2076 | child_process->Shutdown(0, false); |
| 2077 | crash_observer.Wait(); |
| 2078 | |
| 2079 | // Add a new child frame to the third subframe. |
| 2080 | RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1); |
| 2081 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2082 | root->child_at(2), |
alexmos | a398899 | 2015-05-14 23:26:21 | [diff] [blame] | 2083 | "document.body.appendChild(document.createElement('iframe'));")); |
| 2084 | frame_observer.Wait(); |
| 2085 | |
| 2086 | // The new frame should have a RenderFrameProxyHost for B, but it should not |
| 2087 | // be alive, and B should still not have a process (verified by last line of |
| 2088 | // expected DepictFrameTree output). |
| 2089 | EXPECT_EQ( |
| 2090 | " Site A ------------ proxies for B\n" |
| 2091 | " |--Site B ------- proxies for A\n" |
| 2092 | " |--Site A ------- proxies for B\n" |
| 2093 | " +--Site A ------- proxies for B\n" |
| 2094 | " +--Site A -- proxies for B\n" |
| 2095 | "Where A = http://a.com/\n" |
| 2096 | " B = http://b.com/ (no process)", |
| 2097 | DepictFrameTree(root)); |
| 2098 | FrameTreeNode* grandchild = root->child_at(2)->child_at(0); |
| 2099 | RenderFrameProxyHost* grandchild_rfph = |
| 2100 | grandchild->render_manager()->GetRenderFrameProxyHost(b_site_instance); |
| 2101 | EXPECT_FALSE(grandchild_rfph->is_render_frame_proxy_live()); |
| 2102 | |
| 2103 | // Navigate the second subframe to b.com to recreate process B. |
| 2104 | TestNavigationObserver observer(shell()->web_contents()); |
| 2105 | GURL b_url = embedded_test_server()->GetURL("b.com", "/title1.html"); |
| 2106 | NavigateFrameToURL(root->child_at(1), b_url); |
| 2107 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 2108 | EXPECT_EQ(b_url, observer.last_navigation_url()); |
| 2109 | |
| 2110 | // Ensure that the grandchild RenderFrameProxy in B was created when process |
| 2111 | // B was restored. |
| 2112 | EXPECT_TRUE(grandchild_rfph->is_render_frame_proxy_live()); |
| 2113 | } |
| 2114 | |
alexmos | d6ac5467 | 2015-06-25 18:10:14 | [diff] [blame] | 2115 | // Verify that creating a child frame after killing and reloading an opener |
| 2116 | // process doesn't crash. See https://crbug.com/501152. |
| 2117 | // 1. Navigate to site A. |
| 2118 | // 2. Open a popup with window.open and navigate it cross-process to site B. |
| 2119 | // 3. Kill process A for the original tab. |
| 2120 | // 4. Reload the original tab to resurrect process A. |
| 2121 | // 5. Add a child frame to the top-level frame in the popup tab B. |
| 2122 | // In step 5, we try to create proxies for the child frame in all SiteInstances |
| 2123 | // for which its parent has proxies. This includes A. However, even though |
| 2124 | // process A is live (step 4), the parent proxy in A is not live (which was |
| 2125 | // incorrectly assumed previously). This is because step 4 does not resurrect |
| 2126 | // proxies for popups opened before the crash. |
| 2127 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 2128 | CreateChildFrameAfterKillingOpener) { |
| 2129 | GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 2130 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 2131 | |
| 2132 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2133 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | d6ac5467 | 2015-06-25 18:10:14 | [diff] [blame] | 2134 | SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance(); |
| 2135 | |
| 2136 | // Open a popup and navigate it cross-process to b.com. |
| 2137 | ShellAddedObserver new_shell_observer; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2138 | EXPECT_TRUE(ExecuteScript(root, "popup = window.open('about:blank');")); |
alexmos | d6ac5467 | 2015-06-25 18:10:14 | [diff] [blame] | 2139 | Shell* popup = new_shell_observer.GetShell(); |
| 2140 | GURL popup_url(embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 2141 | EXPECT_TRUE(NavigateToURL(popup, popup_url)); |
| 2142 | |
| 2143 | // Verify that each top-level frame has proxies in the other's SiteInstance. |
| 2144 | FrameTreeNode* popup_root = |
| 2145 | static_cast<WebContentsImpl*>(popup->web_contents()) |
| 2146 | ->GetFrameTree() |
| 2147 | ->root(); |
| 2148 | EXPECT_EQ( |
| 2149 | " Site A ------------ proxies for B\n" |
| 2150 | "Where A = http://a.com/\n" |
| 2151 | " B = http://b.com/", |
| 2152 | DepictFrameTree(root)); |
| 2153 | EXPECT_EQ( |
| 2154 | " Site B ------------ proxies for A\n" |
| 2155 | "Where A = http://a.com/\n" |
| 2156 | " B = http://b.com/", |
| 2157 | DepictFrameTree(popup_root)); |
| 2158 | |
| 2159 | // Kill the first window's renderer (a.com). |
| 2160 | RenderProcessHost* child_process = root->current_frame_host()->GetProcess(); |
| 2161 | RenderProcessHostWatcher crash_observer( |
| 2162 | child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 2163 | child_process->Shutdown(0, false); |
| 2164 | crash_observer.Wait(); |
| 2165 | EXPECT_FALSE(root->current_frame_host()->IsRenderFrameLive()); |
| 2166 | |
| 2167 | // The proxy for the popup in a.com should've died. |
| 2168 | RenderFrameProxyHost* rfph = |
| 2169 | popup_root->render_manager()->GetRenderFrameProxyHost(site_instance_a); |
| 2170 | EXPECT_FALSE(rfph->is_render_frame_proxy_live()); |
| 2171 | |
| 2172 | // Recreate the a.com renderer. |
| 2173 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 2174 | EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive()); |
| 2175 | |
| 2176 | // The popup's proxy in a.com should still not be live. Re-navigating the |
| 2177 | // main window to a.com doesn't reinitialize a.com proxies for popups |
| 2178 | // previously opened from the main window. |
| 2179 | EXPECT_FALSE(rfph->is_render_frame_proxy_live()); |
| 2180 | |
| 2181 | // Add a new child frame on the popup. |
| 2182 | RenderFrameHostCreatedObserver frame_observer(popup->web_contents(), 1); |
| 2183 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2184 | popup, "document.body.appendChild(document.createElement('iframe'));")); |
alexmos | d6ac5467 | 2015-06-25 18:10:14 | [diff] [blame] | 2185 | frame_observer.Wait(); |
| 2186 | |
| 2187 | // Both the child frame's and its parent's proxies should still not be live. |
| 2188 | // The main page can't reach them since it lost reference to the popup after |
| 2189 | // it crashed, so there is no need to create them. |
| 2190 | EXPECT_FALSE(rfph->is_render_frame_proxy_live()); |
| 2191 | RenderFrameProxyHost* child_rfph = |
| 2192 | popup_root->child_at(0)->render_manager()->GetRenderFrameProxyHost( |
| 2193 | site_instance_a); |
| 2194 | EXPECT_TRUE(child_rfph); |
| 2195 | EXPECT_FALSE(child_rfph->is_render_frame_proxy_live()); |
| 2196 | } |
| 2197 | |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 2198 | // In A-embed-B-embed-C scenario, verify that killing process B clears proxies |
| 2199 | // of C from the tree. |
| 2200 | // |
| 2201 | // 1 A A |
| 2202 | // / \ / \ / \ . |
| 2203 | // 2 3 -> B A -> Kill B -> B* A |
| 2204 | // / / |
| 2205 | // 4 C |
| 2206 | // |
| 2207 | // node1 is the root. |
| 2208 | // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C. |
| 2209 | // After we kill B, make sure proxies for C are cleared. |
| 2210 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 2211 | KillingRendererClearsDescendantProxies) { |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2212 | GURL main_url(embedded_test_server()->GetURL( |
| 2213 | "a.com", "/frame_tree/page_with_two_frames_nested.html")); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 2214 | NavigateToURL(shell(), main_url); |
| 2215 | |
| 2216 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2217 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
lazyboy | bb1af56 | 2015-02-04 02:36:02 | [diff] [blame] | 2218 | ASSERT_EQ(2U, root->child_count()); |
| 2219 | |
| 2220 | GURL site_b_url( |
| 2221 | embedded_test_server()->GetURL( |
| 2222 | "bar.com", "/frame_tree/page_with_one_frame.html")); |
| 2223 | // We can't use a TestNavigationObserver to verify the URL here, |
| 2224 | // since the frame has children that may have clobbered it in the observer. |
| 2225 | EXPECT_EQ(site_b_url, root->child_at(0)->current_url()); |
| 2226 | |
| 2227 | // Ensure that a new process is created for node2. |
| 2228 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 2229 | root->child_at(0)->current_frame_host()->GetSiteInstance()); |
| 2230 | // Ensure that a new process is *not* created for node3. |
| 2231 | EXPECT_EQ(shell()->web_contents()->GetSiteInstance(), |
| 2232 | root->child_at(1)->current_frame_host()->GetSiteInstance()); |
| 2233 | |
| 2234 | ASSERT_EQ(1U, root->child_at(0)->child_count()); |
| 2235 | |
| 2236 | // Make sure node4 points to the correct cross-site-page. |
| 2237 | FrameTreeNode* node4 = root->child_at(0)->child_at(0); |
| 2238 | GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html")); |
| 2239 | EXPECT_EQ(site_c_url, node4->current_url()); |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 2240 | |
creis | ceaabfd5 | 2015-05-27 20:26:46 | [diff] [blame] | 2241 | // |site_instance_c|'s frames and proxies are expected to go away once we kill |
| 2242 | // |child_process_b| below. |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2243 | scoped_refptr<SiteInstanceImpl> site_instance_c = |
| 2244 | node4->current_frame_host()->GetSiteInstance(); |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 2245 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2246 | // Initially proxies for both B and C will be present in the root. |
| 2247 | EXPECT_EQ( |
| 2248 | " Site A ------------ proxies for B C\n" |
| 2249 | " |--Site B ------- proxies for A C\n" |
| 2250 | " | +--Site C -- proxies for A B\n" |
| 2251 | " +--Site A ------- proxies for B C\n" |
| 2252 | "Where A = http://a.com/\n" |
| 2253 | " B = http://bar.com/\n" |
| 2254 | " C = http://baz.com/", |
| 2255 | DepictFrameTree(root)); |
creis | ceaabfd5 | 2015-05-27 20:26:46 | [diff] [blame] | 2256 | |
| 2257 | EXPECT_GT(site_instance_c->active_frame_count(), 0U); |
| 2258 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2259 | // Kill process B. |
| 2260 | RenderProcessHost* child_process_b = |
| 2261 | root->child_at(0)->current_frame_host()->GetProcess(); |
| 2262 | RenderProcessHostWatcher crash_observer( |
| 2263 | child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 2264 | child_process_b->Shutdown(0, false); |
| 2265 | crash_observer.Wait(); |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 2266 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2267 | // Make sure proxy C has gone from root. |
| 2268 | // Make sure proxy C has gone from node3 as well. |
| 2269 | // Make sure proxy B stays around in root and node3. |
| 2270 | EXPECT_EQ( |
| 2271 | " Site A ------------ proxies for B\n" |
| 2272 | " |--Site B ------- proxies for A\n" |
| 2273 | " +--Site A ------- proxies for B\n" |
| 2274 | "Where A = http://a.com/\n" |
| 2275 | " B = http://bar.com/ (no process)", |
| 2276 | DepictFrameTree(root)); |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 2277 | |
creis | ceaabfd5 | 2015-05-27 20:26:46 | [diff] [blame] | 2278 | EXPECT_EQ(0U, site_instance_c->active_frame_count()); |
lazyboy | f285220 | 2014-12-19 05:31:52 | [diff] [blame] | 2279 | } |
| 2280 | |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2281 | // Crash a subframe and ensures its children are cleared from the FrameTree. |
| 2282 | // See http://crbug.com/338508. |
nasko | 4feae97 | 2015-07-01 16:38:02 | [diff] [blame] | 2283 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrashSubframe) { |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 2284 | GURL main_url(embedded_test_server()->GetURL( |
| 2285 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2286 | NavigateToURL(shell(), main_url); |
| 2287 | |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2288 | // Check the subframe process. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2289 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 2290 | EXPECT_EQ( |
| 2291 | " Site A ------------ proxies for B\n" |
| 2292 | " +--Site B ------- proxies for A\n" |
| 2293 | "Where A = http://a.com/\n" |
| 2294 | " B = http://b.com/", |
| 2295 | DepictFrameTree(root)); |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2296 | FrameTreeNode* child = root->child_at(0); |
creis | e42f2a5 | 2014-09-18 18:14:57 | [diff] [blame] | 2297 | EXPECT_TRUE( |
| 2298 | child->current_frame_host()->render_view_host()->IsRenderViewLive()); |
| 2299 | EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive()); |
| 2300 | |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2301 | // Crash the subframe process. |
| 2302 | RenderProcessHost* root_process = root->current_frame_host()->GetProcess(); |
| 2303 | RenderProcessHost* child_process = child->current_frame_host()->GetProcess(); |
| 2304 | { |
| 2305 | RenderProcessHostWatcher crash_observer( |
| 2306 | child_process, |
| 2307 | RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
jaekyun | 37e572a3 | 2014-12-04 23:33:35 | [diff] [blame] | 2308 | child_process->Shutdown(0, false); |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2309 | crash_observer.Wait(); |
| 2310 | } |
| 2311 | |
| 2312 | // Ensure that the child frame still exists but has been cleared. |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 2313 | EXPECT_EQ( |
| 2314 | " Site A ------------ proxies for B\n" |
| 2315 | " +--Site B ------- proxies for A\n" |
| 2316 | "Where A = http://a.com/\n" |
| 2317 | " B = http://b.com/ (no process)", |
| 2318 | DepictFrameTree(root)); |
| 2319 | EXPECT_EQ(1U, root->child_count()); |
[email protected] | 58faf94 | 2014-02-20 21:03:58 | [diff] [blame] | 2320 | EXPECT_EQ(main_url, root->current_url()); |
| 2321 | EXPECT_EQ(GURL(), child->current_url()); |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2322 | |
creis | e42f2a5 | 2014-09-18 18:14:57 | [diff] [blame] | 2323 | EXPECT_FALSE( |
| 2324 | child->current_frame_host()->render_view_host()->IsRenderViewLive()); |
| 2325 | EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive()); |
| 2326 | EXPECT_FALSE(child->current_frame_host()->render_frame_created_); |
| 2327 | |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2328 | // Now crash the top-level page to clear the child frame. |
| 2329 | { |
| 2330 | RenderProcessHostWatcher crash_observer( |
| 2331 | root_process, |
| 2332 | RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
jaekyun | 37e572a3 | 2014-12-04 23:33:35 | [diff] [blame] | 2333 | root_process->Shutdown(0, false); |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2334 | crash_observer.Wait(); |
| 2335 | } |
| 2336 | EXPECT_EQ(0U, root->child_count()); |
[email protected] | 58faf94 | 2014-02-20 21:03:58 | [diff] [blame] | 2337 | EXPECT_EQ(GURL(), root->current_url()); |
[email protected] | 81c6c5e | 2014-02-13 20:20:07 | [diff] [blame] | 2338 | } |
| 2339 | |
alexmos | 46e85ec | 2015-04-03 21:04:35 | [diff] [blame] | 2340 | // When a new subframe is added, related SiteInstances that can reach the |
| 2341 | // subframe should create proxies for it (https://crbug.com/423587). This test |
| 2342 | // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy |
| 2343 | // in B's process. |
| 2344 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) { |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2345 | GURL main_url(embedded_test_server()->GetURL( |
| 2346 | "b.com", "/frame_tree/page_with_one_frame.html")); |
alexmos | 46e85ec | 2015-04-03 21:04:35 | [diff] [blame] | 2347 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 2348 | |
| 2349 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2350 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 46e85ec | 2015-04-03 21:04:35 | [diff] [blame] | 2351 | ASSERT_EQ(1U, root->child_count()); |
| 2352 | |
| 2353 | // Make sure the frame starts out at the correct cross-site URL. |
| 2354 | EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"), |
| 2355 | root->child_at(0)->current_url()); |
| 2356 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2357 | EXPECT_EQ( |
| 2358 | " Site A ------------ proxies for B\n" |
| 2359 | " +--Site B ------- proxies for A\n" |
| 2360 | "Where A = http://b.com/\n" |
| 2361 | " B = http://baz.com/", |
| 2362 | DepictFrameTree(root)); |
| 2363 | |
alexmos | 46e85ec | 2015-04-03 21:04:35 | [diff] [blame] | 2364 | // Add a new child frame to the top-level frame. |
| 2365 | RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2366 | EXPECT_TRUE(ExecuteScript(shell(), "addFrame('data:text/html,foo');")); |
alexmos | 46e85ec | 2015-04-03 21:04:35 | [diff] [blame] | 2367 | frame_observer.Wait(); |
alexmos | 46e85ec | 2015-04-03 21:04:35 | [diff] [blame] | 2368 | |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2369 | // The new frame should have a proxy in Site B, for use by the old frame. |
| 2370 | EXPECT_EQ( |
| 2371 | " Site A ------------ proxies for B\n" |
| 2372 | " |--Site B ------- proxies for A\n" |
| 2373 | " +--Site A ------- proxies for B\n" |
| 2374 | "Where A = http://b.com/\n" |
| 2375 | " B = http://baz.com/", |
| 2376 | DepictFrameTree(root)); |
alexmos | 46e85ec | 2015-04-03 21:04:35 | [diff] [blame] | 2377 | } |
| 2378 | |
[email protected] | 0f7d449e | 2013-01-23 15:12:35 | [diff] [blame] | 2379 | // TODO(nasko): Disable this test until out-of-process iframes is ready and the |
| 2380 | // security checks are back in place. |
| 2381 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 2382 | DISABLED_CrossSiteIframeRedirectOnce) { |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2383 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 2384 | https_server.ServeFilesFromSourceDirectory("content/test/data"); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2385 | ASSERT_TRUE(https_server.Start()); |
| 2386 | |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2387 | GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html")); |
| 2388 | GURL http_url(embedded_test_server()->GetURL("/title1.html")); |
| 2389 | GURL https_url(https_server.GetURL("/title1.html")); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2390 | |
| 2391 | NavigateToURL(shell(), main_url); |
| 2392 | |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2393 | TestNavigationObserver observer(shell()->web_contents()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2394 | { |
| 2395 | // Load cross-site client-redirect page into Iframe. |
| 2396 | // Should be blocked. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2397 | GURL client_redirect_https_url( |
| 2398 | https_server.GetURL("/client-redirect?/title1.html")); |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2399 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2400 | client_redirect_https_url)); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2401 | // DidFailProvisionalLoad when navigating to client_redirect_https_url. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2402 | EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url); |
| 2403 | EXPECT_FALSE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2404 | } |
| 2405 | |
| 2406 | { |
| 2407 | // Load cross-site server-redirect page into Iframe, |
| 2408 | // which redirects to same-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2409 | GURL server_redirect_http_url( |
| 2410 | https_server.GetURL("/server-redirect?" + http_url.spec())); |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2411 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2412 | server_redirect_http_url)); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2413 | EXPECT_EQ(observer.last_navigation_url(), http_url); |
| 2414 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2415 | } |
| 2416 | |
| 2417 | { |
| 2418 | // Load cross-site server-redirect page into Iframe, |
| 2419 | // which redirects to cross-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2420 | GURL server_redirect_http_url( |
| 2421 | https_server.GetURL("/server-redirect?/title1.html")); |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2422 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2423 | server_redirect_http_url)); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2424 | // DidFailProvisionalLoad when navigating to https_url. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2425 | EXPECT_EQ(observer.last_navigation_url(), https_url); |
| 2426 | EXPECT_FALSE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2427 | } |
| 2428 | |
| 2429 | { |
| 2430 | // Load same-site server-redirect page into Iframe, |
| 2431 | // which redirects to cross-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2432 | GURL server_redirect_http_url( |
| 2433 | embedded_test_server()->GetURL("/server-redirect?" + https_url.spec())); |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2434 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2435 | server_redirect_http_url)); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2436 | |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2437 | EXPECT_EQ(observer.last_navigation_url(), https_url); |
| 2438 | EXPECT_FALSE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2439 | } |
| 2440 | |
| 2441 | { |
| 2442 | // Load same-site client-redirect page into Iframe, |
| 2443 | // which redirects to cross-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2444 | GURL client_redirect_http_url( |
| 2445 | embedded_test_server()->GetURL("/client-redirect?" + https_url.spec())); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2446 | |
| 2447 | RedirectNotificationObserver load_observer2( |
| 2448 | NOTIFICATION_LOAD_STOP, |
| 2449 | Source<NavigationController>( |
| 2450 | &shell()->web_contents()->GetController())); |
| 2451 | |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2452 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2453 | client_redirect_http_url)); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2454 | |
| 2455 | // Same-site Client-Redirect Page should be loaded successfully. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2456 | EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url); |
| 2457 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2458 | |
| 2459 | // Redirecting to Cross-site Page should be blocked. |
| 2460 | load_observer2.Wait(); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2461 | EXPECT_EQ(observer.last_navigation_url(), https_url); |
| 2462 | EXPECT_FALSE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2463 | } |
| 2464 | |
| 2465 | { |
| 2466 | // Load same-site server-redirect page into Iframe, |
| 2467 | // which redirects to same-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2468 | GURL server_redirect_http_url( |
| 2469 | embedded_test_server()->GetURL("/server-redirect?/title1.html")); |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2470 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2471 | server_redirect_http_url)); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2472 | EXPECT_EQ(observer.last_navigation_url(), http_url); |
| 2473 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2474 | } |
| 2475 | |
| 2476 | { |
| 2477 | // Load same-site client-redirect page into Iframe, |
| 2478 | // which redirects to same-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2479 | GURL client_redirect_http_url( |
| 2480 | embedded_test_server()->GetURL("/client-redirect?" + http_url.spec())); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2481 | RedirectNotificationObserver load_observer2( |
| 2482 | NOTIFICATION_LOAD_STOP, |
| 2483 | Source<NavigationController>( |
| 2484 | &shell()->web_contents()->GetController())); |
| 2485 | |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2486 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2487 | client_redirect_http_url)); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2488 | |
| 2489 | // Same-site Client-Redirect Page should be loaded successfully. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2490 | EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url); |
| 2491 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2492 | |
| 2493 | // Redirecting to Same-site Page should be loaded successfully. |
| 2494 | load_observer2.Wait(); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2495 | EXPECT_EQ(observer.last_navigation_url(), http_url); |
| 2496 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2497 | } |
| 2498 | } |
| 2499 | |
[email protected] | 0f7d449e | 2013-01-23 15:12:35 | [diff] [blame] | 2500 | // TODO(nasko): Disable this test until out-of-process iframes is ready and the |
| 2501 | // security checks are back in place. |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2502 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
[email protected] | 0f7d449e | 2013-01-23 15:12:35 | [diff] [blame] | 2503 | DISABLED_CrossSiteIframeRedirectTwice) { |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2504 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 2505 | https_server.ServeFilesFromSourceDirectory("content/test/data"); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2506 | ASSERT_TRUE(https_server.Start()); |
| 2507 | |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2508 | GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html")); |
| 2509 | GURL http_url(embedded_test_server()->GetURL("/title1.html")); |
| 2510 | GURL https_url(https_server.GetURL("/title1.html")); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2511 | |
| 2512 | NavigateToURL(shell(), main_url); |
| 2513 | |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2514 | TestNavigationObserver observer(shell()->web_contents()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2515 | { |
| 2516 | // Load client-redirect page pointing to a cross-site client-redirect page, |
| 2517 | // which eventually redirects back to same-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2518 | GURL client_redirect_https_url( |
| 2519 | https_server.GetURL("/client-redirect?" + http_url.spec())); |
| 2520 | GURL client_redirect_http_url(embedded_test_server()->GetURL( |
| 2521 | "/client-redirect?" + client_redirect_https_url.spec())); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2522 | |
| 2523 | // We should wait until second client redirect get cancelled. |
| 2524 | RedirectNotificationObserver load_observer2( |
| 2525 | NOTIFICATION_LOAD_STOP, |
| 2526 | Source<NavigationController>( |
| 2527 | &shell()->web_contents()->GetController())); |
| 2528 | |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2529 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2530 | client_redirect_http_url)); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2531 | |
| 2532 | // DidFailProvisionalLoad when navigating to client_redirect_https_url. |
| 2533 | load_observer2.Wait(); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2534 | EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url); |
| 2535 | EXPECT_FALSE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2536 | } |
| 2537 | |
| 2538 | { |
| 2539 | // Load server-redirect page pointing to a cross-site server-redirect page, |
| 2540 | // which eventually redirect back to same-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2541 | GURL server_redirect_https_url( |
| 2542 | https_server.GetURL("/server-redirect?" + http_url.spec())); |
| 2543 | GURL server_redirect_http_url(embedded_test_server()->GetURL( |
| 2544 | "/server-redirect?" + server_redirect_https_url.spec())); |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2545 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2546 | server_redirect_http_url)); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2547 | EXPECT_EQ(observer.last_navigation_url(), http_url); |
| 2548 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2549 | } |
| 2550 | |
| 2551 | { |
| 2552 | // Load server-redirect page pointing to a cross-site server-redirect page, |
| 2553 | // which eventually redirects back to cross-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2554 | GURL server_redirect_https_url( |
| 2555 | https_server.GetURL("/server-redirect?" + https_url.spec())); |
| 2556 | GURL server_redirect_http_url(embedded_test_server()->GetURL( |
| 2557 | "/server-redirect?" + server_redirect_https_url.spec())); |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2558 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2559 | server_redirect_http_url)); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2560 | |
| 2561 | // DidFailProvisionalLoad when navigating to https_url. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2562 | EXPECT_EQ(observer.last_navigation_url(), https_url); |
| 2563 | EXPECT_FALSE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2564 | } |
| 2565 | |
| 2566 | { |
| 2567 | // Load server-redirect page pointing to a cross-site client-redirect page, |
| 2568 | // which eventually redirects back to same-site page. |
svaldez | c3a9a17 | 2015-11-03 22:01:33 | [diff] [blame] | 2569 | GURL client_redirect_http_url( |
| 2570 | https_server.GetURL("/client-redirect?" + http_url.spec())); |
| 2571 | GURL server_redirect_http_url(embedded_test_server()->GetURL( |
| 2572 | "/server-redirect?" + client_redirect_http_url.spec())); |
alexmos | 75648bb3 | 2015-01-07 21:06:28 | [diff] [blame] | 2573 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test", |
| 2574 | server_redirect_http_url)); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2575 | |
| 2576 | // DidFailProvisionalLoad when navigating to client_redirect_http_url. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2577 | EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url); |
| 2578 | EXPECT_FALSE(observer.last_navigation_succeeded()); |
[email protected] | bbdd1b20b | 2012-12-11 21:24:13 | [diff] [blame] | 2579 | } |
| 2580 | } |
| 2581 | |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2582 | // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are |
| 2583 | // created in the FrameTree skipping the subtree of the navigating frame. |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2584 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
nick | 53d5cbf | 2015-04-23 22:50:14 | [diff] [blame] | 2585 | ProxyCreationSkipsSubtree) { |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 2586 | GURL main_url(embedded_test_server()->GetURL( |
| 2587 | "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))")); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2588 | NavigateToURL(shell(), main_url); |
| 2589 | |
| 2590 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2591 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2592 | |
| 2593 | EXPECT_TRUE(root->child_at(1) != NULL); |
| 2594 | EXPECT_EQ(2U, root->child_at(1)->child_count()); |
| 2595 | |
| 2596 | { |
| 2597 | // Load same-site page into iframe. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2598 | TestNavigationObserver observer(shell()->web_contents()); |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 2599 | GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2600 | NavigateFrameToURL(root->child_at(0), http_url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2601 | EXPECT_EQ(http_url, observer.last_navigation_url()); |
| 2602 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2603 | EXPECT_EQ( |
| 2604 | " Site A\n" |
| 2605 | " |--Site A\n" |
| 2606 | " +--Site A\n" |
| 2607 | " |--Site A\n" |
| 2608 | " +--Site A\n" |
| 2609 | " +--Site A\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 2610 | "Where A = http://a.com/", |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2611 | DepictFrameTree(root)); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2612 | } |
| 2613 | |
| 2614 | // Create the cross-site URL to navigate to. |
nasko | 30374c7 | 2014-10-30 19:18:37 | [diff] [blame] | 2615 | GURL cross_site_url = |
alexmos | 617df037 | 2015-09-03 21:52:16 | [diff] [blame] | 2616 | embedded_test_server()->GetURL("foo.com", "/frame_tree/title2.html"); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2617 | |
| 2618 | // Load cross-site page into the second iframe without waiting for the |
| 2619 | // navigation to complete. Once LoadURLWithParams returns, we would expect |
| 2620 | // proxies to have been created in the frame tree, but children of the |
| 2621 | // navigating frame to still be present. The reason is that we don't run the |
| 2622 | // message loop, so no IPCs that alter the frame tree can be processed. |
| 2623 | FrameTreeNode* child = root->child_at(1); |
| 2624 | SiteInstance* site = NULL; |
carlosk | d80262f5 | 2015-12-16 14:40:35 | [diff] [blame] | 2625 | bool browser_side_navigation = IsBrowserSideNavigationEnabled(); |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2626 | std::string cross_site_rfh_type = |
| 2627 | browser_side_navigation ? "speculative" : "pending"; |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2628 | { |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2629 | TestNavigationObserver observer(shell()->web_contents()); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2630 | TestFrameNavigationObserver navigation_observer(child); |
| 2631 | NavigationController::LoadURLParams params(cross_site_url); |
| 2632 | params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK); |
| 2633 | params.frame_tree_node_id = child->frame_tree_node_id(); |
| 2634 | child->navigator()->GetController()->LoadURLWithParams(params); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2635 | |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2636 | if (browser_side_navigation) { |
| 2637 | site = child->render_manager() |
clamy | 11e1151 | 2015-07-07 16:42:17 | [diff] [blame] | 2638 | ->speculative_frame_host() |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2639 | ->GetSiteInstance(); |
| 2640 | } else { |
| 2641 | site = child->render_manager()->pending_frame_host()->GetSiteInstance(); |
| 2642 | } |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2643 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site); |
| 2644 | |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2645 | std::string tree = base::StringPrintf( |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2646 | " Site A ------------ proxies for B\n" |
| 2647 | " |--Site A ------- proxies for B\n" |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2648 | " +--Site A (B %s)\n" |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2649 | " |--Site A\n" |
| 2650 | " +--Site A\n" |
| 2651 | " +--Site A\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 2652 | "Where A = http://a.com/\n" |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2653 | " B = http://foo.com/", |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2654 | cross_site_rfh_type.c_str()); |
| 2655 | EXPECT_EQ(tree, DepictFrameTree(root)); |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2656 | |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2657 | // Now that the verification is done, run the message loop and wait for the |
| 2658 | // navigation to complete. |
| 2659 | navigation_observer.Wait(); |
| 2660 | EXPECT_FALSE(child->render_manager()->pending_frame_host()); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2661 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 2662 | EXPECT_EQ(cross_site_url, observer.last_navigation_url()); |
nick | 53d5cbf | 2015-04-23 22:50:14 | [diff] [blame] | 2663 | |
| 2664 | EXPECT_EQ( |
| 2665 | " Site A ------------ proxies for B\n" |
| 2666 | " |--Site A ------- proxies for B\n" |
| 2667 | " +--Site B ------- proxies for A\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 2668 | "Where A = http://a.com/\n" |
nick | 53d5cbf | 2015-04-23 22:50:14 | [diff] [blame] | 2669 | " B = http://foo.com/", |
| 2670 | DepictFrameTree(root)); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2671 | } |
| 2672 | |
| 2673 | // Load another cross-site page into the same iframe. |
alexmos | 617df037 | 2015-09-03 21:52:16 | [diff] [blame] | 2674 | cross_site_url = embedded_test_server()->GetURL("bar.com", "/title3.html"); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2675 | { |
| 2676 | // Perform the same checks as the first cross-site navigation, since |
| 2677 | // there have been issues in subsequent cross-site navigations. Also ensure |
| 2678 | // that the SiteInstance has properly changed. |
| 2679 | // TODO(nasko): Once we have proper cleanup of resources, add code to |
| 2680 | // verify that the intermediate SiteInstance/RenderFrameHost have been |
| 2681 | // properly cleaned up. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2682 | TestNavigationObserver observer(shell()->web_contents()); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2683 | TestFrameNavigationObserver navigation_observer(child); |
| 2684 | NavigationController::LoadURLParams params(cross_site_url); |
| 2685 | params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK); |
| 2686 | params.frame_tree_node_id = child->frame_tree_node_id(); |
| 2687 | child->navigator()->GetController()->LoadURLWithParams(params); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2688 | |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2689 | SiteInstance* site2; |
| 2690 | if (browser_side_navigation) { |
| 2691 | site2 = child->render_manager() |
clamy | 11e1151 | 2015-07-07 16:42:17 | [diff] [blame] | 2692 | ->speculative_frame_host() |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2693 | ->GetSiteInstance(); |
| 2694 | } else { |
| 2695 | site2 = child->render_manager()->pending_frame_host()->GetSiteInstance(); |
| 2696 | } |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2697 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2); |
| 2698 | EXPECT_NE(site, site2); |
| 2699 | |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2700 | std::string tree = base::StringPrintf( |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2701 | " Site A ------------ proxies for B C\n" |
| 2702 | " |--Site A ------- proxies for B C\n" |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2703 | " +--Site B (C %s) -- proxies for A\n" |
nick | 4e68f525 | 2015-08-28 20:17:05 | [diff] [blame] | 2704 | "Where A = http://a.com/\n" |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 2705 | " B = http://foo.com/\n" |
| 2706 | " C = http://bar.com/", |
clamy | a529801 | 2015-06-02 13:28:21 | [diff] [blame] | 2707 | cross_site_rfh_type.c_str()); |
| 2708 | EXPECT_EQ(tree, DepictFrameTree(root)); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2709 | |
| 2710 | navigation_observer.Wait(); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2711 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 2712 | EXPECT_EQ(cross_site_url, observer.last_navigation_url()); |
nasko | e6edde3 | 2014-10-17 15:36:48 | [diff] [blame] | 2713 | EXPECT_EQ(0U, child->child_count()); |
| 2714 | } |
| 2715 | } |
| 2716 | |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2717 | // Verify that "scrolling" property on frame elements propagates to child frames |
| 2718 | // correctly. |
| 2719 | // Does not work on android since android has scrollbars overlayed. |
| 2720 | #if defined(OS_ANDROID) |
| 2721 | #define MAYBE_FrameOwnerPropertiesPropagationScrolling \ |
| 2722 | DISABLED_FrameOwnerPropertiesPropagationScrolling |
| 2723 | #else |
| 2724 | #define MAYBE_FrameOwnerPropertiesPropagationScrolling \ |
| 2725 | FrameOwnerPropertiesPropagationScrolling |
| 2726 | #endif |
| 2727 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 2728 | MAYBE_FrameOwnerPropertiesPropagationScrolling) { |
ahest | 1d019b7 | 2016-02-02 07:24:42 | [diff] [blame] | 2729 | #if defined(OS_MACOSX) |
spqchan | 83534ab0 | 2016-02-23 19:28:27 | [diff] [blame] | 2730 | ui::test::ScopedPreferredScrollerStyle scroller_style_override(false); |
ahest | 1d019b7 | 2016-02-02 07:24:42 | [diff] [blame] | 2731 | #endif |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2732 | GURL main_url(embedded_test_server()->GetURL( |
| 2733 | "a.com", "/frame_owner_properties_scrolling.html")); |
| 2734 | NavigateToURL(shell(), main_url); |
| 2735 | |
| 2736 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2737 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2738 | ASSERT_EQ(1u, root->child_count()); |
| 2739 | |
| 2740 | EXPECT_EQ( |
| 2741 | " Site A ------------ proxies for B\n" |
| 2742 | " +--Site B ------- proxies for A\n" |
| 2743 | "Where A = http://a.com/\n" |
| 2744 | " B = http://b.com/", |
| 2745 | DepictFrameTree(root)); |
| 2746 | |
| 2747 | FrameTreeNode* child = root->child_at(0); |
| 2748 | |
| 2749 | // If the available client width within the iframe is smaller than the |
| 2750 | // frame element's width, we assume there's a scrollbar. |
| 2751 | // Also note that just comparing clientHeight and scrollHeight of the frame's |
| 2752 | // document will not work. |
| 2753 | auto has_scrollbar = [](RenderFrameHostImpl* rfh) { |
| 2754 | int client_width; |
| 2755 | EXPECT_TRUE(ExecuteScriptAndExtractInt(rfh, |
| 2756 | "window.domAutomationController.send(document.body.clientWidth);", |
| 2757 | &client_width)); |
| 2758 | const int kFrameElementWidth = 200; |
| 2759 | return client_width < kFrameElementWidth; |
| 2760 | }; |
| 2761 | |
| 2762 | auto set_scrolling_property = [](RenderFrameHostImpl* parent_rfh, |
| 2763 | const std::string& value) { |
| 2764 | EXPECT_TRUE(ExecuteScript( |
| 2765 | parent_rfh, |
| 2766 | base::StringPrintf( |
| 2767 | "document.getElementById('child-1').setAttribute(" |
| 2768 | " 'scrolling', '%s');", value.c_str()))); |
| 2769 | }; |
| 2770 | |
| 2771 | // Run the test over variety of parent/child cases. |
| 2772 | GURL urls[] = { |
| 2773 | // Remote to remote. |
| 2774 | embedded_test_server()->GetURL("c.com", "/tall_page.html"), |
| 2775 | // Remote to local. |
| 2776 | embedded_test_server()->GetURL("a.com", "/tall_page.html"), |
| 2777 | // Local to remote. |
| 2778 | embedded_test_server()->GetURL("b.com", "/tall_page.html") |
| 2779 | }; |
| 2780 | const std::string scrolling_values[] = { |
| 2781 | "yes", "auto", "no" |
| 2782 | }; |
| 2783 | |
| 2784 | for (size_t i = 0; i < arraysize(scrolling_values); ++i) { |
| 2785 | bool expect_scrollbar = scrolling_values[i] != "no"; |
| 2786 | set_scrolling_property(root->current_frame_host(), scrolling_values[i]); |
| 2787 | for (size_t j = 0; j < arraysize(urls); ++j) { |
| 2788 | NavigateFrameToURL(child, urls[j]); |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2789 | EXPECT_EQ(expect_scrollbar, has_scrollbar(child->current_frame_host())); |
| 2790 | } |
| 2791 | } |
| 2792 | } |
| 2793 | |
| 2794 | // Verify that "marginwidth" and "marginheight" properties on frame elements |
| 2795 | // propagate to child frames correctly. |
| 2796 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 2797 | FrameOwnerPropertiesPropagationMargin) { |
| 2798 | GURL main_url(embedded_test_server()->GetURL( |
| 2799 | "a.com", "/frame_owner_properties_margin.html")); |
| 2800 | NavigateToURL(shell(), main_url); |
| 2801 | |
| 2802 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2803 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2804 | ASSERT_EQ(1u, root->child_count()); |
| 2805 | |
| 2806 | EXPECT_EQ( |
| 2807 | " Site A ------------ proxies for B\n" |
| 2808 | " +--Site B ------- proxies for A\n" |
| 2809 | "Where A = http://a.com/\n" |
| 2810 | " B = http://b.com/", |
| 2811 | DepictFrameTree(root)); |
| 2812 | |
| 2813 | FrameTreeNode* child = root->child_at(0); |
| 2814 | |
| 2815 | std::string margin_width; |
| 2816 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2817 | child, |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2818 | "window.domAutomationController.send(" |
| 2819 | "document.body.getAttribute('marginwidth'));", |
| 2820 | &margin_width)); |
| 2821 | EXPECT_EQ("10", margin_width); |
| 2822 | |
| 2823 | std::string margin_height; |
| 2824 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2825 | child, |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2826 | "window.domAutomationController.send(" |
| 2827 | "document.body.getAttribute('marginheight'));", |
| 2828 | &margin_height)); |
| 2829 | EXPECT_EQ("50", margin_height); |
| 2830 | |
| 2831 | // Run the test over variety of parent/child cases. |
| 2832 | GURL urls[] = { |
| 2833 | // Remote to remote. |
| 2834 | embedded_test_server()->GetURL("c.com", "/title2.html"), |
| 2835 | // Remote to local. |
| 2836 | embedded_test_server()->GetURL("a.com", "/title1.html"), |
| 2837 | // Local to remote. |
| 2838 | embedded_test_server()->GetURL("b.com", "/title2.html") |
| 2839 | }; |
| 2840 | |
| 2841 | int current_margin_width = 15; |
| 2842 | int current_margin_height = 25; |
| 2843 | |
| 2844 | // Before each navigation, we change the marginwidth and marginheight |
| 2845 | // properties of the frame. We then check whether those properties are applied |
| 2846 | // correctly after the navigation has completed. |
| 2847 | for (size_t i = 0; i < arraysize(urls); ++i) { |
| 2848 | // Change marginwidth and marginheight before navigating. |
| 2849 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2850 | root, |
| 2851 | base::StringPrintf("document.getElementById('child-1').setAttribute(" |
| 2852 | " 'marginwidth', '%d');", |
| 2853 | current_margin_width))); |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2854 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2855 | root, |
| 2856 | base::StringPrintf("document.getElementById('child-1').setAttribute(" |
| 2857 | " 'marginheight', '%d');", |
| 2858 | current_margin_height))); |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2859 | |
| 2860 | NavigateFrameToURL(child, urls[i]); |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2861 | |
| 2862 | std::string actual_margin_width; |
| 2863 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2864 | child, |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2865 | "window.domAutomationController.send(" |
| 2866 | "document.body.getAttribute('marginwidth'));", |
| 2867 | &actual_margin_width)); |
| 2868 | EXPECT_EQ(base::IntToString(current_margin_width), actual_margin_width); |
| 2869 | |
| 2870 | std::string actual_margin_height; |
| 2871 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2872 | child, |
lazyboy | 70605c3 | 2015-11-03 01:27:31 | [diff] [blame] | 2873 | "window.domAutomationController.send(" |
| 2874 | "document.body.getAttribute('marginheight'));", |
| 2875 | &actual_margin_height)); |
| 2876 | EXPECT_EQ(base::IntToString(current_margin_height), actual_margin_height); |
| 2877 | |
| 2878 | current_margin_width += 5; |
| 2879 | current_margin_height += 10; |
| 2880 | } |
| 2881 | } |
| 2882 | |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2883 | // Verify origin replication with an A-embed-B-embed-C-embed-A hierarchy. |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2884 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) { |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2885 | GURL main_url(embedded_test_server()->GetURL( |
| 2886 | "a.com", "/cross_site_iframe_factory.html?a(b(c(a),b), a)")); |
alexmos | 35d7b93 | 2014-12-05 03:55:23 | [diff] [blame] | 2887 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 2888 | |
| 2889 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2890 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 35d7b93 | 2014-12-05 03:55:23 | [diff] [blame] | 2891 | |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2892 | EXPECT_EQ( |
| 2893 | " Site A ------------ proxies for B C\n" |
| 2894 | " |--Site B ------- proxies for A C\n" // tiptop_child |
| 2895 | " | |--Site C -- proxies for A B\n" // middle_child |
| 2896 | " | | +--Site A -- proxies for B C\n" // lowest_child |
| 2897 | " | +--Site B -- proxies for A C\n" |
| 2898 | " +--Site A ------- proxies for B C\n" |
| 2899 | "Where A = http://a.com/\n" |
| 2900 | " B = http://b.com/\n" |
| 2901 | " C = http://c.com/", |
| 2902 | DepictFrameTree(root)); |
alexmos | 35d7b93 | 2014-12-05 03:55:23 | [diff] [blame] | 2903 | |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2904 | std::string a_origin = embedded_test_server()->GetURL("a.com", "/").spec(); |
| 2905 | std::string b_origin = embedded_test_server()->GetURL("b.com", "/").spec(); |
| 2906 | std::string c_origin = embedded_test_server()->GetURL("c.com", "/").spec(); |
| 2907 | FrameTreeNode* tiptop_child = root->child_at(0); |
| 2908 | FrameTreeNode* middle_child = root->child_at(0)->child_at(0); |
| 2909 | FrameTreeNode* lowest_child = root->child_at(0)->child_at(0)->child_at(0); |
alexmos | 35d7b93 | 2014-12-05 03:55:23 | [diff] [blame] | 2910 | |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2911 | // Check that b.com frame's location.ancestorOrigins contains the correct |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2912 | // origin for the parent. The origin should have been replicated as part of |
| 2913 | // the ViewMsg_New message that created the parent's RenderFrameProxy in |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2914 | // b.com's process. |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2915 | int ancestor_origins_length = 0; |
| 2916 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2917 | tiptop_child, |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2918 | "window.domAutomationController.send(location.ancestorOrigins.length);", |
| 2919 | &ancestor_origins_length)); |
| 2920 | EXPECT_EQ(1, ancestor_origins_length); |
| 2921 | std::string result; |
| 2922 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2923 | tiptop_child, |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2924 | "window.domAutomationController.send(location.ancestorOrigins[0]);", |
| 2925 | &result)); |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2926 | EXPECT_EQ(a_origin, result + "/"); |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2927 | |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2928 | // Check that c.com frame's location.ancestorOrigins contains the correct |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2929 | // origin for its two ancestors. The topmost parent origin should be |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2930 | // replicated as part of ViewMsg_New, and the middle frame (b.com's) origin |
| 2931 | // should be replicated as part of FrameMsg_NewFrameProxy sent for b.com's |
| 2932 | // frame in c.com's process. |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2933 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2934 | middle_child, |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2935 | "window.domAutomationController.send(location.ancestorOrigins.length);", |
| 2936 | &ancestor_origins_length)); |
| 2937 | EXPECT_EQ(2, ancestor_origins_length); |
| 2938 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2939 | middle_child, |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2940 | "window.domAutomationController.send(location.ancestorOrigins[0]);", |
| 2941 | &result)); |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2942 | EXPECT_EQ(b_origin, result + "/"); |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2943 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2944 | middle_child, |
alexmos | 17f643f | 2014-12-09 18:50:10 | [diff] [blame] | 2945 | "window.domAutomationController.send(location.ancestorOrigins[1]);", |
| 2946 | &result)); |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2947 | EXPECT_EQ(a_origin, result + "/"); |
| 2948 | |
| 2949 | // Check that the nested a.com frame's location.ancestorOrigins contains the |
| 2950 | // correct origin for its three ancestors. |
| 2951 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2952 | lowest_child, |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2953 | "window.domAutomationController.send(location.ancestorOrigins.length);", |
| 2954 | &ancestor_origins_length)); |
| 2955 | EXPECT_EQ(3, ancestor_origins_length); |
| 2956 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2957 | lowest_child, |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2958 | "window.domAutomationController.send(location.ancestorOrigins[0]);", |
| 2959 | &result)); |
| 2960 | EXPECT_EQ(c_origin, result + "/"); |
| 2961 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2962 | lowest_child, |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2963 | "window.domAutomationController.send(location.ancestorOrigins[1]);", |
| 2964 | &result)); |
| 2965 | EXPECT_EQ(b_origin, result + "/"); |
| 2966 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 2967 | lowest_child, |
nick | 9c79de2 | 2015-08-28 20:12:13 | [diff] [blame] | 2968 | "window.domAutomationController.send(location.ancestorOrigins[2]);", |
| 2969 | &result)); |
| 2970 | EXPECT_EQ(a_origin, result + "/"); |
alexmos | 35d7b93 | 2014-12-05 03:55:23 | [diff] [blame] | 2971 | } |
| 2972 | |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 2973 | // Check that iframe sandbox flags are replicated correctly. |
| 2974 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) { |
| 2975 | GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html")); |
| 2976 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 2977 | |
| 2978 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 2979 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 2980 | |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2981 | TestNavigationObserver observer(shell()->web_contents()); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 2982 | |
| 2983 | // Navigate the second (sandboxed) subframe to a cross-site page with a |
alexmos | 54dee8e | 2015-05-15 19:07:01 | [diff] [blame] | 2984 | // subframe. |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 2985 | GURL foo_url( |
| 2986 | embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html")); |
| 2987 | NavigateFrameToURL(root->child_at(1), foo_url); |
alexmos | 54dee8e | 2015-05-15 19:07:01 | [diff] [blame] | 2988 | EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 2989 | |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2990 | // We can't use a TestNavigationObserver to verify the URL here, |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 2991 | // since the frame has children that may have clobbered it in the observer. |
| 2992 | EXPECT_EQ(foo_url, root->child_at(1)->current_url()); |
| 2993 | |
| 2994 | // Load cross-site page into subframe's subframe. |
| 2995 | ASSERT_EQ(2U, root->child_at(1)->child_count()); |
| 2996 | GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html")); |
| 2997 | NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 2998 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 2999 | EXPECT_EQ(bar_url, observer.last_navigation_url()); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3000 | |
| 3001 | // Opening a popup in the sandboxed foo.com iframe should fail. |
| 3002 | bool success = false; |
| 3003 | EXPECT_TRUE( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3004 | ExecuteScriptAndExtractBool(root->child_at(1), |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3005 | "window.domAutomationController.send(" |
| 3006 | "!window.open('data:text/html,dataurl'));", |
| 3007 | &success)); |
| 3008 | EXPECT_TRUE(success); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3009 | EXPECT_EQ(1u, Shell::windows().size()); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3010 | |
| 3011 | // Opening a popup in a frame whose parent is sandboxed should also fail. |
| 3012 | // Here, bar.com frame's sandboxed parent frame is a remote frame in |
| 3013 | // bar.com's process. |
| 3014 | success = false; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3015 | EXPECT_TRUE( |
| 3016 | ExecuteScriptAndExtractBool(root->child_at(1)->child_at(0), |
| 3017 | "window.domAutomationController.send(" |
| 3018 | "!window.open('data:text/html,dataurl'));", |
| 3019 | &success)); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3020 | EXPECT_TRUE(success); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3021 | EXPECT_EQ(1u, Shell::windows().size()); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3022 | |
| 3023 | // Same, but now try the case where bar.com frame's sandboxed parent is a |
| 3024 | // local frame in bar.com's process. |
| 3025 | success = false; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3026 | EXPECT_TRUE( |
| 3027 | ExecuteScriptAndExtractBool(root->child_at(2)->child_at(0), |
| 3028 | "window.domAutomationController.send(" |
| 3029 | "!window.open('data:text/html,dataurl'));", |
| 3030 | &success)); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3031 | EXPECT_TRUE(success); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3032 | EXPECT_EQ(1u, Shell::windows().size()); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3033 | |
| 3034 | // Check that foo.com frame's location.ancestorOrigins contains the correct |
| 3035 | // origin for the parent, which should be unaffected by sandboxing. |
| 3036 | int ancestor_origins_length = 0; |
| 3037 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3038 | root->child_at(1), |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3039 | "window.domAutomationController.send(location.ancestorOrigins.length);", |
| 3040 | &ancestor_origins_length)); |
| 3041 | EXPECT_EQ(1, ancestor_origins_length); |
| 3042 | std::string result; |
| 3043 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3044 | root->child_at(1), |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3045 | "window.domAutomationController.send(location.ancestorOrigins[0]);", |
| 3046 | &result)); |
| 3047 | EXPECT_EQ(result + "/", main_url.GetOrigin().spec()); |
| 3048 | |
| 3049 | // Now check location.ancestorOrigins for the bar.com frame. The middle frame |
| 3050 | // (foo.com's) origin should be unique, since that frame is sandboxed, and |
| 3051 | // the top frame should match |main_url|. |
| 3052 | FrameTreeNode* bottom_child = root->child_at(1)->child_at(0); |
| 3053 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3054 | bottom_child, |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3055 | "window.domAutomationController.send(location.ancestorOrigins.length);", |
| 3056 | &ancestor_origins_length)); |
| 3057 | EXPECT_EQ(2, ancestor_origins_length); |
| 3058 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3059 | bottom_child, |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3060 | "window.domAutomationController.send(location.ancestorOrigins[0]);", |
| 3061 | &result)); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3062 | EXPECT_EQ("null", result); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3063 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3064 | bottom_child, |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3065 | "window.domAutomationController.send(location.ancestorOrigins[1]);", |
| 3066 | &result)); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3067 | EXPECT_EQ(main_url.GetOrigin().spec(), result + "/"); |
| 3068 | } |
| 3069 | |
| 3070 | // Check that dynamic updates to iframe sandbox flags are propagated correctly. |
| 3071 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) { |
| 3072 | GURL main_url( |
| 3073 | embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html")); |
| 3074 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3075 | |
| 3076 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3077 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3078 | |
| 3079 | TestNavigationObserver observer(shell()->web_contents()); |
| 3080 | ASSERT_EQ(2U, root->child_count()); |
| 3081 | |
| 3082 | // Make sure first frame starts out at the correct cross-site page. |
| 3083 | EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"), |
| 3084 | root->child_at(0)->current_url()); |
| 3085 | |
| 3086 | // Navigate second frame to another cross-site page. |
| 3087 | GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html")); |
| 3088 | NavigateFrameToURL(root->child_at(1), baz_url); |
| 3089 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3090 | EXPECT_EQ(baz_url, observer.last_navigation_url()); |
| 3091 | |
| 3092 | // Both frames should not be sandboxed to start with. |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3093 | EXPECT_EQ(blink::WebSandboxFlags::None, |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3094 | root->child_at(0)->pending_sandbox_flags()); |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3095 | EXPECT_EQ(blink::WebSandboxFlags::None, |
| 3096 | root->child_at(0)->effective_sandbox_flags()); |
| 3097 | EXPECT_EQ(blink::WebSandboxFlags::None, |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3098 | root->child_at(1)->pending_sandbox_flags()); |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3099 | EXPECT_EQ(blink::WebSandboxFlags::None, |
| 3100 | root->child_at(1)->effective_sandbox_flags()); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3101 | |
| 3102 | // Dynamically update sandbox flags for the first frame. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3103 | EXPECT_TRUE(ExecuteScript( |
| 3104 | shell(), |
| 3105 | "document.querySelector('iframe').sandbox='allow-scripts';")); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3106 | |
| 3107 | // Check that updated sandbox flags are propagated to browser process. |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3108 | // The new flags should be reflected in pending_sandbox_flags(), while |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3109 | // effective_sandbox_flags() should still reflect the old flags, because |
| 3110 | // sandbox flag updates take place only after navigations. "allow-scripts" |
| 3111 | // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits |
| 3112 | // per blink::parseSandboxPolicy(). |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3113 | blink::WebSandboxFlags expected_flags = |
| 3114 | blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts & |
| 3115 | ~blink::WebSandboxFlags::AutomaticFeatures; |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3116 | EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags()); |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3117 | EXPECT_EQ(blink::WebSandboxFlags::None, |
| 3118 | root->child_at(0)->effective_sandbox_flags()); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3119 | |
| 3120 | // Navigate the first frame to a page on the same site. The new sandbox |
avi | 98405c2 | 2015-05-21 20:47:06 | [diff] [blame] | 3121 | // flags should take effect. |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3122 | GURL bar_url( |
| 3123 | embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html")); |
| 3124 | NavigateFrameToURL(root->child_at(0), bar_url); |
avi | 98405c2 | 2015-05-21 20:47:06 | [diff] [blame] | 3125 | // (The new page has a subframe; wait for it to load as well.) |
| 3126 | ASSERT_TRUE(WaitForLoadStop(shell()->web_contents())); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3127 | EXPECT_EQ(bar_url, root->child_at(0)->current_url()); |
| 3128 | ASSERT_EQ(1U, root->child_at(0)->child_count()); |
| 3129 | |
creis | 2069a0a | 2015-05-22 22:13:47 | [diff] [blame] | 3130 | EXPECT_EQ( |
| 3131 | " Site A ------------ proxies for B C\n" |
| 3132 | " |--Site B ------- proxies for A C\n" |
| 3133 | " | +--Site B -- proxies for A C\n" |
| 3134 | " +--Site C ------- proxies for A B\n" |
| 3135 | "Where A = http://127.0.0.1/\n" |
| 3136 | " B = http://bar.com/\n" |
| 3137 | " C = http://baz.com/", |
| 3138 | DepictFrameTree(root)); |
| 3139 | |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3140 | // Confirm that the browser process has updated the frame's current sandbox |
| 3141 | // flags. |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3142 | EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags()); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3143 | EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags()); |
| 3144 | |
| 3145 | // Opening a popup in the now-sandboxed frame should fail. |
| 3146 | bool success = false; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3147 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
| 3148 | root->child_at(0), |
| 3149 | "window.domAutomationController.send(" |
| 3150 | " !window.open('data:text/html,dataurl'));", |
| 3151 | &success)); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3152 | EXPECT_TRUE(success); |
| 3153 | EXPECT_EQ(1u, Shell::windows().size()); |
| 3154 | |
| 3155 | // Navigate the child of the now-sandboxed frame to a page on baz.com. The |
| 3156 | // child should inherit the latest sandbox flags from its parent frame, which |
| 3157 | // is currently a proxy in baz.com's renderer process. This checks that the |
| 3158 | // proxies of |root->child_at(0)| were also updated with the latest sandbox |
| 3159 | // flags. |
| 3160 | GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html")); |
| 3161 | NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url); |
| 3162 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3163 | EXPECT_EQ(baz_child_url, observer.last_navigation_url()); |
| 3164 | |
creis | 2069a0a | 2015-05-22 22:13:47 | [diff] [blame] | 3165 | EXPECT_EQ( |
| 3166 | " Site A ------------ proxies for B C\n" |
| 3167 | " |--Site B ------- proxies for A C\n" |
| 3168 | " | +--Site C -- proxies for A B\n" |
| 3169 | " +--Site C ------- proxies for A B\n" |
| 3170 | "Where A = http://127.0.0.1/\n" |
| 3171 | " B = http://bar.com/\n" |
| 3172 | " C = http://baz.com/", |
| 3173 | DepictFrameTree(root)); |
| 3174 | |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3175 | // Opening a popup in the child of a sandboxed frame should fail. |
| 3176 | success = false; |
| 3177 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3178 | root->child_at(0)->child_at(0), |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3179 | "window.domAutomationController.send(" |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3180 | " !window.open('data:text/html,dataurl'));", |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3181 | &success)); |
| 3182 | EXPECT_TRUE(success); |
| 3183 | EXPECT_EQ(1u, Shell::windows().size()); |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3184 | |
| 3185 | // Child of a sandboxed frame should also be sandboxed on the browser side. |
| 3186 | EXPECT_EQ(expected_flags, |
| 3187 | root->child_at(0)->child_at(0)->effective_sandbox_flags()); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3188 | } |
| 3189 | |
| 3190 | // Check that dynamic updates to iframe sandbox flags are propagated correctly. |
| 3191 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 3192 | DynamicSandboxFlagsRemoteToLocal) { |
| 3193 | GURL main_url( |
| 3194 | embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html")); |
| 3195 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3196 | |
| 3197 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3198 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3199 | |
| 3200 | TestNavigationObserver observer(shell()->web_contents()); |
| 3201 | ASSERT_EQ(2U, root->child_count()); |
| 3202 | |
| 3203 | // Make sure the two frames starts out at correct URLs. |
| 3204 | EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"), |
| 3205 | root->child_at(0)->current_url()); |
| 3206 | EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"), |
| 3207 | root->child_at(1)->current_url()); |
| 3208 | |
| 3209 | // Update the second frame's sandbox flags. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3210 | EXPECT_TRUE(ExecuteScript( |
| 3211 | shell(), |
| 3212 | "document.querySelectorAll('iframe')[1].sandbox='allow-scripts'")); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3213 | |
| 3214 | // Check that the current sandbox flags are updated but the effective |
| 3215 | // sandbox flags are not. |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3216 | blink::WebSandboxFlags expected_flags = |
| 3217 | blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts & |
| 3218 | ~blink::WebSandboxFlags::AutomaticFeatures; |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3219 | EXPECT_EQ(expected_flags, root->child_at(1)->pending_sandbox_flags()); |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3220 | EXPECT_EQ(blink::WebSandboxFlags::None, |
| 3221 | root->child_at(1)->effective_sandbox_flags()); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3222 | |
| 3223 | // Navigate the second subframe to a page on bar.com. This will trigger a |
nasko | 8206fa1 | 2016-03-22 02:24:13 | [diff] [blame] | 3224 | // remote-to-local frame swap in bar.com's process. |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3225 | GURL bar_url(embedded_test_server()->GetURL( |
| 3226 | "bar.com", "/frame_tree/page_with_one_frame.html")); |
| 3227 | NavigateFrameToURL(root->child_at(1), bar_url); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3228 | EXPECT_EQ(bar_url, root->child_at(1)->current_url()); |
| 3229 | ASSERT_EQ(1U, root->child_at(1)->child_count()); |
| 3230 | |
| 3231 | // Confirm that the browser process has updated the current sandbox flags. |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3232 | EXPECT_EQ(expected_flags, root->child_at(1)->pending_sandbox_flags()); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3233 | EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags()); |
| 3234 | |
| 3235 | // Opening a popup in the sandboxed second frame should fail. |
| 3236 | bool success = false; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3237 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
| 3238 | root->child_at(1), |
| 3239 | "window.domAutomationController.send(" |
| 3240 | " !window.open('data:text/html,dataurl'));", |
| 3241 | &success)); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3242 | EXPECT_TRUE(success); |
| 3243 | EXPECT_EQ(1u, Shell::windows().size()); |
| 3244 | |
| 3245 | // Make sure that the child frame inherits the sandbox flags of its |
| 3246 | // now-sandboxed parent frame. |
| 3247 | success = false; |
| 3248 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3249 | root->child_at(1)->child_at(0), |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3250 | "window.domAutomationController.send(" |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3251 | " !window.open('data:text/html,dataurl'));", |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3252 | &success)); |
| 3253 | EXPECT_TRUE(success); |
| 3254 | EXPECT_EQ(1u, Shell::windows().size()); |
| 3255 | } |
| 3256 | |
| 3257 | // Check that dynamic updates to iframe sandbox flags are propagated correctly. |
| 3258 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 3259 | DynamicSandboxFlagsRendererInitiatedNavigation) { |
| 3260 | GURL main_url( |
| 3261 | embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html")); |
| 3262 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3263 | |
| 3264 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3265 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3266 | |
| 3267 | TestNavigationObserver observer(shell()->web_contents()); |
| 3268 | ASSERT_EQ(1U, root->child_count()); |
| 3269 | |
| 3270 | // Make sure the frame starts out at the correct cross-site page. |
| 3271 | EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"), |
| 3272 | root->child_at(0)->current_url()); |
| 3273 | |
| 3274 | // The frame should not be sandboxed to start with. |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3275 | EXPECT_EQ(blink::WebSandboxFlags::None, |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3276 | root->child_at(0)->pending_sandbox_flags()); |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3277 | EXPECT_EQ(blink::WebSandboxFlags::None, |
| 3278 | root->child_at(0)->effective_sandbox_flags()); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3279 | |
| 3280 | // Dynamically update the frame's sandbox flags. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3281 | EXPECT_TRUE(ExecuteScript( |
| 3282 | shell(), "document.querySelector('iframe').sandbox='allow-scripts';")); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3283 | |
| 3284 | // Check that updated sandbox flags are propagated to browser process. |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3285 | // The new flags should be set in pending_sandbox_flags(), while |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3286 | // effective_sandbox_flags() should still reflect the old flags, because |
| 3287 | // sandbox flag updates take place only after navigations. "allow-scripts" |
| 3288 | // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits |
| 3289 | // per blink::parseSandboxPolicy(). |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3290 | blink::WebSandboxFlags expected_flags = |
| 3291 | blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts & |
| 3292 | ~blink::WebSandboxFlags::AutomaticFeatures; |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3293 | EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags()); |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3294 | EXPECT_EQ(blink::WebSandboxFlags::None, |
| 3295 | root->child_at(0)->effective_sandbox_flags()); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3296 | |
| 3297 | // Perform a renderer-initiated same-site navigation in the first frame. The |
| 3298 | // new sandbox flags should take effect. |
| 3299 | TestFrameNavigationObserver frame_observer(root->child_at(0)); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3300 | ASSERT_TRUE( |
| 3301 | ExecuteScript(root->child_at(0), "window.location.href='/title2.html'")); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3302 | frame_observer.Wait(); |
| 3303 | EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"), |
| 3304 | root->child_at(0)->current_url()); |
| 3305 | |
| 3306 | // Confirm that the browser process has updated the frame's current sandbox |
| 3307 | // flags. |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3308 | EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags()); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3309 | EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags()); |
| 3310 | |
| 3311 | // Opening a popup in the now-sandboxed frame should fail. |
| 3312 | bool success = false; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3313 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
| 3314 | root->child_at(0), |
| 3315 | "window.domAutomationController.send(" |
| 3316 | " !window.open('data:text/html,dataurl'));", |
| 3317 | &success)); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3318 | EXPECT_TRUE(success); |
| 3319 | EXPECT_EQ(1u, Shell::windows().size()); |
alexmos | f832a2f | 2015-01-27 22:44:03 | [diff] [blame] | 3320 | } |
| 3321 | |
alexmos | 6e0ee0c | 2015-05-01 18:57:34 | [diff] [blame] | 3322 | // Verify that when a new child frame is added, the proxies created for it in |
| 3323 | // other SiteInstances have correct sandbox flags and origin. |
| 3324 | // |
| 3325 | // A A A |
| 3326 | // / / \ / \ . |
| 3327 | // B -> B A -> B A |
| 3328 | // \ . |
| 3329 | // B |
| 3330 | // |
| 3331 | // The test checks sandbox flags and origin for the proxy added in step 2, by |
| 3332 | // checking whether the grandchild frame added in step 3 sees proper sandbox |
| 3333 | // flags and origin for its (remote) parent. This wasn't addressed when |
| 3334 | // https://crbug.com/423587 was fixed. |
stanisc | 2b6e1d7 | 2016-05-11 01:31:54 | [diff] [blame] | 3335 | // TODO(alexmos): Re-enable when https://crbug.com/610893 is fixed. |
| 3336 | IN_PROC_BROWSER_TEST_F( |
| 3337 | SitePerProcessBrowserTest, |
| 3338 | DISABLED_ProxiesForNewChildFramesHaveCorrectReplicationState) { |
alexmos | 6e0ee0c | 2015-05-01 18:57:34 | [diff] [blame] | 3339 | GURL main_url( |
| 3340 | embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html")); |
| 3341 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3342 | |
| 3343 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3344 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 6e0ee0c | 2015-05-01 18:57:34 | [diff] [blame] | 3345 | TestNavigationObserver observer(shell()->web_contents()); |
| 3346 | |
| 3347 | EXPECT_EQ( |
| 3348 | " Site A ------------ proxies for B\n" |
| 3349 | " +--Site B ------- proxies for A\n" |
| 3350 | "Where A = http://127.0.0.1/\n" |
| 3351 | " B = http://baz.com/", |
| 3352 | DepictFrameTree(root)); |
| 3353 | |
| 3354 | // In the root frame, add a new sandboxed local frame, which itself has a |
| 3355 | // child frame on baz.com. Wait for three RenderFrameHosts to be created: |
| 3356 | // the new sandboxed local frame, its child (while it's still local), and a |
| 3357 | // pending RFH when starting the cross-site navigation to baz.com. |
| 3358 | RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3359 | EXPECT_TRUE(ExecuteScript(root, |
| 3360 | "addFrame('/frame_tree/page_with_one_frame.html'," |
| 3361 | " 'allow-scripts allow-same-origin'))")); |
alexmos | 6e0ee0c | 2015-05-01 18:57:34 | [diff] [blame] | 3362 | frame_observer.Wait(); |
| 3363 | |
| 3364 | // Wait for the cross-site navigation to baz.com in the grandchild to finish. |
| 3365 | FrameTreeNode* bottom_child = root->child_at(1)->child_at(0); |
| 3366 | TestFrameNavigationObserver navigation_observer(bottom_child); |
| 3367 | navigation_observer.Wait(); |
| 3368 | |
| 3369 | EXPECT_EQ( |
| 3370 | " Site A ------------ proxies for B\n" |
| 3371 | " |--Site B ------- proxies for A\n" |
| 3372 | " +--Site A ------- proxies for B\n" |
| 3373 | " +--Site B -- proxies for A\n" |
| 3374 | "Where A = http://127.0.0.1/\n" |
| 3375 | " B = http://baz.com/", |
| 3376 | DepictFrameTree(root)); |
| 3377 | |
| 3378 | // Use location.ancestorOrigins to check that the grandchild on baz.com sees |
| 3379 | // correct origin for its parent. |
| 3380 | int ancestor_origins_length = 0; |
| 3381 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3382 | bottom_child, |
alexmos | 6e0ee0c | 2015-05-01 18:57:34 | [diff] [blame] | 3383 | "window.domAutomationController.send(location.ancestorOrigins.length);", |
| 3384 | &ancestor_origins_length)); |
| 3385 | EXPECT_EQ(2, ancestor_origins_length); |
| 3386 | std::string parent_origin; |
| 3387 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3388 | bottom_child, |
alexmos | 6e0ee0c | 2015-05-01 18:57:34 | [diff] [blame] | 3389 | "window.domAutomationController.send(location.ancestorOrigins[0]);", |
| 3390 | &parent_origin)); |
| 3391 | EXPECT_EQ(main_url.GetOrigin().spec(), parent_origin + "/"); |
| 3392 | |
| 3393 | // Check that the sandbox flags in the browser process are correct. |
dcheng | 5f60abb | 2015-05-28 01:39:36 | [diff] [blame] | 3394 | // "allow-scripts" resets both WebSandboxFlags::Scripts and |
| 3395 | // WebSandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy(). |
| 3396 | blink::WebSandboxFlags expected_flags = |
| 3397 | blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts & |
| 3398 | ~blink::WebSandboxFlags::AutomaticFeatures & |
| 3399 | ~blink::WebSandboxFlags::Origin; |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3400 | EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags()); |
alexmos | 6e0ee0c | 2015-05-01 18:57:34 | [diff] [blame] | 3401 | |
| 3402 | // The child of the sandboxed frame should've inherited sandbox flags, so it |
| 3403 | // should not be able to create popups. |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 3404 | EXPECT_EQ(expected_flags, bottom_child->effective_sandbox_flags()); |
alexmos | 6e0ee0c | 2015-05-01 18:57:34 | [diff] [blame] | 3405 | bool success = false; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3406 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
| 3407 | bottom_child, |
| 3408 | "window.domAutomationController.send(" |
| 3409 | " !window.open('data:text/html,dataurl'));", |
| 3410 | &success)); |
alexmos | 6e0ee0c | 2015-05-01 18:57:34 | [diff] [blame] | 3411 | EXPECT_TRUE(success); |
| 3412 | EXPECT_EQ(1u, Shell::windows().size()); |
| 3413 | } |
| 3414 | |
alexmos | 998581d | 2015-01-22 01:01:59 | [diff] [blame] | 3415 | // Verify that a child frame can retrieve the name property set by its parent. |
| 3416 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) { |
| 3417 | GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html")); |
| 3418 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3419 | |
| 3420 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3421 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 998581d | 2015-01-22 01:01:59 | [diff] [blame] | 3422 | |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 3423 | TestNavigationObserver observer(shell()->web_contents()); |
alexmos | 998581d | 2015-01-22 01:01:59 | [diff] [blame] | 3424 | |
| 3425 | // Load cross-site page into iframe. |
| 3426 | GURL frame_url = |
| 3427 | embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html"); |
| 3428 | NavigateFrameToURL(root->child_at(0), frame_url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 3429 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3430 | EXPECT_EQ(frame_url, observer.last_navigation_url()); |
alexmos | 998581d | 2015-01-22 01:01:59 | [diff] [blame] | 3431 | |
| 3432 | // Ensure that a new process is created for the subframe. |
| 3433 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 3434 | root->child_at(0)->current_frame_host()->GetSiteInstance()); |
| 3435 | |
| 3436 | // Check that the window.name seen by the frame matches the name attribute |
| 3437 | // specified by its parent in the iframe tag. |
| 3438 | std::string result; |
| 3439 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3440 | root->child_at(0), "window.domAutomationController.send(window.name);", |
| 3441 | &result)); |
alexmos | 6b29456 | 2015-03-05 19:24:10 | [diff] [blame] | 3442 | EXPECT_EQ("3-1-name", result); |
alexmos | 998581d | 2015-01-22 01:01:59 | [diff] [blame] | 3443 | } |
| 3444 | |
alexmos | be2f4c3 | 2015-03-10 02:30:23 | [diff] [blame] | 3445 | // Verify that dynamic updates to a frame's window.name propagate to the |
| 3446 | // frame's proxies, so that the latest frame names can be used in navigations. |
| 3447 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) { |
| 3448 | GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html")); |
| 3449 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3450 | |
| 3451 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3452 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | be2f4c3 | 2015-03-10 02:30:23 | [diff] [blame] | 3453 | TestNavigationObserver observer(shell()->web_contents()); |
| 3454 | |
| 3455 | // Load cross-site page into iframe. |
| 3456 | GURL frame_url = |
| 3457 | embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html"); |
| 3458 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 3459 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3460 | EXPECT_EQ(frame_url, observer.last_navigation_url()); |
| 3461 | |
| 3462 | // Browser process should know the child frame's original window.name |
| 3463 | // specified in the iframe element. |
| 3464 | EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name"); |
| 3465 | |
| 3466 | // Update the child frame's window.name. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3467 | EXPECT_TRUE( |
| 3468 | ExecuteScript(root->child_at(0), "window.name = 'updated-name';")); |
alexmos | be2f4c3 | 2015-03-10 02:30:23 | [diff] [blame] | 3469 | |
| 3470 | // The change should propagate to the browser process. |
| 3471 | EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name"); |
| 3472 | |
| 3473 | // The proxy in the parent process should also receive the updated name. |
| 3474 | // Check that it can reference the child frame by its new name. |
| 3475 | bool success = false; |
| 3476 | EXPECT_TRUE( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3477 | ExecuteScriptAndExtractBool(shell(), |
alexmos | be2f4c3 | 2015-03-10 02:30:23 | [diff] [blame] | 3478 | "window.domAutomationController.send(" |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3479 | " frames['updated-name'] == frames[0]);", |
alexmos | be2f4c3 | 2015-03-10 02:30:23 | [diff] [blame] | 3480 | &success)); |
| 3481 | EXPECT_TRUE(success); |
| 3482 | |
| 3483 | // Issue a renderer-initiated navigation from the root frame to the child |
| 3484 | // frame using the frame's name. Make sure correct frame is navigated. |
| 3485 | // |
| 3486 | // TODO(alexmos): When blink::createWindow is refactored to handle |
| 3487 | // RemoteFrames, this should also be tested via window.open(url, frame_name) |
| 3488 | // and a more complicated frame hierarchy (https://crbug.com/463742) |
| 3489 | TestFrameNavigationObserver frame_observer(root->child_at(0)); |
| 3490 | GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3491 | EXPECT_TRUE(ExecuteScript( |
| 3492 | shell(), |
| 3493 | base::StringPrintf("frames['updated-name'].location.href = '%s';", |
| 3494 | foo_url.spec().c_str()))); |
alexmos | be2f4c3 | 2015-03-10 02:30:23 | [diff] [blame] | 3495 | frame_observer.Wait(); |
| 3496 | EXPECT_EQ(foo_url, root->child_at(0)->current_url()); |
| 3497 | } |
| 3498 | |
alexmos | a7a4ff82 | 2015-04-27 17:59:56 | [diff] [blame] | 3499 | // Verify that when a frame is navigated to a new origin, the origin update |
| 3500 | // propagates to the frame's proxies. |
| 3501 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginUpdatesReachProxies) { |
| 3502 | GURL main_url( |
| 3503 | embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html")); |
| 3504 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3505 | |
| 3506 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3507 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | a7a4ff82 | 2015-04-27 17:59:56 | [diff] [blame] | 3508 | TestNavigationObserver observer(shell()->web_contents()); |
| 3509 | |
| 3510 | EXPECT_EQ( |
| 3511 | " Site A ------------ proxies for B\n" |
| 3512 | " |--Site B ------- proxies for A\n" |
| 3513 | " +--Site A ------- proxies for B\n" |
| 3514 | "Where A = http://127.0.0.1/\n" |
| 3515 | " B = http://bar.com/", |
| 3516 | DepictFrameTree(root)); |
| 3517 | |
| 3518 | // Navigate second subframe to a baz.com. This should send an origin update |
| 3519 | // to the frame's proxy in the bar.com (first frame's) process. |
| 3520 | GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html"); |
| 3521 | NavigateFrameToURL(root->child_at(1), frame_url); |
| 3522 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3523 | EXPECT_EQ(frame_url, observer.last_navigation_url()); |
| 3524 | |
| 3525 | // The first frame can't directly observe the second frame's origin with |
| 3526 | // JavaScript. Instead, try to navigate the second frame from the first |
| 3527 | // frame. This should fail with a console error message, which should |
| 3528 | // contain the second frame's updated origin (see blink::Frame::canNavigate). |
dcheng | 5971627 | 2016-04-09 05:19:08 | [diff] [blame] | 3529 | std::unique_ptr<ConsoleObserverDelegate> console_delegate( |
alexmos | a7a4ff82 | 2015-04-27 17:59:56 | [diff] [blame] | 3530 | new ConsoleObserverDelegate( |
| 3531 | shell()->web_contents(), |
| 3532 | "Unsafe JavaScript attempt to initiate navigation*")); |
| 3533 | shell()->web_contents()->SetDelegate(console_delegate.get()); |
| 3534 | |
| 3535 | // frames[1] can't be used due to a bug where RemoteFrames are created out of |
| 3536 | // order (https://crbug.com/478792). Instead, target second frame by name. |
| 3537 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3538 | root->child_at(0), |
| 3539 | "parent.frames['frame2'].location.href = 'data:text/html,foo'")); |
alexmos | a7a4ff82 | 2015-04-27 17:59:56 | [diff] [blame] | 3540 | console_delegate->Wait(); |
| 3541 | |
creis | abdd2bd6 | 2015-11-21 01:14:58 | [diff] [blame] | 3542 | std::string frame_origin = root->child_at(1)->current_origin().Serialize(); |
alexmos | a7a4ff82 | 2015-04-27 17:59:56 | [diff] [blame] | 3543 | EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec()); |
| 3544 | EXPECT_TRUE( |
brettw | d97eede | 2015-07-06 22:09:00 | [diff] [blame] | 3545 | base::MatchPattern(console_delegate->message(), "*" + frame_origin + "*")) |
alexmos | a7a4ff82 | 2015-04-27 17:59:56 | [diff] [blame] | 3546 | << "Error message does not contain the frame's latest origin (" |
| 3547 | << frame_origin << ")"; |
| 3548 | } |
| 3549 | |
nasko | 3e8c20e | 2014-12-18 06:54:56 | [diff] [blame] | 3550 | // Ensure that navigating subframes in --site-per-process mode properly fires |
| 3551 | // the DidStopLoading event on WebContentsObserver. |
| 3552 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) { |
| 3553 | GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html")); |
| 3554 | NavigateToURL(shell(), main_url); |
| 3555 | |
| 3556 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3557 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
nasko | 3e8c20e | 2014-12-18 06:54:56 | [diff] [blame] | 3558 | |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 3559 | TestNavigationObserver observer(shell()->web_contents()); |
nasko | 3e8c20e | 2014-12-18 06:54:56 | [diff] [blame] | 3560 | |
| 3561 | // Load same-site page into iframe. |
| 3562 | FrameTreeNode* child = root->child_at(0); |
| 3563 | GURL http_url(embedded_test_server()->GetURL("/title1.html")); |
| 3564 | NavigateFrameToURL(child, http_url); |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 3565 | EXPECT_EQ(http_url, observer.last_navigation_url()); |
| 3566 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
nasko | 3e8c20e | 2014-12-18 06:54:56 | [diff] [blame] | 3567 | |
| 3568 | // Load cross-site page into iframe. |
| 3569 | TestNavigationObserver nav_observer(shell()->web_contents(), 1); |
| 3570 | GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html"); |
| 3571 | NavigationController::LoadURLParams params(url); |
| 3572 | params.transition_type = ui::PAGE_TRANSITION_LINK; |
| 3573 | params.frame_tree_node_id = child->frame_tree_node_id(); |
| 3574 | child->navigator()->GetController()->LoadURLWithParams(params); |
| 3575 | nav_observer.Wait(); |
| 3576 | |
| 3577 | // Verify that the navigation succeeded and the expected URL was loaded. |
clamy | f1ccb4d | 2015-01-28 17:40:38 | [diff] [blame] | 3578 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3579 | EXPECT_EQ(url, observer.last_navigation_url()); |
nasko | 3e8c20e | 2014-12-18 06:54:56 | [diff] [blame] | 3580 | } |
| 3581 | |
creis | 0040d34 | 2015-02-19 01:42:37 | [diff] [blame] | 3582 | // Ensure that the renderer does not crash when navigating a frame that has a |
| 3583 | // sibling RemoteFrame. See https://crbug.com/426953. |
| 3584 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 3585 | NavigateWithSiblingRemoteFrame) { |
| 3586 | GURL main_url( |
| 3587 | embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html")); |
| 3588 | NavigateToURL(shell(), main_url); |
| 3589 | |
| 3590 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3591 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
creis | 0040d34 | 2015-02-19 01:42:37 | [diff] [blame] | 3592 | TestNavigationObserver observer(shell()->web_contents()); |
| 3593 | |
| 3594 | // Make sure the first frame is out of process. |
| 3595 | ASSERT_EQ(2U, root->child_count()); |
| 3596 | FrameTreeNode* node2 = root->child_at(0); |
| 3597 | EXPECT_NE(root->current_frame_host()->GetSiteInstance(), |
| 3598 | node2->current_frame_host()->GetSiteInstance()); |
| 3599 | |
| 3600 | // Make sure the second frame is in the parent's process. |
| 3601 | FrameTreeNode* node3 = root->child_at(1); |
| 3602 | EXPECT_EQ(root->current_frame_host()->GetSiteInstance(), |
| 3603 | node3->current_frame_host()->GetSiteInstance()); |
| 3604 | |
| 3605 | // Navigate the second iframe (node3) to a URL in its own process. |
| 3606 | GURL title_url = embedded_test_server()->GetURL("/title2.html"); |
| 3607 | NavigateFrameToURL(node3, title_url); |
| 3608 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3609 | EXPECT_EQ(title_url, observer.last_navigation_url()); |
| 3610 | EXPECT_EQ(root->current_frame_host()->GetSiteInstance(), |
| 3611 | node3->current_frame_host()->GetSiteInstance()); |
| 3612 | EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive()); |
| 3613 | } |
| 3614 | |
kenrb | 77618cd5 | 2016-02-18 19:13:38 | [diff] [blame] | 3615 | // Ensure that the renderer does not crash when a local frame with a remote |
| 3616 | // parent frame is swapped from local to remote, then back to local again. |
| 3617 | // See https://crbug.com/585654. |
| 3618 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 3619 | NavigateSiblingsToSameProcess) { |
| 3620 | GURL main_url( |
| 3621 | embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html")); |
| 3622 | NavigateToURL(shell(), main_url); |
| 3623 | |
| 3624 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3625 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
kenrb | 77618cd5 | 2016-02-18 19:13:38 | [diff] [blame] | 3626 | |
| 3627 | FrameTreeNode* node2 = root->child_at(0); |
| 3628 | FrameTreeNode* node3 = root->child_at(1); |
| 3629 | |
| 3630 | // Navigate the second iframe to the same process as the first. |
| 3631 | GURL frame_url = embedded_test_server()->GetURL("bar.com", "/title1.html"); |
| 3632 | NavigateFrameToURL(node3, frame_url); |
| 3633 | |
| 3634 | // Verify that they are in the same process. |
| 3635 | EXPECT_EQ(node2->current_frame_host()->GetSiteInstance(), |
| 3636 | node3->current_frame_host()->GetSiteInstance()); |
| 3637 | EXPECT_NE(root->current_frame_host()->GetSiteInstance(), |
| 3638 | node3->current_frame_host()->GetSiteInstance()); |
| 3639 | |
| 3640 | // Navigate the first iframe into its parent's process. |
| 3641 | GURL title_url = embedded_test_server()->GetURL("/title2.html"); |
| 3642 | NavigateFrameToURL(node2, title_url); |
| 3643 | EXPECT_NE(node2->current_frame_host()->GetSiteInstance(), |
| 3644 | node3->current_frame_host()->GetSiteInstance()); |
| 3645 | |
| 3646 | // Return the first iframe to the same process as its sibling, and ensure |
| 3647 | // that it does not crash. |
| 3648 | NavigateFrameToURL(node2, frame_url); |
| 3649 | EXPECT_EQ(node2->current_frame_host()->GetSiteInstance(), |
| 3650 | node3->current_frame_host()->GetSiteInstance()); |
| 3651 | EXPECT_TRUE(node2->current_frame_host()->IsRenderFrameLive()); |
| 3652 | } |
| 3653 | |
alexmos | f40ce5b0 | 2015-02-25 20:19:56 | [diff] [blame] | 3654 | // Verify that load events for iframe elements work when the child frame is |
| 3655 | // out-of-process. In such cases, the load event is forwarded from the child |
| 3656 | // frame to the parent frame via the browser process. |
| 3657 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) { |
| 3658 | // Load a page with a cross-site frame. The parent page has an onload |
| 3659 | // handler in the iframe element that appends "LOADED" to the document title. |
| 3660 | { |
| 3661 | GURL main_url( |
| 3662 | embedded_test_server()->GetURL("/frame_with_load_event.html")); |
| 3663 | base::string16 expected_title(base::UTF8ToUTF16("LOADED")); |
| 3664 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| 3665 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3666 | EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title); |
| 3667 | } |
| 3668 | |
| 3669 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3670 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | f40ce5b0 | 2015-02-25 20:19:56 | [diff] [blame] | 3671 | |
| 3672 | // Load another cross-site page into the iframe and check that the load event |
| 3673 | // is fired. |
| 3674 | { |
| 3675 | GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); |
| 3676 | base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED")); |
| 3677 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| 3678 | TestNavigationObserver observer(shell()->web_contents()); |
| 3679 | NavigateFrameToURL(root->child_at(0), foo_url); |
| 3680 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3681 | EXPECT_EQ(foo_url, observer.last_navigation_url()); |
| 3682 | EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title); |
| 3683 | } |
| 3684 | } |
| 3685 | |
alexmos | e7da5a1 | 2015-04-09 02:22:16 | [diff] [blame] | 3686 | // Check that postMessage can be routed between cross-site iframes. |
| 3687 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframePostMessage) { |
| 3688 | GURL main_url(embedded_test_server()->GetURL( |
| 3689 | "/frame_tree/page_with_post_message_frames.html")); |
| 3690 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3691 | |
| 3692 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3693 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | e7da5a1 | 2015-04-09 02:22:16 | [diff] [blame] | 3694 | |
alexmos | e7da5a1 | 2015-04-09 02:22:16 | [diff] [blame] | 3695 | ASSERT_EQ(2U, root->child_count()); |
| 3696 | |
| 3697 | // Verify the frames start at correct URLs. First frame should be |
| 3698 | // same-site; second frame should be cross-site. |
| 3699 | GURL same_site_url(embedded_test_server()->GetURL("/post_message.html")); |
| 3700 | EXPECT_EQ(same_site_url, root->child_at(0)->current_url()); |
| 3701 | GURL foo_url(embedded_test_server()->GetURL("foo.com", |
| 3702 | "/post_message.html")); |
| 3703 | EXPECT_EQ(foo_url, root->child_at(1)->current_url()); |
| 3704 | EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(), |
| 3705 | root->child_at(1)->current_frame_host()->GetSiteInstance()); |
| 3706 | |
| 3707 | // Send a message from first, same-site frame to second, cross-site frame. |
| 3708 | // Expect the second frame to reply back to the first frame. |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3709 | PostMessageAndWaitForReply(root->child_at(0), |
| 3710 | "postToSibling('subframe-msg','subframe2')", |
| 3711 | "\"done-subframe1\""); |
alexmos | e7da5a1 | 2015-04-09 02:22:16 | [diff] [blame] | 3712 | |
| 3713 | // Send a postMessage from second, cross-site frame to its parent. Expect |
| 3714 | // parent to send a reply to the frame. |
| 3715 | base::string16 expected_title(base::ASCIIToUTF16("subframe-msg")); |
| 3716 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3717 | PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')", |
| 3718 | "\"done-subframe2\""); |
alexmos | e7da5a1 | 2015-04-09 02:22:16 | [diff] [blame] | 3719 | EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 3720 | |
alexmos | e7da5a1 | 2015-04-09 02:22:16 | [diff] [blame] | 3721 | // Verify the total number of received messages for each subframe. First |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3722 | // frame should have one message (reply from second frame). Second frame |
alexmos | e7da5a1 | 2015-04-09 02:22:16 | [diff] [blame] | 3723 | // should have two messages (message from first frame and reply from parent). |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3724 | // Parent should have one message (from second frame). |
| 3725 | EXPECT_EQ(1, GetReceivedMessages(root->child_at(0))); |
| 3726 | EXPECT_EQ(2, GetReceivedMessages(root->child_at(1))); |
| 3727 | EXPECT_EQ(1, GetReceivedMessages(root)); |
| 3728 | } |
| 3729 | |
csharrison | 264bca64 | 2016-05-06 19:27:09 | [diff] [blame] | 3730 | // Check that renderer initiated navigations which commit a new RenderFrameHost |
| 3731 | // do not crash if the original RenderFrameHost was being covered by an |
| 3732 | // interstitial. See crbug.com/607964. |
| 3733 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 3734 | NavigateOpenerWithInterstitial) { |
| 3735 | EXPECT_TRUE(NavigateToURL( |
| 3736 | shell(), embedded_test_server()->GetURL("a.com", "/title1.html"))); |
| 3737 | |
| 3738 | // Open a popup and navigate it to bar.com. |
| 3739 | ShellAddedObserver new_shell_observer; |
| 3740 | EXPECT_TRUE(ExecuteScript(web_contents(), "window.open('about:blank');")); |
| 3741 | Shell* popup = new_shell_observer.GetShell(); |
| 3742 | EXPECT_TRUE(NavigateToURL(popup, embedded_test_server()->GetURL( |
| 3743 | "bar.com", "/navigate_opener.html"))); |
| 3744 | |
| 3745 | // Show an interstitial in the opener. |
| 3746 | TestInterstitialDelegate* delegate = new TestInterstitialDelegate; |
| 3747 | WebContentsImpl* opener_contents = |
| 3748 | static_cast<WebContentsImpl*>(web_contents()); |
| 3749 | GURL interstitial_url("http://interstitial"); |
| 3750 | InterstitialPageImpl* interstitial = new InterstitialPageImpl( |
| 3751 | opener_contents, static_cast<RenderWidgetHostDelegate*>(opener_contents), |
| 3752 | true, interstitial_url, delegate); |
| 3753 | interstitial->Show(); |
| 3754 | WaitForInterstitialAttach(opener_contents); |
| 3755 | |
| 3756 | // Now, navigate the opener cross-process using the popup while it still has |
| 3757 | // an interstitial. This should not crash. |
| 3758 | TestNavigationObserver navigation_observer(opener_contents); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3759 | EXPECT_TRUE(ExecuteScript(popup, "navigateOpener();")); |
csharrison | 264bca64 | 2016-05-06 19:27:09 | [diff] [blame] | 3760 | navigation_observer.Wait(); |
| 3761 | } |
| 3762 | |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3763 | // Check that postMessage can be sent from a subframe on a cross-process opener |
| 3764 | // tab, and that its event.source points to a valid proxy. |
| 3765 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
alexmos | 17e5753 | 2015-08-15 02:54:36 | [diff] [blame] | 3766 | PostMessageWithSubframeOnOpenerChain) { |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3767 | GURL main_url(embedded_test_server()->GetURL( |
| 3768 | "a.com", "/frame_tree/page_with_post_message_frames.html")); |
| 3769 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3770 | |
| 3771 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3772 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3773 | |
| 3774 | ASSERT_EQ(2U, root->child_count()); |
| 3775 | |
| 3776 | // Verify the initial state of the world. First frame should be same-site; |
| 3777 | // second frame should be cross-site. |
| 3778 | EXPECT_EQ( |
| 3779 | " Site A ------------ proxies for B\n" |
| 3780 | " |--Site A ------- proxies for B\n" |
| 3781 | " +--Site B ------- proxies for A\n" |
| 3782 | "Where A = http://a.com/\n" |
| 3783 | " B = http://foo.com/", |
| 3784 | DepictFrameTree(root)); |
| 3785 | |
| 3786 | // Open a popup from the first subframe (so that popup's window.opener points |
| 3787 | // to the subframe) and navigate it to bar.com. |
| 3788 | ShellAddedObserver new_shell_observer; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3789 | EXPECT_TRUE(ExecuteScript(root->child_at(0), "openPopup('about:blank');")); |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3790 | Shell* popup = new_shell_observer.GetShell(); |
| 3791 | GURL popup_url( |
| 3792 | embedded_test_server()->GetURL("bar.com", "/post_message.html")); |
| 3793 | EXPECT_TRUE(NavigateToURL(popup, popup_url)); |
| 3794 | |
| 3795 | // From the popup, open another popup for baz.com. This will be used to |
| 3796 | // check that the whole opener chain is processed when creating proxies and |
| 3797 | // not just an immediate opener. |
| 3798 | ShellAddedObserver new_shell_observer2; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3799 | EXPECT_TRUE(ExecuteScript(popup, "openPopup('about:blank');")); |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3800 | Shell* popup2 = new_shell_observer2.GetShell(); |
| 3801 | GURL popup2_url( |
| 3802 | embedded_test_server()->GetURL("baz.com", "/post_message.html")); |
| 3803 | EXPECT_TRUE(NavigateToURL(popup2, popup2_url)); |
| 3804 | |
| 3805 | // Ensure that we've created proxies for SiteInstances of both popups (C, D) |
| 3806 | // in the main window's frame tree. |
| 3807 | EXPECT_EQ( |
| 3808 | " Site A ------------ proxies for B C D\n" |
| 3809 | " |--Site A ------- proxies for B C D\n" |
| 3810 | " +--Site B ------- proxies for A C D\n" |
| 3811 | "Where A = http://a.com/\n" |
| 3812 | " B = http://foo.com/\n" |
| 3813 | " C = http://bar.com/\n" |
| 3814 | " D = http://baz.com/", |
| 3815 | DepictFrameTree(root)); |
| 3816 | |
| 3817 | // Check the first popup's frame tree as well. Note that it doesn't have a |
| 3818 | // proxy for foo.com, since foo.com can't reach the popup. It does have a |
| 3819 | // proxy for its opener a.com (which can reach it via the window.open |
| 3820 | // reference) and second popup (which can reach it via window.opener). |
| 3821 | FrameTreeNode* popup_root = |
| 3822 | static_cast<WebContentsImpl*>(popup->web_contents()) |
| 3823 | ->GetFrameTree() |
| 3824 | ->root(); |
| 3825 | EXPECT_EQ( |
| 3826 | " Site C ------------ proxies for A D\n" |
| 3827 | "Where A = http://a.com/\n" |
| 3828 | " C = http://bar.com/\n" |
| 3829 | " D = http://baz.com/", |
| 3830 | DepictFrameTree(popup_root)); |
| 3831 | |
| 3832 | // Send a message from first subframe on main page to the first popup and |
| 3833 | // wait for a reply back. The reply verifies that the proxy for the opener |
| 3834 | // tab's subframe is targeted properly. |
| 3835 | PostMessageAndWaitForReply(root->child_at(0), "postToPopup('subframe-msg')", |
| 3836 | "\"done-subframe1\""); |
| 3837 | |
alexmos | 5ac402d | 2015-07-09 07:51:10 | [diff] [blame] | 3838 | // Send a postMessage from the popup to window.opener and ensure that it |
| 3839 | // reaches subframe1. This verifies that the subframe opener information |
| 3840 | // propagated to the popup's RenderFrame. Wait for subframe1 to send a reply |
| 3841 | // message to the popup. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3842 | EXPECT_TRUE(ExecuteScript(popup, "window.name = 'popup';")); |
alexmos | 5ac402d | 2015-07-09 07:51:10 | [diff] [blame] | 3843 | PostMessageAndWaitForReply(popup_root, "postToOpener('subframe-msg', '*')", |
| 3844 | "\"done-popup\""); |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3845 | |
alexmos | 5ac402d | 2015-07-09 07:51:10 | [diff] [blame] | 3846 | // Second a postMessage from popup2 to window.opener.opener, which should |
| 3847 | // resolve to subframe1. This tests opener chains of length greater than 1. |
| 3848 | // As before, subframe1 will send a reply to popup2. |
| 3849 | FrameTreeNode* popup2_root = |
| 3850 | static_cast<WebContentsImpl*>(popup2->web_contents()) |
| 3851 | ->GetFrameTree() |
| 3852 | ->root(); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3853 | EXPECT_TRUE(ExecuteScript(popup2, "window.name = 'popup2';")); |
alexmos | 5ac402d | 2015-07-09 07:51:10 | [diff] [blame] | 3854 | PostMessageAndWaitForReply(popup2_root, |
| 3855 | "postToOpenerOfOpener('subframe-msg', '*')", |
| 3856 | "\"done-popup2\""); |
| 3857 | |
| 3858 | // Verify the total number of received messages for each subframe: |
| 3859 | // - 3 for first subframe (two from first popup, one from second popup) |
| 3860 | // - 2 for popup (both from first subframe) |
| 3861 | // - 1 for popup2 (reply from first subframe) |
| 3862 | // - 0 for other frames |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3863 | EXPECT_EQ(0, GetReceivedMessages(root)); |
alexmos | 5ac402d | 2015-07-09 07:51:10 | [diff] [blame] | 3864 | EXPECT_EQ(3, GetReceivedMessages(root->child_at(0))); |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3865 | EXPECT_EQ(0, GetReceivedMessages(root->child_at(1))); |
alexmos | 5ac402d | 2015-07-09 07:51:10 | [diff] [blame] | 3866 | EXPECT_EQ(2, GetReceivedMessages(popup_root)); |
| 3867 | EXPECT_EQ(1, GetReceivedMessages(popup2_root)); |
alexmos | e7da5a1 | 2015-04-09 02:22:16 | [diff] [blame] | 3868 | } |
| 3869 | |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3870 | // Check that parent.frames[num] references correct sibling frames when the |
| 3871 | // parent is remote. See https://crbug.com/478792. |
| 3872 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) { |
| 3873 | // Start on a page with three same-site subframes. |
| 3874 | GURL main_url( |
| 3875 | embedded_test_server()->GetURL("a.com", "/frame_tree/top.html")); |
| 3876 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 3877 | |
| 3878 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3879 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3880 | ASSERT_EQ(3U, root->child_count()); |
| 3881 | FrameTreeNode* child0 = root->child_at(0); |
| 3882 | FrameTreeNode* child1 = root->child_at(1); |
| 3883 | FrameTreeNode* child2 = root->child_at(2); |
| 3884 | |
| 3885 | // Send each of the frames to a different site. Each new renderer will first |
| 3886 | // create proxies for the parent and two sibling subframes and then create |
| 3887 | // and insert the new RenderFrame into the frame tree. |
| 3888 | GURL b_url(embedded_test_server()->GetURL("b.com", "/post_message.html")); |
| 3889 | GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html")); |
| 3890 | GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html")); |
| 3891 | NavigateFrameToURL(child0, b_url); |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3892 | NavigateFrameToURL(child1, c_url); |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3893 | NavigateFrameToURL(child2, d_url); |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3894 | |
| 3895 | EXPECT_EQ( |
| 3896 | " Site A ------------ proxies for B C D\n" |
| 3897 | " |--Site B ------- proxies for A C D\n" |
| 3898 | " |--Site C ------- proxies for A B D\n" |
| 3899 | " +--Site D ------- proxies for A B C\n" |
| 3900 | "Where A = http://a.com/\n" |
| 3901 | " B = http://b.com/\n" |
| 3902 | " C = http://c.com/\n" |
| 3903 | " D = http://d.com/", |
| 3904 | DepictFrameTree(root)); |
| 3905 | |
| 3906 | // Check that each subframe sees itself at correct index in parent.frames. |
| 3907 | bool success = false; |
| 3908 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3909 | child0, |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3910 | "window.domAutomationController.send(window === parent.frames[0]);", |
| 3911 | &success)); |
| 3912 | EXPECT_TRUE(success); |
| 3913 | |
| 3914 | success = false; |
| 3915 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3916 | child1, |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3917 | "window.domAutomationController.send(window === parent.frames[1]);", |
| 3918 | &success)); |
| 3919 | EXPECT_TRUE(success); |
| 3920 | |
| 3921 | success = false; |
| 3922 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 3923 | child2, |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3924 | "window.domAutomationController.send(window === parent.frames[2]);", |
| 3925 | &success)); |
| 3926 | EXPECT_TRUE(success); |
| 3927 | |
| 3928 | // Send a postMessage from B to parent.frames[1], which should go to C, and |
| 3929 | // wait for reply. |
| 3930 | PostMessageAndWaitForReply(child0, "postToSibling('subframe-msg', 1)", |
| 3931 | "\"done-1-1-name\""); |
| 3932 | |
| 3933 | // Send a postMessage from C to parent.frames[2], which should go to D, and |
| 3934 | // wait for reply. |
| 3935 | PostMessageAndWaitForReply(child1, "postToSibling('subframe-msg', 2)", |
| 3936 | "\"done-1-2-name\""); |
| 3937 | |
| 3938 | // Verify the total number of received messages for each subframe. |
alexmos | 5872904 | 2015-06-18 23:20:00 | [diff] [blame] | 3939 | EXPECT_EQ(1, GetReceivedMessages(child0)); |
| 3940 | EXPECT_EQ(2, GetReceivedMessages(child1)); |
| 3941 | EXPECT_EQ(1, GetReceivedMessages(child2)); |
alexmos | 9f8705a | 2015-05-06 19:58:59 | [diff] [blame] | 3942 | } |
| 3943 | |
nick | 59dcb16 | 2015-04-09 20:29:01 | [diff] [blame] | 3944 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RFPHDestruction) { |
| 3945 | GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html")); |
| 3946 | NavigateToURL(shell(), main_url); |
| 3947 | |
| 3948 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 3949 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
nick | 59dcb16 | 2015-04-09 20:29:01 | [diff] [blame] | 3950 | |
| 3951 | TestNavigationObserver observer(shell()->web_contents()); |
| 3952 | |
| 3953 | // Load cross-site page into iframe. |
| 3954 | FrameTreeNode* child = root->child_at(0); |
| 3955 | GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html"); |
| 3956 | NavigateFrameToURL(root->child_at(0), url); |
| 3957 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3958 | EXPECT_EQ(url, observer.last_navigation_url()); |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 3959 | EXPECT_EQ( |
| 3960 | " Site A ------------ proxies for B\n" |
| 3961 | " |--Site B ------- proxies for A\n" |
| 3962 | " +--Site A ------- proxies for B\n" |
| 3963 | " |--Site A -- proxies for B\n" |
| 3964 | " +--Site A -- proxies for B\n" |
| 3965 | " +--Site A -- proxies for B\n" |
| 3966 | "Where A = http://127.0.0.1/\n" |
| 3967 | " B = http://foo.com/", |
| 3968 | DepictFrameTree(root)); |
nick | 59dcb16 | 2015-04-09 20:29:01 | [diff] [blame] | 3969 | |
| 3970 | // Load another cross-site page. |
| 3971 | url = embedded_test_server()->GetURL("bar.com", "/title3.html"); |
| 3972 | NavigateIframeToURL(shell()->web_contents(), "test", url); |
| 3973 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 3974 | EXPECT_EQ(url, observer.last_navigation_url()); |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 3975 | EXPECT_EQ( |
| 3976 | " Site A ------------ proxies for C\n" |
| 3977 | " |--Site C ------- proxies for A\n" |
| 3978 | " +--Site A ------- proxies for C\n" |
| 3979 | " |--Site A -- proxies for C\n" |
| 3980 | " +--Site A -- proxies for C\n" |
| 3981 | " +--Site A -- proxies for C\n" |
| 3982 | "Where A = http://127.0.0.1/\n" |
| 3983 | " C = http://bar.com/", |
| 3984 | DepictFrameTree(root)); |
nick | 59dcb16 | 2015-04-09 20:29:01 | [diff] [blame] | 3985 | |
| 3986 | // Navigate back to the parent's origin. |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 3987 | RenderFrameDeletedObserver deleted_observer(child->current_frame_host()); |
nick | 59dcb16 | 2015-04-09 20:29:01 | [diff] [blame] | 3988 | url = embedded_test_server()->GetURL("/title1.html"); |
| 3989 | NavigateFrameToURL(child, url); |
| 3990 | EXPECT_EQ(url, observer.last_navigation_url()); |
| 3991 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 3992 | |
| 3993 | // Wait for the old process to exit, to verify that the proxies go away. |
| 3994 | deleted_observer.WaitUntilDeleted(); |
nick | 44bacf3 | 2015-04-14 02:06:39 | [diff] [blame] | 3995 | EXPECT_EQ( |
| 3996 | " Site A\n" |
| 3997 | " |--Site A\n" |
| 3998 | " +--Site A\n" |
| 3999 | " |--Site A\n" |
| 4000 | " +--Site A\n" |
| 4001 | " +--Site A\n" |
| 4002 | "Where A = http://127.0.0.1/", |
| 4003 | DepictFrameTree(root)); |
nick | 59dcb16 | 2015-04-09 20:29:01 | [diff] [blame] | 4004 | } |
| 4005 | |
alexmos | 4cf2aa3 | 2015-07-15 23:40:43 | [diff] [blame] | 4006 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenPopupWithRemoteParent) { |
| 4007 | GURL main_url( |
| 4008 | embedded_test_server()->GetURL("a.com", "/site_per_process_main.html")); |
| 4009 | NavigateToURL(shell(), main_url); |
| 4010 | |
| 4011 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4012 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 4cf2aa3 | 2015-07-15 23:40:43 | [diff] [blame] | 4013 | |
| 4014 | // Navigate first child cross-site. |
| 4015 | GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 4016 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 4017 | |
| 4018 | // Open a popup from the first child. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4019 | Shell* new_shell = |
| 4020 | OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), ""); |
alexmos | 4cf2aa3 | 2015-07-15 23:40:43 | [diff] [blame] | 4021 | EXPECT_TRUE(new_shell); |
| 4022 | |
| 4023 | // Check that the popup's opener is correct on both the browser and renderer |
| 4024 | // sides. |
| 4025 | FrameTreeNode* popup_root = |
| 4026 | static_cast<WebContentsImpl*>(new_shell->web_contents()) |
| 4027 | ->GetFrameTree() |
| 4028 | ->root(); |
| 4029 | EXPECT_EQ(root->child_at(0), popup_root->opener()); |
| 4030 | |
| 4031 | std::string opener_url; |
| 4032 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4033 | popup_root, |
alexmos | 4cf2aa3 | 2015-07-15 23:40:43 | [diff] [blame] | 4034 | "window.domAutomationController.send(window.opener.location.href);", |
| 4035 | &opener_url)); |
| 4036 | EXPECT_EQ(frame_url.spec(), opener_url); |
| 4037 | |
| 4038 | // Now try the same with a cross-site popup and make sure it ends up in a new |
| 4039 | // process and with a correct opener. |
| 4040 | GURL popup_url(embedded_test_server()->GetURL("c.com", "/title2.html")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4041 | Shell* cross_site_popup = OpenPopup(root->child_at(0), popup_url, ""); |
alexmos | 4cf2aa3 | 2015-07-15 23:40:43 | [diff] [blame] | 4042 | EXPECT_TRUE(cross_site_popup); |
| 4043 | |
| 4044 | FrameTreeNode* cross_site_popup_root = |
| 4045 | static_cast<WebContentsImpl*>(cross_site_popup->web_contents()) |
| 4046 | ->GetFrameTree() |
| 4047 | ->root(); |
| 4048 | EXPECT_EQ(cross_site_popup_root->current_url(), popup_url); |
| 4049 | |
| 4050 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 4051 | cross_site_popup->web_contents()->GetSiteInstance()); |
| 4052 | EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(), |
| 4053 | cross_site_popup->web_contents()->GetSiteInstance()); |
| 4054 | |
| 4055 | EXPECT_EQ(root->child_at(0), cross_site_popup_root->opener()); |
| 4056 | |
| 4057 | // Ensure the popup's window.opener points to the right subframe. Note that |
| 4058 | // we can't check the opener's location as above since it's cross-origin. |
| 4059 | bool success = false; |
| 4060 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4061 | cross_site_popup_root, |
alexmos | 4cf2aa3 | 2015-07-15 23:40:43 | [diff] [blame] | 4062 | "window.domAutomationController.send(" |
| 4063 | " window.opener === window.opener.top.frames[0]);", |
| 4064 | &success)); |
| 4065 | EXPECT_TRUE(success); |
| 4066 | } |
| 4067 | |
alexmos | 5b50b674 | 2016-03-17 20:38:05 | [diff] [blame] | 4068 | // Test that cross-process popups can't be navigated to disallowed URLs by |
| 4069 | // their opener. This ensures that proper URL validation is performed when |
| 4070 | // RenderFrameProxyHosts are navigated. See https://crbug.com/595339. |
| 4071 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigatePopupToIllegalURL) { |
| 4072 | GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 4073 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4074 | |
| 4075 | // Open a cross-site popup. |
| 4076 | GURL popup_url(embedded_test_server()->GetURL("b.com", "/title2.html")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4077 | Shell* popup = OpenPopup(shell(), popup_url, "foo"); |
alexmos | 5b50b674 | 2016-03-17 20:38:05 | [diff] [blame] | 4078 | EXPECT_TRUE(popup); |
| 4079 | EXPECT_NE(popup->web_contents()->GetSiteInstance(), |
| 4080 | shell()->web_contents()->GetSiteInstance()); |
| 4081 | |
| 4082 | // From the opener, navigate the popup to a file:/// URL. This should be |
| 4083 | // disallowed and result in an about:blank navigation. |
| 4084 | GURL file_url("file:///"); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4085 | NavigateNamedFrame(shell(), file_url, "foo"); |
alexmos | 5b50b674 | 2016-03-17 20:38:05 | [diff] [blame] | 4086 | EXPECT_TRUE(WaitForLoadStop(popup->web_contents())); |
| 4087 | EXPECT_EQ(GURL(url::kAboutBlankURL), |
| 4088 | popup->web_contents()->GetLastCommittedURL()); |
| 4089 | |
| 4090 | // Navigate popup back to a cross-site URL. |
| 4091 | EXPECT_TRUE(NavigateToURL(popup, popup_url)); |
| 4092 | EXPECT_NE(popup->web_contents()->GetSiteInstance(), |
| 4093 | shell()->web_contents()->GetSiteInstance()); |
| 4094 | |
| 4095 | // Now try the same test with a chrome:// URL. |
| 4096 | GURL chrome_url(std::string(kChromeUIScheme) + "://" + |
| 4097 | std::string(kChromeUIGpuHost)); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4098 | NavigateNamedFrame(shell(), chrome_url, "foo"); |
alexmos | 5b50b674 | 2016-03-17 20:38:05 | [diff] [blame] | 4099 | EXPECT_TRUE(WaitForLoadStop(popup->web_contents())); |
| 4100 | EXPECT_EQ(GURL(url::kAboutBlankURL), |
| 4101 | popup->web_contents()->GetLastCommittedURL()); |
| 4102 | } |
| 4103 | |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4104 | // Verify that named frames are discoverable from their opener's ancestors. |
| 4105 | // See https://crbug.com/511474. |
| 4106 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
alexmos | b0f73be | 2015-09-30 22:11:33 | [diff] [blame] | 4107 | DiscoverNamedFrameFromAncestorOfOpener) { |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4108 | GURL main_url( |
| 4109 | embedded_test_server()->GetURL("a.com", "/site_per_process_main.html")); |
| 4110 | NavigateToURL(shell(), main_url); |
| 4111 | |
| 4112 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4113 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4114 | |
| 4115 | // Navigate first child cross-site. |
| 4116 | GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 4117 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 4118 | |
| 4119 | // Open a popup named "foo" from the first child. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4120 | Shell* foo_shell = |
| 4121 | OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "foo"); |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4122 | EXPECT_TRUE(foo_shell); |
| 4123 | |
| 4124 | // Check that a proxy was created for the "foo" popup in a.com. |
| 4125 | FrameTreeNode* foo_root = |
| 4126 | static_cast<WebContentsImpl*>(foo_shell->web_contents()) |
| 4127 | ->GetFrameTree() |
| 4128 | ->root(); |
| 4129 | SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance(); |
| 4130 | RenderFrameProxyHost* popup_rfph_for_a = |
| 4131 | foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a); |
| 4132 | EXPECT_TRUE(popup_rfph_for_a); |
| 4133 | |
| 4134 | // Verify that the main frame can find the "foo" popup by name. If |
| 4135 | // window.open targets the correct frame, the "foo" popup's current URL |
| 4136 | // should be updated to |named_frame_url|. |
| 4137 | GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4138 | NavigateNamedFrame(shell(), named_frame_url, "foo"); |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4139 | EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents())); |
| 4140 | EXPECT_EQ(named_frame_url, foo_root->current_url()); |
| 4141 | |
| 4142 | // Navigate the popup cross-site and ensure it's still reachable via |
| 4143 | // window.open from the main frame. |
| 4144 | GURL d_url(embedded_test_server()->GetURL("d.com", "/title3.html")); |
| 4145 | NavigateToURL(foo_shell, d_url); |
| 4146 | EXPECT_EQ(d_url, foo_root->current_url()); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4147 | NavigateNamedFrame(shell(), named_frame_url, "foo"); |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4148 | EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents())); |
| 4149 | EXPECT_EQ(named_frame_url, foo_root->current_url()); |
| 4150 | } |
| 4151 | |
| 4152 | // Similar to DiscoverNamedFrameFromAncestorOfOpener, but check that if a |
| 4153 | // window is created without a name and acquires window.name later, it will |
| 4154 | // still be discoverable from its opener's ancestors. Also, instead of using |
| 4155 | // an opener's ancestor, this test uses a popup with same origin as that |
| 4156 | // ancestor. See https://crbug.com/511474. |
| 4157 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 4158 | DiscoverFrameAfterSettingWindowName) { |
| 4159 | GURL main_url( |
| 4160 | embedded_test_server()->GetURL("a.com", "/site_per_process_main.html")); |
| 4161 | NavigateToURL(shell(), main_url); |
| 4162 | |
| 4163 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4164 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4165 | |
| 4166 | // Open a same-site popup from the main frame. |
| 4167 | GURL a_com_url(embedded_test_server()->GetURL("a.com", "/title3.html")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4168 | Shell* a_com_shell = OpenPopup(root->child_at(0), a_com_url, ""); |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4169 | EXPECT_TRUE(a_com_shell); |
| 4170 | |
| 4171 | // Navigate first child on main frame cross-site. |
| 4172 | GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 4173 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 4174 | |
| 4175 | // Open an unnamed popup from the first child frame. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4176 | Shell* foo_shell = |
| 4177 | OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), ""); |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4178 | EXPECT_TRUE(foo_shell); |
| 4179 | |
| 4180 | // There should be no proxy created for the "foo" popup in a.com, since |
| 4181 | // there's no way for the two a.com frames to access it yet. |
| 4182 | FrameTreeNode* foo_root = |
| 4183 | static_cast<WebContentsImpl*>(foo_shell->web_contents()) |
| 4184 | ->GetFrameTree() |
| 4185 | ->root(); |
| 4186 | SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance(); |
| 4187 | EXPECT_FALSE( |
| 4188 | foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a)); |
| 4189 | |
| 4190 | // Set window.name in the popup's frame. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4191 | EXPECT_TRUE(ExecuteScript(foo_shell, "window.name = 'foo'")); |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4192 | |
| 4193 | // A proxy for the popup should now exist in a.com. |
| 4194 | EXPECT_TRUE( |
| 4195 | foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a)); |
| 4196 | |
| 4197 | // Verify that the a.com popup can now find the "foo" popup by name. |
| 4198 | GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4199 | NavigateNamedFrame(a_com_shell, named_frame_url, "foo"); |
alexmos | 646fec0 | 2015-07-25 00:11:49 | [diff] [blame] | 4200 | EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents())); |
| 4201 | EXPECT_EQ(named_frame_url, foo_root->current_url()); |
| 4202 | } |
| 4203 | |
alexmos | 9573300 | 2015-08-24 16:38:09 | [diff] [blame] | 4204 | // Check that frame opener updates work with subframes. Set up a window with a |
| 4205 | // popup and update openers for the popup's main frame and subframe to |
| 4206 | // subframes on first window, as follows: |
| 4207 | // |
| 4208 | // foo +---- bar |
| 4209 | // / \ | / \ . |
| 4210 | // bar foo <-+ bar foo |
| 4211 | // ^ | |
| 4212 | // +--------------------+ |
| 4213 | // |
| 4214 | // The sites are carefully set up so that both opener updates are cross-process |
| 4215 | // but still allowed by Blink's navigation checks. |
| 4216 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, UpdateSubframeOpener) { |
| 4217 | GURL main_url = embedded_test_server()->GetURL( |
| 4218 | "foo.com", "/frame_tree/page_with_two_frames.html"); |
| 4219 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4220 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4221 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 9573300 | 2015-08-24 16:38:09 | [diff] [blame] | 4222 | EXPECT_EQ(2U, root->child_count()); |
| 4223 | |
| 4224 | // From the top frame, open a popup and navigate it to a cross-site page with |
| 4225 | // two subframes. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4226 | Shell* popup_shell = OpenPopup(shell(), GURL(url::kAboutBlankURL), "popup"); |
alexmos | 9573300 | 2015-08-24 16:38:09 | [diff] [blame] | 4227 | EXPECT_TRUE(popup_shell); |
| 4228 | GURL popup_url(embedded_test_server()->GetURL( |
| 4229 | "bar.com", "/frame_tree/page_with_post_message_frames.html")); |
| 4230 | NavigateToURL(popup_shell, popup_url); |
| 4231 | |
| 4232 | FrameTreeNode* popup_root = |
| 4233 | static_cast<WebContentsImpl*>(popup_shell->web_contents()) |
| 4234 | ->GetFrameTree() |
| 4235 | ->root(); |
| 4236 | EXPECT_EQ(2U, popup_root->child_count()); |
| 4237 | |
| 4238 | // Popup's opener should point to main frame to start with. |
| 4239 | EXPECT_EQ(root, popup_root->opener()); |
| 4240 | |
| 4241 | // Update the popup's opener to the second subframe on the main page (which |
| 4242 | // is same-origin with the top frame, i.e., foo.com). |
| 4243 | bool success = false; |
| 4244 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4245 | root->child_at(1), |
alexmos | 9573300 | 2015-08-24 16:38:09 | [diff] [blame] | 4246 | "window.domAutomationController.send(!!window.open('','popup'));", |
| 4247 | &success)); |
| 4248 | EXPECT_TRUE(success); |
| 4249 | |
| 4250 | // Check that updated opener propagated to the browser process and the |
| 4251 | // popup's bar.com process. |
| 4252 | EXPECT_EQ(root->child_at(1), popup_root->opener()); |
| 4253 | |
| 4254 | success = false; |
| 4255 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4256 | popup_shell, |
alexmos | 9573300 | 2015-08-24 16:38:09 | [diff] [blame] | 4257 | "window.domAutomationController.send(" |
| 4258 | " window.opener === window.opener.parent.frames['frame2']);", |
| 4259 | &success)); |
| 4260 | EXPECT_TRUE(success); |
| 4261 | |
| 4262 | // Now update opener on the popup's second subframe (foo.com) to the main |
| 4263 | // page's first subframe (bar.com). |
| 4264 | success = false; |
| 4265 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4266 | root->child_at(0), |
alexmos | 9573300 | 2015-08-24 16:38:09 | [diff] [blame] | 4267 | "window.domAutomationController.send(!!window.open('','subframe2'));", |
| 4268 | &success)); |
| 4269 | EXPECT_TRUE(success); |
| 4270 | |
| 4271 | // Check that updated opener propagated to the browser process and the |
| 4272 | // foo.com process. |
| 4273 | EXPECT_EQ(root->child_at(0), popup_root->child_at(1)->opener()); |
| 4274 | |
| 4275 | success = false; |
| 4276 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4277 | popup_root->child_at(1), |
alexmos | 9573300 | 2015-08-24 16:38:09 | [diff] [blame] | 4278 | "window.domAutomationController.send(" |
| 4279 | " window.opener === window.opener.parent.frames['frame1']);", |
| 4280 | &success)); |
| 4281 | EXPECT_TRUE(success); |
| 4282 | } |
| 4283 | |
alexmos | 90325cf | 2015-09-02 17:18:39 | [diff] [blame] | 4284 | // Check that when a subframe navigates to a new SiteInstance, the new |
| 4285 | // SiteInstance will get a proxy for the opener of subframe's parent. I.e., |
| 4286 | // accessing parent.opener from the subframe should still work after a |
| 4287 | // cross-process navigation. |
| 4288 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 4289 | NavigatingSubframePreservesOpenerInParent) { |
| 4290 | GURL main_url = embedded_test_server()->GetURL("a.com", "/post_message.html"); |
| 4291 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4292 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4293 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 90325cf | 2015-09-02 17:18:39 | [diff] [blame] | 4294 | |
| 4295 | // Open a popup with a cross-site page that has a subframe. |
| 4296 | GURL popup_url(embedded_test_server()->GetURL( |
| 4297 | "b.com", "/cross_site_iframe_factory.html?b(b)")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4298 | Shell* popup_shell = OpenPopup(shell(), popup_url, "popup"); |
alexmos | 90325cf | 2015-09-02 17:18:39 | [diff] [blame] | 4299 | EXPECT_TRUE(popup_shell); |
| 4300 | FrameTreeNode* popup_root = |
| 4301 | static_cast<WebContentsImpl*>(popup_shell->web_contents()) |
| 4302 | ->GetFrameTree() |
| 4303 | ->root(); |
| 4304 | EXPECT_EQ(1U, popup_root->child_count()); |
| 4305 | |
| 4306 | // Check that the popup's opener is correct in the browser process. |
| 4307 | EXPECT_EQ(root, popup_root->opener()); |
| 4308 | |
| 4309 | // Navigate popup's subframe to another site. |
| 4310 | GURL frame_url(embedded_test_server()->GetURL("c.com", "/post_message.html")); |
| 4311 | NavigateFrameToURL(popup_root->child_at(0), frame_url); |
alexmos | 90325cf | 2015-09-02 17:18:39 | [diff] [blame] | 4312 | |
| 4313 | // Check that the new subframe process still sees correct opener for its |
| 4314 | // parent by sending a postMessage to subframe's parent.opener. |
| 4315 | bool success = false; |
| 4316 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4317 | popup_root->child_at(0), |
alexmos | 90325cf | 2015-09-02 17:18:39 | [diff] [blame] | 4318 | "window.domAutomationController.send(!!parent.opener);", &success)); |
| 4319 | EXPECT_TRUE(success); |
| 4320 | |
| 4321 | base::string16 expected_title = base::ASCIIToUTF16("msg"); |
| 4322 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| 4323 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4324 | popup_root->child_at(0), |
alexmos | 90325cf | 2015-09-02 17:18:39 | [diff] [blame] | 4325 | "window.domAutomationController.send(postToOpenerOfParent('msg','*'));", |
| 4326 | &success)); |
| 4327 | EXPECT_TRUE(success); |
| 4328 | EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 4329 | } |
| 4330 | |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4331 | // Check that if a subframe has an opener, that opener is preserved when the |
| 4332 | // subframe navigates cross-site. |
| 4333 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateSubframeWithOpener) { |
| 4334 | GURL main_url(embedded_test_server()->GetURL( |
| 4335 | "foo.com", "/frame_tree/page_with_two_frames.html")); |
| 4336 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4337 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4338 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4339 | EXPECT_EQ( |
| 4340 | " Site A ------------ proxies for B\n" |
| 4341 | " |--Site B ------- proxies for A\n" |
| 4342 | " +--Site A ------- proxies for B\n" |
| 4343 | "Where A = http://foo.com/\n" |
| 4344 | " B = http://bar.com/", |
| 4345 | DepictFrameTree(root)); |
| 4346 | |
| 4347 | // Update the first (cross-site) subframe's opener to root frame. |
| 4348 | bool success = false; |
| 4349 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4350 | root, "window.domAutomationController.send(!!window.open('','frame1'));", |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4351 | &success)); |
| 4352 | EXPECT_TRUE(success); |
| 4353 | |
| 4354 | // Check that updated opener propagated to the browser process and subframe's |
| 4355 | // process. |
| 4356 | EXPECT_EQ(root, root->child_at(0)->opener()); |
| 4357 | |
| 4358 | success = false; |
| 4359 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4360 | root->child_at(0), |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4361 | "window.domAutomationController.send(window.opener === window.parent);", |
| 4362 | &success)); |
| 4363 | EXPECT_TRUE(success); |
| 4364 | |
| 4365 | // Navigate the subframe with opener to another site. |
| 4366 | GURL frame_url(embedded_test_server()->GetURL("baz.com", "/title1.html")); |
| 4367 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 4368 | |
| 4369 | // Check that the subframe still sees correct opener in its new process. |
| 4370 | success = false; |
| 4371 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4372 | root->child_at(0), |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4373 | "window.domAutomationController.send(window.opener === window.parent);", |
| 4374 | &success)); |
| 4375 | EXPECT_TRUE(success); |
| 4376 | |
| 4377 | // Navigate second subframe to a new site. Check that the proxy that's |
| 4378 | // created for the first subframe in the new SiteInstance has correct opener. |
| 4379 | GURL frame2_url(embedded_test_server()->GetURL("qux.com", "/title1.html")); |
| 4380 | NavigateFrameToURL(root->child_at(1), frame2_url); |
| 4381 | |
| 4382 | success = false; |
| 4383 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4384 | root->child_at(1), |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4385 | "window.domAutomationController.send(" |
| 4386 | " parent.frames['frame1'].opener === parent);", |
| 4387 | &success)); |
| 4388 | EXPECT_TRUE(success); |
| 4389 | } |
| 4390 | |
| 4391 | // Check that if a subframe has an opener, that opener is preserved when a new |
| 4392 | // RenderFrameProxy is created for that subframe in another renderer process. |
| 4393 | // Similar to NavigateSubframeWithOpener, but this test verifies the subframe |
| 4394 | // opener plumbing for FrameMsg_NewFrameProxy, whereas |
| 4395 | // NavigateSubframeWithOpener targets FrameMsg_NewFrame. |
| 4396 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 4397 | NewRenderFrameProxyPreservesOpener) { |
| 4398 | GURL main_url( |
| 4399 | embedded_test_server()->GetURL("foo.com", "/post_message.html")); |
| 4400 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4401 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4402 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4403 | |
| 4404 | // Open a popup with a cross-site page that has two subframes. |
| 4405 | GURL popup_url(embedded_test_server()->GetURL( |
| 4406 | "bar.com", "/frame_tree/page_with_post_message_frames.html")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4407 | Shell* popup_shell = OpenPopup(shell(), popup_url, "popup"); |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4408 | EXPECT_TRUE(popup_shell); |
| 4409 | FrameTreeNode* popup_root = |
| 4410 | static_cast<WebContentsImpl*>(popup_shell->web_contents()) |
| 4411 | ->GetFrameTree() |
| 4412 | ->root(); |
| 4413 | EXPECT_EQ( |
| 4414 | " Site A ------------ proxies for B\n" |
| 4415 | " |--Site A ------- proxies for B\n" |
| 4416 | " +--Site B ------- proxies for A\n" |
| 4417 | "Where A = http://bar.com/\n" |
| 4418 | " B = http://foo.com/", |
| 4419 | DepictFrameTree(popup_root)); |
| 4420 | |
| 4421 | // Update the popup's second subframe's opener to root frame. This is |
| 4422 | // allowed because that subframe is in the same foo.com SiteInstance as the |
| 4423 | // root frame. |
| 4424 | bool success = false; |
| 4425 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4426 | root, |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4427 | "window.domAutomationController.send(!!window.open('','subframe2'));", |
| 4428 | &success)); |
| 4429 | EXPECT_TRUE(success); |
| 4430 | |
| 4431 | // Check that the opener update propagated to the browser process and bar.com |
| 4432 | // process. |
| 4433 | EXPECT_EQ(root, popup_root->child_at(1)->opener()); |
| 4434 | success = false; |
| 4435 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4436 | popup_root->child_at(0), |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4437 | "window.domAutomationController.send(" |
| 4438 | " parent.frames['subframe2'].opener && " |
| 4439 | " parent.frames['subframe2'].opener === parent.opener);", |
| 4440 | &success)); |
| 4441 | EXPECT_TRUE(success); |
| 4442 | |
| 4443 | // Navigate the popup's first subframe to another site. |
| 4444 | GURL frame_url( |
| 4445 | embedded_test_server()->GetURL("baz.com", "/post_message.html")); |
| 4446 | NavigateFrameToURL(popup_root->child_at(0), frame_url); |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4447 | |
| 4448 | // Check that the second subframe's opener is still correct in the first |
| 4449 | // subframe's new process. Verify it both in JS and with a postMessage. |
| 4450 | success = false; |
| 4451 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4452 | popup_root->child_at(0), |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4453 | "window.domAutomationController.send(" |
| 4454 | " parent.frames['subframe2'].opener && " |
| 4455 | " parent.frames['subframe2'].opener === parent.opener);", |
| 4456 | &success)); |
| 4457 | EXPECT_TRUE(success); |
| 4458 | |
| 4459 | base::string16 expected_title = base::ASCIIToUTF16("msg"); |
| 4460 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| 4461 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4462 | popup_root->child_at(0), |
alexmos | a181efc | 2015-09-03 00:39:04 | [diff] [blame] | 4463 | "window.domAutomationController.send(" |
| 4464 | " postToOpenerOfSibling('subframe2', 'msg', '*'));", |
| 4465 | &success)); |
| 4466 | EXPECT_TRUE(success); |
| 4467 | EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 4468 | } |
| 4469 | |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4470 | // Test for https://crbug.com/515302. Perform two navigations, A->B->A, and |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4471 | // drop the SwapOut ACK from the A->B navigation, so that the second B->A |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4472 | // navigation is initiated before the first page receives the SwapOut ACK. |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4473 | // Ensure that this doesn't crash and that the RVH(A) is not reused in that |
| 4474 | // case. |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4475 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4476 | RenderViewHostIsNotReusedAfterDelayedSwapOutACK) { |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4477 | GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 4478 | NavigateToURL(shell(), a_url); |
| 4479 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4480 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4481 | RenderFrameHostImpl* rfh = root->current_frame_host(); |
| 4482 | RenderViewHostImpl* rvh = rfh->render_view_host(); |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4483 | int rvh_routing_id = rvh->GetRoutingID(); |
| 4484 | SiteInstanceImpl* site_instance = rfh->GetSiteInstance(); |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4485 | RenderFrameDeletedObserver deleted_observer(rfh); |
| 4486 | |
| 4487 | // Install a BrowserMessageFilter to drop SwapOut ACK messages in A's |
| 4488 | // process. |
| 4489 | scoped_refptr<SwapoutACKMessageFilter> filter = new SwapoutACKMessageFilter(); |
| 4490 | rfh->GetProcess()->AddFilter(filter.get()); |
creis | ecf91fe4 | 2016-04-11 18:49:04 | [diff] [blame] | 4491 | rfh->DisableSwapOutTimerForTesting(); |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4492 | |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4493 | // Navigate to B. This must wait for DidCommitProvisionalLoad and not |
| 4494 | // DidStopLoading, so that the SwapOut timer doesn't call OnSwappedOut and |
| 4495 | // destroy |rfh| and |rvh| before they are checked in the test. |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4496 | GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 4497 | TestFrameNavigationObserver commit_observer(root); |
| 4498 | shell()->LoadURL(b_url); |
nasko | 8206fa1 | 2016-03-22 02:24:13 | [diff] [blame] | 4499 | commit_observer.WaitForCommit(); |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4500 | EXPECT_FALSE(deleted_observer.deleted()); |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4501 | |
| 4502 | // Since the SwapOut ACK for A->B is dropped, the first page's |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4503 | // RenderFrameHost should be pending deletion after the last navigation. |
nasko | 19736cc9f | 2016-04-08 22:38:45 | [diff] [blame] | 4504 | EXPECT_FALSE(rfh->is_active()); |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4505 | |
| 4506 | // Wait for process A to exit so we can reinitialize it cleanly for the next |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4507 | // navigation. Since process A doesn't have any active views, it will |
| 4508 | // initiate shutdown via ChildProcessHostMsg_ShutdownRequest. After process |
| 4509 | // A shuts down, the |rfh| and |rvh| should get destroyed via |
| 4510 | // OnRenderProcessGone. |
| 4511 | // |
| 4512 | // Not waiting for process shutdown here could lead to the |rvh| being |
| 4513 | // reused, now that there is no notion of pending deletion RenderViewHosts. |
| 4514 | // This would also be fine; however, the race in https://crbug.com/535246 |
| 4515 | // still needs to be addressed and tested in that case. |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4516 | RenderProcessHostWatcher process_exit_observer( |
| 4517 | rvh->GetProcess(), |
| 4518 | RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 4519 | process_exit_observer.Wait(); |
| 4520 | |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4521 | // Verify that the RVH and RFH for A were cleaned up. |
| 4522 | EXPECT_FALSE(root->frame_tree()->GetRenderViewHost(site_instance)); |
| 4523 | EXPECT_TRUE(deleted_observer.deleted()); |
| 4524 | |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4525 | // Start a navigation back to A and check that the RenderViewHost wasn't |
| 4526 | // reused. |
| 4527 | TestNavigationObserver navigation_observer(shell()->web_contents()); |
| 4528 | shell()->LoadURL(a_url); |
| 4529 | RenderViewHostImpl* pending_rvh = |
clamy | 5cba148 | 2016-02-26 08:58:14 | [diff] [blame] | 4530 | IsBrowserSideNavigationEnabled() |
| 4531 | ? root->render_manager()->speculative_frame_host()->render_view_host() |
| 4532 | : root->render_manager()->pending_render_view_host(); |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4533 | EXPECT_EQ(site_instance, pending_rvh->GetSiteInstance()); |
| 4534 | EXPECT_NE(rvh_routing_id, pending_rvh->GetRoutingID()); |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4535 | |
alexmos | b97d6bb6 | 2015-09-24 07:31:26 | [diff] [blame] | 4536 | // Make sure the last navigation finishes without crashing. |
| 4537 | navigation_observer.Wait(); |
| 4538 | } |
| 4539 | |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4540 | // Test for https://crbug.com/591478, where navigating to a cross-site page with |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4541 | // a subframe on the old site caused a crash while trying to reuse the old |
| 4542 | // RenderViewHost. |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4543 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4544 | ReusePendingDeleteRenderViewHostForSubframe) { |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4545 | GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 4546 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4547 | |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4548 | std::string script = |
| 4549 | "window.onunload = function() { " |
| 4550 | " var start = Date.now();" |
| 4551 | " while (Date.now() - start < 1000);" |
| 4552 | "}"; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4553 | EXPECT_TRUE(ExecuteScript(shell(), script)); |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4554 | |
creis | 05a1cb7 | 2016-03-31 21:26:24 | [diff] [blame] | 4555 | // Navigating cross-site with an iframe to the original site shouldn't crash. |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4556 | GURL second_url(embedded_test_server()->GetURL( |
| 4557 | "b.com", "/cross_site_iframe_factory.html?b(a)")); |
| 4558 | EXPECT_TRUE(NavigateToURL(shell(), second_url)); |
| 4559 | |
creis | 05a1cb7 | 2016-03-31 21:26:24 | [diff] [blame] | 4560 | // If the subframe is created while the main frame is pending deletion, then |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 4561 | // the RVH will be reused. The main frame should've been swapped with a |
| 4562 | // proxy despite being the last active frame in the progress (see |
| 4563 | // https://crbug.com/568836), and this proxy should also be reused by the new |
| 4564 | // page. |
| 4565 | // |
| 4566 | // TODO(creis, alexmos): Find a way to assert this that isn't flaky. For now, |
creis | 05a1cb7 | 2016-03-31 21:26:24 | [diff] [blame] | 4567 | // the test is just likely (not certain) to catch regressions by crashing. |
creis | e73d58ef | 2016-03-29 22:12:15 | [diff] [blame] | 4568 | } |
| 4569 | |
alexmos | ca2c6ba | 2015-10-01 21:52:25 | [diff] [blame] | 4570 | // Check that when a cross-process frame acquires focus, the old focused frame |
| 4571 | // loses focus and fires blur events. Starting on a page with a cross-site |
| 4572 | // subframe, simulate mouse clicks to switch focus from root frame to subframe |
| 4573 | // and then back to root frame. |
| 4574 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 4575 | CrossProcessFocusChangeFiresBlurEvents) { |
| 4576 | GURL main_url( |
| 4577 | embedded_test_server()->GetURL("a.com", "/page_with_input_field.html")); |
| 4578 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4579 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4580 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | ca2c6ba | 2015-10-01 21:52:25 | [diff] [blame] | 4581 | |
| 4582 | EXPECT_EQ( |
| 4583 | " Site A ------------ proxies for B\n" |
| 4584 | " +--Site B ------- proxies for A\n" |
| 4585 | "Where A = http://a.com/\n" |
| 4586 | " B = http://b.com/", |
| 4587 | DepictFrameTree(root)); |
| 4588 | |
| 4589 | // Focus the main frame's text field. The return value "input-focus" |
| 4590 | // indicates that the focus event was fired correctly. |
| 4591 | std::string result; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4592 | EXPECT_TRUE( |
| 4593 | ExecuteScriptAndExtractString(shell(), "focusInputField()", &result)); |
alexmos | ca2c6ba | 2015-10-01 21:52:25 | [diff] [blame] | 4594 | EXPECT_EQ(result, "input-focus"); |
| 4595 | |
| 4596 | // The main frame should be focused. |
| 4597 | EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame()); |
| 4598 | |
| 4599 | DOMMessageQueue msg_queue; |
| 4600 | |
| 4601 | // Click on the cross-process subframe. |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 4602 | SimulateMouseClick( |
| 4603 | root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), 1, 1); |
alexmos | ca2c6ba | 2015-10-01 21:52:25 | [diff] [blame] | 4604 | |
| 4605 | // Check that the main frame lost focus and fired blur event on the input |
| 4606 | // text field. |
| 4607 | std::string status; |
| 4608 | while (msg_queue.WaitForMessage(&status)) { |
| 4609 | if (status == "\"input-blur\"") |
| 4610 | break; |
| 4611 | } |
| 4612 | |
| 4613 | // The subframe should now be focused. |
| 4614 | EXPECT_EQ(root->child_at(0), root->frame_tree()->GetFocusedFrame()); |
| 4615 | |
| 4616 | // Click on the root frame. |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 4617 | SimulateMouseClick( |
| 4618 | shell()->web_contents()->GetRenderViewHost()->GetWidget(), 1, 1); |
alexmos | ca2c6ba | 2015-10-01 21:52:25 | [diff] [blame] | 4619 | |
| 4620 | // Check that the subframe lost focus and fired blur event on its |
| 4621 | // document's body. |
| 4622 | while (msg_queue.WaitForMessage(&status)) { |
| 4623 | if (status == "\"document-blur\"") |
| 4624 | break; |
| 4625 | } |
| 4626 | |
| 4627 | // The root frame should be focused again. |
| 4628 | EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame()); |
| 4629 | } |
| 4630 | |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 4631 | // Check that when a cross-process subframe is focused, its parent's |
| 4632 | // document.activeElement correctly returns the corresponding <iframe> element. |
| 4633 | // The test sets up an A-embed-B-embed-C page and shifts focus A->B->A->C, |
| 4634 | // checking document.activeElement after each change. |
| 4635 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DocumentActiveElement) { |
| 4636 | GURL main_url(embedded_test_server()->GetURL( |
| 4637 | "a.com", "/cross_site_iframe_factory.html?a(b(c))")); |
| 4638 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4639 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4640 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 4641 | |
| 4642 | EXPECT_EQ( |
| 4643 | " Site A ------------ proxies for B C\n" |
| 4644 | " +--Site B ------- proxies for A C\n" |
| 4645 | " +--Site C -- proxies for A B\n" |
| 4646 | "Where A = http://a.com/\n" |
| 4647 | " B = http://b.com/\n" |
| 4648 | " C = http://c.com/", |
| 4649 | DepictFrameTree(root)); |
| 4650 | |
| 4651 | FrameTreeNode* child = root->child_at(0); |
| 4652 | FrameTreeNode* grandchild = root->child_at(0)->child_at(0); |
| 4653 | |
| 4654 | // The main frame should be focused to start with. |
| 4655 | EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame()); |
| 4656 | |
alexmos | 21acae5 | 2015-11-07 01:04:43 | [diff] [blame] | 4657 | // Focus the b.com frame. |
| 4658 | FocusFrame(child); |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 4659 | EXPECT_EQ(child, root->frame_tree()->GetFocusedFrame()); |
| 4660 | |
alexmos | 21acae5 | 2015-11-07 01:04:43 | [diff] [blame] | 4661 | // Helper function to check a property of document.activeElement in the |
| 4662 | // specified frame. |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 4663 | auto verify_active_element_property = [](RenderFrameHost* rfh, |
| 4664 | const std::string& property, |
| 4665 | const std::string& expected_value) { |
| 4666 | std::string script = base::StringPrintf( |
| 4667 | "window.domAutomationController.send(document.activeElement.%s);", |
| 4668 | property.c_str()); |
| 4669 | std::string result; |
| 4670 | EXPECT_TRUE(ExecuteScriptAndExtractString(rfh, script, &result)); |
| 4671 | EXPECT_EQ(expected_value, base::ToLowerASCII(result)); |
| 4672 | }; |
| 4673 | |
alexmos | 21acae5 | 2015-11-07 01:04:43 | [diff] [blame] | 4674 | // Verify that document.activeElement on main frame points to the <iframe> |
| 4675 | // element for the b.com frame. |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 4676 | RenderFrameHost* root_rfh = root->current_frame_host(); |
| 4677 | verify_active_element_property(root_rfh, "tagName", "iframe"); |
| 4678 | verify_active_element_property(root_rfh, "src", child->current_url().spec()); |
| 4679 | |
alexmos | 21acae5 | 2015-11-07 01:04:43 | [diff] [blame] | 4680 | // Focus the a.com main frame again. |
| 4681 | FocusFrame(root); |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 4682 | EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame()); |
| 4683 | |
| 4684 | // Main frame document's <body> should now be the active element. |
| 4685 | verify_active_element_property(root_rfh, "tagName", "body"); |
| 4686 | |
alexmos | 21acae5 | 2015-11-07 01:04:43 | [diff] [blame] | 4687 | // Now shift focus from main frame to c.com frame. |
| 4688 | FocusFrame(grandchild); |
alexmos | b1dc216 | 2015-11-05 00:59:20 | [diff] [blame] | 4689 | |
| 4690 | // Check document.activeElement in main frame. It should still point to |
| 4691 | // <iframe> for the b.com frame, since Blink computes the focused iframe |
| 4692 | // element by walking the parent chain of the focused frame until it hits the |
| 4693 | // current frame. This logic should still work with remote frames. |
| 4694 | verify_active_element_property(root_rfh, "tagName", "iframe"); |
| 4695 | verify_active_element_property(root_rfh, "src", child->current_url().spec()); |
| 4696 | |
| 4697 | // Check document.activeElement in b.com subframe. It should point to |
| 4698 | // <iframe> for the c.com frame. This is a tricky case where B needs to find |
| 4699 | // out that focus changed from one remote frame to another (A to C). |
| 4700 | RenderFrameHost* child_rfh = child->current_frame_host(); |
| 4701 | verify_active_element_property(child_rfh, "tagName", "iframe"); |
| 4702 | verify_active_element_property(child_rfh, "src", |
| 4703 | grandchild->current_url().spec()); |
| 4704 | } |
| 4705 | |
alexmos | 5357efb | 2015-12-16 21:44:00 | [diff] [blame] | 4706 | // Check that window.focus works for cross-process subframes. |
| 4707 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframeWindowFocus) { |
| 4708 | GURL main_url(embedded_test_server()->GetURL( |
| 4709 | "a.com", "/cross_site_iframe_factory.html?a(b,c)")); |
| 4710 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4711 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4712 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 5357efb | 2015-12-16 21:44:00 | [diff] [blame] | 4713 | |
| 4714 | EXPECT_EQ( |
| 4715 | " Site A ------------ proxies for B C\n" |
| 4716 | " |--Site B ------- proxies for A C\n" |
| 4717 | " +--Site C ------- proxies for A B\n" |
| 4718 | "Where A = http://a.com/\n" |
| 4719 | " B = http://b.com/\n" |
| 4720 | " C = http://c.com/", |
| 4721 | DepictFrameTree(root)); |
| 4722 | |
| 4723 | FrameTreeNode* child1 = root->child_at(0); |
| 4724 | FrameTreeNode* child2 = root->child_at(1); |
| 4725 | |
| 4726 | // The main frame should be focused to start with. |
| 4727 | EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame()); |
| 4728 | |
| 4729 | DOMMessageQueue msg_queue; |
| 4730 | |
| 4731 | // Register focus and blur events that will send messages when each frame's |
| 4732 | // window gets or loses focus. |
| 4733 | const char kSetupFocusEvents[] = |
| 4734 | "window.addEventListener('focus', function() {" |
| 4735 | " domAutomationController.setAutomationId(0);" |
| 4736 | " domAutomationController.send('%s-got-focus');" |
| 4737 | "});" |
| 4738 | "window.addEventListener('blur', function() {" |
| 4739 | " domAutomationController.setAutomationId(0);" |
| 4740 | " domAutomationController.send('%s-lost-focus');" |
| 4741 | "});"; |
| 4742 | std::string script = base::StringPrintf(kSetupFocusEvents, "main", "main"); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4743 | EXPECT_TRUE(ExecuteScript(shell(), script)); |
alexmos | 5357efb | 2015-12-16 21:44:00 | [diff] [blame] | 4744 | script = base::StringPrintf(kSetupFocusEvents, "child1", "child1"); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4745 | EXPECT_TRUE(ExecuteScript(child1, script)); |
alexmos | 5357efb | 2015-12-16 21:44:00 | [diff] [blame] | 4746 | script = base::StringPrintf(kSetupFocusEvents, "child2", "child2"); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4747 | EXPECT_TRUE(ExecuteScript(child2, script)); |
alexmos | 5357efb | 2015-12-16 21:44:00 | [diff] [blame] | 4748 | |
| 4749 | // Execute window.focus on the B subframe from the A main frame. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4750 | EXPECT_TRUE(ExecuteScript(root, "frames[0].focus()")); |
alexmos | 5357efb | 2015-12-16 21:44:00 | [diff] [blame] | 4751 | |
| 4752 | // Helper to wait for two specified messages to arrive on the specified |
| 4753 | // DOMMessageQueue, assuming that the two messages can arrive in any order. |
| 4754 | auto wait_for_two_messages = [](DOMMessageQueue* msg_queue, |
| 4755 | const std::string& msg1, |
| 4756 | const std::string& msg2) { |
| 4757 | bool msg1_received = false; |
| 4758 | bool msg2_received = false; |
| 4759 | std::string status; |
| 4760 | while (msg_queue->WaitForMessage(&status)) { |
| 4761 | if (status == msg1) |
| 4762 | msg1_received = true; |
| 4763 | if (status == msg2) |
| 4764 | msg2_received = true; |
| 4765 | if (msg1_received && msg2_received) |
| 4766 | break; |
| 4767 | } |
| 4768 | }; |
| 4769 | |
| 4770 | // Process A should fire a blur event, and process B should fire a focus |
| 4771 | // event. Wait for both events. |
| 4772 | wait_for_two_messages(&msg_queue, "\"main-lost-focus\"", |
| 4773 | "\"child1-got-focus\""); |
| 4774 | |
| 4775 | // The B subframe should now be focused in the browser process. |
| 4776 | EXPECT_EQ(child1, root->frame_tree()->GetFocusedFrame()); |
| 4777 | |
| 4778 | // Now, execute window.focus on the C subframe from A main frame. This |
| 4779 | // checks that we can shift focus from one remote frame to another. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4780 | EXPECT_TRUE(ExecuteScript(root, "frames[1].focus()")); |
alexmos | 5357efb | 2015-12-16 21:44:00 | [diff] [blame] | 4781 | |
| 4782 | // Wait for the two subframes (B and C) to fire blur and focus events. |
| 4783 | wait_for_two_messages(&msg_queue, "\"child1-lost-focus\"", |
| 4784 | "\"child2-got-focus\""); |
| 4785 | |
| 4786 | // The C subframe should now be focused. |
| 4787 | EXPECT_EQ(child2, root->frame_tree()->GetFocusedFrame()); |
| 4788 | |
| 4789 | // window.focus the main frame from the C subframe. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4790 | EXPECT_TRUE(ExecuteScript(child2, "parent.focus()")); |
alexmos | 5357efb | 2015-12-16 21:44:00 | [diff] [blame] | 4791 | |
| 4792 | // Wait for the C subframe to blur and main frame to focus. |
| 4793 | wait_for_two_messages(&msg_queue, "\"child2-lost-focus\"", |
| 4794 | "\"main-got-focus\""); |
| 4795 | |
| 4796 | // The main frame should now be focused. |
| 4797 | EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame()); |
| 4798 | } |
| 4799 | |
kenrb | 77db507 | 2015-10-15 19:21:25 | [diff] [blame] | 4800 | // There are no cursors on Android. |
| 4801 | #if !defined(OS_ANDROID) |
| 4802 | class CursorMessageFilter : public content::BrowserMessageFilter { |
| 4803 | public: |
| 4804 | CursorMessageFilter() |
| 4805 | : content::BrowserMessageFilter(ViewMsgStart), |
| 4806 | message_loop_runner_(new content::MessageLoopRunner), |
| 4807 | last_set_cursor_routing_id_(MSG_ROUTING_NONE) {} |
| 4808 | |
| 4809 | bool OnMessageReceived(const IPC::Message& message) override { |
| 4810 | if (message.type() == ViewHostMsg_SetCursor::ID) { |
| 4811 | content::BrowserThread::PostTask( |
| 4812 | content::BrowserThread::UI, FROM_HERE, |
| 4813 | base::Bind(&CursorMessageFilter::OnSetCursor, this, |
| 4814 | message.routing_id())); |
| 4815 | } |
| 4816 | return false; |
| 4817 | } |
| 4818 | |
| 4819 | void OnSetCursor(int routing_id) { |
| 4820 | last_set_cursor_routing_id_ = routing_id; |
| 4821 | message_loop_runner_->Quit(); |
| 4822 | } |
| 4823 | |
| 4824 | int last_set_cursor_routing_id() const { return last_set_cursor_routing_id_; } |
| 4825 | |
| 4826 | void Wait() { |
| 4827 | last_set_cursor_routing_id_ = MSG_ROUTING_NONE; |
| 4828 | message_loop_runner_->Run(); |
| 4829 | } |
| 4830 | |
| 4831 | private: |
| 4832 | ~CursorMessageFilter() override {} |
| 4833 | |
| 4834 | scoped_refptr<content::MessageLoopRunner> message_loop_runner_; |
| 4835 | int last_set_cursor_routing_id_; |
| 4836 | |
| 4837 | DISALLOW_COPY_AND_ASSIGN(CursorMessageFilter); |
| 4838 | }; |
| 4839 | |
| 4840 | // Verify that we receive a mouse cursor update message when we mouse over |
| 4841 | // a text field contained in an out-of-process iframe. |
reillyg | 96f9f9e | 2015-10-20 00:16:43 | [diff] [blame] | 4842 | // Fails under TSan. http://crbug.com/545237 |
kenrb | 77db507 | 2015-10-15 19:21:25 | [diff] [blame] | 4843 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
reillyg | 96f9f9e | 2015-10-20 00:16:43 | [diff] [blame] | 4844 | DISABLED_CursorUpdateFromReceivedFromCrossSiteIframe) { |
kenrb | 77db507 | 2015-10-15 19:21:25 | [diff] [blame] | 4845 | GURL main_url(embedded_test_server()->GetURL( |
| 4846 | "/frame_tree/page_with_positioned_frame.html")); |
| 4847 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4848 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4849 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
kenrb | 77db507 | 2015-10-15 19:21:25 | [diff] [blame] | 4850 | |
| 4851 | FrameTreeNode* child_node = root->child_at(0); |
| 4852 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 4853 | child_node->current_frame_host()->GetSiteInstance()); |
| 4854 | |
| 4855 | scoped_refptr<CursorMessageFilter> filter = new CursorMessageFilter(); |
| 4856 | child_node->current_frame_host()->GetProcess()->AddFilter(filter.get()); |
| 4857 | |
| 4858 | // Send a MouseMove to the subframe. The frame contains text, and moving the |
| 4859 | // mouse over it should cause the renderer to send a mouse cursor update. |
| 4860 | blink::WebMouseEvent mouse_event; |
| 4861 | mouse_event.type = blink::WebInputEvent::MouseMove; |
| 4862 | mouse_event.x = 60; |
| 4863 | mouse_event.y = 60; |
| 4864 | RenderWidgetHost* rwh_child = |
| 4865 | root->child_at(0)->current_frame_host()->GetRenderWidgetHost(); |
| 4866 | RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>( |
| 4867 | root->current_frame_host()->GetRenderWidgetHost()->GetView()); |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4868 | web_contents()->GetInputEventRouter()->RouteMouseEvent(root_view, |
| 4869 | &mouse_event); |
kenrb | 77db507 | 2015-10-15 19:21:25 | [diff] [blame] | 4870 | |
| 4871 | // CursorMessageFilter::Wait() implicitly tests whether we receive a |
| 4872 | // ViewHostMsg_SetCursor message from the renderer process, because it does |
| 4873 | // does not return otherwise. |
| 4874 | filter->Wait(); |
| 4875 | EXPECT_EQ(filter->last_set_cursor_routing_id(), rwh_child->GetRoutingID()); |
| 4876 | } |
| 4877 | #endif |
| 4878 | |
lfg | 3faeb65 | 2015-10-21 16:34:38 | [diff] [blame] | 4879 | // Tests that we are using the correct RenderFrameProxy when navigating an |
| 4880 | // opener window. |
| 4881 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenerSetLocation) { |
| 4882 | // Navigate the main window. |
| 4883 | GURL main_url(embedded_test_server()->GetURL("/title1.html")); |
| 4884 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4885 | EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), main_url); |
| 4886 | |
| 4887 | // Load cross-site page into a new window. |
| 4888 | GURL cross_url = embedded_test_server()->GetURL("foo.com", "/title1.html"); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4889 | Shell* popup = OpenPopup(shell(), cross_url, ""); |
lfg | 3faeb65 | 2015-10-21 16:34:38 | [diff] [blame] | 4890 | EXPECT_EQ(popup->web_contents()->GetLastCommittedURL(), cross_url); |
| 4891 | |
| 4892 | // Use new window to navigate main window. |
| 4893 | std::string script = |
| 4894 | "window.opener.location.href = '" + cross_url.spec() + "'"; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4895 | EXPECT_TRUE(ExecuteScript(popup, script)); |
lfg | 3faeb65 | 2015-10-21 16:34:38 | [diff] [blame] | 4896 | EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| 4897 | EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), cross_url); |
| 4898 | } |
| 4899 | |
wjmaclean | fab616a | 2016-03-02 18:40:39 | [diff] [blame] | 4900 | // Ensure that a cross-process subframe with a touch-handler can receive touch |
| 4901 | // events. |
| 4902 | #if defined(USE_AURA) |
| 4903 | // Browser process hit testing is not implemented on Android, and this test |
| 4904 | // requires Aura for RenderWidgetHostViewAura::OnTouchEvent(). |
| 4905 | // https://crbug.com/491334 |
| 4906 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 4907 | SubframeTouchEventRouting) { |
| 4908 | GURL main_url(embedded_test_server()->GetURL( |
| 4909 | "/frame_tree/page_with_positioned_nested_frames.html")); |
| 4910 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4911 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4912 | WebContentsImpl* contents = web_contents(); |
| 4913 | FrameTreeNode* root = contents->GetFrameTree()->root(); |
wjmaclean | fab616a | 2016-03-02 18:40:39 | [diff] [blame] | 4914 | ASSERT_EQ(1U, root->child_count()); |
| 4915 | |
| 4916 | GURL frame_url( |
| 4917 | embedded_test_server()->GetURL("b.com", "/page_with_touch_handler.html")); |
| 4918 | NavigateFrameToURL(root->child_at(0), frame_url); |
wjmaclean | fab616a | 2016-03-02 18:40:39 | [diff] [blame] | 4919 | |
| 4920 | // Synchronize with the child and parent renderers to guarantee that the |
| 4921 | // surface information required for event hit testing is ready. |
| 4922 | RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>( |
| 4923 | root->child_at(0)->current_frame_host()->GetView()); |
| 4924 | SurfaceHitTestReadyNotifier notifier( |
| 4925 | static_cast<RenderWidgetHostViewChildFrame*>(child_rwhv)); |
| 4926 | notifier.WaitForSurfaceReady(); |
| 4927 | |
| 4928 | // Simulate touch event to sub-frame. |
| 4929 | gfx::Point child_center(150, 150); |
| 4930 | auto rwhv = static_cast<RenderWidgetHostViewAura*>( |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4931 | contents->GetRenderWidgetHostView()); |
wjmaclean | fab616a | 2016-03-02 18:40:39 | [diff] [blame] | 4932 | ui::TouchEvent touch_event(ui::ET_TOUCH_PRESSED, child_center, 0, 0, |
| 4933 | ui::EventTimeForNow(), 30.f, 30.f, 0.f, 0.f); |
| 4934 | rwhv->OnTouchEvent(&touch_event); |
| 4935 | |
| 4936 | // Verify touch handler in subframe was invoked |
| 4937 | std::string result; |
| 4938 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 4939 | root->child_at(0), |
wjmaclean | fab616a | 2016-03-02 18:40:39 | [diff] [blame] | 4940 | "window.domAutomationController.send(getLastTouchEvent());", &result)); |
| 4941 | EXPECT_EQ("touchstart", result); |
| 4942 | } |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 4943 | |
| 4944 | namespace { |
| 4945 | |
| 4946 | // Declared here to be close to the SubframeGestureEventRouting test. |
| 4947 | void OnSyntheticGestureCompleted(scoped_refptr<MessageLoopRunner> runner, |
| 4948 | SyntheticGesture::Result result) { |
| 4949 | EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result); |
| 4950 | runner->Quit(); |
| 4951 | } |
| 4952 | |
| 4953 | } // namespace anonymous |
| 4954 | |
reillyg | a87c5bb | 2016-03-11 19:25:58 | [diff] [blame] | 4955 | // Flaky under TSan. https://crbug.com/592320 |
| 4956 | #if defined(THREAD_SANITIZER) |
| 4957 | #define MAYBE_SubframeGestureEventRouting DISABLED_SubframeGestureEventRouting |
| 4958 | #else |
| 4959 | #define MAYBE_SubframeGestureEventRouting SubframeGestureEventRouting |
| 4960 | #endif |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 4961 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
reillyg | a87c5bb | 2016-03-11 19:25:58 | [diff] [blame] | 4962 | MAYBE_SubframeGestureEventRouting) { |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 4963 | GURL main_url(embedded_test_server()->GetURL( |
| 4964 | "/frame_tree/page_with_positioned_nested_frames.html")); |
| 4965 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 4966 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 4967 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 4968 | ASSERT_EQ(1U, root->child_count()); |
| 4969 | |
| 4970 | GURL frame_url( |
| 4971 | embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html")); |
| 4972 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 4973 | auto child_frame_host = root->child_at(0)->current_frame_host(); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 4974 | |
| 4975 | // Synchronize with the child and parent renderers to guarantee that the |
| 4976 | // surface information required for event hit testing is ready. |
| 4977 | RenderWidgetHostViewBase* child_rwhv = static_cast<RenderWidgetHostViewBase*>( |
| 4978 | child_frame_host->GetView()); |
| 4979 | SurfaceHitTestReadyNotifier notifier( |
| 4980 | static_cast<RenderWidgetHostViewChildFrame*>(child_rwhv)); |
| 4981 | notifier.WaitForSurfaceReady(); |
| 4982 | |
| 4983 | // There have been no GestureTaps sent yet. |
| 4984 | { |
| 4985 | std::string result; |
| 4986 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 4987 | child_frame_host, |
| 4988 | "window.domAutomationController.send(getClickStatus());", &result)); |
| 4989 | EXPECT_EQ("0 clicks received", result); |
| 4990 | } |
| 4991 | |
| 4992 | // Simulate touch sequence to send GestureTap to sub-frame. |
| 4993 | SyntheticTapGestureParams params; |
| 4994 | params.gesture_source_type = SyntheticGestureParams::TOUCH_INPUT; |
| 4995 | gfx::Point center(150, 150); |
| 4996 | params.position = gfx::PointF(center.x(), center.y()); |
| 4997 | params.duration_ms = 100; |
dcheng | 5971627 | 2016-04-09 05:19:08 | [diff] [blame] | 4998 | std::unique_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params)); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 4999 | |
| 5000 | scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner(); |
| 5001 | |
| 5002 | RenderWidgetHostImpl* render_widget_host = |
| 5003 | root->current_frame_host()->GetRenderWidgetHost(); |
| 5004 | // TODO(wjmaclean): Convert the call to base::Bind() to a lambda someday. |
| 5005 | render_widget_host->QueueSyntheticGesture( |
| 5006 | std::move(gesture), base::Bind(OnSyntheticGestureCompleted, runner)); |
| 5007 | |
| 5008 | // We need to run the message loop while we wait for the synthetic gesture |
| 5009 | // to be processed; the callback registered above will get us out of the |
| 5010 | // message loop when that happens. |
| 5011 | runner->Run(); |
| 5012 | runner = nullptr; |
| 5013 | |
| 5014 | // Verify click handler in subframe was invoked |
| 5015 | { |
| 5016 | std::string result; |
| 5017 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 5018 | child_frame_host, |
| 5019 | "window.domAutomationController.send(getClickStatus());", &result)); |
| 5020 | EXPECT_EQ("1 click received", result); |
| 5021 | } |
| 5022 | } |
| 5023 | |
| 5024 | namespace { |
| 5025 | |
| 5026 | // Defined here to be close to |
| 5027 | // SitePerProcessBrowserTest.InputEventRouterGestureTargetQueueTest. |
| 5028 | void SendTouchTapWithExpectedTarget( |
| 5029 | RenderWidgetHostViewBase* root_view, |
| 5030 | const gfx::Point& touch_point, |
| 5031 | RenderWidgetHostViewBase*& router_touch_target, |
| 5032 | const RenderWidgetHostViewBase* expected_target) { |
| 5033 | auto root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view); |
| 5034 | ui::TouchEvent touch_event_pressed(ui::ET_TOUCH_PRESSED, touch_point, 0, |
| 5035 | 0, ui::EventTimeForNow(), 30.f, 30.f, 0.f, |
| 5036 | 0.f); |
| 5037 | root_view_aura->OnTouchEvent(&touch_event_pressed); |
| 5038 | EXPECT_EQ(expected_target, router_touch_target); |
| 5039 | ui::TouchEvent touch_event_released(ui::ET_TOUCH_RELEASED, touch_point, |
| 5040 | 0, 0, ui::EventTimeForNow(), 30.f, 30.f, |
| 5041 | 0.f, 0.f); |
| 5042 | root_view_aura->OnTouchEvent(&touch_event_released); |
| 5043 | EXPECT_EQ(nullptr, router_touch_target); |
| 5044 | } |
| 5045 | |
| 5046 | void SendGestureTapSequenceWithExpectedTarget( |
| 5047 | RenderWidgetHostViewBase* root_view, |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5048 | const gfx::Point& gesture_point, |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5049 | RenderWidgetHostViewBase*& router_gesture_target, |
| 5050 | const RenderWidgetHostViewBase* old_expected_target, |
| 5051 | const RenderWidgetHostViewBase* expected_target) { |
| 5052 | auto root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view); |
| 5053 | |
mohsen | 7d45a48 | 2016-05-24 21:03:44 | [diff] [blame] | 5054 | ui::GestureEventDetails gesture_begin_details(ui::ET_GESTURE_BEGIN); |
| 5055 | gesture_begin_details.set_device_type( |
| 5056 | ui::GestureDeviceType::DEVICE_TOUCHSCREEN); |
| 5057 | ui::GestureEvent gesture_begin_event(gesture_point.x(), gesture_point.y(), 0, |
| 5058 | ui::EventTimeForNow(), |
| 5059 | gesture_begin_details); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5060 | root_view_aura->OnGestureEvent(&gesture_begin_event); |
| 5061 | // We expect to still have the old gesture target in place for the |
| 5062 | // GestureFlingCancel that will be inserted before GestureTapDown. |
| 5063 | // Note: the GestureFlingCancel is inserted by RenderWidgetHostViewAura:: |
| 5064 | // OnGestureEvent() when it sees ui::ET_GESTURE_TAP_DOWN, so we don't |
| 5065 | // explicitly add it here. |
| 5066 | EXPECT_EQ(old_expected_target, router_gesture_target); |
| 5067 | |
mohsen | 7d45a48 | 2016-05-24 21:03:44 | [diff] [blame] | 5068 | ui::GestureEventDetails gesture_tap_down_details(ui::ET_GESTURE_TAP_DOWN); |
| 5069 | gesture_tap_down_details.set_device_type( |
| 5070 | ui::GestureDeviceType::DEVICE_TOUCHSCREEN); |
| 5071 | ui::GestureEvent gesture_tap_down_event(gesture_point.x(), gesture_point.y(), |
| 5072 | 0, ui::EventTimeForNow(), |
| 5073 | gesture_tap_down_details); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5074 | root_view_aura->OnGestureEvent(&gesture_tap_down_event); |
| 5075 | EXPECT_EQ(expected_target, router_gesture_target); |
| 5076 | |
mohsen | 7d45a48 | 2016-05-24 21:03:44 | [diff] [blame] | 5077 | ui::GestureEventDetails gesture_show_press_details(ui::ET_GESTURE_SHOW_PRESS); |
| 5078 | gesture_show_press_details.set_device_type( |
| 5079 | ui::GestureDeviceType::DEVICE_TOUCHSCREEN); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5080 | ui::GestureEvent gesture_show_press_event( |
| 5081 | gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(), |
mohsen | 7d45a48 | 2016-05-24 21:03:44 | [diff] [blame] | 5082 | gesture_show_press_details); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5083 | root_view_aura->OnGestureEvent(&gesture_show_press_event); |
| 5084 | EXPECT_EQ(expected_target, router_gesture_target); |
| 5085 | |
| 5086 | ui::GestureEventDetails gesture_tap_details(ui::ET_GESTURE_TAP); |
mohsen | 7d45a48 | 2016-05-24 21:03:44 | [diff] [blame] | 5087 | gesture_tap_details.set_device_type( |
| 5088 | ui::GestureDeviceType::DEVICE_TOUCHSCREEN); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5089 | gesture_tap_details.set_tap_count(1); |
mohsen | 7d45a48 | 2016-05-24 21:03:44 | [diff] [blame] | 5090 | ui::GestureEvent gesture_tap_event(gesture_point.x(), gesture_point.y(), 0, |
| 5091 | ui::EventTimeForNow(), |
| 5092 | gesture_tap_details); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5093 | root_view_aura->OnGestureEvent(&gesture_tap_event); |
| 5094 | EXPECT_EQ(expected_target, router_gesture_target); |
| 5095 | |
mohsen | 7d45a48 | 2016-05-24 21:03:44 | [diff] [blame] | 5096 | ui::GestureEventDetails gesture_end_details(ui::ET_GESTURE_END); |
| 5097 | gesture_end_details.set_device_type( |
| 5098 | ui::GestureDeviceType::DEVICE_TOUCHSCREEN); |
| 5099 | ui::GestureEvent gesture_end_event(gesture_point.x(), gesture_point.y(), 0, |
| 5100 | ui::EventTimeForNow(), |
| 5101 | gesture_end_details); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5102 | root_view_aura->OnGestureEvent(&gesture_end_event); |
| 5103 | EXPECT_EQ(expected_target, router_gesture_target); |
| 5104 | } |
| 5105 | |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5106 | void SendTouchpadPinchSequenceWithExpectedTarget( |
| 5107 | RenderWidgetHostViewBase* root_view, |
| 5108 | const gfx::Point& gesture_point, |
| 5109 | RenderWidgetHostViewBase*& router_touchpad_gesture_target, |
| 5110 | RenderWidgetHostViewBase* expected_target) { |
| 5111 | auto root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view); |
| 5112 | |
| 5113 | ui::GestureEventDetails pinch_begin_details(ui::ET_GESTURE_PINCH_BEGIN); |
| 5114 | pinch_begin_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD); |
| 5115 | ui::GestureEvent pinch_begin(gesture_point.x(), gesture_point.y(), 0, |
| 5116 | ui::EventTimeForNow(), pinch_begin_details); |
| 5117 | root_view_aura->OnGestureEvent(&pinch_begin); |
| 5118 | EXPECT_EQ(expected_target, router_touchpad_gesture_target); |
| 5119 | |
| 5120 | ui::GestureEventDetails pinch_update_details(ui::ET_GESTURE_PINCH_UPDATE); |
| 5121 | pinch_update_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD); |
| 5122 | ui::GestureEvent pinch_update(gesture_point.x(), gesture_point.y(), 0, |
| 5123 | ui::EventTimeForNow(), pinch_update_details); |
| 5124 | root_view_aura->OnGestureEvent(&pinch_update); |
| 5125 | EXPECT_EQ(expected_target, router_touchpad_gesture_target); |
| 5126 | |
| 5127 | ui::GestureEventDetails pinch_end_details(ui::ET_GESTURE_PINCH_END); |
| 5128 | pinch_end_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHPAD); |
| 5129 | ui::GestureEvent pinch_end(gesture_point.x(), gesture_point.y(), 0, |
| 5130 | ui::EventTimeForNow(), pinch_end_details); |
| 5131 | root_view_aura->OnGestureEvent(&pinch_end); |
| 5132 | EXPECT_EQ(expected_target, router_touchpad_gesture_target); |
| 5133 | } |
| 5134 | |
| 5135 | #if !defined(OS_WIN) |
| 5136 | // Sending touchpad fling events is not supported on Windows. |
| 5137 | void SendTouchpadFlingSequenceWithExpectedTarget( |
| 5138 | RenderWidgetHostViewBase* root_view, |
| 5139 | const gfx::Point& gesture_point, |
| 5140 | RenderWidgetHostViewBase*& router_touchpad_gesture_target, |
| 5141 | RenderWidgetHostViewBase* expected_target) { |
| 5142 | auto root_view_aura = static_cast<RenderWidgetHostViewAura*>(root_view); |
| 5143 | |
| 5144 | ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, gesture_point, |
| 5145 | ui::EventTimeForNow(), 0, 1, 0, 1, 0, 1); |
| 5146 | root_view_aura->OnScrollEvent(&fling_start); |
| 5147 | EXPECT_EQ(expected_target, router_touchpad_gesture_target); |
| 5148 | |
| 5149 | ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL, gesture_point, |
| 5150 | ui::EventTimeForNow(), 0, 1, 0, 1, 0, 1); |
| 5151 | root_view_aura->OnScrollEvent(&fling_cancel); |
| 5152 | EXPECT_EQ(expected_target, router_touchpad_gesture_target); |
| 5153 | } |
| 5154 | #endif |
| 5155 | |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5156 | } // namespace anonymous |
| 5157 | |
| 5158 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 5159 | InputEventRouterGestureTargetQueueTest) { |
| 5160 | GURL main_url(embedded_test_server()->GetURL( |
| 5161 | "/frame_tree/page_with_positioned_nested_frames.html")); |
| 5162 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 5163 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5164 | WebContentsImpl* contents = web_contents(); |
| 5165 | FrameTreeNode* root = contents->GetFrameTree()->root(); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5166 | ASSERT_EQ(1U, root->child_count()); |
| 5167 | |
| 5168 | GURL frame_url( |
| 5169 | embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html")); |
| 5170 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 5171 | auto child_frame_host = root->child_at(0)->current_frame_host(); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5172 | |
| 5173 | // Synchronize with the child and parent renderers to guarantee that the |
| 5174 | // surface information required for event hit testing is ready. |
| 5175 | auto rwhv_child = |
| 5176 | static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView()); |
| 5177 | SurfaceHitTestReadyNotifier notifier( |
| 5178 | static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child)); |
| 5179 | notifier.WaitForSurfaceReady(); |
| 5180 | |
| 5181 | // All touches & gestures are sent to the main frame's view, and should be |
| 5182 | // routed appropriately from there. |
| 5183 | auto rwhv_parent = static_cast<RenderWidgetHostViewBase*>( |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5184 | contents->GetRenderWidgetHostView()); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5185 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5186 | RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter(); |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5187 | EXPECT_TRUE(router->touchscreen_gesture_target_queue_.empty()); |
| 5188 | EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5189 | |
| 5190 | // Send touch sequence to main-frame. |
| 5191 | gfx::Point main_frame_point(25, 25); |
| 5192 | SendTouchTapWithExpectedTarget(rwhv_parent, main_frame_point, |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5193 | router->touch_target_.target, rwhv_parent); |
| 5194 | EXPECT_EQ(1LU, router->touchscreen_gesture_target_queue_.size()); |
| 5195 | EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5196 | |
| 5197 | // Send touch sequence to child. |
| 5198 | gfx::Point child_center(150, 150); |
| 5199 | SendTouchTapWithExpectedTarget(rwhv_parent, child_center, |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5200 | router->touch_target_.target, rwhv_child); |
| 5201 | EXPECT_EQ(2LU, router->touchscreen_gesture_target_queue_.size()); |
| 5202 | EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5203 | |
| 5204 | // Send another touch sequence to main frame. |
| 5205 | SendTouchTapWithExpectedTarget(rwhv_parent, main_frame_point, |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5206 | router->touch_target_.target, rwhv_parent); |
| 5207 | EXPECT_EQ(3LU, router->touchscreen_gesture_target_queue_.size()); |
| 5208 | EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5209 | |
| 5210 | // Send Gestures to clear GestureTargetQueue. |
| 5211 | |
| 5212 | // The first touch sequence should generate a GestureTapDown, sent to the |
| 5213 | // main frame. |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5214 | SendGestureTapSequenceWithExpectedTarget( |
| 5215 | rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target, |
| 5216 | nullptr, rwhv_parent); |
| 5217 | EXPECT_EQ(2LU, router->touchscreen_gesture_target_queue_.size()); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5218 | // Note: rwhv_parent is the target used for GestureFlingCancel sent by |
| 5219 | // RenderWidgetHostViewAura::OnGestureEvent() at the start of the next gesture |
| 5220 | // sequence; the sequence itself goes to rwhv_child. |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5221 | EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5222 | |
| 5223 | // The second touch sequence should generate a GestureTapDown, sent to the |
| 5224 | // child frame. |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5225 | SendGestureTapSequenceWithExpectedTarget( |
| 5226 | rwhv_parent, child_center, router->touchscreen_gesture_target_.target, |
| 5227 | rwhv_parent, rwhv_child); |
| 5228 | EXPECT_EQ(1LU, router->touchscreen_gesture_target_queue_.size()); |
| 5229 | EXPECT_EQ(rwhv_child, router->touchscreen_gesture_target_.target); |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5230 | |
| 5231 | // The third touch sequence should generate a GestureTapDown, sent to the |
| 5232 | // main frame. |
mohsen | 298aa38 | 2016-06-30 00:19:00 | [diff] [blame] | 5233 | SendGestureTapSequenceWithExpectedTarget( |
| 5234 | rwhv_parent, main_frame_point, router->touchscreen_gesture_target_.target, |
| 5235 | rwhv_child, rwhv_parent); |
| 5236 | EXPECT_EQ(0LU, router->touchscreen_gesture_target_queue_.size()); |
| 5237 | EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target); |
| 5238 | } |
| 5239 | |
| 5240 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 5241 | InputEventRouterTouchpadGestureTargetTest) { |
| 5242 | GURL main_url(embedded_test_server()->GetURL( |
| 5243 | "/frame_tree/page_with_positioned_nested_frames.html")); |
| 5244 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 5245 | |
| 5246 | WebContentsImpl* contents = web_contents(); |
| 5247 | FrameTreeNode* root = contents->GetFrameTree()->root(); |
| 5248 | ASSERT_EQ(1U, root->child_count()); |
| 5249 | |
| 5250 | GURL frame_url( |
| 5251 | embedded_test_server()->GetURL("b.com", "/page_with_click_handler.html")); |
| 5252 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 5253 | auto child_frame_host = root->child_at(0)->current_frame_host(); |
| 5254 | |
| 5255 | // Synchronize with the child and parent renderers to guarantee that the |
| 5256 | // surface information required for event hit testing is ready. |
| 5257 | auto rwhv_child = |
| 5258 | static_cast<RenderWidgetHostViewBase*>(child_frame_host->GetView()); |
| 5259 | SurfaceHitTestReadyNotifier notifier( |
| 5260 | static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child)); |
| 5261 | notifier.WaitForSurfaceReady(); |
| 5262 | |
| 5263 | // All touches & gestures are sent to the main frame's view, and should be |
| 5264 | // routed appropriately from there. |
| 5265 | auto rwhv_parent = static_cast<RenderWidgetHostViewBase*>( |
| 5266 | contents->GetRenderWidgetHostView()); |
| 5267 | |
| 5268 | RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter(); |
| 5269 | EXPECT_EQ(nullptr, router->touchpad_gesture_target_.target); |
| 5270 | |
| 5271 | gfx::Point main_frame_point(25, 25); |
| 5272 | gfx::Point child_center(150, 150); |
| 5273 | |
| 5274 | // Send touchpad pinch sequence to main-frame. |
| 5275 | SendTouchpadPinchSequenceWithExpectedTarget( |
| 5276 | rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target, |
| 5277 | rwhv_parent); |
| 5278 | |
| 5279 | // Send touchpad pinch sequence to child. |
| 5280 | SendTouchpadPinchSequenceWithExpectedTarget( |
| 5281 | rwhv_parent, child_center, router->touchpad_gesture_target_.target, |
| 5282 | rwhv_child); |
| 5283 | |
| 5284 | // Send another touchpad pinch sequence to main frame. |
| 5285 | SendTouchpadPinchSequenceWithExpectedTarget( |
| 5286 | rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target, |
| 5287 | rwhv_parent); |
| 5288 | |
| 5289 | #if !defined(OS_WIN) |
| 5290 | // Sending touchpad fling events is not supported on Windows. |
| 5291 | |
| 5292 | // Send touchpad fling sequence to main-frame. |
| 5293 | SendTouchpadFlingSequenceWithExpectedTarget( |
| 5294 | rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target, |
| 5295 | rwhv_parent); |
| 5296 | |
| 5297 | // Send touchpad fling sequence to child. |
| 5298 | SendTouchpadFlingSequenceWithExpectedTarget( |
| 5299 | rwhv_parent, child_center, router->touchpad_gesture_target_.target, |
| 5300 | rwhv_child); |
| 5301 | |
| 5302 | // Send another touchpad fling sequence to main frame. |
| 5303 | SendTouchpadFlingSequenceWithExpectedTarget( |
| 5304 | rwhv_parent, main_frame_point, router->touchpad_gesture_target_.target, |
| 5305 | rwhv_parent); |
| 5306 | #endif |
wjmaclean | 4446423 | 2016-03-04 21:49:19 | [diff] [blame] | 5307 | } |
wjmaclean | fab616a | 2016-03-02 18:40:39 | [diff] [blame] | 5308 | #endif // defined(USE_AURA) |
| 5309 | |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5310 | // A WebContentsDelegate to capture ContextMenu creation events. |
| 5311 | class ContextMenuObserverDelegate : public WebContentsDelegate { |
| 5312 | public: |
| 5313 | ContextMenuObserverDelegate() |
| 5314 | : context_menu_created_(false), |
| 5315 | message_loop_runner_(new MessageLoopRunner) {} |
| 5316 | |
| 5317 | ~ContextMenuObserverDelegate() override {} |
| 5318 | |
| 5319 | bool HandleContextMenu(const content::ContextMenuParams& params) override { |
| 5320 | context_menu_created_ = true; |
| 5321 | menu_params_ = params; |
| 5322 | message_loop_runner_->Quit(); |
| 5323 | return true; |
| 5324 | } |
| 5325 | |
| 5326 | ContextMenuParams getParams() { return menu_params_; } |
| 5327 | |
| 5328 | void Wait() { |
| 5329 | if (!context_menu_created_) |
| 5330 | message_loop_runner_->Run(); |
| 5331 | context_menu_created_ = false; |
| 5332 | } |
| 5333 | |
| 5334 | private: |
| 5335 | bool context_menu_created_; |
| 5336 | ContextMenuParams menu_params_; |
| 5337 | |
| 5338 | // The MessageLoopRunner used to spin the message loop. |
| 5339 | scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 5340 | |
| 5341 | DISALLOW_COPY_AND_ASSIGN(ContextMenuObserverDelegate); |
| 5342 | }; |
| 5343 | |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5344 | // Helper function to run the CreateContextMenuTest in either normal |
| 5345 | // or high DPI mode. |
| 5346 | void CreateContextMenuTestHelper( |
| 5347 | Shell* shell, |
| 5348 | net::test_server::EmbeddedTestServer* embedded_test_server) { |
| 5349 | GURL main_url(embedded_test_server->GetURL( |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5350 | "/frame_tree/page_with_positioned_frame.html")); |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5351 | EXPECT_TRUE(NavigateToURL(shell, main_url)); |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5352 | |
| 5353 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5354 | FrameTreeNode* root = static_cast<WebContentsImpl*>(shell->web_contents()) |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5355 | ->GetFrameTree() |
| 5356 | ->root(); |
| 5357 | ASSERT_EQ(1U, root->child_count()); |
| 5358 | |
| 5359 | FrameTreeNode* child_node = root->child_at(0); |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5360 | GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html")); |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5361 | EXPECT_EQ(site_url, child_node->current_url()); |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5362 | EXPECT_NE(shell->web_contents()->GetSiteInstance(), |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5363 | child_node->current_frame_host()->GetSiteInstance()); |
| 5364 | |
| 5365 | RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>( |
| 5366 | root->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 5367 | RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>( |
| 5368 | child_node->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 5369 | |
| 5370 | // Ensure that the child process renderer is ready to have input events |
| 5371 | // routed to it. This happens when the browser process has received |
| 5372 | // updated compositor surfaces from both renderer processes. |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5373 | SurfaceHitTestReadyNotifier notifier( |
| 5374 | static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child)); |
| 5375 | notifier.WaitForSurfaceReady(); |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5376 | |
| 5377 | // A WebContentsDelegate to listen for the ShowContextMenu message. |
| 5378 | ContextMenuObserverDelegate context_menu_delegate; |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5379 | shell->web_contents()->SetDelegate(&context_menu_delegate); |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5380 | |
| 5381 | RenderWidgetHostInputEventRouter* router = |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5382 | static_cast<WebContentsImpl*>(shell->web_contents()) |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5383 | ->GetInputEventRouter(); |
| 5384 | |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5385 | gfx::Point point(75, 75); |
| 5386 | |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5387 | // Target right-click event to child frame. |
| 5388 | blink::WebMouseEvent click_event; |
| 5389 | click_event.type = blink::WebInputEvent::MouseDown; |
| 5390 | click_event.button = blink::WebPointerProperties::ButtonRight; |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5391 | click_event.x = point.x(); |
| 5392 | click_event.y = point.y(); |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5393 | click_event.clickCount = 1; |
| 5394 | router->RouteMouseEvent(root_view, &click_event); |
| 5395 | |
| 5396 | // We also need a MouseUp event, needed by Windows. |
| 5397 | click_event.type = blink::WebInputEvent::MouseUp; |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5398 | click_event.x = point.x(); |
| 5399 | click_event.y = point.y(); |
kenrb | 162e42c | 2015-11-24 21:10:00 | [diff] [blame] | 5400 | router->RouteMouseEvent(root_view, &click_event); |
| 5401 | |
| 5402 | context_menu_delegate.Wait(); |
| 5403 | |
| 5404 | ContextMenuParams params = context_menu_delegate.getParams(); |
| 5405 | |
| 5406 | EXPECT_EQ(point.x(), params.x); |
| 5407 | EXPECT_EQ(point.y(), params.y); |
| 5408 | } |
| 5409 | |
kenrb | 611d653 | 2016-03-31 17:37:37 | [diff] [blame] | 5410 | // Test that a mouse right-click to an out-of-process iframe causes a context |
| 5411 | // menu to be generated with the correct screen position. |
| 5412 | #if defined(OS_ANDROID) |
| 5413 | // Browser process hit testing is not implemented on Android. |
| 5414 | // https://crbug.com/491334 |
| 5415 | #define MAYBE_CreateContextMenuTest DISABLED_CreateContextMenuTest |
| 5416 | #else |
| 5417 | #define MAYBE_CreateContextMenuTest CreateContextMenuTest |
| 5418 | #endif |
| 5419 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CreateContextMenuTest) { |
| 5420 | CreateContextMenuTestHelper(shell(), embedded_test_server()); |
| 5421 | } |
| 5422 | |
| 5423 | // Test that a mouse right-click to an out-of-process iframe causes a context |
| 5424 | // menu to be generated with the correct screen position on a screen with |
| 5425 | // non-default scale factor. |
| 5426 | #if defined(OS_ANDROID) || defined(OS_WIN) |
| 5427 | // Browser process hit testing is not implemented on Android. |
| 5428 | // https://crbug.com/491334 |
| 5429 | // Windows is disabled because of https://crbug.com/545547. |
| 5430 | #define MAYBE_HighDPICreateContextMenuTest DISABLED_HighDPICreateContextMenuTest |
| 5431 | #else |
| 5432 | #define MAYBE_HighDPICreateContextMenuTest HighDPICreateContextMenuTest |
| 5433 | #endif |
| 5434 | IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest, |
| 5435 | MAYBE_HighDPICreateContextMenuTest) { |
| 5436 | CreateContextMenuTestHelper(shell(), embedded_test_server()); |
| 5437 | } |
| 5438 | |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5439 | class ShowWidgetMessageFilter : public content::BrowserMessageFilter { |
| 5440 | public: |
| 5441 | ShowWidgetMessageFilter() |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5442 | #if defined(OS_MACOSX) || defined(OS_ANDROID) |
| 5443 | : content::BrowserMessageFilter(FrameMsgStart), |
| 5444 | #else |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5445 | : content::BrowserMessageFilter(ViewMsgStart), |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5446 | #endif |
| 5447 | message_loop_runner_(new content::MessageLoopRunner) { |
| 5448 | } |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5449 | |
| 5450 | bool OnMessageReceived(const IPC::Message& message) override { |
| 5451 | IPC_BEGIN_MESSAGE_MAP(ShowWidgetMessageFilter, message) |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5452 | #if defined(OS_MACOSX) || defined(OS_ANDROID) |
| 5453 | IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup) |
| 5454 | #else |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5455 | IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget) |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5456 | #endif |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5457 | IPC_END_MESSAGE_MAP() |
| 5458 | return false; |
| 5459 | } |
| 5460 | |
| 5461 | gfx::Rect last_initial_rect() const { return initial_rect_; } |
| 5462 | |
| 5463 | void Wait() { |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5464 | initial_rect_ = gfx::Rect(); |
| 5465 | message_loop_runner_->Run(); |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5466 | } |
| 5467 | |
| 5468 | void Reset() { |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5469 | initial_rect_ = gfx::Rect(); |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5470 | message_loop_runner_ = new content::MessageLoopRunner; |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5471 | } |
| 5472 | |
| 5473 | private: |
| 5474 | ~ShowWidgetMessageFilter() override {} |
| 5475 | |
| 5476 | void OnShowWidget(int route_id, const gfx::Rect& initial_rect) { |
| 5477 | content::BrowserThread::PostTask( |
| 5478 | content::BrowserThread::UI, FROM_HERE, |
| 5479 | base::Bind(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this, route_id, |
| 5480 | initial_rect)); |
| 5481 | } |
| 5482 | |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5483 | #if defined(OS_MACOSX) || defined(OS_ANDROID) |
| 5484 | void OnShowPopup(const FrameHostMsg_ShowPopup_Params& params) { |
| 5485 | content::BrowserThread::PostTask( |
| 5486 | content::BrowserThread::UI, FROM_HERE, |
| 5487 | base::Bind(&ShowWidgetMessageFilter::OnShowWidgetOnUI, this, |
| 5488 | MSG_ROUTING_NONE, params.bounds)); |
| 5489 | } |
| 5490 | #endif |
| 5491 | |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5492 | void OnShowWidgetOnUI(int route_id, const gfx::Rect& initial_rect) { |
| 5493 | initial_rect_ = initial_rect; |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5494 | message_loop_runner_->Quit(); |
| 5495 | } |
| 5496 | |
| 5497 | scoped_refptr<content::MessageLoopRunner> message_loop_runner_; |
| 5498 | gfx::Rect initial_rect_; |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5499 | |
| 5500 | DISALLOW_COPY_AND_ASSIGN(ShowWidgetMessageFilter); |
| 5501 | }; |
| 5502 | |
| 5503 | // Test that clicking a select element in an out-of-process iframe creates |
| 5504 | // a popup menu in the correct position. |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5505 | #if defined(OS_ANDROID) |
| 5506 | // Surface-based hit testing and coordinate translation is not yet available |
| 5507 | // on Android. |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5508 | #define MAYBE_PopupMenuTest DISABLED_PopupMenuTest |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5509 | #else |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5510 | #define MAYBE_PopupMenuTest PopupMenuTest |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5511 | #endif |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5512 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_PopupMenuTest) { |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5513 | GURL main_url( |
| 5514 | embedded_test_server()->GetURL("/cross_site_iframe_factory.html?a(a)")); |
| 5515 | NavigateToURL(shell(), main_url); |
| 5516 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5517 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5518 | |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5519 | #if !defined(OS_MACOSX) |
| 5520 | // Unused variable on Mac. |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5521 | RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>( |
| 5522 | root->current_frame_host()->GetRenderWidgetHost()->GetView()); |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5523 | #endif |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5524 | web_contents()->SendScreenRects(); |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5525 | |
| 5526 | content::TestNavigationObserver navigation_observer(shell()->web_contents()); |
| 5527 | FrameTreeNode* child_node = root->child_at(0); |
| 5528 | GURL site_url(embedded_test_server()->GetURL( |
| 5529 | "baz.com", "/site_isolation/page-with-select.html")); |
| 5530 | NavigateFrameToURL(child_node, site_url); |
| 5531 | navigation_observer.Wait(); |
| 5532 | |
| 5533 | RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>( |
| 5534 | child_node->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 5535 | |
| 5536 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 5537 | child_node->current_frame_host()->GetSiteInstance()); |
| 5538 | |
| 5539 | scoped_refptr<ShowWidgetMessageFilter> filter = new ShowWidgetMessageFilter(); |
| 5540 | child_node->current_frame_host()->GetProcess()->AddFilter(filter.get()); |
| 5541 | |
| 5542 | // Target left-click event to child frame. |
| 5543 | blink::WebMouseEvent click_event; |
| 5544 | click_event.type = blink::WebInputEvent::MouseDown; |
| 5545 | click_event.button = blink::WebPointerProperties::ButtonLeft; |
| 5546 | click_event.x = 15; |
| 5547 | click_event.y = 15; |
| 5548 | click_event.clickCount = 1; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 5549 | rwhv_child->ProcessMouseEvent(click_event, ui::LatencyInfo()); |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5550 | |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5551 | // Dismiss the popup. |
| 5552 | click_event.x = 1; |
| 5553 | click_event.y = 1; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 5554 | rwhv_child->ProcessMouseEvent(click_event, ui::LatencyInfo()); |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5555 | |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5556 | filter->Wait(); |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5557 | gfx::Rect popup_rect = filter->last_initial_rect(); |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5558 | #if defined(OS_MACOSX) |
| 5559 | // On Mac we receive the coordinates before they are transformed, so they |
| 5560 | // are still relative to the out-of-process iframe origin. |
| 5561 | EXPECT_EQ(popup_rect.x(), 9); |
| 5562 | EXPECT_EQ(popup_rect.y(), 9); |
| 5563 | #else |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5564 | EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354); |
| 5565 | EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 94); |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5566 | #endif |
kenrb | c52e1b4e | 2016-03-20 01:03:37 | [diff] [blame] | 5567 | } |
| 5568 | |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5569 | // Test that clicking a select element in a nested out-of-process iframe creates |
| 5570 | // a popup menu in the correct position, even if the top-level page repositions |
| 5571 | // its out-of-process iframe. This verifies that screen positioning information |
| 5572 | // is propagating down the frame tree correctly. |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5573 | #if defined(OS_ANDROID) |
| 5574 | // Surface-based hit testing and coordinate translation is not yet avaiable on |
| 5575 | // Android. |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5576 | #define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest |
| 5577 | #else |
benwells | 103e61ce | 2016-04-01 01:38:53 | [diff] [blame] | 5578 | // Times out frequently. https://crbug.com/599730. |
| 5579 | #define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5580 | #endif |
| 5581 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_NestedPopupMenuTest) { |
| 5582 | GURL main_url(embedded_test_server()->GetURL( |
| 5583 | "/cross_site_iframe_factory.html?a(b(c))")); |
| 5584 | NavigateToURL(shell(), main_url); |
| 5585 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5586 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5587 | |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5588 | #if !defined(OS_MACOSX) |
| 5589 | // Undefined variable on Mac. |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5590 | RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>( |
| 5591 | root->current_frame_host()->GetRenderWidgetHost()->GetView()); |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5592 | #endif |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5593 | web_contents()->SendScreenRects(); |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5594 | |
| 5595 | // For clarity, we are labeling the frame tree nodes as: |
| 5596 | // - root_node |
| 5597 | // \-> b_node (out-of-process from root and c_node) |
| 5598 | // \-> c_node (out-of-process from root and b_node) |
| 5599 | |
| 5600 | content::TestNavigationObserver navigation_observer(shell()->web_contents()); |
| 5601 | FrameTreeNode* b_node = root->child_at(0); |
| 5602 | FrameTreeNode* c_node = b_node->child_at(0); |
| 5603 | GURL site_url(embedded_test_server()->GetURL( |
| 5604 | "baz.com", "/site_isolation/page-with-select.html")); |
| 5605 | NavigateFrameToURL(c_node, site_url); |
| 5606 | |
| 5607 | RenderWidgetHostViewBase* rwhv_c_node = |
| 5608 | static_cast<RenderWidgetHostViewBase*>( |
| 5609 | c_node->current_frame_host()->GetRenderWidgetHost()->GetView()); |
| 5610 | |
| 5611 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 5612 | c_node->current_frame_host()->GetSiteInstance()); |
| 5613 | |
| 5614 | scoped_refptr<ShowWidgetMessageFilter> filter = new ShowWidgetMessageFilter(); |
| 5615 | c_node->current_frame_host()->GetProcess()->AddFilter(filter.get()); |
| 5616 | |
| 5617 | // Target left-click event to child frame. |
| 5618 | blink::WebMouseEvent click_event; |
| 5619 | click_event.type = blink::WebInputEvent::MouseDown; |
| 5620 | click_event.button = blink::WebPointerProperties::ButtonLeft; |
| 5621 | click_event.x = 15; |
| 5622 | click_event.y = 15; |
| 5623 | click_event.clickCount = 1; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 5624 | rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo()); |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5625 | |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5626 | // Prompt the WebContents to dismiss the popup by clicking elsewhere. |
| 5627 | click_event.x = 1; |
| 5628 | click_event.y = 1; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 5629 | rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo()); |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5630 | |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5631 | filter->Wait(); |
| 5632 | |
| 5633 | gfx::Rect popup_rect = filter->last_initial_rect(); |
| 5634 | |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5635 | #if defined(OS_MACOSX) |
| 5636 | EXPECT_EQ(popup_rect.x(), 9); |
| 5637 | EXPECT_EQ(popup_rect.y(), 9); |
| 5638 | #else |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5639 | EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354); |
| 5640 | EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 154); |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5641 | #endif |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5642 | |
| 5643 | // Save the screen rect for b_node. Since it updates asynchronously from |
| 5644 | // the script command that changes it, we need to wait for it to change |
| 5645 | // before attempting to create the popup widget again. |
| 5646 | gfx::Rect last_b_node_bounds_rect = |
| 5647 | b_node->current_frame_host()->GetView()->GetViewBounds(); |
| 5648 | |
| 5649 | std::string script = |
| 5650 | "var iframe = document.querySelector('iframe');" |
| 5651 | "iframe.style.position = 'absolute';" |
| 5652 | "iframe.style.left = 150;" |
| 5653 | "iframe.style.top = 150;"; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 5654 | EXPECT_TRUE(ExecuteScript(root, script)); |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5655 | |
| 5656 | filter->Reset(); |
| 5657 | |
| 5658 | // Busy loop to wait for b_node's screen rect to get updated. There |
| 5659 | // doesn't seem to be any better way to find out when this happens. |
| 5660 | while (last_b_node_bounds_rect.x() == |
| 5661 | b_node->current_frame_host()->GetView()->GetViewBounds().x() && |
| 5662 | last_b_node_bounds_rect.y() == |
| 5663 | b_node->current_frame_host()->GetView()->GetViewBounds().y()) { |
| 5664 | base::RunLoop run_loop; |
| 5665 | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
| 5666 | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); |
| 5667 | run_loop.Run(); |
| 5668 | } |
| 5669 | |
| 5670 | click_event.button = blink::WebPointerProperties::ButtonLeft; |
| 5671 | click_event.x = 15; |
| 5672 | click_event.y = 15; |
| 5673 | click_event.clickCount = 1; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 5674 | rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo()); |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5675 | |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5676 | click_event.x = 1; |
| 5677 | click_event.y = 1; |
sahel | d9c26df | 2016-06-07 15:09:56 | [diff] [blame] | 5678 | rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo()); |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5679 | |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5680 | filter->Wait(); |
| 5681 | |
| 5682 | popup_rect = filter->last_initial_rect(); |
| 5683 | |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5684 | #if defined(OS_MACOSX) |
| 5685 | EXPECT_EQ(popup_rect.x(), 9); |
| 5686 | EXPECT_EQ(popup_rect.y(), 9); |
| 5687 | #else |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5688 | EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 203); |
| 5689 | EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 248); |
kenrb | 75b5fe25f | 2016-03-25 00:30:45 | [diff] [blame] | 5690 | #endif |
kenrb | 61b6c25 | 2016-03-22 17:37:15 | [diff] [blame] | 5691 | } |
| 5692 | |
alexmos | ba1fb715 | 2015-12-12 07:20:30 | [diff] [blame] | 5693 | // Test for https://crbug.com/526304, where a parent frame executes a |
| 5694 | // remote-to-local navigation on a child frame and immediately removes the same |
| 5695 | // child frame. This test exercises the path where the detach happens before |
| 5696 | // the provisional local frame is created. |
| 5697 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 5698 | NavigateProxyAndDetachBeforeProvisionalFrameCreation) { |
| 5699 | GURL main_url(embedded_test_server()->GetURL( |
| 5700 | "a.com", "/cross_site_iframe_factory.html?a(b,b)")); |
| 5701 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 5702 | |
| 5703 | WebContents* contents = shell()->web_contents(); |
| 5704 | FrameTreeNode* root = |
| 5705 | static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root(); |
| 5706 | EXPECT_EQ(2U, root->child_count()); |
| 5707 | |
| 5708 | // Navigate the first child frame to 'about:blank' (which is a |
| 5709 | // remote-to-local transition), and then detach it. |
| 5710 | FrameDeletedObserver observer(root->child_at(0)); |
| 5711 | std::string script = |
| 5712 | "var f = document.querySelector('iframe');" |
| 5713 | "f.contentWindow.location.href = 'about:blank';" |
| 5714 | "setTimeout(function() { document.body.removeChild(f); }, 0);"; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 5715 | EXPECT_TRUE(ExecuteScript(root, script)); |
alexmos | ba1fb715 | 2015-12-12 07:20:30 | [diff] [blame] | 5716 | observer.Wait(); |
| 5717 | EXPECT_EQ(1U, root->child_count()); |
| 5718 | |
| 5719 | // Make sure the main frame renderer does not crash and ignores the |
| 5720 | // navigation to the frame that's already been deleted. |
| 5721 | int child_count = 0; |
| 5722 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 5723 | root, "domAutomationController.send(frames.length)", &child_count)); |
alexmos | ba1fb715 | 2015-12-12 07:20:30 | [diff] [blame] | 5724 | EXPECT_EQ(1, child_count); |
| 5725 | } |
| 5726 | |
| 5727 | // Test for a variation of https://crbug.com/526304, where a child frame does a |
| 5728 | // remote-to-local navigation, and the parent frame removes that child frame |
| 5729 | // after the provisional local frame is created and starts to navigate, but |
| 5730 | // before it commits. |
| 5731 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 5732 | NavigateProxyAndDetachBeforeCommit) { |
| 5733 | GURL main_url(embedded_test_server()->GetURL( |
| 5734 | "a.com", "/cross_site_iframe_factory.html?a(b,b)")); |
| 5735 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 5736 | |
| 5737 | WebContents* contents = shell()->web_contents(); |
| 5738 | FrameTreeNode* root = |
| 5739 | static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root(); |
| 5740 | EXPECT_EQ(2U, root->child_count()); |
| 5741 | FrameTreeNode* child = root->child_at(0); |
| 5742 | |
| 5743 | // Start a remote-to-local navigation for the child, but don't wait for |
| 5744 | // commit. |
| 5745 | GURL same_site_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 5746 | NavigationController::LoadURLParams params(same_site_url); |
| 5747 | params.transition_type = ui::PAGE_TRANSITION_LINK; |
| 5748 | params.frame_tree_node_id = child->frame_tree_node_id(); |
| 5749 | child->navigator()->GetController()->LoadURLWithParams(params); |
| 5750 | |
| 5751 | // Tell parent to remove the first child. This should happen after the |
| 5752 | // previous navigation starts but before it commits. |
| 5753 | FrameDeletedObserver observer(child); |
| 5754 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 5755 | root, "document.body.removeChild(document.querySelector('iframe'));")); |
alexmos | ba1fb715 | 2015-12-12 07:20:30 | [diff] [blame] | 5756 | observer.Wait(); |
| 5757 | EXPECT_EQ(1U, root->child_count()); |
| 5758 | |
| 5759 | // Make sure the a.com renderer does not crash. |
| 5760 | int child_count = 0; |
| 5761 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 5762 | root, "domAutomationController.send(frames.length)", &child_count)); |
alexmos | ba1fb715 | 2015-12-12 07:20:30 | [diff] [blame] | 5763 | EXPECT_EQ(1, child_count); |
| 5764 | } |
| 5765 | |
nasko | 13b8e77 | 2016-03-03 19:41:35 | [diff] [blame] | 5766 | // Similar to NavigateProxyAndDetachBeforeCommit, but uses a synchronous |
| 5767 | // navigation to about:blank and the parent removes the child frame in a load |
| 5768 | // event handler for the subframe. |
| 5769 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateAboutBlankAndDetach) { |
| 5770 | GURL main_url( |
| 5771 | embedded_test_server()->GetURL("a.com", "/remove_frame_on_load.html")); |
| 5772 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 5773 | |
| 5774 | WebContents* contents = shell()->web_contents(); |
| 5775 | FrameTreeNode* root = |
| 5776 | static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root(); |
| 5777 | EXPECT_EQ(1U, root->child_count()); |
| 5778 | FrameTreeNode* child = root->child_at(0); |
| 5779 | EXPECT_NE(shell()->web_contents()->GetSiteInstance(), |
| 5780 | child->current_frame_host()->GetSiteInstance()); |
| 5781 | |
| 5782 | // Navigate the child frame to "about:blank" from the parent document. |
| 5783 | TestNavigationObserver observer(shell()->web_contents()); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 5784 | EXPECT_TRUE(ExecuteScript( |
| 5785 | root, base::StringPrintf("f.src = '%s'", url::kAboutBlankURL))); |
nasko | 13b8e77 | 2016-03-03 19:41:35 | [diff] [blame] | 5786 | observer.Wait(); |
| 5787 | |
| 5788 | // Make sure the a.com renderer does not crash and the frame is removed. |
| 5789 | int child_count = 0; |
| 5790 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 5791 | root, "domAutomationController.send(frames.length)", &child_count)); |
nasko | 13b8e77 | 2016-03-03 19:41:35 | [diff] [blame] | 5792 | EXPECT_EQ(0, child_count); |
| 5793 | } |
| 5794 | |
alexmos | e846e41 | 2015-12-18 07:46:45 | [diff] [blame] | 5795 | // Test for https://crbug.com/568670. In A-embed-B, simultaneously have B |
| 5796 | // create a new (local) child frame, and have A detach B's proxy. The child |
| 5797 | // frame creation sends an IPC to create a new proxy in A's process, and if |
| 5798 | // that IPC arrives after the detach, the new frame's parent (a proxy) won't be |
| 5799 | // available, and this shouldn't cause RenderFrameProxy::CreateFrameProxy to |
| 5800 | // crash. |
| 5801 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 5802 | RaceBetweenCreateChildFrameAndDetachParentProxy) { |
| 5803 | GURL main_url(embedded_test_server()->GetURL( |
| 5804 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 5805 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 5806 | |
| 5807 | WebContents* contents = shell()->web_contents(); |
| 5808 | FrameTreeNode* root = |
| 5809 | static_cast<WebContentsImpl*>(contents)->GetFrameTree()->root(); |
| 5810 | |
| 5811 | // Simulate subframe B creating a new child frame in parallel to main frame A |
| 5812 | // detaching subframe B. We can't use ExecuteScript in both A and B to do |
| 5813 | // this simultaneously, as that won't guarantee the timing that we want. |
| 5814 | // Instead, tell A to detach B and then send a fake proxy creation IPC to A |
| 5815 | // that would've come from create-child-frame code in B. Prepare parameters |
| 5816 | // for that IPC ahead of the detach, while B's FrameTreeNode still exists. |
| 5817 | SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance(); |
| 5818 | RenderProcessHost* process_a = |
| 5819 | root->render_manager()->current_frame_host()->GetProcess(); |
| 5820 | int new_routing_id = process_a->GetNextRoutingID(); |
| 5821 | int view_routing_id = |
| 5822 | root->frame_tree()->GetRenderViewHost(site_instance_a)->GetRoutingID(); |
| 5823 | int parent_routing_id = |
| 5824 | root->child_at(0)->render_manager()->GetProxyToParent()->GetRoutingID(); |
| 5825 | |
| 5826 | // Tell main frame A to delete its subframe B. |
| 5827 | FrameDeletedObserver observer(root->child_at(0)); |
| 5828 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 5829 | root, "document.body.removeChild(document.querySelector('iframe'));")); |
alexmos | e846e41 | 2015-12-18 07:46:45 | [diff] [blame] | 5830 | |
| 5831 | // Send the message to create a proxy for B's new child frame in A. This |
| 5832 | // used to crash, as parent_routing_id refers to a proxy that doesn't exist |
| 5833 | // anymore. |
| 5834 | process_a->Send(new FrameMsg_NewFrameProxy( |
| 5835 | new_routing_id, view_routing_id, MSG_ROUTING_NONE, parent_routing_id, |
| 5836 | FrameReplicationState())); |
| 5837 | |
| 5838 | // Ensure the subframe is detached in the browser process. |
| 5839 | observer.Wait(); |
| 5840 | EXPECT_EQ(0U, root->child_count()); |
| 5841 | |
| 5842 | // Make sure process A did not crash. |
| 5843 | int child_count = 0; |
| 5844 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 5845 | root, "domAutomationController.send(frames.length)", &child_count)); |
alexmos | e846e41 | 2015-12-18 07:46:45 | [diff] [blame] | 5846 | EXPECT_EQ(0, child_count); |
| 5847 | } |
| 5848 | |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5849 | // This test ensures that the RenderFrame isn't leaked in the renderer process |
| 5850 | // if a pending cross-process navigation is cancelled. The test works by trying |
| 5851 | // to create a new RenderFrame with the same routing id. If there is an |
| 5852 | // entry with the same routing ID, a CHECK is hit and the process crashes. |
| 5853 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 5854 | SubframePendingAndBackToSameSiteInstance) { |
| 5855 | GURL main_url(embedded_test_server()->GetURL( |
| 5856 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 5857 | NavigateToURL(shell(), main_url); |
| 5858 | |
| 5859 | // Capture the FrameTreeNode this test will be navigating. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5860 | FrameTreeNode* node = web_contents()->GetFrameTree()->root()->child_at(0); |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5861 | EXPECT_TRUE(node); |
| 5862 | EXPECT_NE(node->current_frame_host()->GetSiteInstance(), |
| 5863 | node->parent()->current_frame_host()->GetSiteInstance()); |
| 5864 | |
| 5865 | // Navigate to the site of the parent, but to a page that will not commit. |
| 5866 | GURL same_site_url(embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 5867 | NavigationStallDelegate stall_delegate(same_site_url); |
| 5868 | ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate); |
| 5869 | { |
| 5870 | NavigationController::LoadURLParams params(same_site_url); |
| 5871 | params.transition_type = ui::PAGE_TRANSITION_LINK; |
| 5872 | params.frame_tree_node_id = node->frame_tree_node_id(); |
| 5873 | node->navigator()->GetController()->LoadURLWithParams(params); |
| 5874 | } |
| 5875 | |
| 5876 | // Grab the routing id of the pending RenderFrameHost and set up a process |
| 5877 | // observer to ensure there is no crash when a new RenderFrame creation is |
| 5878 | // attempted. |
| 5879 | RenderProcessHost* process = |
clamy | 5cba148 | 2016-02-26 08:58:14 | [diff] [blame] | 5880 | IsBrowserSideNavigationEnabled() |
| 5881 | ? node->render_manager()->speculative_frame_host()->GetProcess() |
| 5882 | : node->render_manager()->pending_frame_host()->GetProcess(); |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5883 | RenderProcessHostWatcher watcher( |
| 5884 | process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 5885 | int frame_routing_id = |
clamy | 5cba148 | 2016-02-26 08:58:14 | [diff] [blame] | 5886 | IsBrowserSideNavigationEnabled() |
| 5887 | ? node->render_manager()->speculative_frame_host()->GetRoutingID() |
| 5888 | : node->render_manager()->pending_frame_host()->GetRoutingID(); |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5889 | int proxy_routing_id = |
| 5890 | node->render_manager()->GetProxyToParent()->GetRoutingID(); |
| 5891 | |
| 5892 | // Now go to c.com so the navigation to a.com is cancelled and send an IPC |
| 5893 | // to create a new RenderFrame with the routing id of the previously pending |
| 5894 | // one. |
| 5895 | NavigateFrameToURL(node, |
| 5896 | embedded_test_server()->GetURL("c.com", "/title2.html")); |
| 5897 | { |
| 5898 | FrameMsg_NewFrame_Params params; |
| 5899 | params.routing_id = frame_routing_id; |
| 5900 | params.proxy_routing_id = proxy_routing_id; |
| 5901 | params.opener_routing_id = MSG_ROUTING_NONE; |
| 5902 | params.parent_routing_id = |
| 5903 | shell()->web_contents()->GetMainFrame()->GetRoutingID(); |
| 5904 | params.previous_sibling_routing_id = MSG_ROUTING_NONE; |
| 5905 | params.widget_params.routing_id = MSG_ROUTING_NONE; |
| 5906 | params.widget_params.hidden = true; |
lukasza | 464d869 | 2016-02-22 19:26:32 | [diff] [blame] | 5907 | params.replication_state.name = "name"; |
| 5908 | params.replication_state.unique_name = "name"; |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5909 | |
| 5910 | process->Send(new FrameMsg_NewFrame(params)); |
| 5911 | } |
| 5912 | |
| 5913 | // The test must wait for the process to exit, but if there is no leak, the |
| 5914 | // RenderFrame will be properly created and there will be no crash. |
| 5915 | // Therefore, navigate the main frame to completely different site, which |
| 5916 | // will cause the original process to exit cleanly. |
| 5917 | EXPECT_TRUE(NavigateToURL( |
| 5918 | shell(), embedded_test_server()->GetURL("d.com", "/title3.html"))); |
| 5919 | watcher.Wait(); |
| 5920 | EXPECT_TRUE(watcher.did_exit_normally()); |
| 5921 | |
| 5922 | ResourceDispatcherHost::Get()->SetDelegate(nullptr); |
| 5923 | } |
| 5924 | |
| 5925 | // This test ensures that the RenderFrame isn't leaked in the renderer process |
| 5926 | // when a remote parent detaches a child frame. The test works by trying |
| 5927 | // to create a new RenderFrame with the same routing id. If there is an |
| 5928 | // entry with the same routing ID, a CHECK is hit and the process crashes. |
| 5929 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ParentDetachRemoteChild) { |
| 5930 | GURL main_url(embedded_test_server()->GetURL( |
| 5931 | "a.com", "/cross_site_iframe_factory.html?a(b,b)")); |
| 5932 | NavigateToURL(shell(), main_url); |
| 5933 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5934 | WebContentsImpl* contents = web_contents(); |
| 5935 | EXPECT_EQ(2U, contents->GetFrameTree()->root()->child_count()); |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5936 | |
| 5937 | // Capture the FrameTreeNode this test will be navigating. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5938 | FrameTreeNode* node = contents->GetFrameTree()->root()->child_at(0); |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5939 | EXPECT_TRUE(node); |
| 5940 | EXPECT_NE(node->current_frame_host()->GetSiteInstance(), |
| 5941 | node->parent()->current_frame_host()->GetSiteInstance()); |
| 5942 | |
| 5943 | // Grab the routing id of the first child RenderFrameHost and set up a process |
| 5944 | // observer to ensure there is no crash when a new RenderFrame creation is |
| 5945 | // attempted. |
| 5946 | RenderProcessHost* process = node->current_frame_host()->GetProcess(); |
| 5947 | RenderProcessHostWatcher watcher( |
| 5948 | process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 5949 | int frame_routing_id = node->current_frame_host()->GetRoutingID(); |
| 5950 | int widget_routing_id = |
| 5951 | node->current_frame_host()->GetRenderWidgetHost()->GetRoutingID(); |
| 5952 | int parent_routing_id = |
| 5953 | node->parent()->render_manager()->GetRoutingIdForSiteInstance( |
| 5954 | node->current_frame_host()->GetSiteInstance()); |
| 5955 | |
| 5956 | // Have the parent frame remove the child frame from its DOM. This should |
| 5957 | // result in the child RenderFrame being deleted in the remote process. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5958 | EXPECT_TRUE(ExecuteScript(contents, |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5959 | "document.body.removeChild(" |
| 5960 | "document.querySelectorAll('iframe')[0])")); |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5961 | EXPECT_EQ(1U, contents->GetFrameTree()->root()->child_count()); |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5962 | |
| 5963 | { |
| 5964 | FrameMsg_NewFrame_Params params; |
| 5965 | params.routing_id = frame_routing_id; |
| 5966 | params.proxy_routing_id = MSG_ROUTING_NONE; |
| 5967 | params.opener_routing_id = MSG_ROUTING_NONE; |
| 5968 | params.parent_routing_id = parent_routing_id; |
| 5969 | params.previous_sibling_routing_id = MSG_ROUTING_NONE; |
| 5970 | params.widget_params.routing_id = widget_routing_id; |
| 5971 | params.widget_params.hidden = true; |
lukasza | 464d869 | 2016-02-22 19:26:32 | [diff] [blame] | 5972 | params.replication_state.name = "name"; |
| 5973 | params.replication_state.unique_name = "name"; |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5974 | |
| 5975 | process->Send(new FrameMsg_NewFrame(params)); |
| 5976 | } |
| 5977 | |
| 5978 | // The test must wait for the process to exit, but if there is no leak, the |
| 5979 | // RenderFrame will be properly created and there will be no crash. |
| 5980 | // Therefore, navigate the remaining subframe to completely different site, |
| 5981 | // which will cause the original process to exit cleanly. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5982 | NavigateFrameToURL(contents->GetFrameTree()->root()->child_at(0), |
| 5983 | embedded_test_server()->GetURL("d.com", "/title3.html")); |
nasko | eab5c558 | 2015-12-15 05:20:00 | [diff] [blame] | 5984 | watcher.Wait(); |
| 5985 | EXPECT_TRUE(watcher.did_exit_normally()); |
| 5986 | } |
| 5987 | |
ekaramad | babb9bf | 2016-01-12 15:17:02 | [diff] [blame] | 5988 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, VisibilityChanged) { |
| 5989 | GURL main_url( |
| 5990 | embedded_test_server()->GetURL("a.com", "/page_with_iframe.html")); |
| 5991 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 5992 | EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), main_url); |
| 5993 | |
| 5994 | GURL cross_site_url = |
| 5995 | embedded_test_server()->GetURL("oopif.com", "/title1.html"); |
| 5996 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 5997 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
ekaramad | babb9bf | 2016-01-12 15:17:02 | [diff] [blame] | 5998 | |
| 5999 | TestNavigationObserver observer(shell()->web_contents()); |
| 6000 | |
| 6001 | NavigateFrameToURL(root->child_at(0), cross_site_url); |
| 6002 | EXPECT_EQ(cross_site_url, observer.last_navigation_url()); |
| 6003 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 6004 | |
| 6005 | RenderWidgetHostImpl* render_widget_host = |
| 6006 | root->child_at(0)->current_frame_host()->GetRenderWidgetHost(); |
| 6007 | EXPECT_FALSE(render_widget_host->is_hidden()); |
| 6008 | |
| 6009 | std::string show_script = |
| 6010 | "document.querySelector('iframe').style.visibility = 'visible';"; |
| 6011 | std::string hide_script = |
| 6012 | "document.querySelector('iframe').style.visibility = 'hidden';"; |
| 6013 | |
| 6014 | // Verify that hiding leads to a notification from RenderWidgetHost. |
| 6015 | RenderWidgetHostVisibilityObserver hide_observer( |
| 6016 | root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), false); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6017 | EXPECT_TRUE(ExecuteScript(shell(), hide_script)); |
ekaramad | babb9bf | 2016-01-12 15:17:02 | [diff] [blame] | 6018 | EXPECT_TRUE(hide_observer.WaitUntilSatisfied()); |
| 6019 | |
| 6020 | // Verify showing leads to a notification as well. |
| 6021 | RenderWidgetHostVisibilityObserver show_observer( |
| 6022 | root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), true); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6023 | EXPECT_TRUE(ExecuteScript(shell(), show_script)); |
ekaramad | babb9bf | 2016-01-12 15:17:02 | [diff] [blame] | 6024 | EXPECT_TRUE(show_observer.WaitUntilSatisfied()); |
| 6025 | } |
| 6026 | |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 6027 | // Verify that sandbox flags inheritance works across multiple levels of |
| 6028 | // frames. See https://crbug.com/576845. |
| 6029 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsInheritance) { |
| 6030 | GURL main_url(embedded_test_server()->GetURL( |
| 6031 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 6032 | NavigateToURL(shell(), main_url); |
| 6033 | |
| 6034 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6035 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 6036 | |
| 6037 | // Set sandbox flags for child frame. |
| 6038 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6039 | root, "document.querySelector('iframe').sandbox = 'allow-scripts';")); |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 6040 | |
| 6041 | // Calculate expected flags. Note that "allow-scripts" resets both |
| 6042 | // WebSandboxFlags::Scripts and WebSandboxFlags::AutomaticFeatures bits per |
| 6043 | // blink::parseSandboxPolicy(). |
| 6044 | blink::WebSandboxFlags expected_flags = |
| 6045 | blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts & |
| 6046 | ~blink::WebSandboxFlags::AutomaticFeatures; |
| 6047 | EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags()); |
| 6048 | EXPECT_EQ(blink::WebSandboxFlags::None, |
| 6049 | root->child_at(0)->effective_sandbox_flags()); |
| 6050 | |
| 6051 | // Navigate child frame so that the sandbox flags take effect. Use a page |
| 6052 | // with three levels of frames and make sure all frames properly inherit |
| 6053 | // sandbox flags. |
| 6054 | GURL frame_url(embedded_test_server()->GetURL( |
| 6055 | "b.com", "/cross_site_iframe_factory.html?b(c(d))")); |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 6056 | NavigateFrameToURL(root->child_at(0), frame_url); |
nasko | 8206fa1 | 2016-03-22 02:24:13 | [diff] [blame] | 6057 | |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 6058 | // Wait for subframes to load as well. |
| 6059 | ASSERT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| 6060 | |
| 6061 | // Check each new frame's sandbox flags on the browser process side. |
| 6062 | FrameTreeNode* b_child = root->child_at(0); |
| 6063 | FrameTreeNode* c_child = b_child->child_at(0); |
| 6064 | FrameTreeNode* d_child = c_child->child_at(0); |
| 6065 | EXPECT_EQ(expected_flags, b_child->effective_sandbox_flags()); |
| 6066 | EXPECT_EQ(expected_flags, c_child->effective_sandbox_flags()); |
| 6067 | EXPECT_EQ(expected_flags, d_child->effective_sandbox_flags()); |
| 6068 | |
| 6069 | // Check whether each frame is sandboxed on the renderer side, by seeing if |
| 6070 | // each frame's origin is unique ("null"). |
| 6071 | EXPECT_EQ("null", GetDocumentOrigin(b_child)); |
| 6072 | EXPECT_EQ("null", GetDocumentOrigin(c_child)); |
| 6073 | EXPECT_EQ("null", GetDocumentOrigin(d_child)); |
| 6074 | } |
| 6075 | |
| 6076 | // Check that sandbox flags are not inherited before they take effect. Create |
| 6077 | // a child frame, update its sandbox flags but don't navigate the frame, and |
| 6078 | // ensure that a new cross-site grandchild frame doesn't inherit the new flags |
| 6079 | // (which shouldn't have taken effect). |
| 6080 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6081 | SandboxFlagsNotInheritedBeforeNavigation) { |
| 6082 | GURL main_url(embedded_test_server()->GetURL( |
| 6083 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 6084 | NavigateToURL(shell(), main_url); |
| 6085 | |
| 6086 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6087 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 6088 | |
| 6089 | // Set sandbox flags for child frame. |
| 6090 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6091 | root, "document.querySelector('iframe').sandbox = 'allow-scripts';")); |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 6092 | |
| 6093 | // These flags should be pending but not take effect, since there's been no |
| 6094 | // navigation. |
| 6095 | blink::WebSandboxFlags expected_flags = |
| 6096 | blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts & |
| 6097 | ~blink::WebSandboxFlags::AutomaticFeatures; |
| 6098 | FrameTreeNode* child = root->child_at(0); |
| 6099 | EXPECT_EQ(expected_flags, child->pending_sandbox_flags()); |
| 6100 | EXPECT_EQ(blink::WebSandboxFlags::None, child->effective_sandbox_flags()); |
| 6101 | |
| 6102 | // Add a new grandchild frame and navigate it cross-site. |
| 6103 | RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1); |
| 6104 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6105 | child, "document.body.appendChild(document.createElement('iframe'));")); |
alexmos | 6e94010 | 2016-01-19 22:47:25 | [diff] [blame] | 6106 | frame_observer.Wait(); |
| 6107 | |
| 6108 | FrameTreeNode* grandchild = child->child_at(0); |
| 6109 | GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 6110 | TestFrameNavigationObserver navigation_observer(grandchild); |
| 6111 | NavigateFrameToURL(grandchild, frame_url); |
| 6112 | navigation_observer.Wait(); |
| 6113 | |
| 6114 | // Since the update flags haven't yet taken effect in its parent, this |
| 6115 | // grandchild frame should not be sandboxed. |
| 6116 | EXPECT_EQ(blink::WebSandboxFlags::None, grandchild->pending_sandbox_flags()); |
| 6117 | EXPECT_EQ(blink::WebSandboxFlags::None, |
| 6118 | grandchild->effective_sandbox_flags()); |
| 6119 | |
| 6120 | // Check that the grandchild frame isn't sandboxed on the renderer side. If |
| 6121 | // sandboxed, its origin would be unique ("null"). |
| 6122 | EXPECT_EQ(frame_url.GetOrigin().spec(), GetDocumentOrigin(grandchild) + "/"); |
| 6123 | } |
| 6124 | |
alexmos | aedfc6f | 2016-01-21 23:57:38 | [diff] [blame] | 6125 | // Verify that popups opened from sandboxed frames inherit sandbox flags from |
| 6126 | // their opener, and that they keep these inherited flags after being navigated |
| 6127 | // cross-site. See https://crbug.com/483584. |
| 6128 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6129 | NewPopupInheritsSandboxFlagsFromOpener) { |
| 6130 | GURL main_url(embedded_test_server()->GetURL( |
| 6131 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 6132 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 6133 | |
| 6134 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6135 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | aedfc6f | 2016-01-21 23:57:38 | [diff] [blame] | 6136 | |
| 6137 | // Set sandbox flags for child frame. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6138 | EXPECT_TRUE(ExecuteScript(root, |
alexmos | aedfc6f | 2016-01-21 23:57:38 | [diff] [blame] | 6139 | "document.querySelector('iframe').sandbox = " |
| 6140 | " 'allow-scripts allow-popups';")); |
| 6141 | |
| 6142 | // Calculate expected flags. Note that "allow-scripts" resets both |
| 6143 | // WebSandboxFlags::Scripts and WebSandboxFlags::AutomaticFeatures bits per |
| 6144 | // blink::parseSandboxPolicy(). |
| 6145 | blink::WebSandboxFlags expected_flags = |
| 6146 | blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts & |
| 6147 | ~blink::WebSandboxFlags::AutomaticFeatures & |
| 6148 | ~blink::WebSandboxFlags::Popups; |
| 6149 | EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags()); |
| 6150 | |
| 6151 | // Navigate child frame cross-site. The sandbox flags should take effect. |
| 6152 | GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 6153 | TestFrameNavigationObserver frame_observer(root->child_at(0)); |
| 6154 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 6155 | frame_observer.Wait(); |
| 6156 | EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags()); |
| 6157 | |
| 6158 | // Verify that they've also taken effect on the renderer side. The sandboxed |
| 6159 | // frame's origin should be unique. |
| 6160 | EXPECT_EQ("null", GetDocumentOrigin(root->child_at(0))); |
| 6161 | |
| 6162 | // Open a popup named "foo" from the sandboxed child frame. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6163 | Shell* foo_shell = |
| 6164 | OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "foo"); |
alexmos | aedfc6f | 2016-01-21 23:57:38 | [diff] [blame] | 6165 | EXPECT_TRUE(foo_shell); |
| 6166 | |
| 6167 | FrameTreeNode* foo_root = |
| 6168 | static_cast<WebContentsImpl*>(foo_shell->web_contents()) |
| 6169 | ->GetFrameTree() |
| 6170 | ->root(); |
| 6171 | |
| 6172 | // Check that the sandbox flags for new popup are correct in the browser |
| 6173 | // process. |
| 6174 | EXPECT_EQ(expected_flags, foo_root->effective_sandbox_flags()); |
| 6175 | |
| 6176 | // The popup's origin should be unique, since it's sandboxed. |
| 6177 | EXPECT_EQ("null", GetDocumentOrigin(foo_root)); |
| 6178 | |
| 6179 | // Navigate the popup cross-site. This should keep the unique origin and the |
| 6180 | // inherited sandbox flags. |
| 6181 | GURL c_url(embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 6182 | TestFrameNavigationObserver popup_observer(foo_root); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6183 | EXPECT_TRUE( |
| 6184 | ExecuteScript(foo_root, "location.href = '" + c_url.spec() + "';")); |
alexmos | aedfc6f | 2016-01-21 23:57:38 | [diff] [blame] | 6185 | popup_observer.Wait(); |
| 6186 | EXPECT_EQ(c_url, foo_shell->web_contents()->GetLastCommittedURL()); |
| 6187 | |
| 6188 | // Confirm that the popup is still sandboxed, both on browser and renderer |
| 6189 | // sides. |
| 6190 | EXPECT_EQ(expected_flags, foo_root->effective_sandbox_flags()); |
| 6191 | EXPECT_EQ("null", GetDocumentOrigin(foo_root)); |
| 6192 | } |
| 6193 | |
| 6194 | // Verify that popups opened from frames sandboxed with the |
| 6195 | // "allow-popups-to-escape-sandbox" directive do *not* inherit sandbox flags |
| 6196 | // from their opener. |
| 6197 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6198 | OpenUnsandboxedPopupFromSandboxedFrame) { |
| 6199 | GURL main_url(embedded_test_server()->GetURL( |
| 6200 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 6201 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 6202 | |
| 6203 | // It is safe to obtain the root frame tree node here, as it doesn't change. |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6204 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | aedfc6f | 2016-01-21 23:57:38 | [diff] [blame] | 6205 | |
| 6206 | // Set sandbox flags for child frame, specifying that popups opened from it |
| 6207 | // should not be sandboxed. |
| 6208 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6209 | root, |
alexmos | aedfc6f | 2016-01-21 23:57:38 | [diff] [blame] | 6210 | "document.querySelector('iframe').sandbox = " |
| 6211 | " 'allow-scripts allow-popups allow-popups-to-escape-sandbox';")); |
| 6212 | |
| 6213 | // Set expected flags for the child frame. Note that "allow-scripts" resets |
| 6214 | // both WebSandboxFlags::Scripts and WebSandboxFlags::AutomaticFeatures bits |
| 6215 | // per blink::parseSandboxPolicy(). |
| 6216 | blink::WebSandboxFlags expected_flags = |
| 6217 | blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts & |
| 6218 | ~blink::WebSandboxFlags::AutomaticFeatures & |
| 6219 | ~blink::WebSandboxFlags::Popups & |
| 6220 | ~blink::WebSandboxFlags::PropagatesToAuxiliaryBrowsingContexts; |
| 6221 | EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags()); |
| 6222 | |
| 6223 | // Navigate child frame cross-site. The sandbox flags should take effect. |
| 6224 | GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 6225 | TestFrameNavigationObserver frame_observer(root->child_at(0)); |
| 6226 | NavigateFrameToURL(root->child_at(0), frame_url); |
| 6227 | frame_observer.Wait(); |
| 6228 | EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags()); |
| 6229 | |
| 6230 | // Open a cross-site popup named "foo" from the child frame. |
| 6231 | GURL b_url(embedded_test_server()->GetURL("c.com", "/title1.html")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6232 | Shell* foo_shell = OpenPopup(root->child_at(0), b_url, "foo"); |
alexmos | aedfc6f | 2016-01-21 23:57:38 | [diff] [blame] | 6233 | EXPECT_TRUE(foo_shell); |
| 6234 | |
| 6235 | FrameTreeNode* foo_root = |
| 6236 | static_cast<WebContentsImpl*>(foo_shell->web_contents()) |
| 6237 | ->GetFrameTree() |
| 6238 | ->root(); |
| 6239 | |
| 6240 | // Check that the sandbox flags for new popup are correct in the browser |
| 6241 | // process. They should not have been inherited. |
| 6242 | EXPECT_EQ(blink::WebSandboxFlags::None, foo_root->effective_sandbox_flags()); |
| 6243 | |
| 6244 | // The popup's origin should match |b_url|, since it's not sandboxed. |
| 6245 | std::string popup_origin; |
| 6246 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6247 | foo_root, "domAutomationController.send(document.origin)", |
alexmos | aedfc6f | 2016-01-21 23:57:38 | [diff] [blame] | 6248 | &popup_origin)); |
| 6249 | EXPECT_EQ(b_url.GetOrigin().spec(), popup_origin + "/"); |
| 6250 | } |
| 6251 | |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 6252 | // Tests that the WebContents is notified when passive mixed content is |
| 6253 | // displayed in an OOPIF. The test ignores cert errors so that an HTTPS |
| 6254 | // iframe can be loaded from a site other than localhost (the |
| 6255 | // EmbeddedTestServer serves a certificate that is valid for localhost). |
glider | ad70d3f6 | 2016-04-06 09:41:39 | [diff] [blame] | 6256 | // This test crashes on Windows under Dr. Memory, see https://crbug.com/600942. |
| 6257 | #if defined(OS_WIN) |
| 6258 | #define MAYBE_PassiveMixedContentInIframe DISABLED_PassiveMixedContentInIframe |
| 6259 | #else |
| 6260 | #define MAYBE_PassiveMixedContentInIframe PassiveMixedContentInIframe |
| 6261 | #endif |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 6262 | IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, |
glider | ad70d3f6 | 2016-04-06 09:41:39 | [diff] [blame] | 6263 | MAYBE_PassiveMixedContentInIframe) { |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 6264 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 6265 | https_server.ServeFilesFromSourceDirectory("content/test/data"); |
| 6266 | ASSERT_TRUE(https_server.Start()); |
| 6267 | SetupCrossSiteRedirector(&https_server); |
| 6268 | |
| 6269 | GURL iframe_url( |
| 6270 | https_server.GetURL("/mixed-content/basic-passive-in-iframe.html")); |
| 6271 | EXPECT_TRUE(NavigateToURL(shell(), iframe_url)); |
| 6272 | EXPECT_TRUE(shell()->web_contents()->DisplayedInsecureContent()); |
| 6273 | |
| 6274 | // When the subframe navigates, the WebContents should still be marked |
| 6275 | // as having displayed insecure content. |
| 6276 | GURL navigate_url(https_server.GetURL("/title1.html")); |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6277 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 6278 | NavigateFrameToURL(root->child_at(0), navigate_url); |
| 6279 | EXPECT_TRUE(shell()->web_contents()->DisplayedInsecureContent()); |
| 6280 | |
| 6281 | // When the main frame navigates, it should no longer be marked as |
| 6282 | // displaying insecure content. |
| 6283 | EXPECT_TRUE( |
| 6284 | NavigateToURL(shell(), https_server.GetURL("b.com", "/title1.html"))); |
| 6285 | EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent()); |
| 6286 | } |
| 6287 | |
| 6288 | // Tests that, when a parent frame is set to strictly block mixed |
| 6289 | // content via Content Security Policy, child OOPIFs cannot display |
| 6290 | // mixed content. |
| 6291 | IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, |
| 6292 | PassiveMixedContentInIframeWithStrictBlocking) { |
| 6293 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 6294 | https_server.ServeFilesFromSourceDirectory("content/test/data"); |
| 6295 | ASSERT_TRUE(https_server.Start()); |
| 6296 | SetupCrossSiteRedirector(&https_server); |
| 6297 | |
| 6298 | GURL iframe_url_with_strict_blocking(https_server.GetURL( |
| 6299 | "/mixed-content/basic-passive-in-iframe-with-strict-blocking.html")); |
| 6300 | EXPECT_TRUE(NavigateToURL(shell(), iframe_url_with_strict_blocking)); |
| 6301 | EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent()); |
| 6302 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6303 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
mkwst | f672e7ef | 2016-06-09 20:51:07 | [diff] [blame] | 6304 | EXPECT_EQ(blink::kBlockAllMixedContent, |
| 6305 | root->current_replication_state().insecure_request_policy); |
| 6306 | EXPECT_EQ( |
| 6307 | blink::kBlockAllMixedContent, |
| 6308 | root->child_at(0)->current_replication_state().insecure_request_policy); |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 6309 | |
| 6310 | // When the subframe navigates, it should still be marked as enforcing |
| 6311 | // strict mixed content. |
| 6312 | GURL navigate_url(https_server.GetURL("/title1.html")); |
| 6313 | NavigateFrameToURL(root->child_at(0), navigate_url); |
mkwst | f672e7ef | 2016-06-09 20:51:07 | [diff] [blame] | 6314 | EXPECT_EQ(blink::kBlockAllMixedContent, |
| 6315 | root->current_replication_state().insecure_request_policy); |
| 6316 | EXPECT_EQ( |
| 6317 | blink::kBlockAllMixedContent, |
| 6318 | root->child_at(0)->current_replication_state().insecure_request_policy); |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 6319 | |
| 6320 | // When the main frame navigates, it should no longer be marked as |
| 6321 | // enforcing strict mixed content. |
| 6322 | EXPECT_TRUE( |
| 6323 | NavigateToURL(shell(), https_server.GetURL("b.com", "/title1.html"))); |
mkwst | f672e7ef | 2016-06-09 20:51:07 | [diff] [blame] | 6324 | EXPECT_EQ(blink::kLeaveInsecureRequestsAlone, |
| 6325 | root->current_replication_state().insecure_request_policy); |
| 6326 | } |
| 6327 | |
| 6328 | // Tests that, when a parent frame is set to upgrade insecure requests |
| 6329 | // via Content Security Policy, child OOPIFs will upgrade as well. |
| 6330 | IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, |
| 6331 | PassiveMixedContentInIframeWithUpgrade) { |
| 6332 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 6333 | https_server.ServeFilesFromSourceDirectory("content/test/data"); |
| 6334 | ASSERT_TRUE(https_server.Start()); |
| 6335 | SetupCrossSiteRedirector(&https_server); |
| 6336 | |
| 6337 | GURL iframe_url_with_upgrade(https_server.GetURL( |
| 6338 | "/mixed-content/basic-passive-in-iframe-with-upgrade.html")); |
| 6339 | EXPECT_TRUE(NavigateToURL(shell(), iframe_url_with_upgrade)); |
| 6340 | EXPECT_FALSE(shell()->web_contents()->DisplayedInsecureContent()); |
| 6341 | |
| 6342 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 6343 | EXPECT_EQ(blink::kUpgradeInsecureRequests, |
| 6344 | root->current_replication_state().insecure_request_policy); |
| 6345 | EXPECT_EQ( |
| 6346 | blink::kUpgradeInsecureRequests, |
| 6347 | root->child_at(0)->current_replication_state().insecure_request_policy); |
| 6348 | |
| 6349 | // When the subframe navigates, it should still be marked as upgrading |
| 6350 | // insecure requests. |
| 6351 | GURL navigate_url(https_server.GetURL("/title1.html")); |
| 6352 | NavigateFrameToURL(root->child_at(0), navigate_url); |
| 6353 | EXPECT_EQ(blink::kUpgradeInsecureRequests, |
| 6354 | root->current_replication_state().insecure_request_policy); |
| 6355 | EXPECT_EQ( |
| 6356 | blink::kUpgradeInsecureRequests, |
| 6357 | root->child_at(0)->current_replication_state().insecure_request_policy); |
| 6358 | |
| 6359 | // When the main frame navigates, it should no longer be marked as |
| 6360 | // upgrading insecure requests. |
| 6361 | EXPECT_TRUE( |
| 6362 | NavigateToURL(shell(), https_server.GetURL("b.com", "/title1.html"))); |
| 6363 | EXPECT_EQ(blink::kLeaveInsecureRequestsAlone, |
| 6364 | root->current_replication_state().insecure_request_policy); |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 6365 | } |
| 6366 | |
| 6367 | // Tests that active mixed content is blocked in an OOPIF. The test |
| 6368 | // ignores cert errors so that an HTTPS iframe can be loaded from a site |
| 6369 | // other than localhost (the EmbeddedTestServer serves a certificate |
| 6370 | // that is valid for localhost). |
| 6371 | IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, |
| 6372 | ActiveMixedContentInIframe) { |
| 6373 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 6374 | https_server.ServeFilesFromSourceDirectory("content/test/data"); |
| 6375 | ASSERT_TRUE(https_server.Start()); |
| 6376 | SetupCrossSiteRedirector(&https_server); |
| 6377 | |
| 6378 | GURL iframe_url( |
| 6379 | https_server.GetURL("/mixed-content/basic-active-in-iframe.html")); |
| 6380 | EXPECT_TRUE(NavigateToURL(shell(), iframe_url)); |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6381 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 6382 | ASSERT_EQ(1U, root->child_count()); |
| 6383 | FrameTreeNode* mixed_child = root->child_at(0)->child_at(0); |
| 6384 | ASSERT_TRUE(mixed_child); |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6385 | // The child iframe attempted to create a mixed iframe; this should |
| 6386 | // have been blocked, so the mixed iframe should not have committed a |
| 6387 | // load. |
| 6388 | EXPECT_FALSE(mixed_child->has_committed_real_load()); |
estark | 56dc8e2 | 2016-01-26 17:58:29 | [diff] [blame] | 6389 | } |
| 6390 | |
estark | aeda142 | 2016-05-10 02:31:12 | [diff] [blame] | 6391 | // Test that subresources with certificate errors that are redundant |
| 6392 | // with the main page do not get reported to the browser. That is, if |
| 6393 | // https://redundant.test frames https://a.com which frames |
| 6394 | // https://redundant.test which loads an image with certificate errors, |
| 6395 | // the browser doesn't care and doesn't need to know about the image's |
| 6396 | // certificate errors because they are redundant with the main page |
| 6397 | // load. |
| 6398 | IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, |
| 6399 | SubresourceWithRedundantCertificateErrors) { |
| 6400 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 6401 | https_server.ServeFilesFromSourceDirectory("content/test/data"); |
| 6402 | ASSERT_TRUE(https_server.Start()); |
| 6403 | SetupCrossSiteRedirector(&https_server); |
| 6404 | |
| 6405 | GURL url(https_server.GetURL( |
| 6406 | "redundant.test", "/mixed-content/redundant-cert-error-in-iframe.html")); |
| 6407 | EXPECT_TRUE(NavigateToURL(shell(), url)); |
| 6408 | |
| 6409 | NavigationEntry* entry = |
| 6410 | shell()->web_contents()->GetController().GetLastCommittedEntry(); |
| 6411 | ASSERT_TRUE(entry); |
| 6412 | |
| 6413 | // The main page was loaded with certificate errors. |
| 6414 | EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, |
| 6415 | entry->GetSSL().security_style); |
| 6416 | |
| 6417 | // The image that the iframe loaded had certificate errors also, but |
| 6418 | // they were redundant with the main resource, so the page should not |
| 6419 | // be marked as displaying insecure content. |
| 6420 | EXPECT_FALSE(entry->GetSSL().content_status & |
| 6421 | SSLStatus::DISPLAYED_INSECURE_CONTENT); |
| 6422 | } |
| 6423 | |
| 6424 | // Test that subresources with certificate errors that are NOT redundant |
| 6425 | // with the main page DO get reported to the browser. That is, if |
| 6426 | // https://nonredundant.test frames https://a.com which loads an image |
| 6427 | // with certificate errors, the browser should be notified about the |
| 6428 | // subresource with certificate errors and downgrade the UI |
| 6429 | // appropriately. |
| 6430 | IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, |
| 6431 | SubresourceWithNonRedundantCertificateErrors) { |
| 6432 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 6433 | https_server.ServeFilesFromSourceDirectory("content/test/data"); |
| 6434 | ASSERT_TRUE(https_server.Start()); |
| 6435 | SetupCrossSiteRedirector(&https_server); |
| 6436 | |
| 6437 | GURL url(https_server.GetURL( |
| 6438 | "nonredundant.test", |
| 6439 | "/mixed-content/non-redundant-cert-error-in-iframe.html")); |
| 6440 | EXPECT_TRUE(NavigateToURL(shell(), url)); |
| 6441 | |
| 6442 | NavigationEntry* entry = |
| 6443 | shell()->web_contents()->GetController().GetLastCommittedEntry(); |
| 6444 | ASSERT_TRUE(entry); |
| 6445 | |
| 6446 | // The main page was loaded with certificate errors. |
| 6447 | EXPECT_EQ(SECURITY_STYLE_AUTHENTICATION_BROKEN, |
| 6448 | entry->GetSSL().security_style); |
| 6449 | |
| 6450 | // The image that the iframe loaded had certificate errors also, and |
| 6451 | // they were different than the certificate errors of the main |
| 6452 | // resource, so the page should be marked as having displayed insecure |
| 6453 | // content. |
| 6454 | EXPECT_TRUE(entry->GetSSL().content_status & |
| 6455 | SSLStatus::DISPLAYED_INSECURE_CONTENT); |
| 6456 | } |
| 6457 | |
lfg | 43e08e6 | 2016-02-03 18:51:37 | [diff] [blame] | 6458 | // Test setting a cross-origin iframe to display: none. |
| 6459 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframeDisplayNone) { |
| 6460 | GURL main_url(embedded_test_server()->GetURL( |
| 6461 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 6462 | NavigateToURL(shell(), main_url); |
| 6463 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6464 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
lfg | 43e08e6 | 2016-02-03 18:51:37 | [diff] [blame] | 6465 | RenderWidgetHost* root_render_widget_host = |
| 6466 | root->current_frame_host()->GetRenderWidgetHost(); |
| 6467 | |
| 6468 | // Set the iframe to display: none. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6469 | EXPECT_TRUE(ExecuteScript( |
| 6470 | shell(), "document.querySelector('iframe').style.display = 'none'")); |
lfg | 43e08e6 | 2016-02-03 18:51:37 | [diff] [blame] | 6471 | |
| 6472 | // Waits until pending frames are done. |
dcheng | 5971627 | 2016-04-09 05:19:08 | [diff] [blame] | 6473 | std::unique_ptr<MainThreadFrameObserver> observer( |
lfg | 43e08e6 | 2016-02-03 18:51:37 | [diff] [blame] | 6474 | new MainThreadFrameObserver(root_render_widget_host)); |
| 6475 | observer->Wait(); |
| 6476 | |
| 6477 | // Force the renderer to generate a new frame. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6478 | EXPECT_TRUE( |
| 6479 | ExecuteScript(shell(), "document.body.style.background = 'black'")); |
lfg | 43e08e6 | 2016-02-03 18:51:37 | [diff] [blame] | 6480 | |
| 6481 | // Waits for the next frame. |
| 6482 | observer->Wait(); |
| 6483 | } |
| 6484 | |
alexmos | 4170f6e8 | 2016-03-03 22:42:04 | [diff] [blame] | 6485 | // Test that a cross-origin iframe can be blocked by X-Frame-Options and CSP |
| 6486 | // frame-ancestors. |
| 6487 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6488 | CrossSiteIframeBlockedByXFrameOptionsOrCSP) { |
| 6489 | GURL main_url(embedded_test_server()->GetURL( |
| 6490 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 6491 | NavigateToURL(shell(), main_url); |
| 6492 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6493 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
alexmos | 4170f6e8 | 2016-03-03 22:42:04 | [diff] [blame] | 6494 | |
| 6495 | // Add a load event handler for the iframe element. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6496 | EXPECT_TRUE(ExecuteScript(shell(), |
alexmos | 4170f6e8 | 2016-03-03 22:42:04 | [diff] [blame] | 6497 | "document.querySelector('iframe').onload = " |
| 6498 | " function() { document.title = 'loaded'; };")); |
| 6499 | |
| 6500 | GURL blocked_urls[] = { |
| 6501 | embedded_test_server()->GetURL("b.com", "/frame-ancestors-none.html"), |
| 6502 | embedded_test_server()->GetURL("b.com", "/x-frame-options-deny.html") |
| 6503 | }; |
| 6504 | |
| 6505 | for (size_t i = 0; i < arraysize(blocked_urls); ++i) { |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6506 | EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';")); |
alexmos | 4170f6e8 | 2016-03-03 22:42:04 | [diff] [blame] | 6507 | base::string16 expected_title(base::UTF8ToUTF16("loaded")); |
| 6508 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| 6509 | |
| 6510 | // Navigate the subframe to a blocked URL. |
| 6511 | TestNavigationObserver load_observer(shell()->web_contents()); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6512 | EXPECT_TRUE(ExecuteScript(shell(), "frames[0].location.href = '" + |
| 6513 | blocked_urls[i].spec() + "';")); |
alexmos | 4170f6e8 | 2016-03-03 22:42:04 | [diff] [blame] | 6514 | load_observer.Wait(); |
| 6515 | |
| 6516 | // The blocked frame's origin should become unique. |
| 6517 | EXPECT_EQ("null", root->child_at(0)->current_origin().Serialize()); |
| 6518 | |
alexmos | 30535f7 | 2016-06-23 18:48:23 | [diff] [blame] | 6519 | // Ensure that we don't use the blocked URL as the blocked frame's last |
| 6520 | // committed URL (see https://crbug.com/622385). |
| 6521 | EXPECT_NE(root->child_at(0)->current_frame_host()->GetLastCommittedURL(), |
| 6522 | blocked_urls[i]); |
| 6523 | |
alexmos | 4170f6e8 | 2016-03-03 22:42:04 | [diff] [blame] | 6524 | // The blocked frame should still fire a load event in its parent's process. |
| 6525 | EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 6526 | |
| 6527 | // Check that the current RenderFrameHost has stopped loading. |
| 6528 | EXPECT_FALSE(root->child_at(0)->current_frame_host()->is_loading()); |
| 6529 | |
| 6530 | // The blocked navigation should behave like an empty 200 response. Make |
| 6531 | // sure that the frame's document.title is empty: this double-checks both |
| 6532 | // that the blocked URL's contents wasn't loaded, and that the old page |
| 6533 | // isn't active anymore (both of these pages have non-empty titles). |
| 6534 | std::string frame_title; |
| 6535 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6536 | root->child_at(0), "domAutomationController.send(document.title)", |
| 6537 | &frame_title)); |
alexmos | 4170f6e8 | 2016-03-03 22:42:04 | [diff] [blame] | 6538 | EXPECT_EQ("", frame_title); |
| 6539 | |
| 6540 | // Navigate the subframe to another cross-origin page and ensure that this |
| 6541 | // navigation succeeds. Use a renderer-initiated navigation to test the |
| 6542 | // transfer logic, which used to have some issues with this. |
| 6543 | GURL c_url(embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 6544 | EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "child-0", c_url)); |
| 6545 | EXPECT_EQ(c_url, root->child_at(0)->current_url()); |
| 6546 | |
| 6547 | // When a page gets blocked due to XFO or CSP, it is sandboxed with the |
| 6548 | // SandboxOrigin flag (i.e., its origin is set to be unique) to ensure that |
| 6549 | // the blocked page is seen as cross-origin. However, those flags shouldn't |
| 6550 | // affect future navigations for a frame. Verify this for the above |
| 6551 | // navigation. |
| 6552 | EXPECT_EQ(c_url.GetOrigin().spec(), |
| 6553 | root->child_at(0)->current_origin().Serialize() + "/"); |
| 6554 | EXPECT_EQ(blink::WebSandboxFlags::None, |
| 6555 | root->child_at(0)->effective_sandbox_flags()); |
| 6556 | } |
| 6557 | } |
| 6558 | |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6559 | // Test that a cross-origin frame's navigation can be blocked by CSP frame-src. |
| 6560 | // In this version of a test, CSP comes from HTTP headers. |
| 6561 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6562 | CrossSiteIframeBlockedByParentCSPFromHeaders) { |
| 6563 | GURL main_url( |
| 6564 | embedded_test_server()->GetURL("a.com", "/frame-src-self-and-b.html")); |
| 6565 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 6566 | |
| 6567 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 6568 | |
| 6569 | // Sanity-check that the test page has the expected shape for testing. |
| 6570 | GURL old_subframe_url( |
| 6571 | embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 6572 | EXPECT_FALSE(root->child_at(0)->HasSameOrigin(*root)); |
| 6573 | EXPECT_EQ(old_subframe_url, root->child_at(0)->current_url()); |
| 6574 | const std::vector<ContentSecurityPolicyHeader>& root_csp = |
| 6575 | root->current_replication_state().accumulated_csp_headers; |
| 6576 | EXPECT_EQ(1u, root_csp.size()); |
| 6577 | EXPECT_EQ("frame-src 'self' http://b.com:*", root_csp[0].header_value); |
| 6578 | |
| 6579 | // Monitor subframe's load events via main frame's title. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6580 | EXPECT_TRUE(ExecuteScript(shell(), |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6581 | "document.querySelector('iframe').onload = " |
| 6582 | " function() { document.title = 'loaded'; };")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6583 | EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';")); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6584 | base::string16 expected_title(base::UTF8ToUTF16("loaded")); |
| 6585 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| 6586 | |
| 6587 | // Try to navigate the subframe to a blocked URL. |
| 6588 | TestNavigationObserver load_observer(shell()->web_contents()); |
| 6589 | GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html"); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6590 | EXPECT_TRUE(ExecuteScript(root->child_at(0), "window.location.href = '" + |
| 6591 | blocked_url.spec() + "';")); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6592 | |
| 6593 | // The blocked frame should still fire a load event in its parent's process. |
| 6594 | EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 6595 | |
| 6596 | // Check that the current RenderFrameHost has stopped loading. |
| 6597 | if (root->child_at(0)->current_frame_host()->is_loading()) { |
| 6598 | ADD_FAILURE() << "Blocked RenderFrameHost shouldn't be loading anything"; |
| 6599 | load_observer.Wait(); |
| 6600 | } |
| 6601 | |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6602 | // The blocked frame should stay at the old location. |
| 6603 | EXPECT_EQ(old_subframe_url, root->child_at(0)->current_url()); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6604 | |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6605 | // The blocked frame should keep the old title. |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6606 | std::string frame_title; |
| 6607 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6608 | root->child_at(0), "domAutomationController.send(document.title)", |
| 6609 | &frame_title)); |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6610 | EXPECT_EQ("Title Of Awesomeness", frame_title); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6611 | |
| 6612 | // Navigate to a URL without CSP. |
| 6613 | EXPECT_TRUE(NavigateToURL( |
| 6614 | shell(), embedded_test_server()->GetURL("a.com", "/title1.html"))); |
| 6615 | |
| 6616 | // Verify that the frame's CSP got correctly reset to an empty set. |
| 6617 | EXPECT_EQ(0u, |
| 6618 | root->current_replication_state().accumulated_csp_headers.size()); |
| 6619 | } |
| 6620 | |
| 6621 | // Test that a cross-origin frame's navigation can be blocked by CSP frame-src. |
| 6622 | // In this version of a test, CSP comes from a <meta> element added after the |
| 6623 | // page has already loaded. |
| 6624 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6625 | CrossSiteIframeBlockedByParentCSPFromMeta) { |
| 6626 | GURL main_url(embedded_test_server()->GetURL( |
| 6627 | "a.com", "/cross_site_iframe_factory.html?a(a)")); |
| 6628 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 6629 | |
| 6630 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 6631 | |
| 6632 | // Navigate the subframe to a location we will disallow in the future. |
| 6633 | GURL old_subframe_url( |
| 6634 | embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 6635 | NavigateFrameToURL(root->child_at(0), old_subframe_url); |
| 6636 | |
| 6637 | // Add frame-src CSP via a new <meta> element. |
| 6638 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6639 | shell(), |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6640 | "var meta = document.createElement('meta');" |
| 6641 | "meta.httpEquiv = 'Content-Security-Policy';" |
| 6642 | "meta.content = 'frame-src https://a.com:*';" |
| 6643 | "document.getElementsByTagName('head')[0].appendChild(meta);")); |
| 6644 | |
| 6645 | // Sanity-check that the test page has the expected shape for testing. |
| 6646 | // (the CSP should not have an effect on the already loaded frames). |
| 6647 | EXPECT_FALSE(root->child_at(0)->HasSameOrigin(*root)); |
| 6648 | EXPECT_EQ(old_subframe_url, root->child_at(0)->current_url()); |
| 6649 | const std::vector<ContentSecurityPolicyHeader>& root_csp = |
| 6650 | root->current_replication_state().accumulated_csp_headers; |
| 6651 | EXPECT_EQ(1u, root_csp.size()); |
| 6652 | EXPECT_EQ("frame-src https://a.com:*", root_csp[0].header_value); |
| 6653 | |
| 6654 | // Monitor subframe's load events via main frame's title. |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6655 | EXPECT_TRUE(ExecuteScript(shell(), |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6656 | "document.querySelector('iframe').onload = " |
| 6657 | " function() { document.title = 'loaded'; };")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6658 | EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';")); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6659 | base::string16 expected_title(base::UTF8ToUTF16("loaded")); |
| 6660 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| 6661 | |
| 6662 | // Try to navigate the subframe to a blocked URL. |
| 6663 | TestNavigationObserver load_observer2(shell()->web_contents()); |
| 6664 | GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html"); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6665 | EXPECT_TRUE(ExecuteScript(root->child_at(0), "window.location.href = '" + |
| 6666 | blocked_url.spec() + "';")); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6667 | |
| 6668 | // The blocked frame should still fire a load event in its parent's process. |
| 6669 | EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 6670 | |
| 6671 | // Check that the current RenderFrameHost has stopped loading. |
| 6672 | if (root->child_at(0)->current_frame_host()->is_loading()) { |
| 6673 | ADD_FAILURE() << "Blocked RenderFrameHost shouldn't be loading anything"; |
| 6674 | load_observer2.Wait(); |
| 6675 | } |
| 6676 | |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6677 | // The blocked frame should stay at the old location. |
| 6678 | EXPECT_EQ(old_subframe_url, root->child_at(0)->current_url()); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6679 | |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6680 | // The blocked frame should keep the old title. |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6681 | std::string frame_title; |
| 6682 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6683 | root->child_at(0), "domAutomationController.send(document.title)", |
| 6684 | &frame_title)); |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6685 | EXPECT_EQ("Title Of Awesomeness", frame_title); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6686 | } |
| 6687 | |
| 6688 | // Test that a cross-origin frame's navigation can be blocked by CSP frame-src. |
| 6689 | // In this version of a test, CSP is inherited by srcdoc iframe from a parent |
| 6690 | // that declared CSP via HTTP headers. Cross-origin frame navigating to a |
| 6691 | // blocked location is a child of the srcdoc iframe. |
| 6692 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6693 | CrossSiteIframeBlockedByCSPInheritedBySrcDocParent) { |
| 6694 | GURL main_url( |
| 6695 | embedded_test_server()->GetURL("a.com", "/frame-src-self-and-b.html")); |
| 6696 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 6697 | |
| 6698 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 6699 | FrameTreeNode* srcdoc_frame = root->child_at(1); |
| 6700 | EXPECT_TRUE(srcdoc_frame != nullptr); |
| 6701 | FrameTreeNode* navigating_frame = srcdoc_frame->child_at(0); |
| 6702 | EXPECT_TRUE(navigating_frame != nullptr); |
| 6703 | |
| 6704 | // Sanity-check that the test page has the expected shape for testing. |
| 6705 | // (the CSP should not have an effect on the already loaded frames). |
| 6706 | GURL old_subframe_url( |
| 6707 | embedded_test_server()->GetURL("b.com", "/title2.html")); |
| 6708 | EXPECT_TRUE(srcdoc_frame->HasSameOrigin(*root)); |
| 6709 | EXPECT_FALSE(srcdoc_frame->HasSameOrigin(*navigating_frame)); |
| 6710 | EXPECT_EQ(old_subframe_url, navigating_frame->current_url()); |
| 6711 | const std::vector<ContentSecurityPolicyHeader>& srcdoc_csp = |
| 6712 | srcdoc_frame->current_replication_state().accumulated_csp_headers; |
| 6713 | EXPECT_EQ(1u, srcdoc_csp.size()); |
| 6714 | EXPECT_EQ("frame-src 'self' http://b.com:*", srcdoc_csp[0].header_value); |
| 6715 | |
| 6716 | // Monitor navigating_frame's load events via srcdoc_frame posting |
| 6717 | // a message to the parent frame. |
| 6718 | EXPECT_TRUE( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6719 | ExecuteScript(root, |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6720 | "window.addEventListener('message', function(event) {" |
| 6721 | " document.title = event.data;" |
| 6722 | "});")); |
| 6723 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6724 | srcdoc_frame, |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6725 | "document.querySelector('iframe').onload = " |
| 6726 | " function() { window.top.postMessage('loaded', '*'); };")); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6727 | EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';")); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6728 | base::string16 expected_title(base::UTF8ToUTF16("loaded")); |
| 6729 | TitleWatcher title_watcher(shell()->web_contents(), expected_title); |
| 6730 | |
| 6731 | // Try to navigate the subframe to a blocked URL. |
| 6732 | TestNavigationObserver load_observer2(shell()->web_contents()); |
| 6733 | GURL blocked_url = embedded_test_server()->GetURL("c.com", "/title3.html"); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6734 | EXPECT_TRUE(ExecuteScript(navigating_frame, "window.location.href = '" + |
| 6735 | blocked_url.spec() + "';")); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6736 | |
| 6737 | // The blocked frame should still fire a load event in its parent's process. |
| 6738 | EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); |
| 6739 | |
| 6740 | // Check that the current RenderFrameHost has stopped loading. |
| 6741 | if (navigating_frame->current_frame_host()->is_loading()) { |
| 6742 | ADD_FAILURE() << "Blocked RenderFrameHost shouldn't be loading anything"; |
| 6743 | load_observer2.Wait(); |
| 6744 | } |
| 6745 | |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6746 | // The blocked frame should stay at the old location. |
| 6747 | EXPECT_EQ(old_subframe_url, navigating_frame->current_url()); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6748 | |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6749 | // The blocked frame should keep the old title. |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6750 | std::string frame_title; |
| 6751 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6752 | navigating_frame, "domAutomationController.send(document.title)", |
| 6753 | &frame_title)); |
tommycli | 13632cf | 2016-06-13 21:54:19 | [diff] [blame] | 6754 | EXPECT_EQ("Title Of Awesomeness", frame_title); |
lukasza | 8e1c02e4 | 2016-05-17 20:05:10 | [diff] [blame] | 6755 | |
| 6756 | // Navigate the subframe to a URL without CSP. |
| 6757 | NavigateFrameToURL(srcdoc_frame, |
| 6758 | embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 6759 | |
| 6760 | // Verify that the frame's CSP got correctly reset to an empty set. |
| 6761 | EXPECT_EQ( |
| 6762 | 0u, |
| 6763 | srcdoc_frame->current_replication_state().accumulated_csp_headers.size()); |
| 6764 | } |
| 6765 | |
lfg | db5c4ed | 2016-03-04 23:09:07 | [diff] [blame] | 6766 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, ScreenCoordinates) { |
| 6767 | GURL main_url(embedded_test_server()->GetURL( |
| 6768 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 6769 | NavigateToURL(shell(), main_url); |
| 6770 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6771 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
lfg | db5c4ed | 2016-03-04 23:09:07 | [diff] [blame] | 6772 | FrameTreeNode* child = root->child_at(0); |
| 6773 | |
| 6774 | const char* properties[] = {"screenX", "screenY", "outerWidth", |
| 6775 | "outerHeight"}; |
| 6776 | |
| 6777 | for (const char* property : properties) { |
| 6778 | std::string script = "window.domAutomationController.send(window."; |
| 6779 | script += property; |
| 6780 | script += ");"; |
| 6781 | int root_value = 1; |
| 6782 | int child_value = 2; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6783 | EXPECT_TRUE(ExecuteScriptAndExtractInt(root, script.c_str(), &root_value)); |
lfg | db5c4ed | 2016-03-04 23:09:07 | [diff] [blame] | 6784 | |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6785 | EXPECT_TRUE( |
| 6786 | ExecuteScriptAndExtractInt(child, script.c_str(), &child_value)); |
lfg | db5c4ed | 2016-03-04 23:09:07 | [diff] [blame] | 6787 | |
| 6788 | EXPECT_EQ(root_value, child_value); |
| 6789 | } |
| 6790 | } |
| 6791 | |
estark | 693d128 | 2016-03-15 22:41:29 | [diff] [blame] | 6792 | // Tests that the certificate store is updated during a cross-site |
| 6793 | // redirect navigation. (See https://crbug.com/561754.) Ignores |
| 6794 | // certificate errors so that it can use the cross-site redirector to |
| 6795 | // redirect from HTTPS to HTTPS. |
| 6796 | IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest, |
| 6797 | CrossSiteRedirectCertificateStore) { |
| 6798 | net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| 6799 | https_server.ServeFilesFromSourceDirectory("content/test/data"); |
| 6800 | ASSERT_TRUE(https_server.Start()); |
| 6801 | SetupCrossSiteRedirector(&https_server); |
| 6802 | |
| 6803 | ResourceDispatcherHostImpl* rdh = ResourceDispatcherHostImpl::Get(); |
| 6804 | ASSERT_TRUE(rdh); |
| 6805 | MockCertStore mock_cert_store; |
| 6806 | rdh->cert_store_for_testing_ = &mock_cert_store; |
| 6807 | |
| 6808 | // First, navigate to an |https_server| URL to ensure that the site |
| 6809 | // instance is assigned a site. This will force a renderer transfer to |
| 6810 | // happen on the following navigation that redirects to a different |
| 6811 | // site. |
| 6812 | GURL url(https_server.GetURL("/title1.html")); |
| 6813 | EXPECT_TRUE(NavigateToURL(shell(), url)); |
| 6814 | int original_process_id = |
| 6815 | shell()->web_contents()->GetRenderProcessHost()->GetID(); |
| 6816 | |
| 6817 | url = https_server.GetURL("/cross-site/a.test/title1.html"); |
| 6818 | // NavigateToURL() returns false because the committed URL doesn't |
| 6819 | // match |url| (because it redirected). |
| 6820 | EXPECT_FALSE(NavigateToURL(shell(), url)); |
| 6821 | EXPECT_TRUE(IsLastCommittedEntryOfPageType(shell()->web_contents(), |
| 6822 | PAGE_TYPE_NORMAL)); |
| 6823 | int new_process_id = shell()->web_contents()->GetRenderProcessHost()->GetID(); |
| 6824 | |
| 6825 | // Test that the mock certificate store saw the certificate associated with |
| 6826 | // the new renderer process. |
| 6827 | EXPECT_NE(original_process_id, new_process_id); |
| 6828 | scoped_refptr<net::X509Certificate> original_cert; |
| 6829 | scoped_refptr<net::X509Certificate> transfer_cert; |
| 6830 | ASSERT_TRUE( |
| 6831 | mock_cert_store.RetrieveCert(original_process_id, &original_cert)); |
| 6832 | ASSERT_TRUE(mock_cert_store.RetrieveCert(new_process_id, &transfer_cert)); |
| 6833 | EXPECT_TRUE(https_server.GetCertificate()->Equals(original_cert.get())); |
| 6834 | EXPECT_TRUE(https_server.GetCertificate()->Equals(transfer_cert.get())); |
| 6835 | // Test that the final cert id stored in the navigation entry is the |
| 6836 | // cert id corresponding to the second renderer process. |
| 6837 | EXPECT_EQ(new_process_id, shell() |
| 6838 | ->web_contents() |
| 6839 | ->GetController() |
| 6840 | .GetVisibleEntry() |
| 6841 | ->GetSSL() |
| 6842 | .cert_id); |
| 6843 | } |
| 6844 | |
nasko | 7ecc9a6 | 2016-03-17 00:22:22 | [diff] [blame] | 6845 | // Tests that the swapped out state on RenderViewHost is properly reset when |
| 6846 | // the main frame is navigated to the same SiteInstance as one of its child |
| 6847 | // frames. |
| 6848 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6849 | NavigateMainFrameToChildSite) { |
| 6850 | GURL main_url(embedded_test_server()->GetURL( |
| 6851 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 6852 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 6853 | |
ekaramad | fd1b5cfa | 2016-04-19 00:35:00 | [diff] [blame] | 6854 | WebContentsImpl* contents = web_contents(); |
nasko | 7ecc9a6 | 2016-03-17 00:22:22 | [diff] [blame] | 6855 | FrameTreeNode* root = contents->GetFrameTree()->root(); |
| 6856 | EXPECT_EQ(1U, root->child_count()); |
| 6857 | |
| 6858 | // Ensure the RenderViewHost for the SiteInstance of the child is considered |
| 6859 | // in swapped out state. |
| 6860 | RenderViewHostImpl* rvh = contents->GetFrameTree()->GetRenderViewHost( |
| 6861 | root->child_at(0)->current_frame_host()->GetSiteInstance()); |
| 6862 | EXPECT_TRUE(rvh->is_swapped_out_); |
| 6863 | |
| 6864 | // Have the child frame navigate its parent to its SiteInstance. |
| 6865 | GURL b_url(embedded_test_server()->GetURL("b.com", "/title1.html")); |
| 6866 | std::string script = base::StringPrintf( |
| 6867 | "window.domAutomationController.send(" |
| 6868 | "parent.location = '%s');", |
| 6869 | b_url.spec().c_str()); |
| 6870 | |
| 6871 | TestFrameNavigationObserver frame_observer(root); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 6872 | EXPECT_TRUE(ExecuteScript(root->child_at(0), script)); |
nasko | 7ecc9a6 | 2016-03-17 00:22:22 | [diff] [blame] | 6873 | frame_observer.Wait(); |
| 6874 | EXPECT_EQ(b_url, root->current_url()); |
| 6875 | |
| 6876 | // Verify that the same RenderViewHost is preserved and that it is no longer |
| 6877 | // in swapped out state. |
| 6878 | EXPECT_EQ(rvh, contents->GetFrameTree()->GetRenderViewHost( |
| 6879 | root->current_frame_host()->GetSiteInstance())); |
| 6880 | EXPECT_FALSE(rvh->is_swapped_out_); |
| 6881 | } |
| 6882 | |
alexmos | 9aa6123 | 2016-04-26 21:54:02 | [diff] [blame] | 6883 | // Helper class to wait for a ChildProcessHostMsg_ShutdownRequest message to |
| 6884 | // arrive. |
| 6885 | class ShutdownRequestMessageFilter : public BrowserMessageFilter { |
| 6886 | public: |
| 6887 | ShutdownRequestMessageFilter() |
| 6888 | : BrowserMessageFilter(ChildProcessMsgStart), |
| 6889 | message_loop_runner_(new MessageLoopRunner) {} |
| 6890 | |
| 6891 | bool OnMessageReceived(const IPC::Message& message) override { |
| 6892 | if (message.type() == ChildProcessHostMsg_ShutdownRequest::ID) { |
| 6893 | content::BrowserThread::PostTask( |
| 6894 | content::BrowserThread::UI, FROM_HERE, |
| 6895 | base::Bind(&ShutdownRequestMessageFilter::OnShutdownRequest, this)); |
| 6896 | } |
| 6897 | return false; |
| 6898 | } |
| 6899 | |
| 6900 | void OnShutdownRequest() { message_loop_runner_->Quit(); } |
| 6901 | |
| 6902 | void Wait() { message_loop_runner_->Run(); } |
| 6903 | |
| 6904 | private: |
| 6905 | ~ShutdownRequestMessageFilter() override {} |
| 6906 | |
| 6907 | scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 6908 | |
| 6909 | DISALLOW_COPY_AND_ASSIGN(ShutdownRequestMessageFilter); |
| 6910 | }; |
| 6911 | |
| 6912 | // Test for https://crbug.com/568836. From an A-embed-B page, navigate the |
| 6913 | // subframe from B to A. This cleans up the process for B, but the test delays |
| 6914 | // the browser side from killing the B process right away. This allows the |
| 6915 | // B process to process two ViewMsg_Close messages sent to the subframe's |
| 6916 | // RenderWidget and to the RenderView, in that order. In the bug, the latter |
| 6917 | // crashed while detaching the subframe's LocalFrame (triggered as part of |
| 6918 | // closing the RenderView), because this tried to access the subframe's |
| 6919 | // WebFrameWidget (from RenderFrameImpl::didChangeSelection), which had already |
| 6920 | // been cleared by the former. |
| 6921 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6922 | CloseSubframeWidgetAndViewOnProcessExit) { |
| 6923 | GURL main_url(embedded_test_server()->GetURL( |
| 6924 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 6925 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 6926 | |
| 6927 | FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| 6928 | ->GetFrameTree() |
| 6929 | ->root(); |
| 6930 | |
| 6931 | // "Select all" in the subframe. The bug only happens if there's a selection |
| 6932 | // change, which triggers the path through didChangeSelection. |
| 6933 | root->child_at(0)->current_frame_host()->Send(new InputMsg_SelectAll( |
| 6934 | root->child_at(0)->current_frame_host()->GetRoutingID())); |
| 6935 | |
| 6936 | // Prevent b.com process from terminating right away once the subframe |
| 6937 | // navigates away from b.com below. This is necessary so that the renderer |
| 6938 | // process has time to process the closings of RenderWidget and RenderView, |
| 6939 | // which is where the original bug was triggered. Incrementing worker |
| 6940 | // RefCount will cause RenderProcessHostImpl::Cleanup to forego process |
| 6941 | // termination. |
| 6942 | RenderProcessHost* subframe_process = |
| 6943 | root->child_at(0)->current_frame_host()->GetProcess(); |
| 6944 | subframe_process->IncrementWorkerRefCount(); |
| 6945 | |
| 6946 | // Navigate the subframe away from b.com. Since this is the last active |
| 6947 | // frame in the b.com process, this causes the RenderWidget and RenderView to |
| 6948 | // be closed. If this succeeds without crashing, the renderer will release |
| 6949 | // the process and send a ChildProcessHostMsg_ShutdownRequest to the browser |
| 6950 | // process to ask whether it's ok to terminate. Thus, wait for this message |
| 6951 | // to ensure that the RenderView and widget were closed without crashing. |
| 6952 | scoped_refptr<ShutdownRequestMessageFilter> filter = |
| 6953 | new ShutdownRequestMessageFilter(); |
| 6954 | subframe_process->AddFilter(filter.get()); |
| 6955 | NavigateFrameToURL(root->child_at(0), |
| 6956 | embedded_test_server()->GetURL("a.com", "/title1.html")); |
| 6957 | filter->Wait(); |
| 6958 | |
| 6959 | // TODO(alexmos): Navigating the subframe back to b.com at this point would |
| 6960 | // trigger the race in https://crbug.com/535246, where the browser process |
| 6961 | // tries to reuse the b.com process thinking it's still initialized, whereas |
| 6962 | // the process has actually been destroyed by the renderer (but the browser |
| 6963 | // process hasn't heard the OnChannelError yet). This race will need to be |
| 6964 | // fixed. |
| 6965 | |
| 6966 | subframe_process->DecrementWorkerRefCount(); |
| 6967 | } |
| 6968 | |
kenrb | 1922185 | 2016-04-29 17:21:40 | [diff] [blame] | 6969 | // Tests that an input event targeted to a out-of-process iframe correctly |
| 6970 | // triggers a user interaction notification for WebContentsObservers. |
| 6971 | // This is used for browser features such as download request limiting and |
| 6972 | // launching multiple external protocol handlers, which can block repeated |
| 6973 | // actions from a page when a user is not interacting with the page. |
| 6974 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6975 | UserInteractionForChildFrameTest) { |
| 6976 | GURL main_url(embedded_test_server()->GetURL( |
| 6977 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 6978 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 6979 | |
| 6980 | UserInteractionObserver observer(web_contents()); |
| 6981 | |
| 6982 | // Target an event to the child frame's RenderWidgetHostView. |
| 6983 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 6984 | SimulateMouseClick( |
| 6985 | root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), 5, 5); |
| 6986 | |
| 6987 | EXPECT_TRUE(observer.WasUserInteractionReceived()); |
| 6988 | |
| 6989 | // Target an event to the main frame. |
| 6990 | observer.Reset(); |
| 6991 | SimulateMouseClick(root->current_frame_host()->GetRenderWidgetHost(), 1, 1); |
| 6992 | |
| 6993 | EXPECT_TRUE(observer.WasUserInteractionReceived()); |
| 6994 | } |
| 6995 | |
nasko | 58b07f5 | 2016-05-09 22:38:35 | [diff] [blame] | 6996 | // Ensures that navigating to data: URLs present in session history will |
| 6997 | // correctly commit the navigation in the same process as the parent frame. |
| 6998 | // See https://crbug.com/606996. |
| 6999 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 7000 | NavigateSubframeToDataUrlInSessionHistory) { |
| 7001 | GURL main_url(embedded_test_server()->GetURL( |
| 7002 | "a.com", "/cross_site_iframe_factory.html?a(b,b)")); |
| 7003 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 7004 | |
| 7005 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 7006 | EXPECT_EQ(2U, root->child_count()); |
| 7007 | EXPECT_EQ( |
| 7008 | " Site A ------------ proxies for B\n" |
| 7009 | " |--Site B ------- proxies for A\n" |
| 7010 | " +--Site B ------- proxies for A\n" |
| 7011 | "Where A = http://a.com/\n" |
| 7012 | " B = http://b.com/", |
| 7013 | DepictFrameTree(root)); |
| 7014 | |
| 7015 | TestNavigationObserver observer(shell()->web_contents()); |
| 7016 | FrameTreeNode* child = root->child_at(0); |
| 7017 | |
| 7018 | // Navigate iframe to a data URL, which will commit in a new SiteInstance. |
| 7019 | GURL data_url("data:text/html,dataurl"); |
| 7020 | NavigateFrameToURL(child, data_url); |
| 7021 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 7022 | EXPECT_EQ(data_url, observer.last_navigation_url()); |
| 7023 | scoped_refptr<SiteInstanceImpl> orig_site_instance = |
| 7024 | child->current_frame_host()->GetSiteInstance(); |
| 7025 | EXPECT_NE(root->current_frame_host()->GetSiteInstance(), orig_site_instance); |
| 7026 | |
| 7027 | // Navigate it to another cross-site url. |
| 7028 | GURL cross_site_url(embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 7029 | NavigateFrameToURL(child, cross_site_url); |
| 7030 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 7031 | EXPECT_EQ(cross_site_url, observer.last_navigation_url()); |
| 7032 | EXPECT_EQ(3, web_contents()->GetController().GetEntryCount()); |
| 7033 | EXPECT_NE(orig_site_instance, child->current_frame_host()->GetSiteInstance()); |
| 7034 | |
| 7035 | // Go back and ensure the data: URL committed in the same SiteInstance as the |
| 7036 | // original navigation. |
| 7037 | EXPECT_TRUE(web_contents()->GetController().CanGoBack()); |
| 7038 | TestFrameNavigationObserver frame_observer(child); |
| 7039 | web_contents()->GetController().GoBack(); |
| 7040 | frame_observer.WaitForCommit(); |
| 7041 | EXPECT_EQ(orig_site_instance, child->current_frame_host()->GetSiteInstance()); |
| 7042 | } |
| 7043 | |
| 7044 | // Ensures that navigating to about:blank URLs present in session history will |
| 7045 | // correctly commit the navigation in the same process as the one used for |
| 7046 | // the original navigation. |
| 7047 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 7048 | NavigateSubframeToAboutBlankInSessionHistory) { |
| 7049 | GURL main_url(embedded_test_server()->GetURL( |
| 7050 | "a.com", "/cross_site_iframe_factory.html?a(b,b)")); |
| 7051 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 7052 | |
| 7053 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 7054 | EXPECT_EQ(2U, root->child_count()); |
| 7055 | EXPECT_EQ( |
| 7056 | " Site A ------------ proxies for B\n" |
| 7057 | " |--Site B ------- proxies for A\n" |
| 7058 | " +--Site B ------- proxies for A\n" |
| 7059 | "Where A = http://a.com/\n" |
| 7060 | " B = http://b.com/", |
| 7061 | DepictFrameTree(root)); |
| 7062 | |
| 7063 | TestNavigationObserver observer(shell()->web_contents()); |
| 7064 | FrameTreeNode* child = root->child_at(0); |
| 7065 | |
| 7066 | // Navigate iframe to about:blank, which will commit in a new SiteInstance. |
| 7067 | GURL about_blank_url("about:blank"); |
| 7068 | NavigateFrameToURL(child, about_blank_url); |
| 7069 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 7070 | EXPECT_EQ(about_blank_url, observer.last_navigation_url()); |
| 7071 | scoped_refptr<SiteInstanceImpl> orig_site_instance = |
| 7072 | child->current_frame_host()->GetSiteInstance(); |
| 7073 | EXPECT_NE(root->current_frame_host()->GetSiteInstance(), orig_site_instance); |
| 7074 | |
| 7075 | // Navigate it to another cross-site url. |
| 7076 | GURL cross_site_url(embedded_test_server()->GetURL("c.com", "/title1.html")); |
| 7077 | NavigateFrameToURL(child, cross_site_url); |
| 7078 | EXPECT_TRUE(observer.last_navigation_succeeded()); |
| 7079 | EXPECT_EQ(cross_site_url, observer.last_navigation_url()); |
| 7080 | EXPECT_EQ(3, web_contents()->GetController().GetEntryCount()); |
| 7081 | EXPECT_NE(orig_site_instance, child->current_frame_host()->GetSiteInstance()); |
| 7082 | |
| 7083 | // Go back and ensure the about:blank URL committed in the same SiteInstance |
| 7084 | // as the original navigation. |
| 7085 | EXPECT_TRUE(web_contents()->GetController().CanGoBack()); |
| 7086 | TestFrameNavigationObserver frame_observer(child); |
| 7087 | web_contents()->GetController().GoBack(); |
| 7088 | frame_observer.WaitForCommit(); |
| 7089 | EXPECT_EQ(orig_site_instance, child->current_frame_host()->GetSiteInstance()); |
| 7090 | } |
| 7091 | |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 7092 | // Tests that there are no crashes if a subframe is detached in its unload |
| 7093 | // handler. See https://crbug.com/590054. |
| 7094 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DetachInUnloadHandler) { |
| 7095 | GURL main_url(embedded_test_server()->GetURL( |
| 7096 | "a.com", "/cross_site_iframe_factory.html?a(b(b))")); |
| 7097 | NavigateToURL(shell(), main_url); |
| 7098 | |
| 7099 | FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| 7100 | ->GetFrameTree() |
| 7101 | ->root(); |
| 7102 | |
| 7103 | EXPECT_EQ( |
| 7104 | " Site A ------------ proxies for B\n" |
| 7105 | " +--Site B ------- proxies for A\n" |
| 7106 | " +--Site B -- proxies for A\n" |
| 7107 | "Where A = http://a.com/\n" |
| 7108 | " B = http://b.com/", |
| 7109 | DepictFrameTree(root)); |
| 7110 | |
| 7111 | int child_count = 0; |
| 7112 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7113 | root->child_at(0), "window.domAutomationController.send(frames.length);", |
| 7114 | &child_count)); |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 7115 | EXPECT_EQ(1, child_count); |
| 7116 | |
| 7117 | RenderFrameDeletedObserver deleted_observer( |
| 7118 | root->child_at(0)->child_at(0)->current_frame_host()); |
| 7119 | |
| 7120 | // Add an unload handler to the grandchild that causes it to be synchronously |
| 7121 | // detached, then navigate it. |
| 7122 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7123 | root->child_at(0)->child_at(0), |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 7124 | "window.onunload=function(e){\n" |
| 7125 | " window.parent.document.getElementById('child-0').remove();\n" |
| 7126 | "};\n")); |
| 7127 | std::string script = |
| 7128 | std::string("window.document.getElementById('child-0').src = \"") + |
| 7129 | embedded_test_server() |
| 7130 | ->GetURL("c.com", "/cross_site_iframe_factory.html?c") |
| 7131 | .spec() + |
| 7132 | "\""; |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7133 | EXPECT_TRUE(ExecuteScript(root->child_at(0), script.c_str())); |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 7134 | |
| 7135 | deleted_observer.WaitUntilDeleted(); |
| 7136 | |
| 7137 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7138 | root->child_at(0), "window.domAutomationController.send(frames.length);", |
| 7139 | &child_count)); |
lfg | f2d4f91 | 2016-05-11 23:18:48 | [diff] [blame] | 7140 | EXPECT_EQ(0, child_count); |
| 7141 | |
| 7142 | EXPECT_EQ( |
| 7143 | " Site A ------------ proxies for B\n" |
| 7144 | " +--Site B ------- proxies for A\n" |
| 7145 | "Where A = http://a.com/\n" |
| 7146 | " B = http://b.com/", |
| 7147 | DepictFrameTree(root)); |
| 7148 | } |
| 7149 | |
alexmos | c2a8cec | 2016-05-23 22:19:53 | [diff] [blame] | 7150 | // Helper filter class to wait for a ShowView or ShowWidget message, record the |
| 7151 | // routing ID from the message, and then drop the message. |
| 7152 | class PendingWidgetMessageFilter : public BrowserMessageFilter { |
| 7153 | public: |
| 7154 | PendingWidgetMessageFilter() |
| 7155 | : BrowserMessageFilter(ViewMsgStart), |
| 7156 | routing_id_(MSG_ROUTING_NONE), |
| 7157 | message_loop_runner_(new MessageLoopRunner) {} |
| 7158 | |
| 7159 | bool OnMessageReceived(const IPC::Message& message) override { |
| 7160 | bool handled = true; |
| 7161 | IPC_BEGIN_MESSAGE_MAP(PendingWidgetMessageFilter, message) |
| 7162 | IPC_MESSAGE_HANDLER(ViewHostMsg_ShowView, OnShowView) |
| 7163 | IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget) |
| 7164 | IPC_MESSAGE_UNHANDLED(handled = false) |
| 7165 | IPC_END_MESSAGE_MAP() |
| 7166 | return handled; |
| 7167 | } |
| 7168 | |
| 7169 | void Wait() { |
| 7170 | message_loop_runner_->Run(); |
| 7171 | } |
| 7172 | |
| 7173 | int routing_id() { return routing_id_; } |
| 7174 | |
| 7175 | private: |
| 7176 | ~PendingWidgetMessageFilter() override {} |
| 7177 | |
| 7178 | void OnShowView(int routing_id, |
| 7179 | WindowOpenDisposition disposition, |
| 7180 | const gfx::Rect& initial_rect, |
| 7181 | bool user_gesture) { |
| 7182 | content::BrowserThread::PostTask( |
| 7183 | content::BrowserThread::UI, FROM_HERE, |
| 7184 | base::Bind(&PendingWidgetMessageFilter::OnReceivedRoutingIDOnUI, this, |
| 7185 | routing_id)); |
| 7186 | } |
| 7187 | |
| 7188 | void OnShowWidget(int routing_id, const gfx::Rect& initial_rect) { |
| 7189 | content::BrowserThread::PostTask( |
| 7190 | content::BrowserThread::UI, FROM_HERE, |
| 7191 | base::Bind(&PendingWidgetMessageFilter::OnReceivedRoutingIDOnUI, this, |
| 7192 | routing_id)); |
| 7193 | } |
| 7194 | |
| 7195 | void OnReceivedRoutingIDOnUI(int routing_id) { |
| 7196 | routing_id_ = routing_id; |
| 7197 | message_loop_runner_->Quit(); |
| 7198 | } |
| 7199 | |
| 7200 | int routing_id_; |
| 7201 | scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 7202 | |
| 7203 | DISALLOW_COPY_AND_ASSIGN(PendingWidgetMessageFilter); |
| 7204 | }; |
| 7205 | |
| 7206 | // Test for https://crbug.com/612276. Simultaneously open two new windows from |
| 7207 | // two subframes in different processes, where each subframe process's next |
| 7208 | // routing ID is the same. Make sure that both windows are created properly. |
| 7209 | // |
| 7210 | // Each new window requires two IPCs to first create it (handled by |
| 7211 | // CreateNewWindow) and then show it (ShowCreatedWindow). In the bug, both |
| 7212 | // CreateNewWindow calls arrived before the ShowCreatedWindow calls, resulting |
| 7213 | // in the two pending windows colliding in the pending WebContents map, which |
| 7214 | // used to be keyed only by routing_id. |
| 7215 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 7216 | TwoSubframesCreatePopupsSimultaneously) { |
| 7217 | GURL main_url(embedded_test_server()->GetURL( |
| 7218 | "a.com", "/cross_site_iframe_factory.html?a(b,c)")); |
| 7219 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 7220 | |
| 7221 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 7222 | FrameTreeNode* child1 = root->child_at(0); |
| 7223 | FrameTreeNode* child2 = root->child_at(1); |
| 7224 | RenderProcessHost* process1 = child1->current_frame_host()->GetProcess(); |
| 7225 | RenderProcessHost* process2 = child2->current_frame_host()->GetProcess(); |
| 7226 | |
| 7227 | // Call window.open simultaneously in both subframes to create two popups. |
| 7228 | // Wait for and then drop both ViewHostMsg_ShowView messages. This will |
| 7229 | // ensure that both CreateNewWindow calls happen before either |
| 7230 | // ShowCreatedWindow call. |
| 7231 | scoped_refptr<PendingWidgetMessageFilter> filter1 = |
| 7232 | new PendingWidgetMessageFilter(); |
| 7233 | process1->AddFilter(filter1.get()); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7234 | EXPECT_TRUE(ExecuteScript(child1, "window.open();")); |
alexmos | c2a8cec | 2016-05-23 22:19:53 | [diff] [blame] | 7235 | filter1->Wait(); |
| 7236 | |
| 7237 | scoped_refptr<PendingWidgetMessageFilter> filter2 = |
| 7238 | new PendingWidgetMessageFilter(); |
| 7239 | process2->AddFilter(filter2.get()); |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7240 | EXPECT_TRUE(ExecuteScript(child2, "window.open();")); |
alexmos | c2a8cec | 2016-05-23 22:19:53 | [diff] [blame] | 7241 | filter2->Wait(); |
| 7242 | |
| 7243 | // At this point, we should have two pending WebContents. |
| 7244 | EXPECT_TRUE( |
| 7245 | ContainsKey(web_contents()->pending_contents_, |
| 7246 | std::make_pair(process1->GetID(), filter1->routing_id()))); |
| 7247 | EXPECT_TRUE( |
| 7248 | ContainsKey(web_contents()->pending_contents_, |
| 7249 | std::make_pair(process2->GetID(), filter2->routing_id()))); |
| 7250 | |
| 7251 | // Both subframes were set up in the same way, so the next routing ID for the |
| 7252 | // new popup windows should match up (this led to the collision in the |
| 7253 | // pending contents map in the original bug). |
| 7254 | EXPECT_EQ(filter1->routing_id(), filter2->routing_id()); |
| 7255 | |
| 7256 | // Now, simulate that both ShowView messages arrive by showing both of the |
| 7257 | // pending WebContents. |
| 7258 | web_contents()->ShowCreatedWindow(process1->GetID(), filter1->routing_id(), |
| 7259 | NEW_FOREGROUND_TAB, gfx::Rect(), true); |
| 7260 | web_contents()->ShowCreatedWindow(process2->GetID(), filter2->routing_id(), |
| 7261 | NEW_FOREGROUND_TAB, gfx::Rect(), true); |
| 7262 | |
| 7263 | // Verify that both shells were properly created. |
| 7264 | EXPECT_EQ(3u, Shell::windows().size()); |
| 7265 | } |
| 7266 | |
| 7267 | // Test for https://crbug.com/612276. Similar to |
| 7268 | // TwoSubframesOpenWindowsSimultaneously, but use popup menu widgets instead of |
| 7269 | // windows. |
| 7270 | // |
| 7271 | // The plumbing that this test is verifying is not utilized on Mac/Android, |
| 7272 | // where popup menus don't create a popup RenderWidget, but rather they trigger |
| 7273 | // a FrameHostMsg_ShowPopup to ask the browser to build and display the actual |
| 7274 | // popup using native controls. |
| 7275 | #if !defined(OS_MACOSX) && !defined(OS_ANDROID) |
| 7276 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 7277 | TwoSubframesCreatePopupMenuWidgetsSimultaneously) { |
| 7278 | GURL main_url(embedded_test_server()->GetURL( |
| 7279 | "a.com", "/cross_site_iframe_factory.html?a(b,c)")); |
| 7280 | EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| 7281 | |
| 7282 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 7283 | FrameTreeNode* child1 = root->child_at(0); |
| 7284 | FrameTreeNode* child2 = root->child_at(1); |
| 7285 | RenderProcessHost* process1 = child1->current_frame_host()->GetProcess(); |
| 7286 | RenderProcessHost* process2 = child2->current_frame_host()->GetProcess(); |
| 7287 | |
| 7288 | // Navigate both subframes to a page with a <select> element. |
| 7289 | NavigateFrameToURL(child1, embedded_test_server()->GetURL( |
| 7290 | "b.com", "/site_isolation/page-with-select.html")); |
| 7291 | NavigateFrameToURL(child2, embedded_test_server()->GetURL( |
| 7292 | "c.com", "/site_isolation/page-with-select.html")); |
| 7293 | |
dtapuska | e0f8ed7 | 2016-06-17 08:23:41 | [diff] [blame] | 7294 | // Open both <select> menus by focusing each item and sending a space key |
| 7295 | // at the focused node. This creates a popup widget in both processes. |
alexmos | c2a8cec | 2016-05-23 22:19:53 | [diff] [blame] | 7296 | // Wait for and then drop the ViewHostMsg_ShowWidget messages, so that both |
| 7297 | // widgets are left in pending-but-not-shown state. |
dtapuska | e0f8ed7 | 2016-06-17 08:23:41 | [diff] [blame] | 7298 | NativeWebKeyboardEvent event; |
| 7299 | event.text[0] = ' '; |
| 7300 | event.timeStampSeconds = 100; |
| 7301 | event.type = blink::WebKeyboardEvent::Char; |
| 7302 | |
alexmos | c2a8cec | 2016-05-23 22:19:53 | [diff] [blame] | 7303 | scoped_refptr<PendingWidgetMessageFilter> filter1 = |
| 7304 | new PendingWidgetMessageFilter(); |
| 7305 | process1->AddFilter(filter1.get()); |
dtapuska | e0f8ed7 | 2016-06-17 08:23:41 | [diff] [blame] | 7306 | EXPECT_TRUE(ExecuteScript(child1, "focusSelectMenu();")); |
| 7307 | child1->current_frame_host()->GetRenderWidgetHost()->ForwardKeyboardEvent( |
| 7308 | event); |
alexmos | c2a8cec | 2016-05-23 22:19:53 | [diff] [blame] | 7309 | filter1->Wait(); |
| 7310 | |
| 7311 | scoped_refptr<PendingWidgetMessageFilter> filter2 = |
| 7312 | new PendingWidgetMessageFilter(); |
| 7313 | process2->AddFilter(filter2.get()); |
dtapuska | e0f8ed7 | 2016-06-17 08:23:41 | [diff] [blame] | 7314 | EXPECT_TRUE(ExecuteScript(child2, "focusSelectMenu();")); |
| 7315 | child2->current_frame_host()->GetRenderWidgetHost()->ForwardKeyboardEvent( |
| 7316 | event); |
alexmos | c2a8cec | 2016-05-23 22:19:53 | [diff] [blame] | 7317 | filter2->Wait(); |
| 7318 | |
| 7319 | // At this point, we should have two pending widgets. |
| 7320 | EXPECT_TRUE( |
| 7321 | ContainsKey(web_contents()->pending_widget_views_, |
| 7322 | std::make_pair(process1->GetID(), filter1->routing_id()))); |
| 7323 | EXPECT_TRUE( |
| 7324 | ContainsKey(web_contents()->pending_widget_views_, |
| 7325 | std::make_pair(process2->GetID(), filter2->routing_id()))); |
| 7326 | |
| 7327 | // Both subframes were set up in the same way, so the next routing ID for the |
| 7328 | // new popup widgets should match up (this led to the collision in the |
| 7329 | // pending widgets map in the original bug). |
| 7330 | EXPECT_EQ(filter1->routing_id(), filter2->routing_id()); |
| 7331 | |
| 7332 | // Now simulate both widgets being shown. |
| 7333 | web_contents()->ShowCreatedWidget(process1->GetID(), filter1->routing_id(), |
| 7334 | false, gfx::Rect()); |
| 7335 | web_contents()->ShowCreatedWidget(process2->GetID(), filter2->routing_id(), |
| 7336 | false, gfx::Rect()); |
| 7337 | EXPECT_FALSE( |
| 7338 | ContainsKey(web_contents()->pending_widget_views_, |
| 7339 | std::make_pair(process1->GetID(), filter1->routing_id()))); |
| 7340 | EXPECT_FALSE( |
| 7341 | ContainsKey(web_contents()->pending_widget_views_, |
| 7342 | std::make_pair(process2->GetID(), filter2->routing_id()))); |
| 7343 | } |
| 7344 | #endif |
| 7345 | |
alexmos | 788f45b3 | 2016-05-24 00:57:02 | [diff] [blame] | 7346 | // Check that out-of-process frames correctly calculate their ability to enter |
| 7347 | // fullscreen. A frame is allowed enter fullscreen if the allowFullscreen |
| 7348 | // attribute is present in all of its ancestor <iframe> elements. For OOPIF, |
| 7349 | // when a parent frame changes this attribute, the change is replicated to the |
| 7350 | // child frame and its proxies. |
| 7351 | // |
| 7352 | // The test checks the following cases: |
| 7353 | // |
| 7354 | // 1. Static attribute (<iframe allowfullscreen>) |
| 7355 | // 2. Attribute injected dynamically via JavaScript |
| 7356 | // 3. Multiple levels of nesting (A-embed-B-embed-C) |
| 7357 | // 4. Cross-site subframe navigation |
| 7358 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, AllowFullscreen) { |
| 7359 | // Load a page with a cross-site <iframe allowFullscreen>. |
| 7360 | GURL url_1(embedded_test_server()->GetURL( |
| 7361 | "a.com", "/page_with_allowfullscreen_frame.html")); |
| 7362 | EXPECT_TRUE(NavigateToURL(shell(), url_1)); |
| 7363 | |
| 7364 | WebContentsImpl* contents = web_contents(); |
| 7365 | FrameTreeNode* root = contents->GetFrameTree()->root(); |
| 7366 | |
| 7367 | // Helper to check if a frame is allowed to go fullscreen on the renderer |
| 7368 | // side. |
| 7369 | auto is_fullscreen_allowed = [](FrameTreeNode* ftn) { |
| 7370 | bool fullscreen_allowed = false; |
| 7371 | EXPECT_TRUE(ExecuteScriptAndExtractBool( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7372 | ftn, |
alexmos | 788f45b3 | 2016-05-24 00:57:02 | [diff] [blame] | 7373 | "window.domAutomationController.send(document.webkitFullscreenEnabled)", |
| 7374 | &fullscreen_allowed)); |
| 7375 | return fullscreen_allowed; |
| 7376 | }; |
| 7377 | |
| 7378 | EXPECT_TRUE(is_fullscreen_allowed(root)); |
| 7379 | EXPECT_TRUE(is_fullscreen_allowed(root->child_at(0))); |
| 7380 | EXPECT_TRUE(root->child_at(0)->frame_owner_properties().allowFullscreen); |
| 7381 | |
| 7382 | // Now navigate to a page with two <iframe>'s, both without allowFullscreen. |
| 7383 | GURL url_2(embedded_test_server()->GetURL( |
| 7384 | "a.com", "/cross_site_iframe_factory.html?a(b,c)")); |
| 7385 | EXPECT_TRUE(NavigateToURL(shell(), url_2)); |
| 7386 | EXPECT_FALSE(root->child_at(0)->frame_owner_properties().allowFullscreen); |
| 7387 | EXPECT_FALSE(root->child_at(1)->frame_owner_properties().allowFullscreen); |
| 7388 | |
| 7389 | EXPECT_TRUE(is_fullscreen_allowed(root)); |
| 7390 | EXPECT_FALSE(is_fullscreen_allowed(root->child_at(0))); |
| 7391 | EXPECT_FALSE(is_fullscreen_allowed(root->child_at(1))); |
| 7392 | |
| 7393 | // Dynamically enable fullscreen for first subframe and check that the |
| 7394 | // fullscreen property was updated on the FrameTreeNode. |
| 7395 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7396 | root, "document.getElementById('child-0').allowFullscreen='true'")); |
alexmos | 788f45b3 | 2016-05-24 00:57:02 | [diff] [blame] | 7397 | EXPECT_TRUE(root->child_at(0)->frame_owner_properties().allowFullscreen); |
| 7398 | |
| 7399 | // Check that the first subframe is now allowed to go fullscreen. Other |
| 7400 | // frames shouldn't be affected. |
| 7401 | EXPECT_TRUE(is_fullscreen_allowed(root)); |
| 7402 | EXPECT_TRUE(is_fullscreen_allowed(root->child_at(0))); |
| 7403 | EXPECT_FALSE(is_fullscreen_allowed(root->child_at(1))); |
| 7404 | |
| 7405 | // Now navigate to a page with two levels of nesting. |
| 7406 | GURL url_3(embedded_test_server()->GetURL( |
| 7407 | "a.com", "/cross_site_iframe_factory.html?a(b(c))")); |
| 7408 | EXPECT_TRUE(NavigateToURL(shell(), url_3)); |
| 7409 | |
| 7410 | EXPECT_TRUE(is_fullscreen_allowed(root)); |
| 7411 | EXPECT_FALSE(is_fullscreen_allowed(root->child_at(0))); |
| 7412 | EXPECT_FALSE(is_fullscreen_allowed(root->child_at(0)->child_at(0))); |
| 7413 | |
| 7414 | // Dynamically enable fullscreen for bottom subframe. |
| 7415 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7416 | root->child_at(0), |
alexmos | 788f45b3 | 2016-05-24 00:57:02 | [diff] [blame] | 7417 | "document.getElementById('child-0').allowFullscreen='true'")); |
| 7418 | |
| 7419 | // This still shouldn't allow the bottom child to go fullscreen, since the |
| 7420 | // top frame hasn't allowed fullscreen for the middle frame. |
| 7421 | EXPECT_TRUE(is_fullscreen_allowed(root)); |
| 7422 | EXPECT_FALSE(is_fullscreen_allowed(root->child_at(0))); |
| 7423 | EXPECT_FALSE(is_fullscreen_allowed(root->child_at(0)->child_at(0))); |
| 7424 | |
| 7425 | // Now allow fullscreen for the middle frame. |
| 7426 | EXPECT_TRUE(ExecuteScript( |
nick | adef4a5 | 2016-06-09 18:45:54 | [diff] [blame] | 7427 | root, "document.getElementById('child-0').allowFullscreen='true'")); |
alexmos | 788f45b3 | 2016-05-24 00:57:02 | [diff] [blame] | 7428 | |
| 7429 | // All frames should be allowed to go fullscreen now. |
| 7430 | EXPECT_TRUE(is_fullscreen_allowed(root)); |
| 7431 | EXPECT_TRUE(is_fullscreen_allowed(root->child_at(0))); |
| 7432 | EXPECT_TRUE(is_fullscreen_allowed(root->child_at(0)->child_at(0))); |
| 7433 | |
| 7434 | // Cross-site navigation should preserve the fullscreen flags. |
| 7435 | NavigateFrameToURL(root->child_at(0)->child_at(0), |
| 7436 | embedded_test_server()->GetURL("d.com", "/title1.html")); |
| 7437 | EXPECT_TRUE(is_fullscreen_allowed(root->child_at(0)->child_at(0))); |
| 7438 | } |
| 7439 | |
nasko | 39e3eb7 | 2016-06-24 23:15:44 | [diff] [blame] | 7440 | // Test for https://crbug.com/615575. It ensures that file chooser triggered |
| 7441 | // by a document in an out-of-process subframe works properly. |
| 7442 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, FileChooserInSubframe) { |
| 7443 | EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( |
| 7444 | "a.com", "/cross_site_iframe_factory.html?a(b)"))); |
| 7445 | FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 7446 | |
| 7447 | GURL url(embedded_test_server()->GetURL("b.com", "/file_input.html")); |
| 7448 | NavigateFrameToURL(root->child_at(0), url); |
| 7449 | |
| 7450 | // Use FileChooserDelegate to avoid showing the actual dialog and to respond |
| 7451 | // back to the renderer process with predefined file. |
| 7452 | base::FilePath file; |
| 7453 | EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file)); |
| 7454 | file = file.AppendASCII("bar"); |
| 7455 | std::unique_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file)); |
| 7456 | shell()->web_contents()->SetDelegate(delegate.get()); |
| 7457 | EXPECT_TRUE(ExecuteScript(root->child_at(0), |
| 7458 | "document.getElementById('fileinput').click();")); |
| 7459 | EXPECT_TRUE(delegate->file_chosen()); |
| 7460 | |
| 7461 | // Also, extract the file from the renderer process to ensure that the |
| 7462 | // response made it over successfully and the proper filename is set. |
| 7463 | std::string file_name; |
| 7464 | EXPECT_TRUE(ExecuteScriptAndExtractString( |
| 7465 | root->child_at(0), |
| 7466 | "window.domAutomationController.send(" |
| 7467 | "document.getElementById('fileinput').files[0].name);", |
| 7468 | &file_name)); |
| 7469 | EXPECT_EQ("bar", file_name); |
| 7470 | } |
| 7471 | |
lfg | 71715407 | 2016-06-30 15:04:16 | [diff] [blame] | 7472 | // Tests that an out-of-process iframe receives the visibilitychange event. |
| 7473 | IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, VisibilityChange) { |
| 7474 | GURL main_url(embedded_test_server()->GetURL( |
| 7475 | "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| 7476 | NavigateToURL(shell(), main_url); |
| 7477 | |
| 7478 | FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| 7479 | ->GetFrameTree() |
| 7480 | ->root(); |
| 7481 | |
| 7482 | EXPECT_EQ( |
| 7483 | " Site A ------------ proxies for B\n" |
| 7484 | " +--Site B ------- proxies for A\n" |
| 7485 | "Where A = http://a.com/\n" |
| 7486 | " B = http://b.com/", |
| 7487 | DepictFrameTree(root)); |
| 7488 | |
| 7489 | EXPECT_TRUE(ExecuteScript( |
| 7490 | root->child_at(0)->current_frame_host(), |
| 7491 | "var event_fired = 0;\n" |
| 7492 | "document.addEventListener('visibilitychange',\n" |
| 7493 | " function() { event_fired++; });\n")); |
| 7494 | |
| 7495 | shell()->web_contents()->WasHidden(); |
| 7496 | |
| 7497 | int event_fired = 0; |
| 7498 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 7499 | root->child_at(0)->current_frame_host(), |
| 7500 | "window.domAutomationController.send(event_fired);", &event_fired)); |
| 7501 | EXPECT_EQ(1, event_fired); |
| 7502 | |
| 7503 | shell()->web_contents()->WasShown(); |
| 7504 | |
| 7505 | EXPECT_TRUE(ExecuteScriptAndExtractInt( |
| 7506 | root->child_at(0)->current_frame_host(), |
| 7507 | "window.domAutomationController.send(event_fired);", &event_fired)); |
| 7508 | EXPECT_EQ(2, event_fired); |
| 7509 | } |
| 7510 | |
[email protected] | 9b159a5 | 2013-10-03 17:24:55 | [diff] [blame] | 7511 | } // namespace content |