OLD | NEW |
---|---|
(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 | |
OLD | NEW |