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

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: Fix downloads, plugin handling and browser side navigations Created 3 years, 9 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/strings/pattern.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/public/browser/browser_context.h"
9 #include "content/public/browser/navigation_entry.h"
10 #include "content/public/browser/plugin_service.h"
11 #include "content/public/browser/web_contents.h"
12 #include "content/public/common/content_switches.h"
13 #include "content/public/common/webplugininfo.h"
14 #include "content/public/test/browser_test_utils.h"
15 #include "content/public/test/content_browser_test.h"
16 #include "content/public/test/content_browser_test_utils.h"
17 #include "content/public/test/download_test_observer.h"
18 #include "content/public/test/test_navigation_observer.h"
19 #include "content/shell/browser/shell.h"
20 #include "net/test/embedded_test_server/embedded_test_server.h"
21
22 namespace content {
23
24 namespace {
25 const char kDataUrlBlockedPattern[] =
26 "Not allowed to top-level navigate to resource:*";
27
28 const char kHtmlUrl[] = "data:text/html, <html>test</html>";
29
30 // Octet streams are always downloaded.
31 const char kOctetStreamUrl[] = "data:application/octet-stream,test";
32
33 // Unknown mime types that aren't handled by plugins are always downloaded.
34 const char kUnknownMimeTypeUrl[] = "data:unknown/some-mime,test";
35
36 // A "Hello World" PDF encoded as a data URL. Source of this PDF:
37 // -------------------------
38 // %PDF-1.7
39 // 1 0 obj << /Type /Page /Parent 3 0 R /Resources 5 0 R /Contents 2 0 R >>
40 // endobj
41 // 2 0 obj << /Length 51 >>
42 // stream BT
43 // /F1 12 Tf
44 // 1 0 0 1 100 20 Tm
45 // (Hello World)Tj
46 // ET
47 // endstream
48 // endobj
49 // 3 0 obj << /Type /Pages /Kids [ 1 0 R ] /Count 1 /MediaBox [ 0 0 300 50] >>
50 // endobj
51 // 4 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /BaseFont/Arial >>
52 // endobj
53 // 5 0 obj << /ProcSet[/PDF/Text] /Font <</F1 4 0 R >> >>
54 // endobj
55 // 6 0 obj << /Type /Catalog /Pages 3 0 R >>
56 // endobj
57 // trailer << /Root 6 0 R >>
58 // -------------------------
59 const char kPdfUrl[] =
60 "data:application/pdf;base64,JVBERi0xLjcKMSAwIG9iaiA8PCAvVHlwZSAvUGFnZSAvUG"
61 "FyZW50IDMgMCBSIC9SZXNvdXJjZXMgNSAwIFIgL0NvbnRlbnRzIDIgMCBSID4+CmVuZG9iagoy"
62 "IDAgb2JqIDw8IC9MZW5ndGggNTEgPj4KIHN0cmVhbSBCVAogL0YxIDEyIFRmCiAxIDAgMCAxID"
63 "EwMCAyMCBUbQogKEhlbGxvIFdvcmxkKVRqCiBFVAogZW5kc3RyZWFtCmVuZG9iagozIDAgb2Jq"
64 "IDw8IC9UeXBlIC9QYWdlcyAvS2lkcyBbIDEgMCBSIF0gL0NvdW50IDEgL01lZGlhQm94IFsgMC"
65 "AwIDMwMCA1MF0gPj4KZW5kb2JqCjQgMCBvYmogPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1R5"
66 "cGUxIC9OYW1lIC9GMSAvQmFzZUZvbnQvQXJpYWwgPj4KZW5kb2JqCjUgMCBvYmogPDwgL1Byb2"
67 "NTZXRbL1BERi9UZXh0XSAvRm9udCA8PC9GMSA0IDAgUiA+PiA+PgplbmRvYmoKNiAwIG9iaiA8"
68 "PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMyAwIFIgPj4KZW5kb2JqCnRyYWlsZXIgPDwgL1Jvb3"
69 "QgNiAwIFIgPj4K";
70
71 // Helper class for testing data URL navigations with and without browser side
72 // navigation enabled.
73 class DataUrlNavigationTester {
74 public:
75 DataUrlNavigationTester(Shell* shell) : shell_(shell) {}
76
77 // Tests that a direct navigation to a data URL doesn't show a console warning
78 // and is not blocked.
79 void TestBrowserInitiatedAllowed() {
80 ConsoleObserverDelegate console_delegate(shell_->web_contents(), "FINISH");
81 shell_->web_contents()->SetDelegate(&console_delegate);
82
83 NavigateToURL(
84 shell_,
85 GURL("data:text/html,<html><script>console.log('FINISH');</script>"));
86 console_delegate.Wait();
87 EXPECT_TRUE(shell_->web_contents()->GetURL().SchemeIs(url::kDataScheme));
88 EXPECT_TRUE(shell_->web_contents()
89 ->GetController()
90 .GetLastCommittedEntry()
91 ->GetURL()
92 .SchemeIs(url::kDataScheme));
93 }
94
95 // Tests that a direct navigation to a data URL with mime type PDF isn't
96 // blocked.
97 void TestBrowserInitiatedToPDFAllowed() {
98 TestNavigationObserver observer(shell_->web_contents());
99 NavigateToURL(shell_, GURL(kPdfUrl));
100 EXPECT_EQ(GURL(kPdfUrl), observer.last_navigation_url());
101 EXPECT_TRUE(observer.last_navigation_succeeded());
102 EXPECT_TRUE(shell_->web_contents()->GetURL().SchemeIs(url::kDataScheme));
103 EXPECT_TRUE(shell_->web_contents()
104 ->GetController()
105 .GetLastCommittedEntry()
106 ->GetURL()
107 .SchemeIs(url::kDataScheme));
108 }
109
110 // Test that a window.open on ||original_url| to |data_url| URL is blocked
111 // and prints a console message.
112 void TestWindowOpenBlocked(const GURL& original_url, const GURL& data_url) {
113 NavigateToURL(shell_, original_url);
114
115 ShellAddedObserver new_shell_observer;
116 EXPECT_TRUE(ExecuteScript(
117 shell_->web_contents(),
118 base::StringPrintf("window.open('%s');", data_url.spec().c_str())));
119 Shell* new_shell = new_shell_observer.GetShell();
120 WaitForLoadStop(new_shell->web_contents());
121 EXPECT_TRUE(new_shell->web_contents()->GetURL().spec().empty());
122 // No navigation should commit.
123 EXPECT_FALSE(
124 new_shell->web_contents()->GetController().GetLastCommittedEntry());
125 }
126
127 // Tests that a redirect from |original_url| to |data_url| is blocked and
128 // prints a console message.
129 void TestRedirectBlocked(const GURL& original_url, const GURL& data_url) {
130 ASSERT_TRUE(data_url.SchemeIs("data"));
131 LOG(ERROR) << data_url.spec();
132 NavigateToURL(shell_, original_url);
133 ConsoleObserverDelegate console_delegate(shell_->web_contents(),
134 kDataUrlBlockedPattern);
135 shell_->web_contents()->SetDelegate(&console_delegate);
136 EXPECT_TRUE(ExecuteScript(shell_->web_contents(),
137 base::StringPrintf("window.location.href = '%s';",
138 data_url.spec().c_str())));
139 console_delegate.Wait();
140 // Original page shouldn't navigate away.
141 EXPECT_EQ(original_url, shell_->web_contents()->GetURL());
142 EXPECT_EQ(original_url, shell_->web_contents()
143 ->GetController()
144 .GetLastCommittedEntry()
145 ->GetURL());
146 }
147
148 // Tests that window.open to a data URL is not blocked if the mime type
149 // indicates that the URL will be downloaded.
150 void TestWindowOpenDownloadAllowed(const GURL& original_url,
151 const GURL& data_url) {
152 ASSERT_TRUE(data_url.SchemeIs("data"));
153 NavigateToURL(shell_, original_url);
154
155 ShellAddedObserver new_shell_observer;
156 EXPECT_TRUE(ExecuteScript(
157 shell_->web_contents(),
158 //"window.open('data:application/octet-stream,test');"));
159 base::StringPrintf("window.open('%s');", data_url.spec().c_str())));
160 Shell* new_shell = new_shell_observer.GetShell();
161
162 DownloadManager* download_manager = BrowserContext::GetDownloadManager(
163 new_shell->web_contents()->GetBrowserContext());
164 DownloadTestObserverTerminal download_observer(
165 download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
166
167 WaitForLoadStop(new_shell->web_contents());
168 download_observer.WaitForFinished();
169
170 EXPECT_TRUE(new_shell->web_contents()->GetURL().spec().empty());
171 // No navigation should commit.
172 EXPECT_FALSE(
173 new_shell->web_contents()->GetController().GetLastCommittedEntry());
174 // Original page shouldn't navigate away.
175 EXPECT_EQ(original_url, shell_->web_contents()->GetURL());
176 EXPECT_EQ(original_url, shell_->web_contents()
177 ->GetController()
178 .GetLastCommittedEntry()
179 ->GetURL());
180 }
181
182 // Tests that a redirect to a data URL is not blocked if the mime type
183 // indicates that the URL will be downloaded.
184 void TestRedirectDownloadAllowed(const GURL& original_url,
185 const GURL& data_url) {
186 ASSERT_TRUE(data_url.SchemeIs("data"));
187 NavigateToURL(shell_, original_url);
188
189 DownloadManager* download_manager = BrowserContext::GetDownloadManager(
190 shell_->web_contents()->GetBrowserContext());
191 DownloadTestObserverTerminal download_observer(
192 download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
193
194 EXPECT_TRUE(ExecuteScript(shell_->web_contents(),
195 base::StringPrintf("window.location.href = '%s';",
196 data_url.spec().c_str())));
197 download_observer.WaitForFinished();
198
199 // Original page shouldn't navigate away.
200 EXPECT_EQ(original_url, shell_->web_contents()->GetURL());
201 EXPECT_EQ(original_url, shell_->web_contents()
202 ->GetController()
203 .GetLastCommittedEntry()
204 ->GetURL());
205 }
206
207 private:
208 Shell* const shell_;
209 };
210
211 class ScopedPluginRegister {
212 public:
213 ScopedPluginRegister(content::PluginService* plugin_service)
214 : plugin_service_(plugin_service) {
215 const char kPluginName[] = "PDF";
216 const char kPdfMimeType[] = "application/pdf";
217 const char kPdfFileType[] = "pdf";
218 WebPluginInfo plugin_info;
219 plugin_info.type = WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS;
220 plugin_info.name = base::ASCIIToUTF16(kPluginName);
221 plugin_info.mime_types.push_back(
222 WebPluginMimeType(kPdfMimeType, kPdfFileType, std::string()));
223 plugin_service_->RegisterInternalPlugin(plugin_info, false);
224 plugin_service_->RefreshPlugins();
225 }
226
227 ~ScopedPluginRegister() {
228 std::vector<WebPluginInfo> plugins;
229 plugin_service_->GetInternalPlugins(&plugins);
230 EXPECT_EQ(1u, plugins.size());
231 plugin_service_->UnregisterInternalPlugin(plugins[0].path);
232 plugin_service_->RefreshPlugins();
233
234 plugins.clear();
235 plugin_service_->GetInternalPlugins(&plugins);
236 EXPECT_TRUE(plugins.empty());
237 }
238
239 private:
240 content::PluginService* plugin_service_;
241 };
242
243 } // namespace
244
245 class DataUrlNavigationBrowserTest : public ContentBrowserTest {
246 public:
247 DataUrlNavigationBrowserTest()
248 : scoped_plugin_register_(PluginService::GetInstance()) {}
249
250 protected:
251 void SetUpOnMainThread() override {
252 ASSERT_TRUE(embedded_test_server()->Start());
253 }
254
255 private:
256 ScopedPluginRegister scoped_plugin_register_;
257 };
258
259 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, BrowserInitiated) {
260 DataUrlNavigationTester(shell()).TestBrowserInitiatedAllowed();
261 }
262
263 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, RendererInitiated) {
264 DataUrlNavigationTester(shell()).TestRedirectBlocked(
265 embedded_test_server()->GetURL("/simple_links.html"), GURL(kHtmlUrl));
266 }
267
268 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, WindowOpen_Block) {
269 DataUrlNavigationTester(shell()).TestWindowOpenBlocked(
270 embedded_test_server()->GetURL("/simple_page.html"), GURL(kHtmlUrl));
271 }
272
273 // Test that window.open to a data URL is not blocked if the mime type indicates
274 // that the URL will be downloaded.
275 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
276 WindowOpen_OctetStream_Download) {
277 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed(
278 embedded_test_server()->GetURL("/simple_page.html"),
279 GURL(kOctetStreamUrl));
280 }
281
282 // Test that a content initiated navigation to a data URL is not blocked if the
283 // mime type indicates that the URL will be downloaded.
284 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
285 Redirect_OctetStream_Download) {
286 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed(
287 embedded_test_server()->GetURL("/simple_page.html"),
288 GURL(kOctetStreamUrl));
289 }
290
291 // Test that window.open to a data URL results in an allowed download if the URL
292 // has an unknown mime type.
293 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
294 WindowOpen_UnknownMimeType_Download) {
295 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed(
296 embedded_test_server()->GetURL("/simple_page.html"),
297 GURL(kUnknownMimeTypeUrl));
298 }
299
300 // Test that redirect to a data URL results in an allowed download if the URL
301 // has an unknown mime type.
302 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
303 Redirect_UnknownMimeType_Download) {
304 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed(
305 embedded_test_server()->GetURL("/simple_page.html"),
306 GURL(kUnknownMimeTypeUrl));
307 }
308
309 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
310 DirectNavigation_PDF_Allow) {
311 DataUrlNavigationTester(shell()).TestBrowserInitiatedToPDFAllowed();
312 }
313
314 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, WindowOpen_PDF_Block) {
315 DataUrlNavigationTester(shell()).TestWindowOpenBlocked(
316 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl));
317 }
318
319 // Test that a content initiated navigation to a data URL should be blocked if
320 // the data URL has a mime type that will be handled by a plugin (PDF in this
321 // case).
322 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, Redirect_PDF_Block) {
323 DataUrlNavigationTester(shell()).TestRedirectBlocked(
324 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl));
325 }
326
327 // Same as DataUrlNavigationBrowserTest tests, except these tests have browser
328 // side navigation enabled.
329 class DataUrlBrowserSideNavigationBrowserTest : public ContentBrowserTest {
330 public:
331 DataUrlBrowserSideNavigationBrowserTest()
332 : scoped_plugin_register_(PluginService::GetInstance()) {}
333
334 protected:
335 void SetUpCommandLine(base::CommandLine* command_line) override {
336 command_line->AppendSwitch(switches::kEnableBrowserSideNavigation);
337 }
338
339 void SetUpOnMainThread() override {
340 ASSERT_TRUE(embedded_test_server()->Start());
341 }
342
343 private:
344 ScopedPluginRegister scoped_plugin_register_;
345 };
346
347 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
348 BrowserInitiated) {
349 DataUrlNavigationTester(shell()).TestBrowserInitiatedAllowed();
350 }
351
352 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
353 RendererInitiated) {
354 DataUrlNavigationTester(shell()).TestRedirectBlocked(
355 embedded_test_server()->GetURL("/simple_links.html"), GURL(kHtmlUrl));
356 }
357
358 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
359 WindowOpen_Block) {
360 DataUrlNavigationTester(shell()).TestWindowOpenBlocked(
361 embedded_test_server()->GetURL("/simple_page.html"), GURL(kHtmlUrl));
362 }
363
364 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
365 WindowOpen_OctetStream_Download) {
366 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed(
367 embedded_test_server()->GetURL("/simple_page.html"),
368 GURL(kOctetStreamUrl));
369 }
370
371 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
372 Redirect_OctetStream_Download) {
373 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed(
374 embedded_test_server()->GetURL("/simple_page.html"),
375 GURL(kOctetStreamUrl));
376 }
377
378 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
379 WindowOpen_UnknownMimeType_Download) {
380 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed(
381 embedded_test_server()->GetURL("/simple_page.html"),
382 GURL(kUnknownMimeTypeUrl));
383 }
384
385 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
386 Redirect_UnknownMimeType_Download) {
387 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed(
388 embedded_test_server()->GetURL("/simple_page.html"),
389 GURL(kUnknownMimeTypeUrl));
390 }
391
392 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
393 DirectNavigation_PDF_Allow) {
394 DataUrlNavigationTester(shell()).TestBrowserInitiatedToPDFAllowed();
395 }
396
397 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
398 WindowOpen_PDF_Block) {
399 DataUrlNavigationTester(shell()).TestWindowOpenBlocked(
400 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl));
401 }
402
403 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
404 Redirect_PDF_Block) {
405 DataUrlNavigationTester(shell()).TestRedirectBlocked(
406 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl));
407 }
408
409 } // content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698