Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(549)

Side by Side Diff: content/browser/frame_host/data_url_navigation_browsertest.cc

Issue 2702503002: Block renderer-initiated main frame navigations to data URLs (Closed)
Patch Set: nasko comments, fix most tests Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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/files/file_util.h"
7 #include "base/macros.h"
8 #include "base/path_service.h"
9 #include "base/strings/pattern.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "build/build_config.h"
12 #include "build/buildflag.h"
13 #include "content/browser/site_per_process_browsertest.h"
14 #include "content/public/browser/browser_context.h"
15 #include "content/public/browser/navigation_entry.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/common/content_paths.h"
18 #include "content/public/common/content_switches.h"
19 #include "content/public/test/browser_test_utils.h"
20 #include "content/public/test/content_browser_test.h"
21 #include "content/public/test/content_browser_test_utils.h"
22 #include "content/public/test/download_test_observer.h"
23 #include "content/public/test/test_navigation_observer.h"
24 #include "content/shell/browser/shell.h"
25 #include "net/base/escape.h"
26 #include "net/dns/mock_host_resolver.h"
27 #include "net/test/embedded_test_server/embedded_test_server.h"
28 #include "ppapi/features/features.h"
29
30 #if BUILDFLAG(ENABLE_PLUGINS)
31 #include "content/public/browser/plugin_service.h"
32 #include "content/public/common/webplugininfo.h"
33 #endif
34
35 namespace content {
36
37 namespace {
38
39 // The pattern to catch messages printed by the browser when a data URL
40 // navigation is blocked.
41 const char kDataUrlBlockedPattern[] =
42 "Not allowed to top-level navigate to resource:*";
43
44 // The message printed by the data URL when it successfully navigates.
45 const char kDataUrlSuccessfulMessage[] = "NAVIGATION_SUCCESSFUL";
46
47 // A "Hello World" PDF encoded as a data URL. Source of this PDF:
48 // -------------------------
49 // %PDF-1.7
50 // 1 0 obj << /Type /Page /Parent 3 0 R /Resources 5 0 R /Contents 2 0 R >>
51 // endobj
52 // 2 0 obj << /Length 51 >>
53 // stream BT
54 // /F1 12 Tf
55 // 1 0 0 1 100 20 Tm
56 // (Hello World)Tj
57 // ET
58 // endstream
59 // endobj
60 // 3 0 obj << /Type /Pages /Kids [ 1 0 R ] /Count 1 /MediaBox [ 0 0 300 50] >>
61 // endobj
62 // 4 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /BaseFont/Arial >>
63 // endobj
64 // 5 0 obj << /ProcSet[/PDF/Text] /Font <</F1 4 0 R >> >>
65 // endobj
66 // 6 0 obj << /Type /Catalog /Pages 3 0 R >>
67 // endobj
68 // trailer << /Root 6 0 R >>
69 // -------------------------
70 const char kPdfUrl[] =
71 "data:application/pdf;base64,JVBERi0xLjcKMSAwIG9iaiA8PCAvVHlwZSAvUGFnZSAvUG"
72 "FyZW50IDMgMCBSIC9SZXNvdXJjZXMgNSAwIFIgL0NvbnRlbnRzIDIgMCBSID4+CmVuZG9iagoy"
73 "IDAgb2JqIDw8IC9MZW5ndGggNTEgPj4KIHN0cmVhbSBCVAogL0YxIDEyIFRmCiAxIDAgMCAxID"
74 "EwMCAyMCBUbQogKEhlbGxvIFdvcmxkKVRqCiBFVAogZW5kc3RyZWFtCmVuZG9iagozIDAgb2Jq"
75 "IDw8IC9UeXBlIC9QYWdlcyAvS2lkcyBbIDEgMCBSIF0gL0NvdW50IDEgL01lZGlhQm94IFsgMC"
76 "AwIDMwMCA1MF0gPj4KZW5kb2JqCjQgMCBvYmogPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5"
77 "cGUxIC9OYW1lIC9GMSAvQmFzZUZvbnQvQXJpYWwgPj4KZW5kb2JqCjUgMCBvYmogPDwgL1Byb2"
78 "NTZXRbL1BERi9UZXh0XSAvRm9udCA8PC9GMSA0IDAgUiA+PiA+PgplbmRvYmoKNiAwIG9iaiA8"
79 "PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMyAwIFIgPj4KZW5kb2JqCnRyYWlsZXIgPDwgL1Jvb3"
80 "QgNiAwIFIgPj4K";
81
82 enum ExpectedNavigationStatus { NAVIGATION_BLOCKED, NAVIGATION_ALLOWED };
83
84 // This class is similar to ConsoleObserverDelegate in that it listens and waits
85 // for specific console messages. The difference from ConsoleObserverDelegate is
86 // that this class immediately stops waiting if it sees a message matching
87 // fail_pattern, instead of waiting for a message matching success_pattern.
88 class DataURLWarningConsoleObserverDelegate : public WebContentsDelegate {
89 public:
90 DataURLWarningConsoleObserverDelegate(
91 WebContents* web_contents,
92 ExpectedNavigationStatus expected_navigation_status)
93 : web_contents_(web_contents),
94 success_filter_(expected_navigation_status == NAVIGATION_ALLOWED
95 ? kDataUrlSuccessfulMessage
96 : kDataUrlBlockedPattern),
97 fail_filter_(expected_navigation_status == NAVIGATION_ALLOWED
98 ? kDataUrlBlockedPattern
99 : kDataUrlSuccessfulMessage),
100 message_loop_runner_(new MessageLoopRunner()),
101 saw_failure_message_(false) {}
102 ~DataURLWarningConsoleObserverDelegate() override {}
103
104 void Wait() { message_loop_runner_->Run(); }
105
106 // WebContentsDelegate method:
107 bool DidAddMessageToConsole(WebContents* source,
108 int32_t level,
109 const base::string16& message,
110 int32_t line_no,
111 const base::string16& source_id) override {
112 DCHECK(source == web_contents_);
113 const std::string ascii_message = base::UTF16ToASCII(message);
114 if (base::MatchPattern(ascii_message, fail_filter_)) {
115 saw_failure_message_ = true;
116 message_loop_runner_->Quit();
117 }
118 if (base::MatchPattern(ascii_message, success_filter_)) {
119 message_loop_runner_->Quit();
120 }
121 return false;
122 }
123
124 // Returns true if the observer encountered a message that matches
125 // |fail_filter_|.
126 bool saw_failure_message() const { return saw_failure_message_; }
127
128 private:
129 WebContents* web_contents_;
130 const std::string success_filter_;
131 const std::string fail_filter_;
132 scoped_refptr<MessageLoopRunner> message_loop_runner_;
133 bool saw_failure_message_;
134 };
135
136 enum TestNavigationType {
137 NO_PLZNAVIGATE,
138 PLZNAVIGATE,
139 };
140
141 enum TestSitePerProcessType { NO_SITE_PER_PROCESS, SITE_PER_PROCESS };
142
143 #if BUILDFLAG(ENABLE_PLUGINS)
144 // This class registers a fake PDF plugin handler so that data URL navigations
145 // with a PDF mime type end up with a navigation and don't simply download the
146 // file.
147 class ScopedPluginRegister {
148 public:
149 ScopedPluginRegister(content::PluginService* plugin_service)
150 : plugin_service_(plugin_service) {
151 const char kPluginName[] = "PDF";
152 const char kPdfMimeType[] = "application/pdf";
153 const char kPdfFileType[] = "pdf";
154 WebPluginInfo plugin_info;
155 plugin_info.type = WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS;
156 plugin_info.name = base::ASCIIToUTF16(kPluginName);
157 plugin_info.mime_types.push_back(
158 WebPluginMimeType(kPdfMimeType, kPdfFileType, std::string()));
159 plugin_service_->RegisterInternalPlugin(plugin_info, false);
160 plugin_service_->RefreshPlugins();
161 }
162
163 ~ScopedPluginRegister() {
164 std::vector<WebPluginInfo> plugins;
165 plugin_service_->GetInternalPlugins(&plugins);
166 EXPECT_EQ(1u, plugins.size());
167 plugin_service_->UnregisterInternalPlugin(plugins[0].path);
168 plugin_service_->RefreshPlugins();
169
170 plugins.clear();
171 plugin_service_->GetInternalPlugins(&plugins);
172 EXPECT_TRUE(plugins.empty());
173 }
174
175 private:
176 content::PluginService* plugin_service_;
177 };
178 #endif // BUILDFLAG(ENABLE_PLUGINS)
179
180 } // namespace
181
182 class DataUrlNavigationBrowserTest
183 : public ContentBrowserTest,
184 public testing::WithParamInterface<
185 std::tuple<TestNavigationType, TestSitePerProcessType>> {
186 public:
187 #if BUILDFLAG(ENABLE_PLUGINS)
188 DataUrlNavigationBrowserTest()
189 : scoped_plugin_register_(PluginService::GetInstance()) {}
190 #else
191 DataUrlNavigationBrowserTest() {}
192 #endif // BUILDFLAG(ENABLE_PLUGINS)
193
194 protected:
195 void SetUpCommandLine(base::CommandLine* command_line) override {
196 if (IsPlzNavigateTest()) {
197 command_line->AppendSwitch(switches::kEnableBrowserSideNavigation);
198 }
199 if (IsSitePerProcessTest()) {
200 IsolateAllSitesForTesting(command_line);
201 }
202 }
203
204 void SetUpOnMainThread() override {
205 host_resolver()->AddRule("*", "127.0.0.1");
206 ASSERT_TRUE(embedded_test_server()->Start());
207
208 base::FilePath path;
209 ASSERT_TRUE(PathService::Get(content::DIR_TEST_DATA, &path));
210 path = path.AppendASCII("data_url_navigations.html");
211 ASSERT_TRUE(base::PathExists(path));
212
213 std::string contents;
214 ASSERT_TRUE(base::ReadFileToString(path, &contents));
215 data_url_ = GURL(std::string("data:text/html,") + contents);
216 }
217
218 // Adds an iframe to |rfh| pointing to |url|.
219 void AddIFrame(RenderFrameHost* rfh, const GURL& url) {
220 const std::string javascript = base::StringPrintf(
221 "f = document.createElement('iframe'); f.src = '%s';"
222 "document.body.appendChild(f);",
223 url.spec().c_str());
224 bool iframe_loaded = false;
225 EXPECT_TRUE(ExecuteScriptAndExtractBool(rfh, javascript, &iframe_loaded));
226 EXPECT_TRUE(iframe_loaded);
227 }
228
229 // Runs |javascript| on the first child frame and checks for a navigation.
230 void TestNavigationFromFrame(
231 const std::string& javascript,
232 ExpectedNavigationStatus expected_navigation_status) {
233 RenderFrameHost* child =
234 ChildFrameAt(shell()->web_contents()->GetMainFrame(), 0);
235 ASSERT_TRUE(child);
236 if (IsSitePerProcessTest()) {
237 ASSERT_TRUE(child->IsCrossProcessSubframe());
238 }
239 ExecuteScriptAndCheckNavigation(child, javascript,
240 expected_navigation_status);
241 }
242
243 // Runs |javascript| on the first child frame and expects a download to occur.
244 void TestDownloadFromFrame(const std::string& javascript) {
245 RenderFrameHost* child =
246 ChildFrameAt(shell()->web_contents()->GetMainFrame(), 0);
247 ASSERT_TRUE(child);
248 if (IsSitePerProcessTest()) {
249 ASSERT_TRUE(child->IsCrossProcessSubframe());
250 }
251 ExecuteScriptAndCheckNavigationDownload(child, javascript);
252 }
253
254 // Runs |javascript| on the first child frame and checks for a navigation to
255 // the PDF file pointed by the test case.
256 void TestPDFNavigationFromFrame(
257 const std::string& javascript,
258 ExpectedNavigationStatus expected_navigation_status) {
259 RenderFrameHost* child =
260 ChildFrameAt(shell()->web_contents()->GetMainFrame(), 0);
261 ASSERT_TRUE(child);
262 if (IsSitePerProcessTest()) {
263 ASSERT_TRUE(child->IsCrossProcessSubframe());
264 }
265 ExecuteScriptAndCheckPDFNavigation(child, javascript,
266 expected_navigation_status);
267 }
268
269 // Same as TestNavigationFromFrame, but instead of navigating, the child frame
270 // tries to open a new window with a data URL.
271 void TestWindowOpenFromFrame(
272 const std::string& javascript,
273 ExpectedNavigationStatus expected_navigation_status) {
274 RenderFrameHost* child =
275 ChildFrameAt(shell()->web_contents()->GetMainFrame(), 0);
276 if (IsSitePerProcessTest()) {
277 ASSERT_TRUE(child->IsCrossProcessSubframe());
278 }
279 ExecuteScriptAndCheckWindowOpen(child, javascript,
280 expected_navigation_status);
281 }
282
283 // Executes |javascript| on |rfh| and waits for a console message based on
284 // |expected_navigation_status|.
285 // - Blocked navigations should print kDataUrlBlockedPattern.
286 // - Allowed navigations should print kDataUrlSuccessfulMessage.
287 void ExecuteScriptAndCheckNavigation(
288 RenderFrameHost* rfh,
289 const std::string& javascript,
290 ExpectedNavigationStatus expected_navigation_status) {
291 const GURL original_url(shell()->web_contents()->GetLastCommittedURL());
292 const std::string expected_message;
293
294 DataURLWarningConsoleObserverDelegate console_delegate(
295 shell()->web_contents(), expected_navigation_status);
296 shell()->web_contents()->SetDelegate(&console_delegate);
297
298 TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
299 EXPECT_TRUE(ExecuteScript(rfh, javascript));
300 console_delegate.Wait();
301 EXPECT_FALSE(console_delegate.saw_failure_message());
302 shell()->web_contents()->SetDelegate(nullptr);
303
304 switch (expected_navigation_status) {
305 case NAVIGATION_ALLOWED:
306 navigation_observer.Wait();
307 // The new page should have a data URL.
308 EXPECT_TRUE(
309 shell()->web_contents()->GetURL().SchemeIs(url::kDataScheme));
310 EXPECT_TRUE(shell()
311 ->web_contents()
312 ->GetController()
313 .GetLastCommittedEntry()
314 ->GetURL()
315 .SchemeIs(url::kDataScheme));
316 EXPECT_TRUE(navigation_observer.last_navigation_url().SchemeIs(
317 url::kDataScheme));
318 EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
319 break;
320
321 case NAVIGATION_BLOCKED:
322 // Original page shouldn't navigate away.
323 EXPECT_EQ(original_url, shell()->web_contents()->GetURL());
324 EXPECT_EQ(original_url, shell()
325 ->web_contents()
326 ->GetController()
327 .GetLastCommittedEntry()
328 ->GetURL());
329 EXPECT_FALSE(navigation_observer.last_navigation_succeeded());
330 break;
331
332 default:
333 NOTREACHED();
334 }
335 }
336
337 // Similar to ExecuteScriptAndCheckNavigation(), but doesn't wait for a
338 // console message if the navigation is expected to be allowed (this is
339 // because PDF files can't print to the console).
340 void ExecuteScriptAndCheckPDFNavigation(
341 RenderFrameHost* rfh,
342 const std::string& javascript,
343 ExpectedNavigationStatus expected_navigation_status) {
344 const GURL original_url(shell()->web_contents()->GetLastCommittedURL());
345
346 const std::string expected_message =
347 (expected_navigation_status == NAVIGATION_ALLOWED)
348 ? std::string()
349 : kDataUrlBlockedPattern;
350
351 std::unique_ptr<ConsoleObserverDelegate> console_delegate;
352 if (!expected_message.empty()) {
353 console_delegate.reset(new ConsoleObserverDelegate(
354 shell()->web_contents(), expected_message));
355 shell()->web_contents()->SetDelegate(console_delegate.get());
356 }
357
358 TestNavigationObserver navigation_observer(shell()->web_contents(), 1);
359 EXPECT_TRUE(ExecuteScript(rfh, javascript));
360
361 if (console_delegate) {
362 console_delegate->Wait();
363 shell()->web_contents()->SetDelegate(nullptr);
364 }
365
366 switch (expected_navigation_status) {
367 case NAVIGATION_ALLOWED:
368 navigation_observer.Wait();
369 // The new page should have a data URL.
370 EXPECT_TRUE(
371 shell()->web_contents()->GetURL().SchemeIs(url::kDataScheme));
372 EXPECT_TRUE(shell()
373 ->web_contents()
374 ->GetController()
375 .GetLastCommittedEntry()
376 ->GetURL()
377 .SchemeIs(url::kDataScheme));
378 EXPECT_TRUE(navigation_observer.last_navigation_url().SchemeIs(
379 url::kDataScheme));
380 EXPECT_TRUE(navigation_observer.last_navigation_succeeded());
381 break;
382
383 case NAVIGATION_BLOCKED:
384 // Original page shouldn't navigate away.
385 EXPECT_EQ(original_url, shell()->web_contents()->GetURL());
386 EXPECT_EQ(original_url, shell()
387 ->web_contents()
388 ->GetController()
389 .GetLastCommittedEntry()
390 ->GetURL());
391 EXPECT_FALSE(navigation_observer.last_navigation_succeeded());
392 break;
393
394 default:
395 NOTREACHED();
396 }
397 }
398
399 // Executes |javascript| on |rfh| and waits for a new window to be opened.
400 // Does not check for console messages (it's currently not possible to
401 // concurrently wait for a new shell to be created and a console message to be
402 // printed on that new shell).
403 void ExecuteScriptAndCheckWindowOpen(
404 RenderFrameHost* rfh,
405 const std::string& javascript,
406 ExpectedNavigationStatus expected_navigation_status) {
407 ShellAddedObserver new_shell_observer;
408 EXPECT_TRUE(ExecuteScript(rfh, javascript));
409
410 Shell* new_shell = new_shell_observer.GetShell();
411 WaitForLoadStop(new_shell->web_contents());
412
413 switch (expected_navigation_status) {
414 case NAVIGATION_ALLOWED:
415 EXPECT_TRUE(new_shell->web_contents()->GetLastCommittedURL().SchemeIs(
416 url::kDataScheme));
417 break;
418
419 case NAVIGATION_BLOCKED:
420 EXPECT_TRUE(
421 new_shell->web_contents()->GetLastCommittedURL().is_empty());
422 break;
423
424 default:
425 NOTREACHED();
426 }
427 }
428
429 // Executes |javascript| on |rfh| and waits for a download to be started by
430 // a window.open call.
431 void ExecuteScriptAndCheckWindowOpenDownload(RenderFrameHost* rfh,
432 const std::string& javascript) {
433 const GURL original_url(shell()->web_contents()->GetLastCommittedURL());
434 ShellAddedObserver new_shell_observer;
435 EXPECT_TRUE(ExecuteScript(rfh, javascript));
436 Shell* new_shell = new_shell_observer.GetShell();
437
438 DownloadManager* download_manager = BrowserContext::GetDownloadManager(
439 new_shell->web_contents()->GetBrowserContext());
440 DownloadTestObserverTerminal download_observer(
441 download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
442
443 WaitForLoadStop(new_shell->web_contents());
444 download_observer.WaitForFinished();
445
446 EXPECT_TRUE(new_shell->web_contents()->GetURL().spec().empty());
447 // No navigation should commit.
448 EXPECT_FALSE(
449 new_shell->web_contents()->GetController().GetLastCommittedEntry());
450 // Original page shouldn't navigate away.
451 EXPECT_EQ(original_url, shell()->web_contents()->GetURL());
452 EXPECT_EQ(original_url, shell()
453 ->web_contents()
454 ->GetController()
455 .GetLastCommittedEntry()
456 ->GetURL());
457 }
458
459 // Executes |javascript| on |rfh| and waits for a download to be started.
460 void ExecuteScriptAndCheckNavigationDownload(RenderFrameHost* rfh,
461 const std::string& javascript) {
462 const GURL original_url(shell()->web_contents()->GetLastCommittedURL());
463 DownloadManager* download_manager = BrowserContext::GetDownloadManager(
464 shell()->web_contents()->GetBrowserContext());
465 DownloadTestObserverTerminal download_observer(
466 download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
467
468 EXPECT_TRUE(ExecuteScript(rfh, javascript));
469 // If no download happens, this will timeout.
470 download_observer.WaitForFinished();
471
472 // Original page shouldn't navigate away.
473 EXPECT_EQ(original_url, shell()->web_contents()->GetURL());
474 EXPECT_EQ(original_url, shell()
475 ->web_contents()
476 ->GetController()
477 .GetLastCommittedEntry()
478 ->GetURL());
479 }
480
481 bool IsPlzNavigateTest() const {
482 return std::get<0>(GetParam()) == PLZNAVIGATE;
483 }
484
485 bool IsSitePerProcessTest() const {
486 return std::get<1>(GetParam()) == SITE_PER_PROCESS;
487 }
488
489 // data URL form of the file at content/test/data/data_url_navigations.html
490 GURL data_url() const { return data_url_; }
491
492 private:
493 #if BUILDFLAG(ENABLE_PLUGINS)
494 ScopedPluginRegister scoped_plugin_register_;
495 #endif // BUILDFLAG(ENABLE_PLUGINS)
496
497 GURL data_url_;
498
499 DISALLOW_COPY_AND_ASSIGN(DataUrlNavigationBrowserTest);
500 };
501
502 INSTANTIATE_TEST_CASE_P(
503 ,
504 DataUrlNavigationBrowserTest,
505 ::testing::Combine(::testing::Values(NO_PLZNAVIGATE, PLZNAVIGATE),
506 ::testing::Values(NO_SITE_PER_PROCESS,
507 SITE_PER_PROCESS)));
508
509 ////////////////////////////////////////////////////////////////////////////////
510 // data URLs with HTML mimetype
511 //
512 // Tests that a direct navigation to a data URL doesn't show a console warning
513 // and is not blocked.
514 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest, BrowserInitiated_Allow) {
515 DataURLWarningConsoleObserverDelegate console_delegate(
516 shell()->web_contents(), NAVIGATION_ALLOWED);
517 shell()->web_contents()->SetDelegate(&console_delegate);
518
519 NavigateToURL(shell(), GURL("data:text/"
520 "html,<html><script>console.log('NAVIGATION_"
521 "SUCCESSFUL');</script>"));
522 console_delegate.Wait();
523 shell()->web_contents()->SetDelegate(nullptr);
524
525 EXPECT_TRUE(shell()->web_contents()->GetURL().SchemeIs(url::kDataScheme));
526 EXPECT_TRUE(shell()
527 ->web_contents()
528 ->GetController()
529 .GetLastCommittedEntry()
530 ->GetURL()
531 .SchemeIs(url::kDataScheme));
532 }
533
534 // Tests that a content initiated navigation to a data URL is blocked.
535 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest, HTML_Navigation_Block) {
536 NavigateToURL(shell(),
537 embedded_test_server()->GetURL("/data_url_navigations.html"));
538 ExecuteScriptAndCheckNavigation(
539 shell()->web_contents()->GetMainFrame(),
540 "document.getElementById('navigate-top-frame-to-html').click()",
541 NAVIGATION_BLOCKED);
542 }
543
544 // Test that a window.open to a data URL with HTML mime type is blocked.
545 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest, HTML_WindowOpen_Block) {
546 NavigateToURL(shell(),
547 embedded_test_server()->GetURL("/data_url_navigations.html"));
548 ExecuteScriptAndCheckWindowOpen(
549 shell()->web_contents()->GetMainFrame(),
550 "document.getElementById('window-open-html').click()",
551 NAVIGATION_BLOCKED);
552 }
553
554 // Test that a form post to a data URL with HTML mime type is blocked.
555 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest, HTML_FormPost_Block) {
556 NavigateToURL(shell(),
557 embedded_test_server()->GetURL("/data_url_navigations.html"));
558 ExecuteScriptAndCheckNavigation(
559 shell()->web_contents()->GetMainFrame(),
560 "document.getElementById('form-post-to-html').click()",
561 NAVIGATION_BLOCKED);
562 }
563
564 // Tests that navigating the main frame to a data URL with HTML mimetype from a
565 // subframe is blocked.
566 // TODO(meacer): Enable for all cases once crbug.com/651895 is fixed.
567 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
568 HTML_NavigationFromFrame_Block) {
569 // This test fails and is disabled in site-per-process + no plznavigate mode.
570 // request->originDocument is null in FrameLoader::prepareForRequest,
571 // allowing the navigation by default.
572 if (!IsSitePerProcessTest() || IsPlzNavigateTest()) {
573 NavigateToURL(shell(),
574 embedded_test_server()->GetURL("a.com", "/simple_page.html"));
575 AddIFrame(
576 shell()->web_contents()->GetMainFrame(),
577 embedded_test_server()->GetURL("b.com", "/data_url_navigations.html"));
578
579 TestNavigationFromFrame(
580 "document.getElementById('navigate-top-frame-to-html').click()",
581 NAVIGATION_BLOCKED);
582 }
583 }
584
585 // Tests that opening a new data URL window from a subframe is blocked.
586 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
587 HTML_WindowOpenFromFrame_Block) {
588 NavigateToURL(shell(),
589 embedded_test_server()->GetURL("a.com", "/simple_page.html"));
590 AddIFrame(
591 shell()->web_contents()->GetMainFrame(),
592 embedded_test_server()->GetURL("b.com", "/data_url_navigations.html"));
593
594 TestWindowOpenFromFrame("document.getElementById('window-open-html').click()",
595 NAVIGATION_BLOCKED);
596 }
597
598 // Tests that navigation to a data URL is allowed if the top frame is already a
599 // data URL.
600 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
601 HTML_Navigation_DataToData_Allow) {
602 NavigateToURL(shell(), data_url());
603 ExecuteScriptAndCheckNavigation(
604 shell()->web_contents()->GetMainFrame(),
605 "document.getElementById('navigate-top-frame-to-html').click()",
606 NAVIGATION_ALLOWED);
607 }
608
609 // Test that a form post to a data URL with HTML mime type is allowed if the top
610 // frame is already a data URL.
611 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
612 HTML_FormPost_DataToData_Allow) {
613 NavigateToURL(shell(), data_url());
614 ExecuteScriptAndCheckNavigation(
615 shell()->web_contents()->GetMainFrame(),
616 "document.getElementById('form-post-to-html').click()",
617 NAVIGATION_ALLOWED);
618 }
619
620 // Tests that navigating the top frame to a data URL with HTML mimetype is
621 // allowed if the top frame is already a data URL.
622 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
623 HTML_NavigationFromFrame_TopFrameIsDataURL_Allow) {
624 const GURL top_url(
625 base::StringPrintf("data:text/html, <iframe src='%s'></iframe>",
626 embedded_test_server()
627 ->GetURL("/data_url_navigations.html")
628 .spec()
629 .c_str()));
630 NavigateToURL(shell(), top_url);
631
632 TestNavigationFromFrame(
633 "document.getElementById('navigate-top-frame-to-html').click()",
634 NAVIGATION_ALLOWED);
635 }
636
637 // Tests that opening a new window with a data URL with HTML mimetype is allowed
638 // if the top frame already is a data URL.
639 // TODO(meacer): Disabled for PlzNavigate. DataUrlNavigationThrottler doesn't
640 // know about the initiator window and fails to allow.
641 // Enable for all cases once crbug.com/651895 is fixed.
642 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
643 HTML_WindowOpenFromFrame_TopFrameIsDataURL_Allow) {
644 if (!IsPlzNavigateTest()) {
645 const GURL top_url(
646 base::StringPrintf("data:text/html, <iframe src='%s'></iframe>",
647 embedded_test_server()
648 ->GetURL("/data_url_navigations.html")
649 .spec()
650 .c_str()));
651 NavigateToURL(shell(), top_url);
652
653 TestWindowOpenFromFrame(
654 "document.getElementById('window-open-html').click()",
655 NAVIGATION_ALLOWED);
656 }
657 }
658 ////////////////////////////////////////////////////////////////////////////////
659 // data URLs with octet-stream mimetype (binary)
660 //
661 // Test that window.open to a data URL results in an allowed download if the URL
662 // has a binary mime type.
663 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
664 OctetStream_WindowOpen_Download) {
665 NavigateToURL(shell(),
666 embedded_test_server()->GetURL("/data_url_navigations.html"));
667 ExecuteScriptAndCheckWindowOpenDownload(
668 shell()->web_contents()->GetMainFrame(),
669 "document.getElementById('window-open-octetstream').click()");
670 }
671
672 // Test that a navigation to a data URL results in a download if the URL has a
673 // binary mime type.
674 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
675 OctetStream_Navigation_Download) {
676 NavigateToURL(shell(),
677 embedded_test_server()->GetURL("/data_url_navigations.html"));
678 ExecuteScriptAndCheckNavigationDownload(
679 shell()->web_contents()->GetMainFrame(),
680 "document.getElementById('navigate-top-frame-to-octetstream').click()");
681 }
682
683 // Test that a form post to a data URL results in a download if the URL has a
684 // binary mime type.
685 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
686 OctetStream_FormPost_Download) {
687 NavigateToURL(shell(),
688 embedded_test_server()->GetURL("/data_url_navigations.html"));
689 ExecuteScriptAndCheckNavigationDownload(
690 shell()->web_contents()->GetMainFrame(),
691 "document.getElementById('form-post-to-octetstream').click()");
692 }
693
694 // Tests that navigating the main frame from a subframe results in a download
695 // if the URL has a binary mimetype.
696 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
697 OctetStream_NavigationFromFrame_Download) {
698 NavigateToURL(shell(),
699 embedded_test_server()->GetURL("a.com", "/simple_page.html"));
700 AddIFrame(
701 shell()->web_contents()->GetMainFrame(),
702 embedded_test_server()->GetURL("b.com", "/data_url_navigations.html"));
703
704 TestDownloadFromFrame(
705 "document.getElementById('navigate-top-frame-to-octetstream').click()");
706 }
707
708 ////////////////////////////////////////////////////////////////////////////////
709 // data URLs with unknown mimetype
710 //
711 // Test that window.open to a data URL results in an allowed download if the URL
712 // has an unknown mime type.
713 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
714 UnknownMimeType_WindowOpen_Download) {
715 NavigateToURL(shell(),
716 embedded_test_server()->GetURL("/data_url_navigations.html"));
717 ExecuteScriptAndCheckWindowOpenDownload(
718 shell()->web_contents()->GetMainFrame(),
719 "document.getElementById('window-open-unknown-mimetype').click()");
720 }
721
722 // Test that a navigation to a data URL results in a download if the URL has an
723 // unknown mime type.
724 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
725 UnknownMimeType_Navigation_Download) {
726 NavigateToURL(shell(),
727 embedded_test_server()->GetURL("/data_url_navigations.html"));
728 ExecuteScriptAndCheckNavigationDownload(
729 shell()->web_contents()->GetMainFrame(),
730 "document.getElementById('navigate-top-"
731 "frame-to-unknown-mimetype').click()");
732 }
733
734 // Test that a form post to a data URL results in a download if the URL has an
735 // unknown mime type.
736 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
737 UnknownMimeType_FormPost_Download) {
738 NavigateToURL(shell(),
739 embedded_test_server()->GetURL("/data_url_navigations.html"));
740 ExecuteScriptAndCheckNavigationDownload(
741 shell()->web_contents()->GetMainFrame(),
742 "document.getElementById('form-post-to-unknown-mimetype').click()");
743 }
744
745 ////////////////////////////////////////////////////////////////////////////////
746 // data URLs with PDF mimetype
747 //
748 // Tests that a direct navigation to a data URL with PDF mime type is allowed.
749 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
750 PDF_DirectNavigation_Allow) {
751 TestNavigationObserver observer(shell()->web_contents());
752 NavigateToURL(shell(), GURL(kPdfUrl));
753 EXPECT_EQ(GURL(kPdfUrl), observer.last_navigation_url());
754 EXPECT_TRUE(observer.last_navigation_succeeded());
755 EXPECT_TRUE(shell()->web_contents()->GetURL().SchemeIs(url::kDataScheme));
756 EXPECT_TRUE(shell()
757 ->web_contents()
758 ->GetController()
759 .GetLastCommittedEntry()
760 ->GetURL()
761 .SchemeIs(url::kDataScheme));
762 }
763
764 // Tests that a window.open to a data URL is blocked if the data URL has a
765 // mime type that will be handled by a plugin (PDF in this case).
766 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest, PDF_WindowOpen_Block) {
767 NavigateToURL(shell(),
768 embedded_test_server()->GetURL("/data_url_navigations.html"));
769 ExecuteScriptAndCheckWindowOpen(
770 shell()->web_contents()->GetMainFrame(),
771 "document.getElementById('window-open-pdf').click()", NAVIGATION_BLOCKED);
772 }
773
774 // Test that a navigation to a data URL is blocked if the data URL has a mime
775 // type that will be handled by a plugin (PDF in this case).
776 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest, PDF_Navigation_Block) {
777 NavigateToURL(shell(),
778 embedded_test_server()->GetURL("/data_url_navigations.html"));
779 ExecuteScriptAndCheckPDFNavigation(
780 shell()->web_contents()->GetMainFrame(),
781 "document.getElementById('navigate-top-frame-to-pdf').click()",
782 NAVIGATION_BLOCKED);
783 }
784
785 // Test that a navigation to a data URL is blocked if the data URL has a mime
786 // type that will be handled by a plugin (PDF in this case).
787 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest, PDF_FormPost_Block) {
788 NavigateToURL(shell(),
789 embedded_test_server()->GetURL("/data_url_navigations.html"));
790 ExecuteScriptAndCheckPDFNavigation(
791 shell()->web_contents()->GetMainFrame(),
792 "document.getElementById('form-post-to-pdf').click()",
793 NAVIGATION_BLOCKED);
794 }
795
796 // Tests that navigating the main frame to a data URL with PDF mimetype from a
797 // subframe is blocked.
798 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
799 PDF_NavigationFromFrame_Block) {
800 NavigateToURL(shell(),
801 embedded_test_server()->GetURL("a.com", "/simple_page.html"));
802 AddIFrame(
803 shell()->web_contents()->GetMainFrame(),
804 embedded_test_server()->GetURL("b.com", "/data_url_navigations.html"));
805
806 TestPDFNavigationFromFrame(
807 "document.getElementById('navigate-top-frame-to-pdf').click()",
808 NAVIGATION_BLOCKED);
809 }
810
811 // Tests that opening a window with a data URL with PDF mimetype from a
812 // subframe is blocked.
813 // TODO(meacer): Disabled because PDF navigations are handled by
814 // DataURLNavigationThrottler, and DataURLNavigationThrottler
815 // doesn't yet know anything about the opener of the window.
816 // Blocked on crbug.com/651895.
817 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
818 DISABLED_PDF_WindowOpenFromFrame_Block) {
819 NavigateToURL(shell(),
820 embedded_test_server()->GetURL("a.com", "/simple_page.html"));
821 AddIFrame(
822 shell()->web_contents()->GetMainFrame(),
823 embedded_test_server()->GetURL("b.com", "/data_url_navigations.html"));
824
825 TestPDFNavigationFromFrame(
826 "document.getElementById('window-open-pdf').click()", NAVIGATION_BLOCKED);
827 }
828
829 // Tests that navigating the top frame to a data URL with PDF mimetype from a
830 // subframe is allowed if the top frame is already a data URL.
831 IN_PROC_BROWSER_TEST_P(DataUrlNavigationBrowserTest,
832 PDF_NavigationFromFrame_TopFrameIsDataURL_Allow) {
833 const GURL top_url(
834 base::StringPrintf("data:text/html, <iframe src='%s'></iframe>",
835 embedded_test_server()
836 ->GetURL("/data_url_navigations.html")
837 .spec()
838 .c_str()));
839 NavigateToURL(shell(), top_url);
840
841 TestPDFNavigationFromFrame(
842 "document.getElementById('navigate-top-frame-to-pdf').click()",
843 NAVIGATION_ALLOWED);
844 }
845
846 // Tests that opening a window with a data URL with PDF mimetype from a
847 // subframe is allowed if the top frame is already a data URL.
848 // TODO(meacer): Disabled because PDF navigations are handled by
849 // DataURLNavigationThrottler, and DataURLNavigationThrottler
850 // doesn't yet know anything about the opener of the window.
851 // Blocked on crbug.com/651895.
852 IN_PROC_BROWSER_TEST_P(
853 DataUrlNavigationBrowserTest,
854 DISABLED_PDF_WindowOpenFromFrame_TopFrameIsDataURL_Allow) {
855 const GURL top_url(
856 base::StringPrintf("data:text/html, <iframe src='%s'></iframe>",
857 embedded_test_server()
858 ->GetURL("/data_url_navigations.html")
859 .spec()
860 .c_str()));
861 NavigateToURL(shell(), top_url);
862
863 TestWindowOpenFromFrame("document.getElementById('window-open-pdf').click()",
864 NAVIGATION_ALLOWED);
865 }
866
867 typedef ContentBrowserTest DataUrlXSSBrowserTest;
868
869 // This was previously a layout test called
870 // xss-DENIED-from-javascript-url-window-open.html. It's moved here now that
871 // pages can't open windows with data URLs. This test runs the same code on a
872 // data URL, as data URLs can open windows with data URLs.
873 IN_PROC_BROWSER_TEST_F(DataUrlXSSBrowserTest, DenyXSSFromDataUrlWindowOpen) {
874 const char kMainPage[] =
875 "data:text/html,"
876 "<script>"
877 " window.addEventListener('message', function() {"
878 " window.domAutomationController.send("
879 " document.getElementById('accessMe')"
880 " .textContent.startsWith('PASS'));"
881 " });"
882 "</script>"
883 "<body>"
884 "<p id='accessMe'>PASS: Access from a window opened with a data: URL was "
885 "denied.</p>"
886 "</body>";
887
888 // Opens a window, attempts to modify the opener's DOM and notifies the opener
889 // after the attempt.
890 const char kWindowOpen[] =
891 "window.open('data:text/html,"
892 "<script>"
893 " try {"
894 " opener.document.getElementById(`accessMe`).innerHTML = "
895 " `FAIL: Access from a window opened with a data: URL was allowed!`;"
896 " } catch (e) {}"
897 " window.opener.postMessage(`done`, `*`);"
898 "</script>', '', '_blank')";
899 NavigateToURL(shell(), GURL(kMainPage));
900 bool pass = false;
901 ASSERT_TRUE(
902 ExecuteScriptAndExtractBool(shell()->web_contents(), kWindowOpen, &pass));
903 EXPECT_TRUE(pass);
904 }
905
906 // Similar to DenyXSSToDataUrlInOtherWindow, but this time the opener tries
907 // to modify the opened data URL. Used to be a layout test called
908 // xss-DENIED-to-data-url-window-open.html.
909 IN_PROC_BROWSER_TEST_F(DataUrlXSSBrowserTest, DenyXSSToDataUrlWindowOpen) {
910 const char kMainPage[] =
911 "data:text/html,"
912 "<script>"
913 " var openedWindow = null;"
914 " window.addEventListener('message', function(evt) {"
915 " if (evt.data == 'try-accessing-window') {"
916 " try {"
917 " openedWindow.document.getElementById('accessMe').innerHTML = "
918 " 'FAIL: Access to a window opened with a data: URL was "
919 "allowed.';"
920 " } catch (e) {}"
921 " openedWindow.postMessage('done', '*');"
922 " }"
923 " if (evt.data == 'test-succeed')"
924 " window.domAutomationController.send(true);"
925 " if (evt.data == 'test-fail')"
926 " window.domAutomationController.send(false);"
927 " });"
928 "</script>";
929
930 // Opens a window. Once loaded, the window sends a message asking the opener
931 // to access its (the window's) DOM. The opener attempts to change the
932 // window's DOM and then asks the window to notify whether its DOM changed.
933 const char kWindowOpen[] =
934 "openedWindow = window.open('data:text/html,"
935 "<body>"
936 " <p id=accessMe>PASS: Access from a window opened with a data: URL"
937 " was denied.</p>"
938 "<script>"
939 " window.addEventListener(`message`, function() {"
940 " if (document.getElementById(`accessMe`)"
941 " .textContent.startsWith(`PASS`)) {"
942 " window.opener.postMessage(`test-succeed`, `*`);"
943 " } else {"
944 " window.opener.postMessage(`test-fail`, `*`);"
945 " }"
946 " });"
947 " window.onload = function() {"
948 " window.opener.postMessage(`try-accessing-window`, `*`);"
949 " }"
950 "</scr' + 'ipt>"
951 "</body>');";
952 NavigateToURL(shell(), GURL(kMainPage));
953 bool pass = false;
954 ASSERT_TRUE(
955 ExecuteScriptAndExtractBool(shell()->web_contents(), kWindowOpen, &pass));
956 EXPECT_TRUE(pass);
957 }
958
959 } // content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698