blob: 9e5c99ab29b9aac99982db702d8c2d7df3547138 [file] [log] [blame]
[email protected]bbdd1b20b2012-12-11 21:24:131// 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
dmazzoni0b5d2482014-09-10 19:45:575#include "content/browser/site_per_process_browsertest.h"
6
avib7348942015-12-25 20:57:107#include <stddef.h>
8#include <stdint.h>
9
nick59dcb162015-04-09 20:29:0110#include <algorithm>
11#include <vector>
12
[email protected]bbdd1b20b2012-12-11 21:24:1313#include "base/command_line.h"
skyostil95082a62015-06-05 19:53:0714#include "base/location.h"
avib7348942015-12-25 20:57:1015#include "base/macros.h"
nasko39e3eb72016-06-24 23:15:4416#include "base/path_service.h"
skyostil95082a62015-06-05 19:53:0717#include "base/single_thread_task_runner.h"
brettwd97eede2015-07-06 22:09:0018#include "base/strings/pattern.h"
[email protected]348fbaac2013-06-11 06:31:5119#include "base/strings/stringprintf.h"
lfg9ef7d2d2014-12-15 22:32:3020#include "base/strings/utf_string_conversions.h"
kenrb162e42c2015-11-24 21:10:0021#include "base/test/test_timeouts.h"
gab30f26df2016-05-11 19:37:5522#include "base/threading/thread_task_runner_handle.h"
avib7348942015-12-25 20:57:1023#include "build/build_config.h"
bnc210d6f32016-05-24 07:40:4724#include "components/network_session_configurator/switches.h"
[email protected]9a1abe72014-06-19 23:49:0225#include "content/browser/frame_host/cross_process_frame_connector.h"
[email protected]d4a8ca482013-10-30 21:06:4026#include "content/browser/frame_host/frame_tree.h"
csharrison264bca642016-05-06 19:27:0927#include "content/browser/frame_host/interstitial_page_impl.h"
naskoe6edde32014-10-17 15:36:4828#include "content/browser/frame_host/navigator.h"
[email protected]9a1abe72014-06-19 23:49:0229#include "content/browser/frame_host/render_frame_proxy_host.h"
30#include "content/browser/frame_host/render_widget_host_view_child_frame.h"
kenrb2a565f82015-09-02 20:24:5931#include "content/browser/gpu/compositor_util.h"
estark693d1282016-03-15 22:41:2932#include "content/browser/loader/resource_dispatcher_host_impl.h"
wjmaclean44464232016-03-04 21:49:1933#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
[email protected]9b159a52013-10-03 17:24:5534#include "content/browser/renderer_host/render_view_host_impl.h"
kenrb2a565f82015-09-02 20:24:5935#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
wjmaclean44464232016-03-04 21:49:1936#include "content/browser/renderer_host/render_widget_host_view_aura.h"
alexmos9aa61232016-04-26 21:54:0237#include "content/common/child_process_messages.h"
creis0f6edddc2015-04-08 00:20:5238#include "content/common/frame_messages.h"
wjmaclean44464232016-03-04 21:49:1939#include "content/common/input/synthetic_tap_gesture_params.h"
alexmos9aa61232016-04-26 21:54:0240#include "content/common/input_messages.h"
kenrb77db5072015-10-15 19:21:2541#include "content/common/view_messages.h"
estark693d1282016-03-15 22:41:2942#include "content/public/browser/cert_store.h"
csharrison264bca642016-05-06 19:27:0943#include "content/public/browser/interstitial_page_delegate.h"
[email protected]bbdd1b20b2012-12-11 21:24:1344#include "content/public/browser/notification_observer.h"
45#include "content/public/browser/notification_service.h"
46#include "content/public/browser/notification_types.h"
naskoeab5c5582015-12-15 05:20:0047#include "content/public/browser/resource_dispatcher_host.h"
carloskd80262f52015-12-16 14:40:3548#include "content/public/common/browser_side_navigation_policy.h"
[email protected]bbdd1b20b2012-12-11 21:24:1349#include "content/public/common/content_switches.h"
alexmos5b50b6742016-03-17 20:38:0550#include "content/public/common/url_constants.h"
[email protected]bbdd1b20b2012-12-11 21:24:1351#include "content/public/test/browser_test_utils.h"
[email protected]6e9def12014-03-27 20:23:2852#include "content/public/test/content_browser_test_utils.h"
nasko3e8c20e2014-12-18 06:54:5653#include "content/public/test/test_navigation_observer.h"
[email protected]bbdd1b20b2012-12-11 21:24:1354#include "content/public/test/test_utils.h"
[email protected]893558b2014-04-25 23:01:0655#include "content/test/content_browser_test_utils_internal.h"
naskoe6edde32014-10-17 15:36:4856#include "content/test/test_frame_navigation_observer.h"
creis0f6edddc2015-04-08 00:20:5257#include "ipc/ipc_security_test_util.h"
[email protected]9b159a52013-10-03 17:24:5558#include "net/dns/mock_host_resolver.h"
naskocbce0e62014-10-07 14:04:2659#include "net/test/embedded_test_server/embedded_test_server.h"
lukasza8e1c02e42016-05-17 20:05:1060#include "testing/gtest/include/gtest/gtest.h"
mkwstf672e7ef2016-06-09 20:51:0761#include "third_party/WebKit/public/platform/WebInsecureRequestPolicy.h"
kenrb2a565f82015-09-02 20:24:5962#include "third_party/WebKit/public/web/WebInputEvent.h"
dcheng5f60abb2015-05-28 01:39:3663#include "third_party/WebKit/public/web/WebSandboxFlags.h"
oshima06b39602016-05-11 02:40:1064#include "ui/display/display_switches.h"
wjmacleanfab616a2016-03-02 18:40:3965#include "ui/events/event.h"
66#include "ui/events/event_utils.h"
67#include "ui/gfx/geometry/point.h"
[email protected]bbdd1b20b2012-12-11 21:24:1368
wjmacleanfab616a2016-03-02 18:40:3969#if defined(USE_AURA)
70#include "content/browser/renderer_host/render_widget_host_view_aura.h"
71#endif
72
ahest1d019b72016-02-02 07:24:4273#if defined(OS_MACOSX)
spqchan83534ab02016-02-23 19:28:2774#include "ui/base/test/scoped_preferred_scroller_style_mac.h"
ahest1d019b72016-02-02 07:24:4275#endif
76
[email protected]bbdd1b20b2012-12-11 21:24:1377namespace content {
78
alexmos9f8705a2015-05-06 19:58:5979namespace {
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.
85void PostMessageAndWaitForReply(FrameTreeNode* sender_ftn,
86 const std::string& post_message_script,
87 const std::string& reply_status) {
alexmos17e57532015-08-15 02:54:3688 // 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
alexmos9f8705a2015-05-06 19:58:5992 bool success = false;
93 EXPECT_TRUE(ExecuteScriptAndExtractBool(
nickadef4a52016-06-09 18:45:5494 sender_ftn,
alexmos9f8705a2015-05-06 19:58:5995 "window.domAutomationController.send(" + post_message_script + ");",
96 &success));
97 EXPECT_TRUE(success);
98
alexmos9f8705a2015-05-06 19:58:5999 std::string status;
100 while (msg_queue.WaitForMessage(&status)) {
101 if (status == reply_status)
102 break;
103 }
104}
105
alexmos58729042015-06-18 23:20:00106// 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.
109int GetReceivedMessages(FrameTreeNode* ftn) {
110 int received_messages = 0;
111 EXPECT_TRUE(ExecuteScriptAndExtractInt(
nickadef4a52016-06-09 18:45:54112 ftn, "window.domAutomationController.send(window.receivedMessages);",
alexmos58729042015-06-18 23:20:00113 &received_messages));
114 return received_messages;
115}
116
alexmos646fec02015-07-25 00:11:49117// Helper function to perform a window.open from the |caller_frame| targeting a
118// frame with the specified name.
119void 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
alexmosb1dc2162015-11-05 00:59:20131// 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.
134void 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
alexmos6e940102016-01-19 22:47:25143// Retrieve document.origin for the frame |ftn|.
144std::string GetDocumentOrigin(FrameTreeNode* ftn) {
145 std::string origin;
146 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:54147 ftn, "domAutomationController.send(document.origin)", &origin));
alexmos6e940102016-01-19 22:47:25148 return origin;
149}
150
lfg52bac9072015-11-06 17:27:52151class 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
kenrb0b678202016-06-23 19:07:35181class 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
lfg52bac9072015-11-06 17:27:52208// Helper function that performs a surface hittest.
209void SurfaceHitTestTestHelper(
210 Shell* shell,
211 net::test_server::EmbeddedTestServer* embedded_test_server) {
lfg52bac9072015-11-06 17:27:52212 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
kenrbe9756552016-02-27 00:53:50243 SurfaceHitTestReadyNotifier notifier(
244 static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child));
245 notifier.WaitForSurfaceReady();
lfg52bac9072015-11-06 17:27:52246
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
lfg52bac9072015-11-06 17:27:52258 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]bbdd1b20b2012-12-11 21:24:13282class 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);
dchengc2282aa2014-10-21 12:07:58289 ~RedirectNotificationObserver() override;
[email protected]bbdd1b20b2012-12-11 21:24:13290
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:
dchengc2282aa2014-10-21 12:07:58307 void Observe(int type,
308 const NotificationSource& source,
309 const NotificationDetails& details) override;
[email protected]bbdd1b20b2012-12-11 21:24:13310
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
324RedirectNotificationObserver::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
333RedirectNotificationObserver::~RedirectNotificationObserver() {}
334
335void 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
345void 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
alexmos35d7b932014-12-05 03:55:23360// 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.
363class 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
394RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
395}
396
397void RenderFrameHostCreatedObserver::Wait() {
398 message_loop_runner_->Run();
399}
400
401void 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
kenrb19221852016-04-29 17:21:40409// 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.
412class 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
alexmos21acae52015-11-07 01:04:43437// This observer is used to wait for its owner FrameTreeNode to become focused.
438class 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
alexmosba1fb7152015-12-12 07:20:30462// This observer is used to wait for its owner FrameTreeNode to become deleted.
463class 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
alexmos21acae52015-11-07 01:04:43485// Helper function to focus a frame by sending it a mouse click and then
486// waiting for it to become focused.
487void FocusFrame(FrameTreeNode* frame) {
488 FrameFocusedObserver focus_observer(frame);
489 SimulateMouseClick(frame->current_frame_host()->GetRenderWidgetHost(), 1, 1);
490 focus_observer.Wait();
491}
492
alexmosb97d6bb62015-09-24 07:31:26493// A BrowserMessageFilter that drops SwapOut ACK messages.
494class 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
ekaramadbabb9bf2016-01-12 15:17:02510class 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
ekaramadbabb9bf2016-01-12 15:17:02542 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
estark693d1282016-03-15 22:41:29552// A mock CertStore that always assigns the render process host id as
553// the certificate id. Certificates are never removed.
554class 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
csharrison264bca642016-05-06 19:27:09579class TestInterstitialDelegate : public InterstitialPageDelegate {
580 private:
581 // InterstitialPageDelegate:
582 std::string GetHTMLContents() override { return "<p>Interstitial</p>"; }
583};
584
nick5f3d76072015-06-09 00:24:00585} // namespace
586
dmazzoni0b5d2482014-09-10 19:45:57587//
588// SitePerProcessBrowserTest
589//
[email protected]c96e9702014-02-15 08:29:50590
dmazzoni0b5d2482014-09-10 19:45:57591SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
592};
593
nick44bacf32015-04-14 02:06:39594std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) {
595 return visualizer_.DepictFrameTree(node);
nick59dcb162015-04-09 20:29:01596}
597
avi83883c82014-12-23 00:08:49598void SitePerProcessBrowserTest::SetUpCommandLine(
599 base::CommandLine* command_line) {
nickd30fd962015-07-27 21:51:08600 IsolateAllSitesForTesting(command_line);
[email protected]bbdd1b20b2012-12-11 21:24:13601};
602
naskocbce0e62014-10-07 14:04:26603void SitePerProcessBrowserTest::SetUpOnMainThread() {
604 host_resolver()->AddRule("*", "127.0.0.1");
svaldezc3a9a172015-11-03 22:01:33605 ASSERT_TRUE(embedded_test_server()->Start());
naskocbce0e62014-10-07 14:04:26606 SetupCrossSiteRedirector(embedded_test_server());
naskocbce0e62014-10-07 14:04:26607}
608
lfg52bac9072015-11-06 17:27:52609//
610// SitePerProcessHighDPIBrowserTest
611//
612
613
614class 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
estark56dc8e22016-01-26 17:58:29626// SitePerProcessIgnoreCertErrorsBrowserTest
627
628class 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
nasko983ea9c2014-10-25 00:27:53640// Ensure that navigating subframes in --site-per-process mode works and the
641// correct documents are committed.
642IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
nick4e68f5252015-08-28 20:17:05643 GURL main_url(embedded_test_server()->GetURL(
644 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
[email protected]bbdd1b20b2012-12-11 21:24:13645 NavigateToURL(shell(), main_url);
646
[email protected]893558b2014-04-25 23:01:06647 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:00648 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
[email protected]8d613aa2014-02-12 20:37:20649
clamyf1ccb4d2015-01-28 17:40:38650 TestNavigationObserver observer(shell()->web_contents());
[email protected]bbdd1b20b2012-12-11 21:24:13651
[email protected]a1b99262013-12-27 21:56:22652 // Load same-site page into iframe.
[email protected]9a1abe72014-06-19 23:49:02653 FrameTreeNode* child = root->child_at(0);
nick4e68f5252015-08-28 20:17:05654 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
[email protected]9a1abe72014-06-19 23:49:02655 NavigateFrameToURL(child, http_url);
clamyf1ccb4d2015-01-28 17:40:38656 EXPECT_EQ(http_url, observer.last_navigation_url());
657 EXPECT_TRUE(observer.last_navigation_succeeded());
[email protected]de3c5d82014-05-28 22:12:59658 {
659 // There should be only one RenderWidgetHost when there are no
660 // cross-process iframes.
[email protected]948481d2014-06-11 18:32:22661 std::set<RenderWidgetHostView*> views_set =
ekaramadfd1b5cfa2016-04-19 00:35:00662 web_contents()->GetRenderWidgetHostViewsInTree();
[email protected]948481d2014-06-11 18:32:22663 EXPECT_EQ(1U, views_set.size());
[email protected]de3c5d82014-05-28 22:12:59664 }
nick44bacf32015-04-14 02:06:39665
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"
nick4e68f5252015-08-28 20:17:05673 "Where A = http://a.com/",
nick44bacf32015-04-14 02:06:39674 DepictFrameTree(root));
[email protected]a1b99262013-12-27 21:56:22675
676 // Load cross-site page into iframe.
nasko30374c72014-10-30 19:18:37677 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
678 NavigateFrameToURL(root->child_at(0), url);
naskocbce0e62014-10-07 14:04:26679 // Verify that the navigation succeeded and the expected URL was loaded.
clamyf1ccb4d2015-01-28 17:40:38680 EXPECT_TRUE(observer.last_navigation_succeeded());
681 EXPECT_EQ(url, observer.last_navigation_url());
[email protected]a1b99262013-12-27 21:56:22682
683 // Ensure that we have created a new process for the subframe.
naskoe6edde32014-10-17 15:36:48684 ASSERT_EQ(2U, root->child_count());
[email protected]893558b2014-04-25 23:01:06685 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]de3c5d82014-05-28 22:12:59691 {
692 // There should be now two RenderWidgetHosts, one for each process
693 // rendering a frame.
[email protected]948481d2014-06-11 18:32:22694 std::set<RenderWidgetHostView*> views_set =
ekaramadfd1b5cfa2016-04-19 00:35:00695 web_contents()->GetRenderWidgetHostViewsInTree();
[email protected]948481d2014-06-11 18:32:22696 EXPECT_EQ(2U, views_set.size());
[email protected]de3c5d82014-05-28 22:12:59697 }
nick44bacf32015-04-14 02:06:39698 RenderFrameProxyHost* proxy_to_parent =
699 child->render_manager()->GetProxyToParent();
[email protected]9a1abe72014-06-19 23:49:02700 EXPECT_TRUE(proxy_to_parent);
701 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
kenrba7199832015-01-22 23:44:59702 // The out-of-process iframe should have its own RenderWidgetHost,
703 // independent of any RenderViewHost.
704 EXPECT_NE(
avif9ab5d942015-10-15 14:05:44705 rvh->GetWidget()->GetView(),
[email protected]9a1abe72014-06-19 23:49:02706 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
kenrba7199832015-01-22 23:44:59707 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
[email protected]893558b2014-04-25 23:01:06708
nick44bacf32015-04-14 02:06:39709 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"
nick4e68f5252015-08-28 20:17:05716 "Where A = http://a.com/\n"
nick44bacf32015-04-14 02:06:39717 " B = http://foo.com/",
718 DepictFrameTree(root));
719
[email protected]893558b2014-04-25 23:01:06720 // Load another cross-site page into the same iframe.
nasko30374c72014-10-30 19:18:37721 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
722 NavigateFrameToURL(root->child_at(0), url);
clamyf1ccb4d2015-01-28 17:40:38723 EXPECT_TRUE(observer.last_navigation_succeeded());
724 EXPECT_EQ(url, observer.last_navigation_url());
[email protected]893558b2014-04-25 23:01:06725
726 // Check again that a new process is created and is different from the
727 // top level one and the previous one.
naskoe6edde32014-10-17 15:36:48728 ASSERT_EQ(2U, root->child_count());
[email protected]893558b2014-04-25 23:01:06729 child = root->child_at(0);
[email protected]a1b99262013-12-27 21:56:22730 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
731 child->current_frame_host()->render_view_host());
[email protected]893558b2014-04-25 23:01:06732 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
[email protected]a1b99262013-12-27 21:56:22733 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
[email protected]893558b2014-04-25 23:01:06734 child->current_frame_host()->GetSiteInstance());
735 EXPECT_NE(site_instance,
736 child->current_frame_host()->GetSiteInstance());
[email protected]a1b99262013-12-27 21:56:22737 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
738 child->current_frame_host()->GetProcess());
[email protected]893558b2014-04-25 23:01:06739 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
[email protected]de3c5d82014-05-28 22:12:59740 {
[email protected]948481d2014-06-11 18:32:22741 std::set<RenderWidgetHostView*> views_set =
ekaramadfd1b5cfa2016-04-19 00:35:00742 web_contents()->GetRenderWidgetHostViewsInTree();
[email protected]948481d2014-06-11 18:32:22743 EXPECT_EQ(2U, views_set.size());
[email protected]de3c5d82014-05-28 22:12:59744 }
[email protected]9a1abe72014-06-19 23:49:02745 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
746 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
kenrba7199832015-01-22 23:44:59747 EXPECT_NE(
avi3627ecac2015-10-16 17:40:43748 child->current_frame_host()->render_view_host()->GetWidget()->GetView(),
[email protected]9a1abe72014-06-19 23:49:02749 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
kenrba7199832015-01-22 23:44:59750 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
nick44bacf32015-04-14 02:06:39751
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"
nick4e68f5252015-08-28 20:17:05759 "Where A = http://a.com/\n"
nick44bacf32015-04-14 02:06:39760 " C = http://bar.com/",
761 DepictFrameTree(root));
[email protected]bbdd1b20b2012-12-11 21:24:13762}
763
creis0bfe5282016-06-02 06:46:20764// Ensure that title updates affect the correct NavigationEntry after a new
765// subframe navigation with an out-of-process iframe. https://crbug.com/616609.
766IN_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
kenrb1b1ab8e2016-04-13 17:27:44802// Class to sniff incoming IPCs for FrameHostMsg_FrameRectChanged messages.
803class 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() {
kenrb1b1ab8e2016-04-13 17:27:44820 message_loop_runner_->Run();
821 }
822
kenrb42ba7e82016-05-16 18:54:18823 void Reset() {
824 last_rect_ = gfx::Rect();
825 message_loop_runner_ = new content::MessageLoopRunner;
826 frame_rect_received_ = false;
827 }
828
kenrb1b1ab8e2016-04-13 17:27:44829 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
864IN_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;
saheld9c26df2016-06-07 15:09:56920 rwhv_root->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo());
kenrb1b1ab8e2016-04-13 17:27:44921
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
kenrb42ba7e82016-05-16 18:54:18931// Test that scrolling a nested out-of-process iframe bubbles unused scroll
932// delta to a parent frame.
kenrb42ba7e82016-05-16 18:54:18933// Browser process hit testing is not implemented on Android.
934// https://crbug.com/491334
lfg0d3213a2016-07-12 13:48:30935// Flaky https://crbug.com/627238.
kenrb42ba7e82016-05-16 18:54:18936IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
lfg0d3213a2016-07-12 13:48:30937 DISABLED_ScrollBubblingFromOOPIFTest) {
kenrb42ba7e82016-05-16 18:54:18938 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.
kenrb3bdfea52016-07-08 21:50:30953 // It gets created early to catch the initial rects from the navigation.
kenrb42ba7e82016-05-16 18:54:18954 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
kenrb3bdfea52016-07-08 21:50:30963 // 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
kenrb42ba7e82016-05-16 18:54:18969 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
kenrb42ba7e82016-05-16 18:54:18984 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;
saheld9c26df2016-06-07 15:09:561007 rwhv_parent->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo());
kenrb42ba7e82016-05-16 18:54:181008
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;
saheld9c26df2016-06-07 15:09:561019 rwhv_nested->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo());
kenrb42ba7e82016-05-16 18:54:181020
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;
saheld9c26df2016-06-07 15:09:561042 rwhv_parent->ProcessMouseWheelEvent(scroll_event, ui::LatencyInfo());
kenrb42ba7e82016-05-16 18:54:181043
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 }
kenrb3bdfea52016-07-08 21:50:301078
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);
kenrb42ba7e82016-05-16 18:54:181096}
1097
kenrb0b678202016-06-23 19:07:351098// 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
1106IN_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
kenrb2a565f82015-09-02 20:24:591151// Test that mouse events are being routed to the correct RenderWidgetHostView
1152// based on coordinates.
oshimacc0f3ba2016-03-02 19:16:341153#if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
kenrb2a565f82015-09-02 20:24:591154// Browser process hit testing is not implemented on Android.
1155// https://crbug.com/491334
oshimacc0f3ba2016-03-02 19:16:341156// The test times out often on TSAN bot.
1157// https://crbug.com/591170.
kenrb2a565f82015-09-02 20:24:591158#define MAYBE_SurfaceHitTestTest DISABLED_SurfaceHitTestTest
1159#else
1160#define MAYBE_SurfaceHitTestTest SurfaceHitTestTest
1161#endif
1162IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_SurfaceHitTestTest) {
lfg52bac9072015-11-06 17:27:521163 SurfaceHitTestTestHelper(shell(), embedded_test_server());
1164}
kenrb2a565f82015-09-02 20:24:591165
lfg52bac9072015-11-06 17:27:521166// 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
1175IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
1176 MAYBE_HighDPISurfaceHitTestTest) {
1177 SurfaceHitTestTestHelper(shell(), embedded_test_server());
kenrb2a565f82015-09-02 20:24:591178}
1179
kenrb9d8b8322016-03-01 18:53:241180// 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
1189IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:001196 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
kenrb9d8b8322016-03-01 18:53:241197 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 =
ekaramadfd1b5cfa2016-04-19 00:35:001222 web_contents()->GetInputEventRouter();
kenrb9d8b8322016-03-01 18:53:241223
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
lfge6119aac2016-01-27 02:14:311253// 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
thestige45d56d32016-01-29 00:58:471260#elif defined(THREAD_SANITIZER)
1261// Flaky on TSAN. https://crbug.com/582277
1262#define MAYBE_SurfaceHitTestPointerEventsNone \
1263 DISABLED_SurfaceHitTestPointerEventsNone
lfge6119aac2016-01-27 02:14:311264#else
1265#define MAYBE_SurfaceHitTestPointerEventsNone SurfaceHitTestPointerEventsNone
1266#endif
1267IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:001274 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
lfge6119aac2016-01-27 02:14:311275 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 =
ekaramadfd1b5cfa2016-04-19 00:35:001290 web_contents()->GetInputEventRouter();
lfge6119aac2016-01-27 02:14:311291
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
kenrbe9756552016-02-27 00:53:501297 SurfaceHitTestReadyNotifier notifier(
1298 static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child));
1299 notifier.WaitForSurfaceReady();
lfge6119aac2016-01-27 02:14:311300
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
lazyboy2f1a9d12015-04-03 05:16:151318// 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
1326IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1327 MAYBE_CompositorFrameSwapped) {
nick4e68f5252015-08-28 20:17:051328 GURL main_url(embedded_test_server()->GetURL(
1329 "a.com", "/cross_site_iframe_factory.html?a(baz)"));
lazyboy2f1a9d12015-04-03 05:16:151330 NavigateToURL(shell(), main_url);
1331
1332 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:001333 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
lazyboy2f1a9d12015-04-03 05:16:151334 ASSERT_EQ(1U, root->child_count());
1335
1336 FrameTreeNode* child_node = root->child_at(0);
nick4e68f5252015-08-28 20:17:051337 GURL site_url(embedded_test_server()->GetURL(
1338 "baz.com", "/cross_site_iframe_factory.html?baz()"));
lazyboy2f1a9d12015-04-03 05:16:151339 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;
skyostil95082a62015-06-05 19:53:071350 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
lazyboy2f1a9d12015-04-03 05:16:151351 FROM_HERE, run_loop.QuitClosure(),
1352 base::TimeDelta::FromMilliseconds(10));
1353 run_loop.Run();
1354 }
1355}
1356
creis0f6edddc2015-04-08 00:20:521357// Ensure that OOPIFs are deleted after navigating to a new main frame.
1358IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
nick4e68f5252015-08-28 20:17:051359 GURL main_url(embedded_test_server()->GetURL(
1360 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
creis0f6edddc2015-04-08 00:20:521361 NavigateToURL(shell(), main_url);
1362
1363 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:001364 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
creis0f6edddc2015-04-08 00:20:521365
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.
naskof95ab0e2015-05-23 02:27:241378 EXPECT_EQ(
1379 " Site A ------------ proxies for B\n"
1380 " |--Site B ------- proxies for A\n"
1381 " +--Site B ------- proxies for A\n"
nick4e68f5252015-08-28 20:17:051382 "Where A = http://a.com/\n"
naskof95ab0e2015-05-23 02:27:241383 " 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));
creis0f6edddc2015-04-08 00:20:521396
1397 // Use Javascript in the parent to remove one of the frames and ensure that
1398 // the subframe goes away.
nickadef4a52016-06-09 18:45:541399 EXPECT_TRUE(ExecuteScript(shell(),
creis0f6edddc2015-04-08 00:20:521400 "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.
nick4e68f5252015-08-28 20:17:051406 GURL new_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
creis0f6edddc2015-04-08 00:20:521407 NavigateToURL(shell(), new_url);
1408 ASSERT_EQ(0U, root->child_count());
naskof95ab0e2015-05-23 02:27:241409
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));
creis0f6edddc2015-04-08 00:20:521412}
1413
1414// Ensure that root frames cannot be detached.
1415IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
nick4e68f5252015-08-28 20:17:051416 GURL main_url(embedded_test_server()->GetURL(
1417 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
creis0f6edddc2015-04-08 00:20:521418 NavigateToURL(shell(), main_url);
1419
1420 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:001421 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
creis0f6edddc2015-04-08 00:20:521422
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
nick44bacf32015-04-14 02:06:391446 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"
nick4e68f5252015-08-28 20:17:051450 "Where A = http://a.com/\n"
nick44bacf32015-04-14 02:06:391451 " B = http://foo.com/\n"
1452 " C = http://bar.com/",
1453 DepictFrameTree(root));
nick44bacf32015-04-14 02:06:391454
creis0f6edddc2015-04-08 00:20:521455 // 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();
nick44bacf32015-04-14 02:06:391466
nick44bacf32015-04-14 02:06:391467 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"
nick4e68f5252015-08-28 20:17:051471 "Where A = http://a.com/\n"
nick44bacf32015-04-14 02:06:391472 " B = http://foo.com/ (no process)\n"
1473 " C = http://bar.com/",
1474 DepictFrameTree(root));
creis0f6edddc2015-04-08 00:20:521475}
1476
nick4e68f5252015-08-28 20:17:051477IN_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)))"));
japhet70ea1342014-09-30 21:56:391480 NavigateToURL(shell(), main_url);
1481
1482 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:001483 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
japhet70ea1342014-09-30 21:56:391484
clamyf1ccb4d2015-01-28 17:40:381485 TestNavigationObserver observer(shell()->web_contents());
japhet70ea1342014-09-30 21:56:391486
1487 // Load same-site page into iframe.
1488 FrameTreeNode* child = root->child_at(0);
nick4e68f5252015-08-28 20:17:051489 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
japhet70ea1342014-09-30 21:56:391490 NavigateFrameToURL(child, http_url);
clamyf1ccb4d2015-01-28 17:40:381491 EXPECT_EQ(http_url, observer.last_navigation_url());
1492 EXPECT_TRUE(observer.last_navigation_succeeded());
japhet70ea1342014-09-30 21:56:391493
japhet70ea1342014-09-30 21:56:391494 // Load cross-site page into iframe.
nasko30374c72014-10-30 19:18:371495 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
1496 NavigateFrameToURL(root->child_at(0), url);
clamyf1ccb4d2015-01-28 17:40:381497 EXPECT_TRUE(observer.last_navigation_succeeded());
1498 EXPECT_EQ(url, observer.last_navigation_url());
japhet70ea1342014-09-30 21:56:391499
1500 // Ensure that we have created a new process for the subframe.
nick4e68f5252015-08-28 20:17:051501 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));
japhet70ea1342014-09-30 21:56:391511 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.
nasko30374c72014-10-30 19:18:371516 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
nick4e68f5252015-08-28 20:17:051517 NavigateIframeToURL(shell()->web_contents(), "child-0", url);
clamyf1ccb4d2015-01-28 17:40:381518 EXPECT_TRUE(observer.last_navigation_succeeded());
1519 EXPECT_EQ(url, observer.last_navigation_url());
japhet70ea1342014-09-30 21:56:391520
1521 // Check again that a new process is created and is different from the
1522 // top level one and the previous one.
nick4e68f5252015-08-28 20:17:051523 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));
japhet70ea1342014-09-30 21:56:391533
japhete6adf142014-10-31 00:01:491534 // Navigate back to the parent's origin and ensure we return to the
1535 // parent's process.
1536 NavigateFrameToURL(child, http_url);
clamyf1ccb4d2015-01-28 17:40:381537 EXPECT_EQ(http_url, observer.last_navigation_url());
1538 EXPECT_TRUE(observer.last_navigation_succeeded());
japhete6adf142014-10-31 00:01:491539 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1540 child->current_frame_host()->GetSiteInstance());
japhet70ea1342014-09-30 21:56:391541}
1542
lfgf52ea142015-03-07 23:03:331543IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
nick4e68f5252015-08-28 20:17:051544 NavigateRemoteFrameToBlankAndDataURLs) {
1545 GURL main_url(embedded_test_server()->GetURL(
1546 "a.com", "/cross_site_iframe_factory.html?a(a,a(a))"));
lfgf52ea142015-03-07 23:03:331547 NavigateToURL(shell(), main_url);
1548
1549 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:001550 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
lfgf52ea142015-03-07 23:03:331551
1552 TestNavigationObserver observer(shell()->web_contents());
1553
1554 // Load same-site page into iframe.
1555 FrameTreeNode* child = root->child_at(0);
nick4e68f5252015-08-28 20:17:051556 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
lfgf52ea142015-03-07 23:03:331557 NavigateFrameToURL(child, http_url);
1558 EXPECT_EQ(http_url, observer.last_navigation_url());
1559 EXPECT_TRUE(observer.last_navigation_succeeded());
nick4e68f5252015-08-28 20:17:051560 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));
lfgf52ea142015-03-07 23:03:331567
1568 // Load cross-site page into iframe.
1569 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
naskod948aa862016-04-26 19:58:521570 NavigateFrameToURL(child, url);
lfgf52ea142015-03-07 23:03:331571 EXPECT_TRUE(observer.last_navigation_succeeded());
1572 EXPECT_EQ(url, observer.last_navigation_url());
nick4e68f5252015-08-28 20:17:051573 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));
lfgf52ea142015-03-07 23:03:331581
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.
lfgf2d4f912016-05-11 23:18:481585 RenderFrameDeletedObserver deleted_observer1(
1586 root->child_at(0)->current_frame_host());
lfgf52ea142015-03-07 23:03:331587 GURL data_url("data:text/html,dataurl");
nick4e68f5252015-08-28 20:17:051588 NavigateIframeToURL(shell()->web_contents(), "child-0", data_url);
lfgf52ea142015-03-07 23:03:331589 EXPECT_TRUE(observer.last_navigation_succeeded());
1590 EXPECT_EQ(data_url, observer.last_navigation_url());
1591
lfgf2d4f912016-05-11 23:18:481592 // Wait for the old process to exit, to verify that the proxies go away.
1593 deleted_observer1.WaitUntilDeleted();
1594
lfgf52ea142015-03-07 23:03:331595 // Ensure that we have navigated using the top level process.
nick4e68f5252015-08-28 20:17:051596 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));
lfgf52ea142015-03-07 23:03:331603
1604 // Load cross-site page into iframe.
1605 url = embedded_test_server()->GetURL("bar.com", "/title2.html");
naskod948aa862016-04-26 19:58:521606 NavigateFrameToURL(child, url);
lfgf52ea142015-03-07 23:03:331607 EXPECT_TRUE(observer.last_navigation_succeeded());
1608 EXPECT_EQ(url, observer.last_navigation_url());
nick4e68f5252015-08-28 20:17:051609 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));
lfgf52ea142015-03-07 23:03:331617
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.
lfgf2d4f912016-05-11 23:18:481621 RenderFrameDeletedObserver deleted_observer2(
1622 root->child_at(0)->current_frame_host());
lfgf52ea142015-03-07 23:03:331623 GURL about_blank_url("about:blank");
nick4e68f5252015-08-28 20:17:051624 NavigateIframeToURL(shell()->web_contents(), "child-0", about_blank_url);
lfgf52ea142015-03-07 23:03:331625 EXPECT_TRUE(observer.last_navigation_succeeded());
1626 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
1627
lfgf2d4f912016-05-11 23:18:481628 // Wait for the old process to exit, to verify that the proxies go away.
1629 deleted_observer2.WaitUntilDeleted();
1630
lfgf52ea142015-03-07 23:03:331631 // Ensure that we have navigated using the top level process.
nick4e68f5252015-08-28 20:17:051632 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));
naskod948aa862016-04-26 19:58:521639
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);
nickadef4a52016-06-09 18:45:541661 EXPECT_TRUE(ExecuteScript(child, script));
naskod948aa862016-04-26 19:58:521662 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));
lfgf52ea142015-03-07 23:03:331674}
1675
lazyboybb1af562015-02-04 02:36:021676// 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:
lazyboyf2852202014-12-19 05:31:521682//
lazyboybb1af562015-02-04 02:36:021683// 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.
1694IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1695 NavigateRemoteFrameToKilledProcess) {
1696 GURL main_url(embedded_test_server()->GetURL(
nick4e68f5252015-08-28 20:17:051697 "foo.com", "/cross_site_iframe_factory.html?foo.com(bar.com, foo.com)"));
lazyboybb1af562015-02-04 02:36:021698 NavigateToURL(shell(), main_url);
1699
1700 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:001701 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
lazyboybb1af562015-02-04 02:36:021702
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.
nick4e68f5252015-08-28 20:17:051707 GURL site_b_url = embedded_test_server()->GetURL(
1708 "bar.com", "/cross_site_iframe_factory.html?bar.com()");
lazyboybb1af562015-02-04 02:36:021709 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
lazyboyf2852202014-12-19 05:31:521734// / /
1735// 4 C
1736//
lazyboybb1af562015-02-04 02:36:021737// 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_.
lazyboyf2852202014-12-19 05:31:521740//
lazyboybb1af562015-02-04 02:36:021741// Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
1742// site B and stays in not rendered state.
lazyboyf2852202014-12-19 05:31:521743IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
lazyboybb1af562015-02-04 02:36:021744 NavigateRemoteFrameToKilledProcessWithSubtree) {
nick44bacf32015-04-14 02:06:391745 GURL main_url(embedded_test_server()->GetURL(
nick4e68f5252015-08-28 20:17:051746 "a.com", "/cross_site_iframe_factory.html?a(bar(baz), a)"));
lazyboyf2852202014-12-19 05:31:521747 NavigateToURL(shell(), main_url);
1748
1749 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:001750 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
clamyf1ccb4d2015-01-28 17:40:381751 TestNavigationObserver observer(shell()->web_contents());
lazyboyf2852202014-12-19 05:31:521752
1753 ASSERT_EQ(2U, root->child_count());
1754
nick4e68f5252015-08-28 20:17:051755 GURL site_b_url(embedded_test_server()->GetURL(
1756 "bar.com", "/cross_site_iframe_factory.html?bar(baz())"));
clamyf1ccb4d2015-01-28 17:40:381757 // We can't use a TestNavigationObserver to verify the URL here,
lazyboyf2852202014-12-19 05:31:521758 // 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
lazyboybb1af562015-02-04 02:36:021770 // Make sure node4 points to the correct cross-site page.
lazyboyf2852202014-12-19 05:31:521771 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
nick4e68f5252015-08-28 20:17:051772 GURL site_c_url(embedded_test_server()->GetURL(
1773 "baz.com", "/cross_site_iframe_factory.html?baz()"));
lazyboybb1af562015-02-04 02:36:021774 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 {
nick44bacf32015-04-14 02:06:391780 // 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));
lazyboybb1af562015-02-04 02:36:021790
nick44bacf32015-04-14 02:06:391791 // Kill the render process for Site B.
lazyboybb1af562015-02-04 02:36:021792 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
nick44bacf32015-04-14 02:06:391799 // 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));
lazyboybb1af562015-02-04 02:36:021808 }
1809
nick44bacf32015-04-14 02:06:391810 // Now navigate the second iframe (node3) to Site B also.
lazyboybb1af562015-02-04 02:36:021811 FrameTreeNode* node3 = root->child_at(1);
1812 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
1813 NavigateFrameToURL(node3, url);
clamyf1ccb4d2015-01-28 17:40:381814 EXPECT_TRUE(observer.last_navigation_succeeded());
lazyboybb1af562015-02-04 02:36:021815 EXPECT_EQ(url, observer.last_navigation_url());
nick44bacf32015-04-14 02:06:391816
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));
lazyboybb1af562015-02-04 02:36:021824}
1825
creis93218682016-01-28 04:34:101826// 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.
1829IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:001835 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
creis93218682016-01-28 04:34:101836
creis93218682016-01-28 04:34:101837 // Load same-site page into iframe.
clamy7531fd262016-02-26 12:37:151838 {
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 }
creis93218682016-01-28 04:34:101847
1848 // Load cross-site page into iframe.
clamy7531fd262016-02-26 12:37:151849 {
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();
creis93218682016-01-28 04:34:101857
clamy7531fd262016-02-26 12:37:151858 // 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 }
creis93218682016-01-28 04:34:101869
1870 // Stop the test server and try to navigate the remote frame.
clamy7531fd262016-02-26 12:37:151871 {
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 }
creis93218682016-01-28 04:34:101876}
1877
creis1857908a2016-02-25 20:31:521878// 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.
1883IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:001889 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
creis1857908a2016-02-25 20:31:521890 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());
clamy6e0ee03e2016-03-02 15:15:521902 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 }
creis1857908a2016-02-25 20:31:521915
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.
clamy6e0ee03e2016-03-02 15:15:521919 // 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());
creis1857908a2016-02-25 20:31:521926 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.
clamy6e0ee03e2016-03-02 15:15:521942 // PlzNavigate: the subframe should still be in its separate process.
creis1857908a2016-02-25 20:31:521943 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 {
lfgf2d4f912016-05-11 23:18:481956 RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
creis1857908a2016-02-25 20:31:521957 TestNavigationObserver back_load_observer(shell()->web_contents());
1958 shell()->web_contents()->GetController().GoBack();
1959 back_load_observer.Wait();
lfgf2d4f912016-05-11 23:18:481960
1961 // Wait for the old process to exit, to verify that the proxies go away.
1962 deleted_observer.WaitUntilDeleted();
creis1857908a2016-02-25 20:31:521963 }
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
alexmosdcbe3fb42015-04-29 23:10:371977// 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.
1987IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:001995 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosdcbe3fb42015-04-29 23:10:371996 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);
alexmosdcbe3fb42015-04-29 23:10:372018 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
alexmos9f8705a2015-05-06 19:58:592032 // 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\"");
alexmosdcbe3fb42015-04-29 23:10:372036}
2037
alexmosa3988992015-05-14 23:26:212038// 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.
2050IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:002058 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosa3988992015-05-14 23:26:212059
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(
nickadef4a52016-06-09 18:45:542082 root->child_at(2),
alexmosa3988992015-05-14 23:26:212083 "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
alexmosd6ac54672015-06-25 18:10:142115// 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.
2127IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:002133 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosd6ac54672015-06-25 18:10:142134 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;
nickadef4a52016-06-09 18:45:542138 EXPECT_TRUE(ExecuteScript(root, "popup = window.open('about:blank');"));
alexmosd6ac54672015-06-25 18:10:142139 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(
nickadef4a52016-06-09 18:45:542184 popup, "document.body.appendChild(document.createElement('iframe'));"));
alexmosd6ac54672015-06-25 18:10:142185 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
lazyboybb1af562015-02-04 02:36:022198// 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.
2210IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2211 KillingRendererClearsDescendantProxies) {
nick44bacf32015-04-14 02:06:392212 GURL main_url(embedded_test_server()->GetURL(
2213 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
lazyboybb1af562015-02-04 02:36:022214 NavigateToURL(shell(), main_url);
2215
2216 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:002217 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
lazyboybb1af562015-02-04 02:36:022218 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());
lazyboyf2852202014-12-19 05:31:522240
creisceaabfd52015-05-27 20:26:462241 // |site_instance_c|'s frames and proxies are expected to go away once we kill
2242 // |child_process_b| below.
nick44bacf32015-04-14 02:06:392243 scoped_refptr<SiteInstanceImpl> site_instance_c =
2244 node4->current_frame_host()->GetSiteInstance();
lazyboyf2852202014-12-19 05:31:522245
nick44bacf32015-04-14 02:06:392246 // 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));
creisceaabfd52015-05-27 20:26:462256
2257 EXPECT_GT(site_instance_c->active_frame_count(), 0U);
2258
nick44bacf32015-04-14 02:06:392259 // 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();
lazyboyf2852202014-12-19 05:31:522266
nick44bacf32015-04-14 02:06:392267 // 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));
lazyboyf2852202014-12-19 05:31:522277
creisceaabfd52015-05-27 20:26:462278 EXPECT_EQ(0U, site_instance_c->active_frame_count());
lazyboyf2852202014-12-19 05:31:522279}
2280
[email protected]81c6c5e2014-02-13 20:20:072281// Crash a subframe and ensures its children are cleared from the FrameTree.
2282// See http://crbug.com/338508.
nasko4feae972015-07-01 16:38:022283IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrashSubframe) {
nick4e68f5252015-08-28 20:17:052284 GURL main_url(embedded_test_server()->GetURL(
2285 "a.com", "/cross_site_iframe_factory.html?a(b)"));
[email protected]81c6c5e2014-02-13 20:20:072286 NavigateToURL(shell(), main_url);
2287
[email protected]81c6c5e2014-02-13 20:20:072288 // Check the subframe process.
ekaramadfd1b5cfa2016-04-19 00:35:002289 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
nick4e68f5252015-08-28 20:17:052290 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]81c6c5e2014-02-13 20:20:072296 FrameTreeNode* child = root->child_at(0);
creise42f2a52014-09-18 18:14:572297 EXPECT_TRUE(
2298 child->current_frame_host()->render_view_host()->IsRenderViewLive());
2299 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
2300
[email protected]81c6c5e2014-02-13 20:20:072301 // 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);
jaekyun37e572a32014-12-04 23:33:352308 child_process->Shutdown(0, false);
[email protected]81c6c5e2014-02-13 20:20:072309 crash_observer.Wait();
2310 }
2311
2312 // Ensure that the child frame still exists but has been cleared.
nick4e68f5252015-08-28 20:17:052313 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]58faf942014-02-20 21:03:582320 EXPECT_EQ(main_url, root->current_url());
2321 EXPECT_EQ(GURL(), child->current_url());
[email protected]81c6c5e2014-02-13 20:20:072322
creise42f2a52014-09-18 18:14:572323 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]81c6c5e2014-02-13 20:20:072328 // 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);
jaekyun37e572a32014-12-04 23:33:352333 root_process->Shutdown(0, false);
[email protected]81c6c5e2014-02-13 20:20:072334 crash_observer.Wait();
2335 }
2336 EXPECT_EQ(0U, root->child_count());
[email protected]58faf942014-02-20 21:03:582337 EXPECT_EQ(GURL(), root->current_url());
[email protected]81c6c5e2014-02-13 20:20:072338}
2339
alexmos46e85ec2015-04-03 21:04:352340// 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.
2344IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
nick44bacf32015-04-14 02:06:392345 GURL main_url(embedded_test_server()->GetURL(
2346 "b.com", "/frame_tree/page_with_one_frame.html"));
alexmos46e85ec2015-04-03 21:04:352347 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2348
2349 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:002350 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos46e85ec2015-04-03 21:04:352351 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
nick44bacf32015-04-14 02:06:392357 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
alexmos46e85ec2015-04-03 21:04:352364 // Add a new child frame to the top-level frame.
2365 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
nickadef4a52016-06-09 18:45:542366 EXPECT_TRUE(ExecuteScript(shell(), "addFrame('data:text/html,foo');"));
alexmos46e85ec2015-04-03 21:04:352367 frame_observer.Wait();
alexmos46e85ec2015-04-03 21:04:352368
nick44bacf32015-04-14 02:06:392369 // 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));
alexmos46e85ec2015-04-03 21:04:352377}
2378
[email protected]0f7d449e2013-01-23 15:12:352379// TODO(nasko): Disable this test until out-of-process iframes is ready and the
2380// security checks are back in place.
2381IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2382 DISABLED_CrossSiteIframeRedirectOnce) {
svaldezc3a9a172015-11-03 22:01:332383 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
2384 https_server.ServeFilesFromSourceDirectory("content/test/data");
[email protected]bbdd1b20b2012-12-11 21:24:132385 ASSERT_TRUE(https_server.Start());
2386
svaldezc3a9a172015-11-03 22:01:332387 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]bbdd1b20b2012-12-11 21:24:132390
2391 NavigateToURL(shell(), main_url);
2392
clamyf1ccb4d2015-01-28 17:40:382393 TestNavigationObserver observer(shell()->web_contents());
[email protected]bbdd1b20b2012-12-11 21:24:132394 {
2395 // Load cross-site client-redirect page into Iframe.
2396 // Should be blocked.
svaldezc3a9a172015-11-03 22:01:332397 GURL client_redirect_https_url(
2398 https_server.GetURL("/client-redirect?/title1.html"));
alexmos75648bb32015-01-07 21:06:282399 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2400 client_redirect_https_url));
[email protected]bbdd1b20b2012-12-11 21:24:132401 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
clamyf1ccb4d2015-01-28 17:40:382402 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
2403 EXPECT_FALSE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132404 }
2405
2406 {
2407 // Load cross-site server-redirect page into Iframe,
2408 // which redirects to same-site page.
svaldezc3a9a172015-11-03 22:01:332409 GURL server_redirect_http_url(
2410 https_server.GetURL("/server-redirect?" + http_url.spec()));
alexmos75648bb32015-01-07 21:06:282411 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2412 server_redirect_http_url));
clamyf1ccb4d2015-01-28 17:40:382413 EXPECT_EQ(observer.last_navigation_url(), http_url);
2414 EXPECT_TRUE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132415 }
2416
2417 {
2418 // Load cross-site server-redirect page into Iframe,
2419 // which redirects to cross-site page.
svaldezc3a9a172015-11-03 22:01:332420 GURL server_redirect_http_url(
2421 https_server.GetURL("/server-redirect?/title1.html"));
alexmos75648bb32015-01-07 21:06:282422 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2423 server_redirect_http_url));
[email protected]bbdd1b20b2012-12-11 21:24:132424 // DidFailProvisionalLoad when navigating to https_url.
clamyf1ccb4d2015-01-28 17:40:382425 EXPECT_EQ(observer.last_navigation_url(), https_url);
2426 EXPECT_FALSE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132427 }
2428
2429 {
2430 // Load same-site server-redirect page into Iframe,
2431 // which redirects to cross-site page.
svaldezc3a9a172015-11-03 22:01:332432 GURL server_redirect_http_url(
2433 embedded_test_server()->GetURL("/server-redirect?" + https_url.spec()));
alexmos75648bb32015-01-07 21:06:282434 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2435 server_redirect_http_url));
[email protected]bbdd1b20b2012-12-11 21:24:132436
clamyf1ccb4d2015-01-28 17:40:382437 EXPECT_EQ(observer.last_navigation_url(), https_url);
2438 EXPECT_FALSE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132439 }
2440
2441 {
2442 // Load same-site client-redirect page into Iframe,
2443 // which redirects to cross-site page.
svaldezc3a9a172015-11-03 22:01:332444 GURL client_redirect_http_url(
2445 embedded_test_server()->GetURL("/client-redirect?" + https_url.spec()));
[email protected]bbdd1b20b2012-12-11 21:24:132446
2447 RedirectNotificationObserver load_observer2(
2448 NOTIFICATION_LOAD_STOP,
2449 Source<NavigationController>(
2450 &shell()->web_contents()->GetController()));
2451
alexmos75648bb32015-01-07 21:06:282452 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2453 client_redirect_http_url));
[email protected]bbdd1b20b2012-12-11 21:24:132454
2455 // Same-site Client-Redirect Page should be loaded successfully.
clamyf1ccb4d2015-01-28 17:40:382456 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
2457 EXPECT_TRUE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132458
2459 // Redirecting to Cross-site Page should be blocked.
2460 load_observer2.Wait();
clamyf1ccb4d2015-01-28 17:40:382461 EXPECT_EQ(observer.last_navigation_url(), https_url);
2462 EXPECT_FALSE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132463 }
2464
2465 {
2466 // Load same-site server-redirect page into Iframe,
2467 // which redirects to same-site page.
svaldezc3a9a172015-11-03 22:01:332468 GURL server_redirect_http_url(
2469 embedded_test_server()->GetURL("/server-redirect?/title1.html"));
alexmos75648bb32015-01-07 21:06:282470 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2471 server_redirect_http_url));
clamyf1ccb4d2015-01-28 17:40:382472 EXPECT_EQ(observer.last_navigation_url(), http_url);
2473 EXPECT_TRUE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132474 }
2475
2476 {
2477 // Load same-site client-redirect page into Iframe,
2478 // which redirects to same-site page.
svaldezc3a9a172015-11-03 22:01:332479 GURL client_redirect_http_url(
2480 embedded_test_server()->GetURL("/client-redirect?" + http_url.spec()));
[email protected]bbdd1b20b2012-12-11 21:24:132481 RedirectNotificationObserver load_observer2(
2482 NOTIFICATION_LOAD_STOP,
2483 Source<NavigationController>(
2484 &shell()->web_contents()->GetController()));
2485
alexmos75648bb32015-01-07 21:06:282486 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2487 client_redirect_http_url));
[email protected]bbdd1b20b2012-12-11 21:24:132488
2489 // Same-site Client-Redirect Page should be loaded successfully.
clamyf1ccb4d2015-01-28 17:40:382490 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
2491 EXPECT_TRUE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132492
2493 // Redirecting to Same-site Page should be loaded successfully.
2494 load_observer2.Wait();
clamyf1ccb4d2015-01-28 17:40:382495 EXPECT_EQ(observer.last_navigation_url(), http_url);
2496 EXPECT_TRUE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132497 }
2498}
2499
[email protected]0f7d449e2013-01-23 15:12:352500// TODO(nasko): Disable this test until out-of-process iframes is ready and the
2501// security checks are back in place.
[email protected]bbdd1b20b2012-12-11 21:24:132502IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
[email protected]0f7d449e2013-01-23 15:12:352503 DISABLED_CrossSiteIframeRedirectTwice) {
svaldezc3a9a172015-11-03 22:01:332504 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
2505 https_server.ServeFilesFromSourceDirectory("content/test/data");
[email protected]bbdd1b20b2012-12-11 21:24:132506 ASSERT_TRUE(https_server.Start());
2507
svaldezc3a9a172015-11-03 22:01:332508 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]bbdd1b20b2012-12-11 21:24:132511
2512 NavigateToURL(shell(), main_url);
2513
clamyf1ccb4d2015-01-28 17:40:382514 TestNavigationObserver observer(shell()->web_contents());
[email protected]bbdd1b20b2012-12-11 21:24:132515 {
2516 // Load client-redirect page pointing to a cross-site client-redirect page,
2517 // which eventually redirects back to same-site page.
svaldezc3a9a172015-11-03 22:01:332518 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]bbdd1b20b2012-12-11 21:24:132522
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
alexmos75648bb32015-01-07 21:06:282529 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2530 client_redirect_http_url));
[email protected]bbdd1b20b2012-12-11 21:24:132531
2532 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
2533 load_observer2.Wait();
clamyf1ccb4d2015-01-28 17:40:382534 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
2535 EXPECT_FALSE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132536 }
2537
2538 {
2539 // Load server-redirect page pointing to a cross-site server-redirect page,
2540 // which eventually redirect back to same-site page.
svaldezc3a9a172015-11-03 22:01:332541 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()));
alexmos75648bb32015-01-07 21:06:282545 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2546 server_redirect_http_url));
clamyf1ccb4d2015-01-28 17:40:382547 EXPECT_EQ(observer.last_navigation_url(), http_url);
2548 EXPECT_TRUE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132549 }
2550
2551 {
2552 // Load server-redirect page pointing to a cross-site server-redirect page,
2553 // which eventually redirects back to cross-site page.
svaldezc3a9a172015-11-03 22:01:332554 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()));
alexmos75648bb32015-01-07 21:06:282558 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2559 server_redirect_http_url));
[email protected]bbdd1b20b2012-12-11 21:24:132560
2561 // DidFailProvisionalLoad when navigating to https_url.
clamyf1ccb4d2015-01-28 17:40:382562 EXPECT_EQ(observer.last_navigation_url(), https_url);
2563 EXPECT_FALSE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132564 }
2565
2566 {
2567 // Load server-redirect page pointing to a cross-site client-redirect page,
2568 // which eventually redirects back to same-site page.
svaldezc3a9a172015-11-03 22:01:332569 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()));
alexmos75648bb32015-01-07 21:06:282573 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
2574 server_redirect_http_url));
[email protected]bbdd1b20b2012-12-11 21:24:132575
2576 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
clamyf1ccb4d2015-01-28 17:40:382577 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
2578 EXPECT_FALSE(observer.last_navigation_succeeded());
[email protected]bbdd1b20b2012-12-11 21:24:132579 }
2580}
2581
naskoe6edde32014-10-17 15:36:482582// Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
2583// created in the FrameTree skipping the subtree of the navigating frame.
naskoe6edde32014-10-17 15:36:482584IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
nick53d5cbf2015-04-23 22:50:142585 ProxyCreationSkipsSubtree) {
nick4e68f5252015-08-28 20:17:052586 GURL main_url(embedded_test_server()->GetURL(
2587 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
naskoe6edde32014-10-17 15:36:482588 NavigateToURL(shell(), main_url);
2589
2590 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:002591 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
naskoe6edde32014-10-17 15:36:482592
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.
clamyf1ccb4d2015-01-28 17:40:382598 TestNavigationObserver observer(shell()->web_contents());
nick4e68f5252015-08-28 20:17:052599 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
naskoe6edde32014-10-17 15:36:482600 NavigateFrameToURL(root->child_at(0), http_url);
clamyf1ccb4d2015-01-28 17:40:382601 EXPECT_EQ(http_url, observer.last_navigation_url());
2602 EXPECT_TRUE(observer.last_navigation_succeeded());
nick44bacf32015-04-14 02:06:392603 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"
nick4e68f5252015-08-28 20:17:052610 "Where A = http://a.com/",
nick44bacf32015-04-14 02:06:392611 DepictFrameTree(root));
naskoe6edde32014-10-17 15:36:482612 }
2613
2614 // Create the cross-site URL to navigate to.
nasko30374c72014-10-30 19:18:372615 GURL cross_site_url =
alexmos617df0372015-09-03 21:52:162616 embedded_test_server()->GetURL("foo.com", "/frame_tree/title2.html");
naskoe6edde32014-10-17 15:36:482617
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;
carloskd80262f52015-12-16 14:40:352625 bool browser_side_navigation = IsBrowserSideNavigationEnabled();
clamya5298012015-06-02 13:28:212626 std::string cross_site_rfh_type =
2627 browser_side_navigation ? "speculative" : "pending";
naskoe6edde32014-10-17 15:36:482628 {
clamyf1ccb4d2015-01-28 17:40:382629 TestNavigationObserver observer(shell()->web_contents());
naskoe6edde32014-10-17 15:36:482630 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);
naskoe6edde32014-10-17 15:36:482635
clamya5298012015-06-02 13:28:212636 if (browser_side_navigation) {
2637 site = child->render_manager()
clamy11e11512015-07-07 16:42:172638 ->speculative_frame_host()
clamya5298012015-06-02 13:28:212639 ->GetSiteInstance();
2640 } else {
2641 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
2642 }
naskoe6edde32014-10-17 15:36:482643 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
2644
clamya5298012015-06-02 13:28:212645 std::string tree = base::StringPrintf(
nick44bacf32015-04-14 02:06:392646 " Site A ------------ proxies for B\n"
2647 " |--Site A ------- proxies for B\n"
clamya5298012015-06-02 13:28:212648 " +--Site A (B %s)\n"
nick44bacf32015-04-14 02:06:392649 " |--Site A\n"
2650 " +--Site A\n"
2651 " +--Site A\n"
nick4e68f5252015-08-28 20:17:052652 "Where A = http://a.com/\n"
nick44bacf32015-04-14 02:06:392653 " B = http://foo.com/",
clamya5298012015-06-02 13:28:212654 cross_site_rfh_type.c_str());
2655 EXPECT_EQ(tree, DepictFrameTree(root));
nick44bacf32015-04-14 02:06:392656
naskoe6edde32014-10-17 15:36:482657 // 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());
clamyf1ccb4d2015-01-28 17:40:382661 EXPECT_TRUE(observer.last_navigation_succeeded());
2662 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
nick53d5cbf2015-04-23 22:50:142663
2664 EXPECT_EQ(
2665 " Site A ------------ proxies for B\n"
2666 " |--Site A ------- proxies for B\n"
2667 " +--Site B ------- proxies for A\n"
nick4e68f5252015-08-28 20:17:052668 "Where A = http://a.com/\n"
nick53d5cbf2015-04-23 22:50:142669 " B = http://foo.com/",
2670 DepictFrameTree(root));
naskoe6edde32014-10-17 15:36:482671 }
2672
2673 // Load another cross-site page into the same iframe.
alexmos617df0372015-09-03 21:52:162674 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title3.html");
naskoe6edde32014-10-17 15:36:482675 {
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.
clamyf1ccb4d2015-01-28 17:40:382682 TestNavigationObserver observer(shell()->web_contents());
naskoe6edde32014-10-17 15:36:482683 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);
naskoe6edde32014-10-17 15:36:482688
clamya5298012015-06-02 13:28:212689 SiteInstance* site2;
2690 if (browser_side_navigation) {
2691 site2 = child->render_manager()
clamy11e11512015-07-07 16:42:172692 ->speculative_frame_host()
clamya5298012015-06-02 13:28:212693 ->GetSiteInstance();
2694 } else {
2695 site2 = child->render_manager()->pending_frame_host()->GetSiteInstance();
2696 }
naskoe6edde32014-10-17 15:36:482697 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
2698 EXPECT_NE(site, site2);
2699
clamya5298012015-06-02 13:28:212700 std::string tree = base::StringPrintf(
nick44bacf32015-04-14 02:06:392701 " Site A ------------ proxies for B C\n"
2702 " |--Site A ------- proxies for B C\n"
clamya5298012015-06-02 13:28:212703 " +--Site B (C %s) -- proxies for A\n"
nick4e68f5252015-08-28 20:17:052704 "Where A = http://a.com/\n"
nick44bacf32015-04-14 02:06:392705 " B = http://foo.com/\n"
2706 " C = http://bar.com/",
clamya5298012015-06-02 13:28:212707 cross_site_rfh_type.c_str());
2708 EXPECT_EQ(tree, DepictFrameTree(root));
naskoe6edde32014-10-17 15:36:482709
2710 navigation_observer.Wait();
clamyf1ccb4d2015-01-28 17:40:382711 EXPECT_TRUE(observer.last_navigation_succeeded());
2712 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
naskoe6edde32014-10-17 15:36:482713 EXPECT_EQ(0U, child->child_count());
2714 }
2715}
2716
lazyboy70605c32015-11-03 01:27:312717// 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
2727IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2728 MAYBE_FrameOwnerPropertiesPropagationScrolling) {
ahest1d019b72016-02-02 07:24:422729#if defined(OS_MACOSX)
spqchan83534ab02016-02-23 19:28:272730 ui::test::ScopedPreferredScrollerStyle scroller_style_override(false);
ahest1d019b72016-02-02 07:24:422731#endif
lazyboy70605c32015-11-03 01:27:312732 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.
ekaramadfd1b5cfa2016-04-19 00:35:002737 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
lazyboy70605c32015-11-03 01:27:312738 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]);
lazyboy70605c32015-11-03 01:27:312789 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.
2796IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:002803 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
lazyboy70605c32015-11-03 01:27:312804 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(
nickadef4a52016-06-09 18:45:542817 child,
lazyboy70605c32015-11-03 01:27:312818 "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(
nickadef4a52016-06-09 18:45:542825 child,
lazyboy70605c32015-11-03 01:27:312826 "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(
nickadef4a52016-06-09 18:45:542850 root,
2851 base::StringPrintf("document.getElementById('child-1').setAttribute("
2852 " 'marginwidth', '%d');",
2853 current_margin_width)));
lazyboy70605c32015-11-03 01:27:312854 EXPECT_TRUE(ExecuteScript(
nickadef4a52016-06-09 18:45:542855 root,
2856 base::StringPrintf("document.getElementById('child-1').setAttribute("
2857 " 'marginheight', '%d');",
2858 current_margin_height)));
lazyboy70605c32015-11-03 01:27:312859
2860 NavigateFrameToURL(child, urls[i]);
lazyboy70605c32015-11-03 01:27:312861
2862 std::string actual_margin_width;
2863 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:542864 child,
lazyboy70605c32015-11-03 01:27:312865 "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(
nickadef4a52016-06-09 18:45:542872 child,
lazyboy70605c32015-11-03 01:27:312873 "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
nick9c79de22015-08-28 20:12:132883// Verify origin replication with an A-embed-B-embed-C-embed-A hierarchy.
alexmos17f643f2014-12-09 18:50:102884IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
nick9c79de22015-08-28 20:12:132885 GURL main_url(embedded_test_server()->GetURL(
2886 "a.com", "/cross_site_iframe_factory.html?a(b(c(a),b), a)"));
alexmos35d7b932014-12-05 03:55:232887 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2888
2889 // It is safe to obtain the root frame tree node here, as it doesn't change.
ekaramadfd1b5cfa2016-04-19 00:35:002890 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos35d7b932014-12-05 03:55:232891
nick9c79de22015-08-28 20:12:132892 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));
alexmos35d7b932014-12-05 03:55:232903
nick9c79de22015-08-28 20:12:132904 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);
alexmos35d7b932014-12-05 03:55:232910
nick9c79de22015-08-28 20:12:132911 // Check that b.com frame's location.ancestorOrigins contains the correct
alexmos17f643f2014-12-09 18:50:102912 // 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
nick9c79de22015-08-28 20:12:132914 // b.com's process.
alexmos17f643f2014-12-09 18:50:102915 int ancestor_origins_length = 0;
2916 EXPECT_TRUE(ExecuteScriptAndExtractInt(
nickadef4a52016-06-09 18:45:542917 tiptop_child,
alexmos17f643f2014-12-09 18:50:102918 "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(
nickadef4a52016-06-09 18:45:542923 tiptop_child,
alexmos17f643f2014-12-09 18:50:102924 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2925 &result));
nick9c79de22015-08-28 20:12:132926 EXPECT_EQ(a_origin, result + "/");
alexmos17f643f2014-12-09 18:50:102927
nick9c79de22015-08-28 20:12:132928 // Check that c.com frame's location.ancestorOrigins contains the correct
alexmos17f643f2014-12-09 18:50:102929 // origin for its two ancestors. The topmost parent origin should be
nick9c79de22015-08-28 20:12:132930 // 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.
alexmos17f643f2014-12-09 18:50:102933 EXPECT_TRUE(ExecuteScriptAndExtractInt(
nickadef4a52016-06-09 18:45:542934 middle_child,
alexmos17f643f2014-12-09 18:50:102935 "window.domAutomationController.send(location.ancestorOrigins.length);",
2936 &ancestor_origins_length));
2937 EXPECT_EQ(2, ancestor_origins_length);
2938 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:542939 middle_child,
alexmos17f643f2014-12-09 18:50:102940 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2941 &result));
nick9c79de22015-08-28 20:12:132942 EXPECT_EQ(b_origin, result + "/");
alexmos17f643f2014-12-09 18:50:102943 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:542944 middle_child,
alexmos17f643f2014-12-09 18:50:102945 "window.domAutomationController.send(location.ancestorOrigins[1]);",
2946 &result));
nick9c79de22015-08-28 20:12:132947 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(
nickadef4a52016-06-09 18:45:542952 lowest_child,
nick9c79de22015-08-28 20:12:132953 "window.domAutomationController.send(location.ancestorOrigins.length);",
2954 &ancestor_origins_length));
2955 EXPECT_EQ(3, ancestor_origins_length);
2956 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:542957 lowest_child,
nick9c79de22015-08-28 20:12:132958 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2959 &result));
2960 EXPECT_EQ(c_origin, result + "/");
2961 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:542962 lowest_child,
nick9c79de22015-08-28 20:12:132963 "window.domAutomationController.send(location.ancestorOrigins[1]);",
2964 &result));
2965 EXPECT_EQ(b_origin, result + "/");
2966 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:542967 lowest_child,
nick9c79de22015-08-28 20:12:132968 "window.domAutomationController.send(location.ancestorOrigins[2]);",
2969 &result));
2970 EXPECT_EQ(a_origin, result + "/");
alexmos35d7b932014-12-05 03:55:232971}
2972
alexmosf832a2f2015-01-27 22:44:032973// Check that iframe sandbox flags are replicated correctly.
2974IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:002979 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosf832a2f2015-01-27 22:44:032980
clamyf1ccb4d2015-01-28 17:40:382981 TestNavigationObserver observer(shell()->web_contents());
alexmosf832a2f2015-01-27 22:44:032982
2983 // Navigate the second (sandboxed) subframe to a cross-site page with a
alexmos54dee8e2015-05-15 19:07:012984 // subframe.
alexmosf832a2f2015-01-27 22:44:032985 GURL foo_url(
2986 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
2987 NavigateFrameToURL(root->child_at(1), foo_url);
alexmos54dee8e2015-05-15 19:07:012988 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
alexmosf832a2f2015-01-27 22:44:032989
clamyf1ccb4d2015-01-28 17:40:382990 // We can't use a TestNavigationObserver to verify the URL here,
alexmosf832a2f2015-01-27 22:44:032991 // 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);
clamyf1ccb4d2015-01-28 17:40:382998 EXPECT_TRUE(observer.last_navigation_succeeded());
2999 EXPECT_EQ(bar_url, observer.last_navigation_url());
alexmosf832a2f2015-01-27 22:44:033000
3001 // Opening a popup in the sandboxed foo.com iframe should fail.
3002 bool success = false;
3003 EXPECT_TRUE(
nickadef4a52016-06-09 18:45:543004 ExecuteScriptAndExtractBool(root->child_at(1),
alexmosf832a2f2015-01-27 22:44:033005 "window.domAutomationController.send("
3006 "!window.open('data:text/html,dataurl'));",
3007 &success));
3008 EXPECT_TRUE(success);
alexmos6b294562015-03-05 19:24:103009 EXPECT_EQ(1u, Shell::windows().size());
alexmosf832a2f2015-01-27 22:44:033010
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;
nickadef4a52016-06-09 18:45:543015 EXPECT_TRUE(
3016 ExecuteScriptAndExtractBool(root->child_at(1)->child_at(0),
3017 "window.domAutomationController.send("
3018 "!window.open('data:text/html,dataurl'));",
3019 &success));
alexmosf832a2f2015-01-27 22:44:033020 EXPECT_TRUE(success);
alexmos6b294562015-03-05 19:24:103021 EXPECT_EQ(1u, Shell::windows().size());
alexmosf832a2f2015-01-27 22:44:033022
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;
nickadef4a52016-06-09 18:45:543026 EXPECT_TRUE(
3027 ExecuteScriptAndExtractBool(root->child_at(2)->child_at(0),
3028 "window.domAutomationController.send("
3029 "!window.open('data:text/html,dataurl'));",
3030 &success));
alexmosf832a2f2015-01-27 22:44:033031 EXPECT_TRUE(success);
alexmos6b294562015-03-05 19:24:103032 EXPECT_EQ(1u, Shell::windows().size());
alexmosf832a2f2015-01-27 22:44:033033
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(
nickadef4a52016-06-09 18:45:543038 root->child_at(1),
alexmosf832a2f2015-01-27 22:44:033039 "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(
nickadef4a52016-06-09 18:45:543044 root->child_at(1),
alexmosf832a2f2015-01-27 22:44:033045 "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(
nickadef4a52016-06-09 18:45:543054 bottom_child,
alexmosf832a2f2015-01-27 22:44:033055 "window.domAutomationController.send(location.ancestorOrigins.length);",
3056 &ancestor_origins_length));
3057 EXPECT_EQ(2, ancestor_origins_length);
3058 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:543059 bottom_child,
alexmosf832a2f2015-01-27 22:44:033060 "window.domAutomationController.send(location.ancestorOrigins[0]);",
3061 &result));
alexmos6b294562015-03-05 19:24:103062 EXPECT_EQ("null", result);
alexmosf832a2f2015-01-27 22:44:033063 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:543064 bottom_child,
alexmosf832a2f2015-01-27 22:44:033065 "window.domAutomationController.send(location.ancestorOrigins[1]);",
3066 &result));
alexmos6b294562015-03-05 19:24:103067 EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
3068}
3069
3070// Check that dynamic updates to iframe sandbox flags are propagated correctly.
3071IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003077 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos6b294562015-03-05 19:24:103078
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.
dcheng5f60abb2015-05-28 01:39:363093 EXPECT_EQ(blink::WebSandboxFlags::None,
alexmos6e940102016-01-19 22:47:253094 root->child_at(0)->pending_sandbox_flags());
dcheng5f60abb2015-05-28 01:39:363095 EXPECT_EQ(blink::WebSandboxFlags::None,
3096 root->child_at(0)->effective_sandbox_flags());
3097 EXPECT_EQ(blink::WebSandboxFlags::None,
alexmos6e940102016-01-19 22:47:253098 root->child_at(1)->pending_sandbox_flags());
dcheng5f60abb2015-05-28 01:39:363099 EXPECT_EQ(blink::WebSandboxFlags::None,
3100 root->child_at(1)->effective_sandbox_flags());
alexmos6b294562015-03-05 19:24:103101
3102 // Dynamically update sandbox flags for the first frame.
nickadef4a52016-06-09 18:45:543103 EXPECT_TRUE(ExecuteScript(
3104 shell(),
3105 "document.querySelector('iframe').sandbox='allow-scripts';"));
alexmos6b294562015-03-05 19:24:103106
3107 // Check that updated sandbox flags are propagated to browser process.
alexmos6e940102016-01-19 22:47:253108 // The new flags should be reflected in pending_sandbox_flags(), while
alexmos6b294562015-03-05 19:24:103109 // 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().
dcheng5f60abb2015-05-28 01:39:363113 blink::WebSandboxFlags expected_flags =
3114 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
3115 ~blink::WebSandboxFlags::AutomaticFeatures;
alexmos6e940102016-01-19 22:47:253116 EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
dcheng5f60abb2015-05-28 01:39:363117 EXPECT_EQ(blink::WebSandboxFlags::None,
3118 root->child_at(0)->effective_sandbox_flags());
alexmos6b294562015-03-05 19:24:103119
3120 // Navigate the first frame to a page on the same site. The new sandbox
avi98405c22015-05-21 20:47:063121 // flags should take effect.
alexmos6b294562015-03-05 19:24:103122 GURL bar_url(
3123 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
3124 NavigateFrameToURL(root->child_at(0), bar_url);
avi98405c22015-05-21 20:47:063125 // (The new page has a subframe; wait for it to load as well.)
3126 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
alexmos6b294562015-03-05 19:24:103127 EXPECT_EQ(bar_url, root->child_at(0)->current_url());
3128 ASSERT_EQ(1U, root->child_at(0)->child_count());
3129
creis2069a0a2015-05-22 22:13:473130 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
alexmos6b294562015-03-05 19:24:103140 // Confirm that the browser process has updated the frame's current sandbox
3141 // flags.
alexmos6e940102016-01-19 22:47:253142 EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
alexmos6b294562015-03-05 19:24:103143 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;
nickadef4a52016-06-09 18:45:543147 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3148 root->child_at(0),
3149 "window.domAutomationController.send("
3150 " !window.open('data:text/html,dataurl'));",
3151 &success));
alexmos6b294562015-03-05 19:24:103152 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
creis2069a0a2015-05-22 22:13:473165 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
alexmos6b294562015-03-05 19:24:103175 // Opening a popup in the child of a sandboxed frame should fail.
3176 success = false;
3177 EXPECT_TRUE(ExecuteScriptAndExtractBool(
nickadef4a52016-06-09 18:45:543178 root->child_at(0)->child_at(0),
alexmos6b294562015-03-05 19:24:103179 "window.domAutomationController.send("
nickadef4a52016-06-09 18:45:543180 " !window.open('data:text/html,dataurl'));",
alexmos6b294562015-03-05 19:24:103181 &success));
3182 EXPECT_TRUE(success);
3183 EXPECT_EQ(1u, Shell::windows().size());
alexmos6e940102016-01-19 22:47:253184
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());
alexmos6b294562015-03-05 19:24:103188}
3189
3190// Check that dynamic updates to iframe sandbox flags are propagated correctly.
3191IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003198 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos6b294562015-03-05 19:24:103199
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.
nickadef4a52016-06-09 18:45:543210 EXPECT_TRUE(ExecuteScript(
3211 shell(),
3212 "document.querySelectorAll('iframe')[1].sandbox='allow-scripts'"));
alexmos6b294562015-03-05 19:24:103213
3214 // Check that the current sandbox flags are updated but the effective
3215 // sandbox flags are not.
dcheng5f60abb2015-05-28 01:39:363216 blink::WebSandboxFlags expected_flags =
3217 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
3218 ~blink::WebSandboxFlags::AutomaticFeatures;
alexmos6e940102016-01-19 22:47:253219 EXPECT_EQ(expected_flags, root->child_at(1)->pending_sandbox_flags());
dcheng5f60abb2015-05-28 01:39:363220 EXPECT_EQ(blink::WebSandboxFlags::None,
3221 root->child_at(1)->effective_sandbox_flags());
alexmos6b294562015-03-05 19:24:103222
3223 // Navigate the second subframe to a page on bar.com. This will trigger a
nasko8206fa12016-03-22 02:24:133224 // remote-to-local frame swap in bar.com's process.
alexmos6b294562015-03-05 19:24:103225 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);
alexmos6b294562015-03-05 19:24:103228 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.
alexmos6e940102016-01-19 22:47:253232 EXPECT_EQ(expected_flags, root->child_at(1)->pending_sandbox_flags());
alexmos6b294562015-03-05 19:24:103233 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;
nickadef4a52016-06-09 18:45:543237 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3238 root->child_at(1),
3239 "window.domAutomationController.send("
3240 " !window.open('data:text/html,dataurl'));",
3241 &success));
alexmos6b294562015-03-05 19:24:103242 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(
nickadef4a52016-06-09 18:45:543249 root->child_at(1)->child_at(0),
alexmos6b294562015-03-05 19:24:103250 "window.domAutomationController.send("
nickadef4a52016-06-09 18:45:543251 " !window.open('data:text/html,dataurl'));",
alexmos6b294562015-03-05 19:24:103252 &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.
3258IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003265 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos6b294562015-03-05 19:24:103266
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.
dcheng5f60abb2015-05-28 01:39:363275 EXPECT_EQ(blink::WebSandboxFlags::None,
alexmos6e940102016-01-19 22:47:253276 root->child_at(0)->pending_sandbox_flags());
dcheng5f60abb2015-05-28 01:39:363277 EXPECT_EQ(blink::WebSandboxFlags::None,
3278 root->child_at(0)->effective_sandbox_flags());
alexmos6b294562015-03-05 19:24:103279
3280 // Dynamically update the frame's sandbox flags.
nickadef4a52016-06-09 18:45:543281 EXPECT_TRUE(ExecuteScript(
3282 shell(), "document.querySelector('iframe').sandbox='allow-scripts';"));
alexmos6b294562015-03-05 19:24:103283
3284 // Check that updated sandbox flags are propagated to browser process.
alexmos6e940102016-01-19 22:47:253285 // The new flags should be set in pending_sandbox_flags(), while
alexmos6b294562015-03-05 19:24:103286 // 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().
dcheng5f60abb2015-05-28 01:39:363290 blink::WebSandboxFlags expected_flags =
3291 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
3292 ~blink::WebSandboxFlags::AutomaticFeatures;
alexmos6e940102016-01-19 22:47:253293 EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
dcheng5f60abb2015-05-28 01:39:363294 EXPECT_EQ(blink::WebSandboxFlags::None,
3295 root->child_at(0)->effective_sandbox_flags());
alexmos6b294562015-03-05 19:24:103296
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));
nickadef4a52016-06-09 18:45:543300 ASSERT_TRUE(
3301 ExecuteScript(root->child_at(0), "window.location.href='/title2.html'"));
alexmos6b294562015-03-05 19:24:103302 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.
alexmos6e940102016-01-19 22:47:253308 EXPECT_EQ(expected_flags, root->child_at(0)->pending_sandbox_flags());
alexmos6b294562015-03-05 19:24:103309 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;
nickadef4a52016-06-09 18:45:543313 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3314 root->child_at(0),
3315 "window.domAutomationController.send("
3316 " !window.open('data:text/html,dataurl'));",
3317 &success));
alexmos6b294562015-03-05 19:24:103318 EXPECT_TRUE(success);
3319 EXPECT_EQ(1u, Shell::windows().size());
alexmosf832a2f2015-01-27 22:44:033320}
3321
alexmos6e0ee0c2015-05-01 18:57:343322// 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.
stanisc2b6e1d72016-05-11 01:31:543335// TODO(alexmos): Re-enable when https://crbug.com/610893 is fixed.
3336IN_PROC_BROWSER_TEST_F(
3337 SitePerProcessBrowserTest,
3338 DISABLED_ProxiesForNewChildFramesHaveCorrectReplicationState) {
alexmos6e0ee0c2015-05-01 18:57:343339 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.
ekaramadfd1b5cfa2016-04-19 00:35:003344 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos6e0ee0c2015-05-01 18:57:343345 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);
nickadef4a52016-06-09 18:45:543359 EXPECT_TRUE(ExecuteScript(root,
3360 "addFrame('/frame_tree/page_with_one_frame.html',"
3361 " 'allow-scripts allow-same-origin'))"));
alexmos6e0ee0c2015-05-01 18:57:343362 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(
nickadef4a52016-06-09 18:45:543382 bottom_child,
alexmos6e0ee0c2015-05-01 18:57:343383 "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(
nickadef4a52016-06-09 18:45:543388 bottom_child,
alexmos6e0ee0c2015-05-01 18:57:343389 "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.
dcheng5f60abb2015-05-28 01:39:363394 // "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;
alexmos6e940102016-01-19 22:47:253400 EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
alexmos6e0ee0c2015-05-01 18:57:343401
3402 // The child of the sandboxed frame should've inherited sandbox flags, so it
3403 // should not be able to create popups.
alexmos6e940102016-01-19 22:47:253404 EXPECT_EQ(expected_flags, bottom_child->effective_sandbox_flags());
alexmos6e0ee0c2015-05-01 18:57:343405 bool success = false;
nickadef4a52016-06-09 18:45:543406 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3407 bottom_child,
3408 "window.domAutomationController.send("
3409 " !window.open('data:text/html,dataurl'));",
3410 &success));
alexmos6e0ee0c2015-05-01 18:57:343411 EXPECT_TRUE(success);
3412 EXPECT_EQ(1u, Shell::windows().size());
3413}
3414
alexmos998581d2015-01-22 01:01:593415// Verify that a child frame can retrieve the name property set by its parent.
3416IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003421 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos998581d2015-01-22 01:01:593422
clamyf1ccb4d2015-01-28 17:40:383423 TestNavigationObserver observer(shell()->web_contents());
alexmos998581d2015-01-22 01:01:593424
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);
clamyf1ccb4d2015-01-28 17:40:383429 EXPECT_TRUE(observer.last_navigation_succeeded());
3430 EXPECT_EQ(frame_url, observer.last_navigation_url());
alexmos998581d2015-01-22 01:01:593431
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(
nickadef4a52016-06-09 18:45:543440 root->child_at(0), "window.domAutomationController.send(window.name);",
3441 &result));
alexmos6b294562015-03-05 19:24:103442 EXPECT_EQ("3-1-name", result);
alexmos998581d2015-01-22 01:01:593443}
3444
alexmosbe2f4c32015-03-10 02:30:233445// 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.
3447IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003452 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosbe2f4c32015-03-10 02:30:233453 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.
nickadef4a52016-06-09 18:45:543467 EXPECT_TRUE(
3468 ExecuteScript(root->child_at(0), "window.name = 'updated-name';"));
alexmosbe2f4c32015-03-10 02:30:233469
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(
nickadef4a52016-06-09 18:45:543477 ExecuteScriptAndExtractBool(shell(),
alexmosbe2f4c32015-03-10 02:30:233478 "window.domAutomationController.send("
nickadef4a52016-06-09 18:45:543479 " frames['updated-name'] == frames[0]);",
alexmosbe2f4c32015-03-10 02:30:233480 &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"));
nickadef4a52016-06-09 18:45:543491 EXPECT_TRUE(ExecuteScript(
3492 shell(),
3493 base::StringPrintf("frames['updated-name'].location.href = '%s';",
3494 foo_url.spec().c_str())));
alexmosbe2f4c32015-03-10 02:30:233495 frame_observer.Wait();
3496 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
3497}
3498
alexmosa7a4ff822015-04-27 17:59:563499// Verify that when a frame is navigated to a new origin, the origin update
3500// propagates to the frame's proxies.
3501IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003507 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosa7a4ff822015-04-27 17:59:563508 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).
dcheng59716272016-04-09 05:19:083529 std::unique_ptr<ConsoleObserverDelegate> console_delegate(
alexmosa7a4ff822015-04-27 17:59:563530 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(
nickadef4a52016-06-09 18:45:543538 root->child_at(0),
3539 "parent.frames['frame2'].location.href = 'data:text/html,foo'"));
alexmosa7a4ff822015-04-27 17:59:563540 console_delegate->Wait();
3541
creisabdd2bd62015-11-21 01:14:583542 std::string frame_origin = root->child_at(1)->current_origin().Serialize();
alexmosa7a4ff822015-04-27 17:59:563543 EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec());
3544 EXPECT_TRUE(
brettwd97eede2015-07-06 22:09:003545 base::MatchPattern(console_delegate->message(), "*" + frame_origin + "*"))
alexmosa7a4ff822015-04-27 17:59:563546 << "Error message does not contain the frame's latest origin ("
3547 << frame_origin << ")";
3548}
3549
nasko3e8c20e2014-12-18 06:54:563550// Ensure that navigating subframes in --site-per-process mode properly fires
3551// the DidStopLoading event on WebContentsObserver.
3552IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003557 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
nasko3e8c20e2014-12-18 06:54:563558
clamyf1ccb4d2015-01-28 17:40:383559 TestNavigationObserver observer(shell()->web_contents());
nasko3e8c20e2014-12-18 06:54:563560
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);
clamyf1ccb4d2015-01-28 17:40:383565 EXPECT_EQ(http_url, observer.last_navigation_url());
3566 EXPECT_TRUE(observer.last_navigation_succeeded());
nasko3e8c20e2014-12-18 06:54:563567
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.
clamyf1ccb4d2015-01-28 17:40:383578 EXPECT_TRUE(observer.last_navigation_succeeded());
3579 EXPECT_EQ(url, observer.last_navigation_url());
nasko3e8c20e2014-12-18 06:54:563580}
3581
creis0040d342015-02-19 01:42:373582// Ensure that the renderer does not crash when navigating a frame that has a
3583// sibling RemoteFrame. See https://crbug.com/426953.
3584IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003591 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
creis0040d342015-02-19 01:42:373592 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
kenrb77618cd52016-02-18 19:13:383615// 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.
3618IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003625 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
kenrb77618cd52016-02-18 19:13:383626
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
alexmosf40ce5b02015-02-25 20:19:563654// 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.
3657IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003670 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosf40ce5b02015-02-25 20:19:563671
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
alexmose7da5a12015-04-09 02:22:163686// Check that postMessage can be routed between cross-site iframes.
3687IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003693 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmose7da5a12015-04-09 02:22:163694
alexmose7da5a12015-04-09 02:22:163695 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.
alexmos9f8705a2015-05-06 19:58:593709 PostMessageAndWaitForReply(root->child_at(0),
3710 "postToSibling('subframe-msg','subframe2')",
3711 "\"done-subframe1\"");
alexmose7da5a12015-04-09 02:22:163712
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);
alexmos9f8705a2015-05-06 19:58:593717 PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')",
3718 "\"done-subframe2\"");
alexmose7da5a12015-04-09 02:22:163719 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
3720
alexmose7da5a12015-04-09 02:22:163721 // Verify the total number of received messages for each subframe. First
alexmos58729042015-06-18 23:20:003722 // frame should have one message (reply from second frame). Second frame
alexmose7da5a12015-04-09 02:22:163723 // should have two messages (message from first frame and reply from parent).
alexmos58729042015-06-18 23:20:003724 // 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
csharrison264bca642016-05-06 19:27:093730// 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.
3733IN_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);
nickadef4a52016-06-09 18:45:543759 EXPECT_TRUE(ExecuteScript(popup, "navigateOpener();"));
csharrison264bca642016-05-06 19:27:093760 navigation_observer.Wait();
3761}
3762
alexmos58729042015-06-18 23:20:003763// 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.
3765IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
alexmos17e57532015-08-15 02:54:363766 PostMessageWithSubframeOnOpenerChain) {
alexmos58729042015-06-18 23:20:003767 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.
ekaramadfd1b5cfa2016-04-19 00:35:003772 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos58729042015-06-18 23:20:003773
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;
nickadef4a52016-06-09 18:45:543789 EXPECT_TRUE(ExecuteScript(root->child_at(0), "openPopup('about:blank');"));
alexmos58729042015-06-18 23:20:003790 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;
nickadef4a52016-06-09 18:45:543799 EXPECT_TRUE(ExecuteScript(popup, "openPopup('about:blank');"));
alexmos58729042015-06-18 23:20:003800 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
alexmos5ac402d2015-07-09 07:51:103838 // 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.
nickadef4a52016-06-09 18:45:543842 EXPECT_TRUE(ExecuteScript(popup, "window.name = 'popup';"));
alexmos5ac402d2015-07-09 07:51:103843 PostMessageAndWaitForReply(popup_root, "postToOpener('subframe-msg', '*')",
3844 "\"done-popup\"");
alexmos58729042015-06-18 23:20:003845
alexmos5ac402d2015-07-09 07:51:103846 // 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();
nickadef4a52016-06-09 18:45:543853 EXPECT_TRUE(ExecuteScript(popup2, "window.name = 'popup2';"));
alexmos5ac402d2015-07-09 07:51:103854 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
alexmos58729042015-06-18 23:20:003863 EXPECT_EQ(0, GetReceivedMessages(root));
alexmos5ac402d2015-07-09 07:51:103864 EXPECT_EQ(3, GetReceivedMessages(root->child_at(0)));
alexmos58729042015-06-18 23:20:003865 EXPECT_EQ(0, GetReceivedMessages(root->child_at(1)));
alexmos5ac402d2015-07-09 07:51:103866 EXPECT_EQ(2, GetReceivedMessages(popup_root));
3867 EXPECT_EQ(1, GetReceivedMessages(popup2_root));
alexmose7da5a12015-04-09 02:22:163868}
3869
alexmos9f8705a2015-05-06 19:58:593870// Check that parent.frames[num] references correct sibling frames when the
3871// parent is remote. See https://crbug.com/478792.
3872IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003879 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos9f8705a2015-05-06 19:58:593880 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);
alexmos9f8705a2015-05-06 19:58:593892 NavigateFrameToURL(child1, c_url);
alexmos9f8705a2015-05-06 19:58:593893 NavigateFrameToURL(child2, d_url);
alexmos9f8705a2015-05-06 19:58:593894
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(
nickadef4a52016-06-09 18:45:543909 child0,
alexmos9f8705a2015-05-06 19:58:593910 "window.domAutomationController.send(window === parent.frames[0]);",
3911 &success));
3912 EXPECT_TRUE(success);
3913
3914 success = false;
3915 EXPECT_TRUE(ExecuteScriptAndExtractBool(
nickadef4a52016-06-09 18:45:543916 child1,
alexmos9f8705a2015-05-06 19:58:593917 "window.domAutomationController.send(window === parent.frames[1]);",
3918 &success));
3919 EXPECT_TRUE(success);
3920
3921 success = false;
3922 EXPECT_TRUE(ExecuteScriptAndExtractBool(
nickadef4a52016-06-09 18:45:543923 child2,
alexmos9f8705a2015-05-06 19:58:593924 "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.
alexmos58729042015-06-18 23:20:003939 EXPECT_EQ(1, GetReceivedMessages(child0));
3940 EXPECT_EQ(2, GetReceivedMessages(child1));
3941 EXPECT_EQ(1, GetReceivedMessages(child2));
alexmos9f8705a2015-05-06 19:58:593942}
3943
nick59dcb162015-04-09 20:29:013944IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:003949 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
nick59dcb162015-04-09 20:29:013950
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());
nick44bacf32015-04-14 02:06:393959 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));
nick59dcb162015-04-09 20:29:013969
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());
nick44bacf32015-04-14 02:06:393975 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));
nick59dcb162015-04-09 20:29:013985
3986 // Navigate back to the parent's origin.
lfgf2d4f912016-05-11 23:18:483987 RenderFrameDeletedObserver deleted_observer(child->current_frame_host());
nick59dcb162015-04-09 20:29:013988 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());
lfgf2d4f912016-05-11 23:18:483992
3993 // Wait for the old process to exit, to verify that the proxies go away.
3994 deleted_observer.WaitUntilDeleted();
nick44bacf32015-04-14 02:06:393995 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));
nick59dcb162015-04-09 20:29:014004}
4005
alexmos4cf2aa32015-07-15 23:40:434006IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:004012 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos4cf2aa32015-07-15 23:40:434013
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.
nickadef4a52016-06-09 18:45:544019 Shell* new_shell =
4020 OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "");
alexmos4cf2aa32015-07-15 23:40:434021 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(
nickadef4a52016-06-09 18:45:544033 popup_root,
alexmos4cf2aa32015-07-15 23:40:434034 "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"));
nickadef4a52016-06-09 18:45:544041 Shell* cross_site_popup = OpenPopup(root->child_at(0), popup_url, "");
alexmos4cf2aa32015-07-15 23:40:434042 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(
nickadef4a52016-06-09 18:45:544061 cross_site_popup_root,
alexmos4cf2aa32015-07-15 23:40:434062 "window.domAutomationController.send("
4063 " window.opener === window.opener.top.frames[0]);",
4064 &success));
4065 EXPECT_TRUE(success);
4066}
4067
alexmos5b50b6742016-03-17 20:38:054068// 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.
4071IN_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"));
nickadef4a52016-06-09 18:45:544077 Shell* popup = OpenPopup(shell(), popup_url, "foo");
alexmos5b50b6742016-03-17 20:38:054078 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:///");
nickadef4a52016-06-09 18:45:544085 NavigateNamedFrame(shell(), file_url, "foo");
alexmos5b50b6742016-03-17 20:38:054086 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));
nickadef4a52016-06-09 18:45:544098 NavigateNamedFrame(shell(), chrome_url, "foo");
alexmos5b50b6742016-03-17 20:38:054099 EXPECT_TRUE(WaitForLoadStop(popup->web_contents()));
4100 EXPECT_EQ(GURL(url::kAboutBlankURL),
4101 popup->web_contents()->GetLastCommittedURL());
4102}
4103
alexmos646fec02015-07-25 00:11:494104// Verify that named frames are discoverable from their opener's ancestors.
4105// See https://crbug.com/511474.
4106IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
alexmosb0f73be2015-09-30 22:11:334107 DiscoverNamedFrameFromAncestorOfOpener) {
alexmos646fec02015-07-25 00:11:494108 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.
ekaramadfd1b5cfa2016-04-19 00:35:004113 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos646fec02015-07-25 00:11:494114
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.
nickadef4a52016-06-09 18:45:544120 Shell* foo_shell =
4121 OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "foo");
alexmos646fec02015-07-25 00:11:494122 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"));
nickadef4a52016-06-09 18:45:544138 NavigateNamedFrame(shell(), named_frame_url, "foo");
alexmos646fec02015-07-25 00:11:494139 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());
nickadef4a52016-06-09 18:45:544147 NavigateNamedFrame(shell(), named_frame_url, "foo");
alexmos646fec02015-07-25 00:11:494148 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.
4157IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:004164 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos646fec02015-07-25 00:11:494165
4166 // Open a same-site popup from the main frame.
4167 GURL a_com_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
nickadef4a52016-06-09 18:45:544168 Shell* a_com_shell = OpenPopup(root->child_at(0), a_com_url, "");
alexmos646fec02015-07-25 00:11:494169 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.
nickadef4a52016-06-09 18:45:544176 Shell* foo_shell =
4177 OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "");
alexmos646fec02015-07-25 00:11:494178 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.
nickadef4a52016-06-09 18:45:544191 EXPECT_TRUE(ExecuteScript(foo_shell, "window.name = 'foo'"));
alexmos646fec02015-07-25 00:11:494192
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"));
nickadef4a52016-06-09 18:45:544199 NavigateNamedFrame(a_com_shell, named_frame_url, "foo");
alexmos646fec02015-07-25 00:11:494200 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
4201 EXPECT_EQ(named_frame_url, foo_root->current_url());
4202}
4203
alexmos95733002015-08-24 16:38:094204// 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.
4216IN_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
ekaramadfd1b5cfa2016-04-19 00:35:004221 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos95733002015-08-24 16:38:094222 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.
nickadef4a52016-06-09 18:45:544226 Shell* popup_shell = OpenPopup(shell(), GURL(url::kAboutBlankURL), "popup");
alexmos95733002015-08-24 16:38:094227 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(
nickadef4a52016-06-09 18:45:544245 root->child_at(1),
alexmos95733002015-08-24 16:38:094246 "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(
nickadef4a52016-06-09 18:45:544256 popup_shell,
alexmos95733002015-08-24 16:38:094257 "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(
nickadef4a52016-06-09 18:45:544266 root->child_at(0),
alexmos95733002015-08-24 16:38:094267 "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(
nickadef4a52016-06-09 18:45:544277 popup_root->child_at(1),
alexmos95733002015-08-24 16:38:094278 "window.domAutomationController.send("
4279 " window.opener === window.opener.parent.frames['frame1']);",
4280 &success));
4281 EXPECT_TRUE(success);
4282}
4283
alexmos90325cf2015-09-02 17:18:394284// 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.
4288IN_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
ekaramadfd1b5cfa2016-04-19 00:35:004293 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos90325cf2015-09-02 17:18:394294
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)"));
nickadef4a52016-06-09 18:45:544298 Shell* popup_shell = OpenPopup(shell(), popup_url, "popup");
alexmos90325cf2015-09-02 17:18:394299 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);
alexmos90325cf2015-09-02 17:18:394312
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(
nickadef4a52016-06-09 18:45:544317 popup_root->child_at(0),
alexmos90325cf2015-09-02 17:18:394318 "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(
nickadef4a52016-06-09 18:45:544324 popup_root->child_at(0),
alexmos90325cf2015-09-02 17:18:394325 "window.domAutomationController.send(postToOpenerOfParent('msg','*'));",
4326 &success));
4327 EXPECT_TRUE(success);
4328 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
4329}
4330
alexmosa181efc2015-09-03 00:39:044331// Check that if a subframe has an opener, that opener is preserved when the
4332// subframe navigates cross-site.
4333IN_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
ekaramadfd1b5cfa2016-04-19 00:35:004338 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosa181efc2015-09-03 00:39:044339 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(
nickadef4a52016-06-09 18:45:544350 root, "window.domAutomationController.send(!!window.open('','frame1'));",
alexmosa181efc2015-09-03 00:39:044351 &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(
nickadef4a52016-06-09 18:45:544360 root->child_at(0),
alexmosa181efc2015-09-03 00:39:044361 "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(
nickadef4a52016-06-09 18:45:544372 root->child_at(0),
alexmosa181efc2015-09-03 00:39:044373 "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(
nickadef4a52016-06-09 18:45:544384 root->child_at(1),
alexmosa181efc2015-09-03 00:39:044385 "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.
4396IN_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
ekaramadfd1b5cfa2016-04-19 00:35:004402 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosa181efc2015-09-03 00:39:044403
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"));
nickadef4a52016-06-09 18:45:544407 Shell* popup_shell = OpenPopup(shell(), popup_url, "popup");
alexmosa181efc2015-09-03 00:39:044408 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(
nickadef4a52016-06-09 18:45:544426 root,
alexmosa181efc2015-09-03 00:39:044427 "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(
nickadef4a52016-06-09 18:45:544436 popup_root->child_at(0),
alexmosa181efc2015-09-03 00:39:044437 "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);
alexmosa181efc2015-09-03 00:39:044447
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(
nickadef4a52016-06-09 18:45:544452 popup_root->child_at(0),
alexmosa181efc2015-09-03 00:39:044453 "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(
nickadef4a52016-06-09 18:45:544462 popup_root->child_at(0),
alexmosa181efc2015-09-03 00:39:044463 "window.domAutomationController.send("
4464 " postToOpenerOfSibling('subframe2', 'msg', '*'));",
4465 &success));
4466 EXPECT_TRUE(success);
4467 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
4468}
4469
alexmosb97d6bb62015-09-24 07:31:264470// Test for https://crbug.com/515302. Perform two navigations, A->B->A, and
alexmos9aa61232016-04-26 21:54:024471// drop the SwapOut ACK from the A->B navigation, so that the second B->A
alexmosb97d6bb62015-09-24 07:31:264472// navigation is initiated before the first page receives the SwapOut ACK.
alexmos9aa61232016-04-26 21:54:024473// Ensure that this doesn't crash and that the RVH(A) is not reused in that
4474// case.
alexmosb97d6bb62015-09-24 07:31:264475IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
alexmos9aa61232016-04-26 21:54:024476 RenderViewHostIsNotReusedAfterDelayedSwapOutACK) {
alexmosb97d6bb62015-09-24 07:31:264477 GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
4478 NavigateToURL(shell(), a_url);
4479
ekaramadfd1b5cfa2016-04-19 00:35:004480 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosb97d6bb62015-09-24 07:31:264481 RenderFrameHostImpl* rfh = root->current_frame_host();
4482 RenderViewHostImpl* rvh = rfh->render_view_host();
creise73d58ef2016-03-29 22:12:154483 int rvh_routing_id = rvh->GetRoutingID();
4484 SiteInstanceImpl* site_instance = rfh->GetSiteInstance();
alexmosb97d6bb62015-09-24 07:31:264485 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());
creisecf91fe42016-04-11 18:49:044491 rfh->DisableSwapOutTimerForTesting();
alexmosb97d6bb62015-09-24 07:31:264492
alexmos9aa61232016-04-26 21:54:024493 // 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.
alexmosb97d6bb62015-09-24 07:31:264496 GURL b_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
4497 TestFrameNavigationObserver commit_observer(root);
4498 shell()->LoadURL(b_url);
nasko8206fa12016-03-22 02:24:134499 commit_observer.WaitForCommit();
creise73d58ef2016-03-29 22:12:154500 EXPECT_FALSE(deleted_observer.deleted());
alexmosb97d6bb62015-09-24 07:31:264501
4502 // Since the SwapOut ACK for A->B is dropped, the first page's
alexmos9aa61232016-04-26 21:54:024503 // RenderFrameHost should be pending deletion after the last navigation.
nasko19736cc9f2016-04-08 22:38:454504 EXPECT_FALSE(rfh->is_active());
alexmosb97d6bb62015-09-24 07:31:264505
4506 // Wait for process A to exit so we can reinitialize it cleanly for the next
alexmos9aa61232016-04-26 21:54:024507 // 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.
alexmosb97d6bb62015-09-24 07:31:264516 RenderProcessHostWatcher process_exit_observer(
4517 rvh->GetProcess(),
4518 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
4519 process_exit_observer.Wait();
4520
alexmos9aa61232016-04-26 21:54:024521 // 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
alexmosb97d6bb62015-09-24 07:31:264525 // 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 =
clamy5cba1482016-02-26 08:58:144530 IsBrowserSideNavigationEnabled()
4531 ? root->render_manager()->speculative_frame_host()->render_view_host()
4532 : root->render_manager()->pending_render_view_host();
creise73d58ef2016-03-29 22:12:154533 EXPECT_EQ(site_instance, pending_rvh->GetSiteInstance());
4534 EXPECT_NE(rvh_routing_id, pending_rvh->GetRoutingID());
alexmosb97d6bb62015-09-24 07:31:264535
alexmosb97d6bb62015-09-24 07:31:264536 // Make sure the last navigation finishes without crashing.
4537 navigation_observer.Wait();
4538}
4539
creise73d58ef2016-03-29 22:12:154540// Test for https://crbug.com/591478, where navigating to a cross-site page with
alexmos9aa61232016-04-26 21:54:024541// a subframe on the old site caused a crash while trying to reuse the old
4542// RenderViewHost.
creise73d58ef2016-03-29 22:12:154543IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
alexmos9aa61232016-04-26 21:54:024544 ReusePendingDeleteRenderViewHostForSubframe) {
creise73d58ef2016-03-29 22:12:154545 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
4546 EXPECT_TRUE(NavigateToURL(shell(), main_url));
4547
creise73d58ef2016-03-29 22:12:154548 std::string script =
4549 "window.onunload = function() { "
4550 " var start = Date.now();"
4551 " while (Date.now() - start < 1000);"
4552 "}";
nickadef4a52016-06-09 18:45:544553 EXPECT_TRUE(ExecuteScript(shell(), script));
creise73d58ef2016-03-29 22:12:154554
creis05a1cb72016-03-31 21:26:244555 // Navigating cross-site with an iframe to the original site shouldn't crash.
creise73d58ef2016-03-29 22:12:154556 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
creis05a1cb72016-03-31 21:26:244560 // If the subframe is created while the main frame is pending deletion, then
alexmos9aa61232016-04-26 21:54:024561 // 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,
creis05a1cb72016-03-31 21:26:244567 // the test is just likely (not certain) to catch regressions by crashing.
creise73d58ef2016-03-29 22:12:154568}
4569
alexmosca2c6ba2015-10-01 21:52:254570// 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.
4574IN_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
ekaramadfd1b5cfa2016-04-19 00:35:004580 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosca2c6ba2015-10-01 21:52:254581
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;
nickadef4a52016-06-09 18:45:544592 EXPECT_TRUE(
4593 ExecuteScriptAndExtractString(shell(), "focusInputField()", &result));
alexmosca2c6ba2015-10-01 21:52:254594 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.
alexmosb1dc2162015-11-05 00:59:204602 SimulateMouseClick(
4603 root->child_at(0)->current_frame_host()->GetRenderWidgetHost(), 1, 1);
alexmosca2c6ba2015-10-01 21:52:254604
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.
alexmosb1dc2162015-11-05 00:59:204617 SimulateMouseClick(
4618 shell()->web_contents()->GetRenderViewHost()->GetWidget(), 1, 1);
alexmosca2c6ba2015-10-01 21:52:254619
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
alexmosb1dc2162015-11-05 00:59:204631// 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.
4635IN_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
ekaramadfd1b5cfa2016-04-19 00:35:004640 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosb1dc2162015-11-05 00:59:204641
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
alexmos21acae52015-11-07 01:04:434657 // Focus the b.com frame.
4658 FocusFrame(child);
alexmosb1dc2162015-11-05 00:59:204659 EXPECT_EQ(child, root->frame_tree()->GetFocusedFrame());
4660
alexmos21acae52015-11-07 01:04:434661 // Helper function to check a property of document.activeElement in the
4662 // specified frame.
alexmosb1dc2162015-11-05 00:59:204663 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
alexmos21acae52015-11-07 01:04:434674 // Verify that document.activeElement on main frame points to the <iframe>
4675 // element for the b.com frame.
alexmosb1dc2162015-11-05 00:59:204676 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
alexmos21acae52015-11-07 01:04:434680 // Focus the a.com main frame again.
4681 FocusFrame(root);
alexmosb1dc2162015-11-05 00:59:204682 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
alexmos21acae52015-11-07 01:04:434687 // Now shift focus from main frame to c.com frame.
4688 FocusFrame(grandchild);
alexmosb1dc2162015-11-05 00:59:204689
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
alexmos5357efb2015-12-16 21:44:004706// Check that window.focus works for cross-process subframes.
4707IN_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
ekaramadfd1b5cfa2016-04-19 00:35:004712 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos5357efb2015-12-16 21:44:004713
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");
nickadef4a52016-06-09 18:45:544743 EXPECT_TRUE(ExecuteScript(shell(), script));
alexmos5357efb2015-12-16 21:44:004744 script = base::StringPrintf(kSetupFocusEvents, "child1", "child1");
nickadef4a52016-06-09 18:45:544745 EXPECT_TRUE(ExecuteScript(child1, script));
alexmos5357efb2015-12-16 21:44:004746 script = base::StringPrintf(kSetupFocusEvents, "child2", "child2");
nickadef4a52016-06-09 18:45:544747 EXPECT_TRUE(ExecuteScript(child2, script));
alexmos5357efb2015-12-16 21:44:004748
4749 // Execute window.focus on the B subframe from the A main frame.
nickadef4a52016-06-09 18:45:544750 EXPECT_TRUE(ExecuteScript(root, "frames[0].focus()"));
alexmos5357efb2015-12-16 21:44:004751
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.
nickadef4a52016-06-09 18:45:544780 EXPECT_TRUE(ExecuteScript(root, "frames[1].focus()"));
alexmos5357efb2015-12-16 21:44:004781
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.
nickadef4a52016-06-09 18:45:544790 EXPECT_TRUE(ExecuteScript(child2, "parent.focus()"));
alexmos5357efb2015-12-16 21:44:004791
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
kenrb77db5072015-10-15 19:21:254800// There are no cursors on Android.
4801#if !defined(OS_ANDROID)
4802class 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.
reillyg96f9f9e2015-10-20 00:16:434842// Fails under TSan. http://crbug.com/545237
kenrb77db5072015-10-15 19:21:254843IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
reillyg96f9f9e2015-10-20 00:16:434844 DISABLED_CursorUpdateFromReceivedFromCrossSiteIframe) {
kenrb77db5072015-10-15 19:21:254845 GURL main_url(embedded_test_server()->GetURL(
4846 "/frame_tree/page_with_positioned_frame.html"));
4847 EXPECT_TRUE(NavigateToURL(shell(), main_url));
4848
ekaramadfd1b5cfa2016-04-19 00:35:004849 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
kenrb77db5072015-10-15 19:21:254850
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());
ekaramadfd1b5cfa2016-04-19 00:35:004868 web_contents()->GetInputEventRouter()->RouteMouseEvent(root_view,
4869 &mouse_event);
kenrb77db5072015-10-15 19:21:254870
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
lfg3faeb652015-10-21 16:34:384879// Tests that we are using the correct RenderFrameProxy when navigating an
4880// opener window.
4881IN_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");
nickadef4a52016-06-09 18:45:544889 Shell* popup = OpenPopup(shell(), cross_url, "");
lfg3faeb652015-10-21 16:34:384890 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() + "'";
nickadef4a52016-06-09 18:45:544895 EXPECT_TRUE(ExecuteScript(popup, script));
lfg3faeb652015-10-21 16:34:384896 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
4897 EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), cross_url);
4898}
4899
wjmacleanfab616a2016-03-02 18:40:394900// 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
4906IN_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
ekaramadfd1b5cfa2016-04-19 00:35:004912 WebContentsImpl* contents = web_contents();
4913 FrameTreeNode* root = contents->GetFrameTree()->root();
wjmacleanfab616a2016-03-02 18:40:394914 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);
wjmacleanfab616a2016-03-02 18:40:394919
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*>(
ekaramadfd1b5cfa2016-04-19 00:35:004931 contents->GetRenderWidgetHostView());
wjmacleanfab616a2016-03-02 18:40:394932 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(
nickadef4a52016-06-09 18:45:544939 root->child_at(0),
wjmacleanfab616a2016-03-02 18:40:394940 "window.domAutomationController.send(getLastTouchEvent());", &result));
4941 EXPECT_EQ("touchstart", result);
4942}
wjmaclean44464232016-03-04 21:49:194943
4944namespace {
4945
4946// Declared here to be close to the SubframeGestureEventRouting test.
4947void 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
reillyga87c5bb2016-03-11 19:25:584955// 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
wjmaclean44464232016-03-04 21:49:194961IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
reillyga87c5bb2016-03-11 19:25:584962 MAYBE_SubframeGestureEventRouting) {
wjmaclean44464232016-03-04 21:49:194963 GURL main_url(embedded_test_server()->GetURL(
4964 "/frame_tree/page_with_positioned_nested_frames.html"));
4965 EXPECT_TRUE(NavigateToURL(shell(), main_url));
4966
ekaramadfd1b5cfa2016-04-19 00:35:004967 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
wjmaclean44464232016-03-04 21:49:194968 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();
wjmaclean44464232016-03-04 21:49:194974
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;
dcheng59716272016-04-09 05:19:084998 std::unique_ptr<SyntheticTapGesture> gesture(new SyntheticTapGesture(params));
wjmaclean44464232016-03-04 21:49:194999
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
5024namespace {
5025
5026// Defined here to be close to
5027// SitePerProcessBrowserTest.InputEventRouterGestureTargetQueueTest.
5028void 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
5046void SendGestureTapSequenceWithExpectedTarget(
5047 RenderWidgetHostViewBase* root_view,
mohsen298aa382016-06-30 00:19:005048 const gfx::Point& gesture_point,
wjmaclean44464232016-03-04 21:49:195049 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
mohsen7d45a482016-05-24 21:03:445054 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);
wjmaclean44464232016-03-04 21:49:195060 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
mohsen7d45a482016-05-24 21:03:445068 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);
wjmaclean44464232016-03-04 21:49:195074 root_view_aura->OnGestureEvent(&gesture_tap_down_event);
5075 EXPECT_EQ(expected_target, router_gesture_target);
5076
mohsen7d45a482016-05-24 21:03:445077 ui::GestureEventDetails gesture_show_press_details(ui::ET_GESTURE_SHOW_PRESS);
5078 gesture_show_press_details.set_device_type(
5079 ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
wjmaclean44464232016-03-04 21:49:195080 ui::GestureEvent gesture_show_press_event(
5081 gesture_point.x(), gesture_point.y(), 0, ui::EventTimeForNow(),
mohsen7d45a482016-05-24 21:03:445082 gesture_show_press_details);
wjmaclean44464232016-03-04 21:49:195083 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);
mohsen7d45a482016-05-24 21:03:445087 gesture_tap_details.set_device_type(
5088 ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
wjmaclean44464232016-03-04 21:49:195089 gesture_tap_details.set_tap_count(1);
mohsen7d45a482016-05-24 21:03:445090 ui::GestureEvent gesture_tap_event(gesture_point.x(), gesture_point.y(), 0,
5091 ui::EventTimeForNow(),
5092 gesture_tap_details);
wjmaclean44464232016-03-04 21:49:195093 root_view_aura->OnGestureEvent(&gesture_tap_event);
5094 EXPECT_EQ(expected_target, router_gesture_target);
5095
mohsen7d45a482016-05-24 21:03:445096 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);
wjmaclean44464232016-03-04 21:49:195102 root_view_aura->OnGestureEvent(&gesture_end_event);
5103 EXPECT_EQ(expected_target, router_gesture_target);
5104}
5105
mohsen298aa382016-06-30 00:19:005106void 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.
5137void 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
wjmaclean44464232016-03-04 21:49:195156} // namespace anonymous
5157
5158IN_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
ekaramadfd1b5cfa2016-04-19 00:35:005164 WebContentsImpl* contents = web_contents();
5165 FrameTreeNode* root = contents->GetFrameTree()->root();
wjmaclean44464232016-03-04 21:49:195166 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();
wjmaclean44464232016-03-04 21:49:195172
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*>(
ekaramadfd1b5cfa2016-04-19 00:35:005184 contents->GetRenderWidgetHostView());
wjmaclean44464232016-03-04 21:49:195185
ekaramadfd1b5cfa2016-04-19 00:35:005186 RenderWidgetHostInputEventRouter* router = contents->GetInputEventRouter();
mohsen298aa382016-06-30 00:19:005187 EXPECT_TRUE(router->touchscreen_gesture_target_queue_.empty());
5188 EXPECT_EQ(nullptr, router->touchscreen_gesture_target_.target);
wjmaclean44464232016-03-04 21:49:195189
5190 // Send touch sequence to main-frame.
5191 gfx::Point main_frame_point(25, 25);
5192 SendTouchTapWithExpectedTarget(rwhv_parent, main_frame_point,
mohsen298aa382016-06-30 00:19:005193 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);
wjmaclean44464232016-03-04 21:49:195196
5197 // Send touch sequence to child.
5198 gfx::Point child_center(150, 150);
5199 SendTouchTapWithExpectedTarget(rwhv_parent, child_center,
mohsen298aa382016-06-30 00:19:005200 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);
wjmaclean44464232016-03-04 21:49:195203
5204 // Send another touch sequence to main frame.
5205 SendTouchTapWithExpectedTarget(rwhv_parent, main_frame_point,
mohsen298aa382016-06-30 00:19:005206 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);
wjmaclean44464232016-03-04 21:49:195209
5210 // Send Gestures to clear GestureTargetQueue.
5211
5212 // The first touch sequence should generate a GestureTapDown, sent to the
5213 // main frame.
mohsen298aa382016-06-30 00:19:005214 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());
wjmaclean44464232016-03-04 21:49:195218 // 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.
mohsen298aa382016-06-30 00:19:005221 EXPECT_EQ(rwhv_parent, router->touchscreen_gesture_target_.target);
wjmaclean44464232016-03-04 21:49:195222
5223 // The second touch sequence should generate a GestureTapDown, sent to the
5224 // child frame.
mohsen298aa382016-06-30 00:19:005225 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);
wjmaclean44464232016-03-04 21:49:195230
5231 // The third touch sequence should generate a GestureTapDown, sent to the
5232 // main frame.
mohsen298aa382016-06-30 00:19:005233 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
5240IN_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
wjmaclean44464232016-03-04 21:49:195307}
wjmacleanfab616a2016-03-02 18:40:395308#endif // defined(USE_AURA)
5309
kenrb162e42c2015-11-24 21:10:005310// A WebContentsDelegate to capture ContextMenu creation events.
5311class 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
kenrb611d6532016-03-31 17:37:375344// Helper function to run the CreateContextMenuTest in either normal
5345// or high DPI mode.
5346void CreateContextMenuTestHelper(
5347 Shell* shell,
5348 net::test_server::EmbeddedTestServer* embedded_test_server) {
5349 GURL main_url(embedded_test_server->GetURL(
kenrb162e42c2015-11-24 21:10:005350 "/frame_tree/page_with_positioned_frame.html"));
kenrb611d6532016-03-31 17:37:375351 EXPECT_TRUE(NavigateToURL(shell, main_url));
kenrb162e42c2015-11-24 21:10:005352
5353 // It is safe to obtain the root frame tree node here, as it doesn't change.
kenrb611d6532016-03-31 17:37:375354 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell->web_contents())
kenrb162e42c2015-11-24 21:10:005355 ->GetFrameTree()
5356 ->root();
5357 ASSERT_EQ(1U, root->child_count());
5358
5359 FrameTreeNode* child_node = root->child_at(0);
kenrb611d6532016-03-31 17:37:375360 GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
kenrb162e42c2015-11-24 21:10:005361 EXPECT_EQ(site_url, child_node->current_url());
kenrb611d6532016-03-31 17:37:375362 EXPECT_NE(shell->web_contents()->GetSiteInstance(),
kenrb162e42c2015-11-24 21:10:005363 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.
kenrb611d6532016-03-31 17:37:375373 SurfaceHitTestReadyNotifier notifier(
5374 static_cast<RenderWidgetHostViewChildFrame*>(rwhv_child));
5375 notifier.WaitForSurfaceReady();
kenrb162e42c2015-11-24 21:10:005376
5377 // A WebContentsDelegate to listen for the ShowContextMenu message.
5378 ContextMenuObserverDelegate context_menu_delegate;
kenrb611d6532016-03-31 17:37:375379 shell->web_contents()->SetDelegate(&context_menu_delegate);
kenrb162e42c2015-11-24 21:10:005380
5381 RenderWidgetHostInputEventRouter* router =
kenrb611d6532016-03-31 17:37:375382 static_cast<WebContentsImpl*>(shell->web_contents())
kenrb162e42c2015-11-24 21:10:005383 ->GetInputEventRouter();
5384
kenrb611d6532016-03-31 17:37:375385 gfx::Point point(75, 75);
5386
kenrb162e42c2015-11-24 21:10:005387 // 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;
kenrb611d6532016-03-31 17:37:375391 click_event.x = point.x();
5392 click_event.y = point.y();
kenrb162e42c2015-11-24 21:10:005393 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;
kenrb611d6532016-03-31 17:37:375398 click_event.x = point.x();
5399 click_event.y = point.y();
kenrb162e42c2015-11-24 21:10:005400 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
kenrb611d6532016-03-31 17:37:375410// 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
5419IN_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
5434IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
5435 MAYBE_HighDPICreateContextMenuTest) {
5436 CreateContextMenuTestHelper(shell(), embedded_test_server());
5437}
5438
kenrbc52e1b4e2016-03-20 01:03:375439class ShowWidgetMessageFilter : public content::BrowserMessageFilter {
5440 public:
5441 ShowWidgetMessageFilter()
kenrb75b5fe25f2016-03-25 00:30:455442#if defined(OS_MACOSX) || defined(OS_ANDROID)
5443 : content::BrowserMessageFilter(FrameMsgStart),
5444#else
kenrbc52e1b4e2016-03-20 01:03:375445 : content::BrowserMessageFilter(ViewMsgStart),
kenrb75b5fe25f2016-03-25 00:30:455446#endif
5447 message_loop_runner_(new content::MessageLoopRunner) {
5448 }
kenrbc52e1b4e2016-03-20 01:03:375449
5450 bool OnMessageReceived(const IPC::Message& message) override {
5451 IPC_BEGIN_MESSAGE_MAP(ShowWidgetMessageFilter, message)
kenrb75b5fe25f2016-03-25 00:30:455452#if defined(OS_MACOSX) || defined(OS_ANDROID)
5453 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
5454#else
kenrbc52e1b4e2016-03-20 01:03:375455 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
kenrb75b5fe25f2016-03-25 00:30:455456#endif
kenrbc52e1b4e2016-03-20 01:03:375457 IPC_END_MESSAGE_MAP()
5458 return false;
5459 }
5460
5461 gfx::Rect last_initial_rect() const { return initial_rect_; }
5462
5463 void Wait() {
kenrb75b5fe25f2016-03-25 00:30:455464 initial_rect_ = gfx::Rect();
5465 message_loop_runner_->Run();
kenrbc52e1b4e2016-03-20 01:03:375466 }
5467
5468 void Reset() {
kenrbc52e1b4e2016-03-20 01:03:375469 initial_rect_ = gfx::Rect();
kenrb61b6c252016-03-22 17:37:155470 message_loop_runner_ = new content::MessageLoopRunner;
kenrbc52e1b4e2016-03-20 01:03:375471 }
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
kenrb75b5fe25f2016-03-25 00:30:455483#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
kenrbc52e1b4e2016-03-20 01:03:375492 void OnShowWidgetOnUI(int route_id, const gfx::Rect& initial_rect) {
5493 initial_rect_ = initial_rect;
kenrbc52e1b4e2016-03-20 01:03:375494 message_loop_runner_->Quit();
5495 }
5496
5497 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
5498 gfx::Rect initial_rect_;
kenrbc52e1b4e2016-03-20 01:03:375499
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.
kenrb75b5fe25f2016-03-25 00:30:455505#if defined(OS_ANDROID)
5506// Surface-based hit testing and coordinate translation is not yet available
5507// on Android.
kenrb61b6c252016-03-22 17:37:155508#define MAYBE_PopupMenuTest DISABLED_PopupMenuTest
kenrbc52e1b4e2016-03-20 01:03:375509#else
kenrb61b6c252016-03-22 17:37:155510#define MAYBE_PopupMenuTest PopupMenuTest
kenrbc52e1b4e2016-03-20 01:03:375511#endif
kenrb61b6c252016-03-22 17:37:155512IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_PopupMenuTest) {
kenrbc52e1b4e2016-03-20 01:03:375513 GURL main_url(
5514 embedded_test_server()->GetURL("/cross_site_iframe_factory.html?a(a)"));
5515 NavigateToURL(shell(), main_url);
5516
ekaramadfd1b5cfa2016-04-19 00:35:005517 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
kenrbc52e1b4e2016-03-20 01:03:375518
kenrb75b5fe25f2016-03-25 00:30:455519#if !defined(OS_MACOSX)
5520 // Unused variable on Mac.
kenrbc52e1b4e2016-03-20 01:03:375521 RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
5522 root->current_frame_host()->GetRenderWidgetHost()->GetView());
kenrb75b5fe25f2016-03-25 00:30:455523#endif
ekaramadfd1b5cfa2016-04-19 00:35:005524 web_contents()->SendScreenRects();
kenrbc52e1b4e2016-03-20 01:03:375525
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;
saheld9c26df2016-06-07 15:09:565549 rwhv_child->ProcessMouseEvent(click_event, ui::LatencyInfo());
kenrbc52e1b4e2016-03-20 01:03:375550
kenrb75b5fe25f2016-03-25 00:30:455551 // Dismiss the popup.
5552 click_event.x = 1;
5553 click_event.y = 1;
saheld9c26df2016-06-07 15:09:565554 rwhv_child->ProcessMouseEvent(click_event, ui::LatencyInfo());
kenrb75b5fe25f2016-03-25 00:30:455555
kenrbc52e1b4e2016-03-20 01:03:375556 filter->Wait();
kenrbc52e1b4e2016-03-20 01:03:375557 gfx::Rect popup_rect = filter->last_initial_rect();
kenrb75b5fe25f2016-03-25 00:30:455558#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
kenrbc52e1b4e2016-03-20 01:03:375564 EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354);
5565 EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 94);
kenrb75b5fe25f2016-03-25 00:30:455566#endif
kenrbc52e1b4e2016-03-20 01:03:375567}
5568
kenrb61b6c252016-03-22 17:37:155569// 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.
kenrb75b5fe25f2016-03-25 00:30:455573#if defined(OS_ANDROID)
5574// Surface-based hit testing and coordinate translation is not yet avaiable on
5575// Android.
kenrb61b6c252016-03-22 17:37:155576#define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest
5577#else
benwells103e61ce2016-04-01 01:38:535578// Times out frequently. https://crbug.com/599730.
5579#define MAYBE_NestedPopupMenuTest DISABLED_NestedPopupMenuTest
kenrb61b6c252016-03-22 17:37:155580#endif
5581IN_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
ekaramadfd1b5cfa2016-04-19 00:35:005586 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
kenrb61b6c252016-03-22 17:37:155587
kenrb75b5fe25f2016-03-25 00:30:455588#if !defined(OS_MACOSX)
5589 // Undefined variable on Mac.
kenrb61b6c252016-03-22 17:37:155590 RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
5591 root->current_frame_host()->GetRenderWidgetHost()->GetView());
kenrb75b5fe25f2016-03-25 00:30:455592#endif
ekaramadfd1b5cfa2016-04-19 00:35:005593 web_contents()->SendScreenRects();
kenrb61b6c252016-03-22 17:37:155594
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;
saheld9c26df2016-06-07 15:09:565624 rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
kenrb61b6c252016-03-22 17:37:155625
kenrb75b5fe25f2016-03-25 00:30:455626 // Prompt the WebContents to dismiss the popup by clicking elsewhere.
5627 click_event.x = 1;
5628 click_event.y = 1;
saheld9c26df2016-06-07 15:09:565629 rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
kenrb75b5fe25f2016-03-25 00:30:455630
kenrb61b6c252016-03-22 17:37:155631 filter->Wait();
5632
5633 gfx::Rect popup_rect = filter->last_initial_rect();
5634
kenrb75b5fe25f2016-03-25 00:30:455635#if defined(OS_MACOSX)
5636 EXPECT_EQ(popup_rect.x(), 9);
5637 EXPECT_EQ(popup_rect.y(), 9);
5638#else
kenrb61b6c252016-03-22 17:37:155639 EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 354);
5640 EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 154);
kenrb75b5fe25f2016-03-25 00:30:455641#endif
kenrb61b6c252016-03-22 17:37:155642
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;";
nickadef4a52016-06-09 18:45:545654 EXPECT_TRUE(ExecuteScript(root, script));
kenrb61b6c252016-03-22 17:37:155655
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;
saheld9c26df2016-06-07 15:09:565674 rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
kenrb61b6c252016-03-22 17:37:155675
kenrb75b5fe25f2016-03-25 00:30:455676 click_event.x = 1;
5677 click_event.y = 1;
saheld9c26df2016-06-07 15:09:565678 rwhv_c_node->ProcessMouseEvent(click_event, ui::LatencyInfo());
kenrb75b5fe25f2016-03-25 00:30:455679
kenrb61b6c252016-03-22 17:37:155680 filter->Wait();
5681
5682 popup_rect = filter->last_initial_rect();
5683
kenrb75b5fe25f2016-03-25 00:30:455684#if defined(OS_MACOSX)
5685 EXPECT_EQ(popup_rect.x(), 9);
5686 EXPECT_EQ(popup_rect.y(), 9);
5687#else
kenrb61b6c252016-03-22 17:37:155688 EXPECT_EQ(popup_rect.x() - rwhv_root->GetViewBounds().x(), 203);
5689 EXPECT_EQ(popup_rect.y() - rwhv_root->GetViewBounds().y(), 248);
kenrb75b5fe25f2016-03-25 00:30:455690#endif
kenrb61b6c252016-03-22 17:37:155691}
5692
alexmosba1fb7152015-12-12 07:20:305693// 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.
5697IN_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);";
nickadef4a52016-06-09 18:45:545715 EXPECT_TRUE(ExecuteScript(root, script));
alexmosba1fb7152015-12-12 07:20:305716 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(
nickadef4a52016-06-09 18:45:545723 root, "domAutomationController.send(frames.length)", &child_count));
alexmosba1fb7152015-12-12 07:20:305724 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.
5731IN_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(
nickadef4a52016-06-09 18:45:545755 root, "document.body.removeChild(document.querySelector('iframe'));"));
alexmosba1fb7152015-12-12 07:20:305756 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(
nickadef4a52016-06-09 18:45:545762 root, "domAutomationController.send(frames.length)", &child_count));
alexmosba1fb7152015-12-12 07:20:305763 EXPECT_EQ(1, child_count);
5764}
5765
nasko13b8e772016-03-03 19:41:355766// 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.
5769IN_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());
nickadef4a52016-06-09 18:45:545784 EXPECT_TRUE(ExecuteScript(
5785 root, base::StringPrintf("f.src = '%s'", url::kAboutBlankURL)));
nasko13b8e772016-03-03 19:41:355786 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(
nickadef4a52016-06-09 18:45:545791 root, "domAutomationController.send(frames.length)", &child_count));
nasko13b8e772016-03-03 19:41:355792 EXPECT_EQ(0, child_count);
5793}
5794
alexmose846e412015-12-18 07:46:455795// 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.
5801IN_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(
nickadef4a52016-06-09 18:45:545829 root, "document.body.removeChild(document.querySelector('iframe'));"));
alexmose846e412015-12-18 07:46:455830
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(
nickadef4a52016-06-09 18:45:545845 root, "domAutomationController.send(frames.length)", &child_count));
alexmose846e412015-12-18 07:46:455846 EXPECT_EQ(0, child_count);
5847}
5848
naskoeab5c5582015-12-15 05:20:005849// 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.
5853IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:005860 FrameTreeNode* node = web_contents()->GetFrameTree()->root()->child_at(0);
naskoeab5c5582015-12-15 05:20:005861 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 =
clamy5cba1482016-02-26 08:58:145880 IsBrowserSideNavigationEnabled()
5881 ? node->render_manager()->speculative_frame_host()->GetProcess()
5882 : node->render_manager()->pending_frame_host()->GetProcess();
naskoeab5c5582015-12-15 05:20:005883 RenderProcessHostWatcher watcher(
5884 process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
5885 int frame_routing_id =
clamy5cba1482016-02-26 08:58:145886 IsBrowserSideNavigationEnabled()
5887 ? node->render_manager()->speculative_frame_host()->GetRoutingID()
5888 : node->render_manager()->pending_frame_host()->GetRoutingID();
naskoeab5c5582015-12-15 05:20:005889 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;
lukasza464d8692016-02-22 19:26:325907 params.replication_state.name = "name";
5908 params.replication_state.unique_name = "name";
naskoeab5c5582015-12-15 05:20:005909
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.
5929IN_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
ekaramadfd1b5cfa2016-04-19 00:35:005934 WebContentsImpl* contents = web_contents();
5935 EXPECT_EQ(2U, contents->GetFrameTree()->root()->child_count());
naskoeab5c5582015-12-15 05:20:005936
5937 // Capture the FrameTreeNode this test will be navigating.
ekaramadfd1b5cfa2016-04-19 00:35:005938 FrameTreeNode* node = contents->GetFrameTree()->root()->child_at(0);
naskoeab5c5582015-12-15 05:20:005939 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.
ekaramadfd1b5cfa2016-04-19 00:35:005958 EXPECT_TRUE(ExecuteScript(contents,
naskoeab5c5582015-12-15 05:20:005959 "document.body.removeChild("
5960 "document.querySelectorAll('iframe')[0])"));
ekaramadfd1b5cfa2016-04-19 00:35:005961 EXPECT_EQ(1U, contents->GetFrameTree()->root()->child_count());
naskoeab5c5582015-12-15 05:20:005962
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;
lukasza464d8692016-02-22 19:26:325972 params.replication_state.name = "name";
5973 params.replication_state.unique_name = "name";
naskoeab5c5582015-12-15 05:20:005974
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.
ekaramadfd1b5cfa2016-04-19 00:35:005982 NavigateFrameToURL(contents->GetFrameTree()->root()->child_at(0),
5983 embedded_test_server()->GetURL("d.com", "/title3.html"));
naskoeab5c5582015-12-15 05:20:005984 watcher.Wait();
5985 EXPECT_TRUE(watcher.did_exit_normally());
5986}
5987
ekaramadbabb9bf2016-01-12 15:17:025988IN_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
ekaramadfd1b5cfa2016-04-19 00:35:005997 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
ekaramadbabb9bf2016-01-12 15:17:025998
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);
nickadef4a52016-06-09 18:45:546017 EXPECT_TRUE(ExecuteScript(shell(), hide_script));
ekaramadbabb9bf2016-01-12 15:17:026018 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);
nickadef4a52016-06-09 18:45:546023 EXPECT_TRUE(ExecuteScript(shell(), show_script));
ekaramadbabb9bf2016-01-12 15:17:026024 EXPECT_TRUE(show_observer.WaitUntilSatisfied());
6025}
6026
alexmos6e940102016-01-19 22:47:256027// Verify that sandbox flags inheritance works across multiple levels of
6028// frames. See https://crbug.com/576845.
6029IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:006035 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos6e940102016-01-19 22:47:256036
6037 // Set sandbox flags for child frame.
6038 EXPECT_TRUE(ExecuteScript(
nickadef4a52016-06-09 18:45:546039 root, "document.querySelector('iframe').sandbox = 'allow-scripts';"));
alexmos6e940102016-01-19 22:47:256040
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))"));
alexmos6e940102016-01-19 22:47:256056 NavigateFrameToURL(root->child_at(0), frame_url);
nasko8206fa12016-03-22 02:24:136057
alexmos6e940102016-01-19 22:47:256058 // 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).
6080IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:006087 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos6e940102016-01-19 22:47:256088
6089 // Set sandbox flags for child frame.
6090 EXPECT_TRUE(ExecuteScript(
nickadef4a52016-06-09 18:45:546091 root, "document.querySelector('iframe').sandbox = 'allow-scripts';"));
alexmos6e940102016-01-19 22:47:256092
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(
nickadef4a52016-06-09 18:45:546105 child, "document.body.appendChild(document.createElement('iframe'));"));
alexmos6e940102016-01-19 22:47:256106 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
alexmosaedfc6f2016-01-21 23:57:386125// 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.
6128IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:006135 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosaedfc6f2016-01-21 23:57:386136
6137 // Set sandbox flags for child frame.
nickadef4a52016-06-09 18:45:546138 EXPECT_TRUE(ExecuteScript(root,
alexmosaedfc6f2016-01-21 23:57:386139 "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.
nickadef4a52016-06-09 18:45:546163 Shell* foo_shell =
6164 OpenPopup(root->child_at(0), GURL(url::kAboutBlankURL), "foo");
alexmosaedfc6f2016-01-21 23:57:386165 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);
nickadef4a52016-06-09 18:45:546183 EXPECT_TRUE(
6184 ExecuteScript(foo_root, "location.href = '" + c_url.spec() + "';"));
alexmosaedfc6f2016-01-21 23:57:386185 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.
6197IN_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.
ekaramadfd1b5cfa2016-04-19 00:35:006204 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmosaedfc6f2016-01-21 23:57:386205
6206 // Set sandbox flags for child frame, specifying that popups opened from it
6207 // should not be sandboxed.
6208 EXPECT_TRUE(ExecuteScript(
nickadef4a52016-06-09 18:45:546209 root,
alexmosaedfc6f2016-01-21 23:57:386210 "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"));
nickadef4a52016-06-09 18:45:546232 Shell* foo_shell = OpenPopup(root->child_at(0), b_url, "foo");
alexmosaedfc6f2016-01-21 23:57:386233 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(
nickadef4a52016-06-09 18:45:546247 foo_root, "domAutomationController.send(document.origin)",
alexmosaedfc6f2016-01-21 23:57:386248 &popup_origin));
6249 EXPECT_EQ(b_url.GetOrigin().spec(), popup_origin + "/");
6250}
6251
estark56dc8e22016-01-26 17:58:296252// 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).
gliderad70d3f62016-04-06 09:41:396256// 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
estark56dc8e22016-01-26 17:58:296262IN_PROC_BROWSER_TEST_F(SitePerProcessIgnoreCertErrorsBrowserTest,
gliderad70d3f62016-04-06 09:41:396263 MAYBE_PassiveMixedContentInIframe) {
estark56dc8e22016-01-26 17:58:296264 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"));
ekaramadfd1b5cfa2016-04-19 00:35:006277 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
estark56dc8e22016-01-26 17:58:296278 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.
6291IN_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
ekaramadfd1b5cfa2016-04-19 00:35:006303 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
mkwstf672e7ef2016-06-09 20:51:076304 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);
estark56dc8e22016-01-26 17:58:296309
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);
mkwstf672e7ef2016-06-09 20:51:076314 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);
estark56dc8e22016-01-26 17:58:296319
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")));
mkwstf672e7ef2016-06-09 20:51:076324 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.
6330IN_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);
estark56dc8e22016-01-26 17:58:296365}
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).
6371IN_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));
ekaramadfd1b5cfa2016-04-19 00:35:006381 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
estark56dc8e22016-01-26 17:58:296382 ASSERT_EQ(1U, root->child_count());
6383 FrameTreeNode* mixed_child = root->child_at(0)->child_at(0);
6384 ASSERT_TRUE(mixed_child);
tommycli13632cf2016-06-13 21:54:196385 // 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());
estark56dc8e22016-01-26 17:58:296389}
6390
estarkaeda1422016-05-10 02:31:126391// 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.
6398IN_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.
6430IN_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
lfg43e08e62016-02-03 18:51:376458// Test setting a cross-origin iframe to display: none.
6459IN_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
ekaramadfd1b5cfa2016-04-19 00:35:006464 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
lfg43e08e62016-02-03 18:51:376465 RenderWidgetHost* root_render_widget_host =
6466 root->current_frame_host()->GetRenderWidgetHost();
6467
6468 // Set the iframe to display: none.
nickadef4a52016-06-09 18:45:546469 EXPECT_TRUE(ExecuteScript(
6470 shell(), "document.querySelector('iframe').style.display = 'none'"));
lfg43e08e62016-02-03 18:51:376471
6472 // Waits until pending frames are done.
dcheng59716272016-04-09 05:19:086473 std::unique_ptr<MainThreadFrameObserver> observer(
lfg43e08e62016-02-03 18:51:376474 new MainThreadFrameObserver(root_render_widget_host));
6475 observer->Wait();
6476
6477 // Force the renderer to generate a new frame.
nickadef4a52016-06-09 18:45:546478 EXPECT_TRUE(
6479 ExecuteScript(shell(), "document.body.style.background = 'black'"));
lfg43e08e62016-02-03 18:51:376480
6481 // Waits for the next frame.
6482 observer->Wait();
6483}
6484
alexmos4170f6e82016-03-03 22:42:046485// Test that a cross-origin iframe can be blocked by X-Frame-Options and CSP
6486// frame-ancestors.
6487IN_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
ekaramadfd1b5cfa2016-04-19 00:35:006493 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
alexmos4170f6e82016-03-03 22:42:046494
6495 // Add a load event handler for the iframe element.
nickadef4a52016-06-09 18:45:546496 EXPECT_TRUE(ExecuteScript(shell(),
alexmos4170f6e82016-03-03 22:42:046497 "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) {
nickadef4a52016-06-09 18:45:546506 EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';"));
alexmos4170f6e82016-03-03 22:42:046507 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());
nickadef4a52016-06-09 18:45:546512 EXPECT_TRUE(ExecuteScript(shell(), "frames[0].location.href = '" +
6513 blocked_urls[i].spec() + "';"));
alexmos4170f6e82016-03-03 22:42:046514 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
alexmos30535f72016-06-23 18:48:236519 // 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
alexmos4170f6e82016-03-03 22:42:046524 // 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(
nickadef4a52016-06-09 18:45:546536 root->child_at(0), "domAutomationController.send(document.title)",
6537 &frame_title));
alexmos4170f6e82016-03-03 22:42:046538 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
lukasza8e1c02e42016-05-17 20:05:106559// 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.
6561IN_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.
nickadef4a52016-06-09 18:45:546580 EXPECT_TRUE(ExecuteScript(shell(),
lukasza8e1c02e42016-05-17 20:05:106581 "document.querySelector('iframe').onload = "
6582 " function() { document.title = 'loaded'; };"));
nickadef4a52016-06-09 18:45:546583 EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';"));
lukasza8e1c02e42016-05-17 20:05:106584 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");
nickadef4a52016-06-09 18:45:546590 EXPECT_TRUE(ExecuteScript(root->child_at(0), "window.location.href = '" +
6591 blocked_url.spec() + "';"));
lukasza8e1c02e42016-05-17 20:05:106592
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
tommycli13632cf2016-06-13 21:54:196602 // The blocked frame should stay at the old location.
6603 EXPECT_EQ(old_subframe_url, root->child_at(0)->current_url());
lukasza8e1c02e42016-05-17 20:05:106604
tommycli13632cf2016-06-13 21:54:196605 // The blocked frame should keep the old title.
lukasza8e1c02e42016-05-17 20:05:106606 std::string frame_title;
6607 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:546608 root->child_at(0), "domAutomationController.send(document.title)",
6609 &frame_title));
tommycli13632cf2016-06-13 21:54:196610 EXPECT_EQ("Title Of Awesomeness", frame_title);
lukasza8e1c02e42016-05-17 20:05:106611
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.
6624IN_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(
nickadef4a52016-06-09 18:45:546639 shell(),
lukasza8e1c02e42016-05-17 20:05:106640 "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.
nickadef4a52016-06-09 18:45:546655 EXPECT_TRUE(ExecuteScript(shell(),
lukasza8e1c02e42016-05-17 20:05:106656 "document.querySelector('iframe').onload = "
6657 " function() { document.title = 'loaded'; };"));
nickadef4a52016-06-09 18:45:546658 EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';"));
lukasza8e1c02e42016-05-17 20:05:106659 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");
nickadef4a52016-06-09 18:45:546665 EXPECT_TRUE(ExecuteScript(root->child_at(0), "window.location.href = '" +
6666 blocked_url.spec() + "';"));
lukasza8e1c02e42016-05-17 20:05:106667
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
tommycli13632cf2016-06-13 21:54:196677 // The blocked frame should stay at the old location.
6678 EXPECT_EQ(old_subframe_url, root->child_at(0)->current_url());
lukasza8e1c02e42016-05-17 20:05:106679
tommycli13632cf2016-06-13 21:54:196680 // The blocked frame should keep the old title.
lukasza8e1c02e42016-05-17 20:05:106681 std::string frame_title;
6682 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:546683 root->child_at(0), "domAutomationController.send(document.title)",
6684 &frame_title));
tommycli13632cf2016-06-13 21:54:196685 EXPECT_EQ("Title Of Awesomeness", frame_title);
lukasza8e1c02e42016-05-17 20:05:106686}
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.
6692IN_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(
nickadef4a52016-06-09 18:45:546719 ExecuteScript(root,
lukasza8e1c02e42016-05-17 20:05:106720 "window.addEventListener('message', function(event) {"
6721 " document.title = event.data;"
6722 "});"));
6723 EXPECT_TRUE(ExecuteScript(
nickadef4a52016-06-09 18:45:546724 srcdoc_frame,
lukasza8e1c02e42016-05-17 20:05:106725 "document.querySelector('iframe').onload = "
6726 " function() { window.top.postMessage('loaded', '*'); };"));
nickadef4a52016-06-09 18:45:546727 EXPECT_TRUE(ExecuteScript(shell(), "document.title = 'not loaded';"));
lukasza8e1c02e42016-05-17 20:05:106728 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");
nickadef4a52016-06-09 18:45:546734 EXPECT_TRUE(ExecuteScript(navigating_frame, "window.location.href = '" +
6735 blocked_url.spec() + "';"));
lukasza8e1c02e42016-05-17 20:05:106736
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
tommycli13632cf2016-06-13 21:54:196746 // The blocked frame should stay at the old location.
6747 EXPECT_EQ(old_subframe_url, navigating_frame->current_url());
lukasza8e1c02e42016-05-17 20:05:106748
tommycli13632cf2016-06-13 21:54:196749 // The blocked frame should keep the old title.
lukasza8e1c02e42016-05-17 20:05:106750 std::string frame_title;
6751 EXPECT_TRUE(ExecuteScriptAndExtractString(
nickadef4a52016-06-09 18:45:546752 navigating_frame, "domAutomationController.send(document.title)",
6753 &frame_title));
tommycli13632cf2016-06-13 21:54:196754 EXPECT_EQ("Title Of Awesomeness", frame_title);
lukasza8e1c02e42016-05-17 20:05:106755
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
lfgdb5c4ed2016-03-04 23:09:076766IN_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
ekaramadfd1b5cfa2016-04-19 00:35:006771 FrameTreeNode* root = web_contents()->GetFrameTree()->root();
lfgdb5c4ed2016-03-04 23:09:076772 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;
nickadef4a52016-06-09 18:45:546783 EXPECT_TRUE(ExecuteScriptAndExtractInt(root, script.c_str(), &root_value));
lfgdb5c4ed2016-03-04 23:09:076784
nickadef4a52016-06-09 18:45:546785 EXPECT_TRUE(
6786 ExecuteScriptAndExtractInt(child, script.c_str(), &child_value));
lfgdb5c4ed2016-03-04 23:09:076787
6788 EXPECT_EQ(root_value, child_value);
6789 }
6790}
6791
estark693d1282016-03-15 22:41:296792// 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.
6796IN_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
nasko7ecc9a62016-03-17 00:22:226845// 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.
6848IN_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
ekaramadfd1b5cfa2016-04-19 00:35:006854 WebContentsImpl* contents = web_contents();
nasko7ecc9a62016-03-17 00:22:226855 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);
nickadef4a52016-06-09 18:45:546872 EXPECT_TRUE(ExecuteScript(root->child_at(0), script));
nasko7ecc9a62016-03-17 00:22:226873 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
alexmos9aa61232016-04-26 21:54:026883// Helper class to wait for a ChildProcessHostMsg_ShutdownRequest message to
6884// arrive.
6885class 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.
6921IN_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
kenrb19221852016-04-29 17:21:406969// 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.
6974IN_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
nasko58b07f52016-05-09 22:38:356996// 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.
6999IN_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.
7047IN_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
lfgf2d4f912016-05-11 23:18:487092// Tests that there are no crashes if a subframe is detached in its unload
7093// handler. See https://crbug.com/590054.
7094IN_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(
nickadef4a52016-06-09 18:45:547113 root->child_at(0), "window.domAutomationController.send(frames.length);",
7114 &child_count));
lfgf2d4f912016-05-11 23:18:487115 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(
nickadef4a52016-06-09 18:45:547123 root->child_at(0)->child_at(0),
lfgf2d4f912016-05-11 23:18:487124 "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 "\"";
nickadef4a52016-06-09 18:45:547133 EXPECT_TRUE(ExecuteScript(root->child_at(0), script.c_str()));
lfgf2d4f912016-05-11 23:18:487134
7135 deleted_observer.WaitUntilDeleted();
7136
7137 EXPECT_TRUE(ExecuteScriptAndExtractInt(
nickadef4a52016-06-09 18:45:547138 root->child_at(0), "window.domAutomationController.send(frames.length);",
7139 &child_count));
lfgf2d4f912016-05-11 23:18:487140 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
alexmosc2a8cec2016-05-23 22:19:537150// Helper filter class to wait for a ShowView or ShowWidget message, record the
7151// routing ID from the message, and then drop the message.
7152class 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.
7215IN_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());
nickadef4a52016-06-09 18:45:547234 EXPECT_TRUE(ExecuteScript(child1, "window.open();"));
alexmosc2a8cec2016-05-23 22:19:537235 filter1->Wait();
7236
7237 scoped_refptr<PendingWidgetMessageFilter> filter2 =
7238 new PendingWidgetMessageFilter();
7239 process2->AddFilter(filter2.get());
nickadef4a52016-06-09 18:45:547240 EXPECT_TRUE(ExecuteScript(child2, "window.open();"));
alexmosc2a8cec2016-05-23 22:19:537241 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)
7276IN_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
dtapuskae0f8ed72016-06-17 08:23:417294 // 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.
alexmosc2a8cec2016-05-23 22:19:537296 // Wait for and then drop the ViewHostMsg_ShowWidget messages, so that both
7297 // widgets are left in pending-but-not-shown state.
dtapuskae0f8ed72016-06-17 08:23:417298 NativeWebKeyboardEvent event;
7299 event.text[0] = ' ';
7300 event.timeStampSeconds = 100;
7301 event.type = blink::WebKeyboardEvent::Char;
7302
alexmosc2a8cec2016-05-23 22:19:537303 scoped_refptr<PendingWidgetMessageFilter> filter1 =
7304 new PendingWidgetMessageFilter();
7305 process1->AddFilter(filter1.get());
dtapuskae0f8ed72016-06-17 08:23:417306 EXPECT_TRUE(ExecuteScript(child1, "focusSelectMenu();"));
7307 child1->current_frame_host()->GetRenderWidgetHost()->ForwardKeyboardEvent(
7308 event);
alexmosc2a8cec2016-05-23 22:19:537309 filter1->Wait();
7310
7311 scoped_refptr<PendingWidgetMessageFilter> filter2 =
7312 new PendingWidgetMessageFilter();
7313 process2->AddFilter(filter2.get());
dtapuskae0f8ed72016-06-17 08:23:417314 EXPECT_TRUE(ExecuteScript(child2, "focusSelectMenu();"));
7315 child2->current_frame_host()->GetRenderWidgetHost()->ForwardKeyboardEvent(
7316 event);
alexmosc2a8cec2016-05-23 22:19:537317 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
alexmos788f45b32016-05-24 00:57:027346// 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
7358IN_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(
nickadef4a52016-06-09 18:45:547372 ftn,
alexmos788f45b32016-05-24 00:57:027373 "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(
nickadef4a52016-06-09 18:45:547396 root, "document.getElementById('child-0').allowFullscreen='true'"));
alexmos788f45b32016-05-24 00:57:027397 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(
nickadef4a52016-06-09 18:45:547416 root->child_at(0),
alexmos788f45b32016-05-24 00:57:027417 "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(
nickadef4a52016-06-09 18:45:547427 root, "document.getElementById('child-0').allowFullscreen='true'"));
alexmos788f45b32016-05-24 00:57:027428
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
nasko39e3eb72016-06-24 23:15:447440// Test for https://crbug.com/615575. It ensures that file chooser triggered
7441// by a document in an out-of-process subframe works properly.
7442IN_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
lfg717154072016-06-30 15:04:167472// Tests that an out-of-process iframe receives the visibilitychange event.
7473IN_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]9b159a52013-10-03 17:24:557511} // namespace content