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

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

Powered by Google App Engine
This is Rietveld 408576698