- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / site_per_process_browsertest.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/command_line.h"
6 #include "base/strings/stringprintf.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/frame_host/frame_tree.h"
9 #include "content/browser/renderer_host/render_view_host_impl.h"
10 #include "content/browser/web_contents/web_contents_impl.h"
11 #include "content/public/browser/notification_observer.h"
12 #include "content/public/browser/notification_service.h"
13 #include "content/public/browser/notification_types.h"
14 #include "content/public/browser/web_contents_observer.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/test/browser_test_utils.h"
17 #include "content/public/test/test_utils.h"
18 #include "content/shell/browser/shell.h"
19 #include "content/test/content_browser_test.h"
20 #include "content/test/content_browser_test_utils.h"
21 #include "net/dns/mock_host_resolver.h"
22
23 namespace content {
24
25 class SitePerProcessWebContentsObserver: public WebContentsObserver {
26  public:
27   explicit SitePerProcessWebContentsObserver(WebContents* web_contents)
28       : WebContentsObserver(web_contents),
29         navigation_succeeded_(true) {}
30   virtual ~SitePerProcessWebContentsObserver() {}
31
32   virtual void DidFailProvisionalLoad(
33       int64 frame_id,
34       const string16& frame_unique_name,
35       bool is_main_frame,
36       const GURL& validated_url,
37       int error_code,
38       const string16& error_description,
39       RenderViewHost* render_view_host) OVERRIDE {
40     navigation_url_ = validated_url;
41     navigation_succeeded_ = false;
42   }
43
44   virtual void DidCommitProvisionalLoadForFrame(
45       int64 frame_id,
46       const string16& frame_unique_name,
47       bool is_main_frame,
48       const GURL& url,
49       PageTransition transition_type,
50       RenderViewHost* render_view_host) OVERRIDE{
51     navigation_url_ = url;
52     navigation_succeeded_ = true;
53   }
54
55   const GURL& navigation_url() const {
56     return navigation_url_;
57   }
58
59   int navigation_succeeded() const { return navigation_succeeded_; }
60
61  private:
62   GURL navigation_url_;
63   bool navigation_succeeded_;
64
65   DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver);
66 };
67
68 class RedirectNotificationObserver : public NotificationObserver {
69  public:
70   // Register to listen for notifications of the given type from either a
71   // specific source, or from all sources if |source| is
72   // NotificationService::AllSources().
73   RedirectNotificationObserver(int notification_type,
74                                const NotificationSource& source);
75   virtual ~RedirectNotificationObserver();
76
77   // Wait until the specified notification occurs.  If the notification was
78   // emitted between the construction of this object and this call then it
79   // returns immediately.
80   void Wait();
81
82   // Returns NotificationService::AllSources() if we haven't observed a
83   // notification yet.
84   const NotificationSource& source() const {
85     return source_;
86   }
87
88   const NotificationDetails& details() const {
89     return details_;
90   }
91
92   // NotificationObserver:
93   virtual void Observe(int type,
94                        const NotificationSource& source,
95                        const NotificationDetails& details) OVERRIDE;
96
97  private:
98   bool seen_;
99   bool seen_twice_;
100   bool running_;
101   NotificationRegistrar registrar_;
102
103   NotificationSource source_;
104   NotificationDetails details_;
105   scoped_refptr<MessageLoopRunner> message_loop_runner_;
106
107   DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
108 };
109
110 RedirectNotificationObserver::RedirectNotificationObserver(
111     int notification_type,
112     const NotificationSource& source)
113     : seen_(false),
114       running_(false),
115       source_(NotificationService::AllSources()) {
116   registrar_.Add(this, notification_type, source);
117 }
118
119 RedirectNotificationObserver::~RedirectNotificationObserver() {}
120
121 void RedirectNotificationObserver::Wait() {
122   if (seen_ && seen_twice_)
123     return;
124
125   running_ = true;
126   message_loop_runner_ = new MessageLoopRunner;
127   message_loop_runner_->Run();
128   EXPECT_TRUE(seen_);
129 }
130
131 void RedirectNotificationObserver::Observe(
132     int type,
133     const NotificationSource& source,
134     const NotificationDetails& details) {
135   source_ = source;
136   details_ = details;
137   seen_twice_ = seen_;
138   seen_ = true;
139   if (!running_)
140     return;
141
142   message_loop_runner_->Quit();
143   running_ = false;
144 }
145
146 class SitePerProcessBrowserTest : public ContentBrowserTest {
147  protected:
148   bool NavigateIframeToURL(Shell* window,
149                            const GURL& url,
150                            std::string iframe_id) {
151     std::string script = base::StringPrintf(
152         "var iframes = document.getElementById('%s');iframes.src='%s';",
153         iframe_id.c_str(), url.spec().c_str());
154     WindowedNotificationObserver load_observer(
155         NOTIFICATION_LOAD_STOP,
156         Source<NavigationController>(
157             &shell()->web_contents()->GetController()));
158     bool result = ExecuteScript(window->web_contents(), script);
159     load_observer.Wait();
160     return result;
161   }
162
163   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
164     command_line->AppendSwitch(switches::kSitePerProcess);
165   }
166 };
167
168 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
169 // security checks are back in place.
170 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrossSiteIframe) {
171   ASSERT_TRUE(test_server()->Start());
172   net::SpawnedTestServer https_server(
173       net::SpawnedTestServer::TYPE_HTTPS,
174       net::SpawnedTestServer::kLocalhost,
175       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
176   ASSERT_TRUE(https_server.Start());
177   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
178
179   NavigateToURL(shell(), main_url);
180
181   SitePerProcessWebContentsObserver observer(shell()->web_contents());
182   {
183     // Load same-site page into Iframe.
184     GURL http_url(test_server()->GetURL("files/title1.html"));
185     EXPECT_TRUE(NavigateIframeToURL(shell(), http_url, "test"));
186     EXPECT_EQ(observer.navigation_url(), http_url);
187     EXPECT_TRUE(observer.navigation_succeeded());
188   }
189
190   {
191     // Load cross-site page into Iframe.
192     GURL https_url(https_server.GetURL("files/title1.html"));
193     EXPECT_TRUE(NavigateIframeToURL(shell(), https_url, "test"));
194     EXPECT_EQ(observer.navigation_url(), https_url);
195     EXPECT_FALSE(observer.navigation_succeeded());
196   }
197 }
198
199 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
200 // security checks are back in place.
201 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
202                        DISABLED_CrossSiteIframeRedirectOnce) {
203   ASSERT_TRUE(test_server()->Start());
204   net::SpawnedTestServer https_server(
205       net::SpawnedTestServer::TYPE_HTTPS,
206       net::SpawnedTestServer::kLocalhost,
207       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
208   ASSERT_TRUE(https_server.Start());
209
210   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
211   GURL http_url(test_server()->GetURL("files/title1.html"));
212   GURL https_url(https_server.GetURL("files/title1.html"));
213
214   NavigateToURL(shell(), main_url);
215
216   SitePerProcessWebContentsObserver observer(shell()->web_contents());
217   {
218     // Load cross-site client-redirect page into Iframe.
219     // Should be blocked.
220     GURL client_redirect_https_url(https_server.GetURL(
221         "client-redirect?files/title1.html"));
222     EXPECT_TRUE(NavigateIframeToURL(shell(),
223                                     client_redirect_https_url, "test"));
224     // DidFailProvisionalLoad when navigating to client_redirect_https_url.
225     EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
226     EXPECT_FALSE(observer.navigation_succeeded());
227   }
228
229   {
230     // Load cross-site server-redirect page into Iframe,
231     // which redirects to same-site page.
232     GURL server_redirect_http_url(https_server.GetURL(
233         "server-redirect?" + http_url.spec()));
234     EXPECT_TRUE(NavigateIframeToURL(shell(),
235                                     server_redirect_http_url, "test"));
236     EXPECT_EQ(observer.navigation_url(), http_url);
237     EXPECT_TRUE(observer.navigation_succeeded());
238   }
239
240   {
241     // Load cross-site server-redirect page into Iframe,
242     // which redirects to cross-site page.
243     GURL server_redirect_http_url(https_server.GetURL(
244         "server-redirect?files/title1.html"));
245     EXPECT_TRUE(NavigateIframeToURL(shell(),
246                                     server_redirect_http_url, "test"));
247     // DidFailProvisionalLoad when navigating to https_url.
248     EXPECT_EQ(observer.navigation_url(), https_url);
249     EXPECT_FALSE(observer.navigation_succeeded());
250   }
251
252   {
253     // Load same-site server-redirect page into Iframe,
254     // which redirects to cross-site page.
255     GURL server_redirect_http_url(test_server()->GetURL(
256         "server-redirect?" + https_url.spec()));
257     EXPECT_TRUE(NavigateIframeToURL(shell(),
258                                     server_redirect_http_url, "test"));
259
260     EXPECT_EQ(observer.navigation_url(), https_url);
261     EXPECT_FALSE(observer.navigation_succeeded());
262    }
263
264   {
265     // Load same-site client-redirect page into Iframe,
266     // which redirects to cross-site page.
267     GURL client_redirect_http_url(test_server()->GetURL(
268         "client-redirect?" + https_url.spec()));
269
270     RedirectNotificationObserver load_observer2(
271         NOTIFICATION_LOAD_STOP,
272         Source<NavigationController>(
273             &shell()->web_contents()->GetController()));
274
275     EXPECT_TRUE(NavigateIframeToURL(shell(),
276                                     client_redirect_http_url, "test"));
277
278     // Same-site Client-Redirect Page should be loaded successfully.
279     EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
280     EXPECT_TRUE(observer.navigation_succeeded());
281
282     // Redirecting to Cross-site Page should be blocked.
283     load_observer2.Wait();
284     EXPECT_EQ(observer.navigation_url(), https_url);
285     EXPECT_FALSE(observer.navigation_succeeded());
286   }
287
288   {
289     // Load same-site server-redirect page into Iframe,
290     // which redirects to same-site page.
291     GURL server_redirect_http_url(test_server()->GetURL(
292         "server-redirect?files/title1.html"));
293     EXPECT_TRUE(NavigateIframeToURL(shell(),
294                                     server_redirect_http_url, "test"));
295     EXPECT_EQ(observer.navigation_url(), http_url);
296     EXPECT_TRUE(observer.navigation_succeeded());
297    }
298
299   {
300     // Load same-site client-redirect page into Iframe,
301     // which redirects to same-site page.
302     GURL client_redirect_http_url(test_server()->GetURL(
303         "client-redirect?" + http_url.spec()));
304     RedirectNotificationObserver load_observer2(
305         NOTIFICATION_LOAD_STOP,
306         Source<NavigationController>(
307             &shell()->web_contents()->GetController()));
308
309     EXPECT_TRUE(NavigateIframeToURL(shell(),
310                                     client_redirect_http_url, "test"));
311
312     // Same-site Client-Redirect Page should be loaded successfully.
313     EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
314     EXPECT_TRUE(observer.navigation_succeeded());
315
316     // Redirecting to Same-site Page should be loaded successfully.
317     load_observer2.Wait();
318     EXPECT_EQ(observer.navigation_url(), http_url);
319     EXPECT_TRUE(observer.navigation_succeeded());
320   }
321 }
322
323 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
324 // security checks are back in place.
325 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
326                        DISABLED_CrossSiteIframeRedirectTwice) {
327   ASSERT_TRUE(test_server()->Start());
328   net::SpawnedTestServer https_server(
329       net::SpawnedTestServer::TYPE_HTTPS,
330       net::SpawnedTestServer::kLocalhost,
331       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
332   ASSERT_TRUE(https_server.Start());
333
334   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
335   GURL http_url(test_server()->GetURL("files/title1.html"));
336   GURL https_url(https_server.GetURL("files/title1.html"));
337
338   NavigateToURL(shell(), main_url);
339
340   SitePerProcessWebContentsObserver observer(shell()->web_contents());
341   {
342     // Load client-redirect page pointing to a cross-site client-redirect page,
343     // which eventually redirects back to same-site page.
344     GURL client_redirect_https_url(https_server.GetURL(
345         "client-redirect?" + http_url.spec()));
346     GURL client_redirect_http_url(test_server()->GetURL(
347         "client-redirect?" + client_redirect_https_url.spec()));
348
349     // We should wait until second client redirect get cancelled.
350     RedirectNotificationObserver load_observer2(
351         NOTIFICATION_LOAD_STOP,
352         Source<NavigationController>(
353             &shell()->web_contents()->GetController()));
354
355     EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
356
357     // DidFailProvisionalLoad when navigating to client_redirect_https_url.
358     load_observer2.Wait();
359     EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
360     EXPECT_FALSE(observer.navigation_succeeded());
361   }
362
363   {
364     // Load server-redirect page pointing to a cross-site server-redirect page,
365     // which eventually redirect back to same-site page.
366     GURL server_redirect_https_url(https_server.GetURL(
367         "server-redirect?" + http_url.spec()));
368     GURL server_redirect_http_url(test_server()->GetURL(
369         "server-redirect?" + server_redirect_https_url.spec()));
370     EXPECT_TRUE(NavigateIframeToURL(shell(),
371                                     server_redirect_http_url, "test"));
372     EXPECT_EQ(observer.navigation_url(), http_url);
373     EXPECT_TRUE(observer.navigation_succeeded());
374   }
375
376   {
377     // Load server-redirect page pointing to a cross-site server-redirect page,
378     // which eventually redirects back to cross-site page.
379     GURL server_redirect_https_url(https_server.GetURL(
380         "server-redirect?" + https_url.spec()));
381     GURL server_redirect_http_url(test_server()->GetURL(
382         "server-redirect?" + server_redirect_https_url.spec()));
383     EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
384
385     // DidFailProvisionalLoad when navigating to https_url.
386     EXPECT_EQ(observer.navigation_url(), https_url);
387     EXPECT_FALSE(observer.navigation_succeeded());
388   }
389
390   {
391     // Load server-redirect page pointing to a cross-site client-redirect page,
392     // which eventually redirects back to same-site page.
393     GURL client_redirect_http_url(https_server.GetURL(
394         "client-redirect?" + http_url.spec()));
395     GURL server_redirect_http_url(test_server()->GetURL(
396         "server-redirect?" + client_redirect_http_url.spec()));
397     EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
398
399     // DidFailProvisionalLoad when navigating to client_redirect_http_url.
400     EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
401     EXPECT_FALSE(observer.navigation_succeeded());
402   }
403 }
404
405 // Ensures FrameTree correctly reflects page structure during navigations.
406 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
407                        FrameTreeShape) {
408   host_resolver()->AddRule("*", "127.0.0.1");
409   ASSERT_TRUE(test_server()->Start());
410
411   GURL base_url = test_server()->GetURL("files/site_isolation/");
412   GURL::Replacements replace_host;
413   std::string host_str("A.com");  // Must stay in scope with replace_host.
414   replace_host.SetHostStr(host_str);
415   base_url = base_url.ReplaceComponents(replace_host);
416
417   // Load doc without iframes. Verify FrameTree just has root.
418   // Frame tree:
419   //   Site-A Root
420   NavigateToURL(shell(), base_url.Resolve("blank.html"));
421   FrameTreeNode* root =
422       static_cast<WebContentsImpl*>(shell()->web_contents())->
423       GetFrameTree()->GetRootForTesting();
424   EXPECT_EQ(0U, root->child_count());
425
426   // Add 2 same-site frames. Verify 3 nodes in tree with proper names.
427   // Frame tree:
428   //   Site-A Root -- Site-A frame1
429   //              \-- Site-A frame2
430   WindowedNotificationObserver observer1(
431       content::NOTIFICATION_LOAD_STOP,
432       content::Source<NavigationController>(
433           &shell()->web_contents()->GetController()));
434   NavigateToURL(shell(), base_url.Resolve("frames-X-X.html"));
435   observer1.Wait();
436   ASSERT_EQ(2U, root->child_count());
437   EXPECT_EQ(0U, root->child_at(0)->child_count());
438   EXPECT_EQ(0U, root->child_at(1)->child_count());
439 }
440
441 // TODO(ajwong): Talk with nasko and merge this functionality with
442 // FrameTreeShape.
443 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
444                        FrameTreeShape2) {
445   host_resolver()->AddRule("*", "127.0.0.1");
446   ASSERT_TRUE(test_server()->Start());
447
448   NavigateToURL(shell(),
449                 test_server()->GetURL("files/frame_tree/top.html"));
450
451   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
452   RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
453       wc->GetRenderViewHost());
454   FrameTreeNode* root = wc->GetFrameTree()->GetRootForTesting();
455
456   // Check that the root node is properly created with the frame id of the
457   // initial navigation.
458   ASSERT_EQ(3UL, root->child_count());
459   EXPECT_EQ(std::string(), root->frame_name());
460   EXPECT_EQ(rvh->main_frame_id(), root->frame_id());
461
462   ASSERT_EQ(2UL, root->child_at(0)->child_count());
463   EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str());
464
465   // Verify the deepest node exists and has the right name.
466   ASSERT_EQ(2UL, root->child_at(2)->child_count());
467   EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count());
468   EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count());
469   EXPECT_STREQ("3-1-id",
470       root->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str());
471
472   // Navigate to about:blank, which should leave only the root node of the frame
473   // tree in the browser process.
474   NavigateToURL(shell(), test_server()->GetURL("files/title1.html"));
475
476   root = wc->GetFrameTree()->GetRootForTesting();
477   EXPECT_EQ(0UL, root->child_count());
478   EXPECT_EQ(std::string(), root->frame_name());
479   EXPECT_EQ(rvh->main_frame_id(), root->frame_id());
480 }
481
482 }  // namespace content