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

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: Cleanup 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
nasko 2017/03/28 19:58:01 nit: Only one |.
meacer 2017/03/30 20:43:55 Done.
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) {
nasko 2017/03/28 19:58:00 I don't see any redirects in this test method. How
meacer 2017/03/30 20:43:55 As we discussed, my terminology was wrong here. I
130 ASSERT_TRUE(data_url.SchemeIs("data"));
131 NavigateToURL(shell_, original_url);
132 ConsoleObserverDelegate console_delegate(shell_->web_contents(),
133 kDataUrlBlockedPattern);
134 shell_->web_contents()->SetDelegate(&console_delegate);
135 EXPECT_TRUE(ExecuteScript(shell_->web_contents(),
136 base::StringPrintf("window.location.href = '%s';",
137 data_url.spec().c_str())));
138 console_delegate.Wait();
139 // Original page shouldn't navigate away.
140 EXPECT_EQ(original_url, shell_->web_contents()->GetURL());
141 EXPECT_EQ(original_url, shell_->web_contents()
142 ->GetController()
143 .GetLastCommittedEntry()
144 ->GetURL());
145 }
146
147 // Tests that window.open to a data URL is not blocked if the mime type
148 // indicates that the URL will be downloaded.
149 void TestWindowOpenDownloadAllowed(const GURL& original_url,
150 const GURL& data_url) {
151 ASSERT_TRUE(data_url.SchemeIs("data"));
152 NavigateToURL(shell_, original_url);
153
154 ShellAddedObserver new_shell_observer;
155 EXPECT_TRUE(ExecuteScript(
156 shell_->web_contents(),
157 base::StringPrintf("window.open('%s');", data_url.spec().c_str())));
158 Shell* new_shell = new_shell_observer.GetShell();
159
160 DownloadManager* download_manager = BrowserContext::GetDownloadManager(
161 new_shell->web_contents()->GetBrowserContext());
162 DownloadTestObserverTerminal download_observer(
163 download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
164
165 WaitForLoadStop(new_shell->web_contents());
166 download_observer.WaitForFinished();
nasko 2017/03/28 19:58:01 Would this observer time out if no download occurr
meacer 2017/03/30 20:43:55 Yes, added a comment.
167
168 EXPECT_TRUE(new_shell->web_contents()->GetURL().spec().empty());
169 // No navigation should commit.
170 EXPECT_FALSE(
171 new_shell->web_contents()->GetController().GetLastCommittedEntry());
172 // Original page shouldn't navigate away.
173 EXPECT_EQ(original_url, shell_->web_contents()->GetURL());
174 EXPECT_EQ(original_url, shell_->web_contents()
175 ->GetController()
176 .GetLastCommittedEntry()
177 ->GetURL());
178 }
179
180 // Tests that a redirect to a data URL is not blocked if the mime type
181 // indicates that the URL will be downloaded.
182 void TestRedirectDownloadAllowed(const GURL& original_url,
183 const GURL& data_url) {
184 ASSERT_TRUE(data_url.SchemeIs("data"));
185 NavigateToURL(shell_, original_url);
186
187 DownloadManager* download_manager = BrowserContext::GetDownloadManager(
188 shell_->web_contents()->GetBrowserContext());
189 DownloadTestObserverTerminal download_observer(
190 download_manager, 1, DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
191
192 EXPECT_TRUE(ExecuteScript(shell_->web_contents(),
193 base::StringPrintf("window.location.href = '%s';",
194 data_url.spec().c_str())));
195 download_observer.WaitForFinished();
196
197 // Original page shouldn't navigate away.
198 EXPECT_EQ(original_url, shell_->web_contents()->GetURL());
199 EXPECT_EQ(original_url, shell_->web_contents()
200 ->GetController()
201 .GetLastCommittedEntry()
202 ->GetURL());
203 }
204
205 private:
206 Shell* const shell_;
207 };
208
209 class ScopedPluginRegister {
210 public:
211 ScopedPluginRegister(content::PluginService* plugin_service)
212 : plugin_service_(plugin_service) {
213 const char kPluginName[] = "PDF";
214 const char kPdfMimeType[] = "application/pdf";
215 const char kPdfFileType[] = "pdf";
216 WebPluginInfo plugin_info;
217 plugin_info.type = WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS;
218 plugin_info.name = base::ASCIIToUTF16(kPluginName);
219 plugin_info.mime_types.push_back(
220 WebPluginMimeType(kPdfMimeType, kPdfFileType, std::string()));
221 plugin_service_->RegisterInternalPlugin(plugin_info, false);
222 plugin_service_->RefreshPlugins();
223 }
224
225 ~ScopedPluginRegister() {
226 std::vector<WebPluginInfo> plugins;
227 plugin_service_->GetInternalPlugins(&plugins);
228 EXPECT_EQ(1u, plugins.size());
229 plugin_service_->UnregisterInternalPlugin(plugins[0].path);
230 plugin_service_->RefreshPlugins();
231
232 plugins.clear();
233 plugin_service_->GetInternalPlugins(&plugins);
234 EXPECT_TRUE(plugins.empty());
235 }
236
237 private:
238 content::PluginService* plugin_service_;
239 };
240
241 } // namespace
242
243 class DataUrlNavigationBrowserTest : public ContentBrowserTest {
244 public:
245 DataUrlNavigationBrowserTest()
246 : scoped_plugin_register_(PluginService::GetInstance()) {}
247
248 protected:
249 void SetUpOnMainThread() override {
250 ASSERT_TRUE(embedded_test_server()->Start());
251 }
252
253 private:
254 ScopedPluginRegister scoped_plugin_register_;
255 };
256
257 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, BrowserInitiated) {
258 DataUrlNavigationTester(shell()).TestBrowserInitiatedAllowed();
259 }
260
261 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, RendererInitiated) {
262 DataUrlNavigationTester(shell()).TestRedirectBlocked(
263 embedded_test_server()->GetURL("/simple_links.html"), GURL(kHtmlUrl));
264 }
265
266 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, WindowOpen_Block) {
267 DataUrlNavigationTester(shell()).TestWindowOpenBlocked(
268 embedded_test_server()->GetURL("/simple_page.html"), GURL(kHtmlUrl));
269 }
270
271 // Test that window.open to a data URL is not blocked if the mime type indicates
272 // that the URL will be downloaded.
273 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
274 WindowOpen_OctetStream_Download) {
275 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed(
276 embedded_test_server()->GetURL("/simple_page.html"),
277 GURL(kOctetStreamUrl));
278 }
279
280 // Test that a content initiated navigation to a data URL is not blocked if the
281 // mime type indicates that the URL will be downloaded.
282 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
283 Redirect_OctetStream_Download) {
284 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed(
285 embedded_test_server()->GetURL("/simple_page.html"),
286 GURL(kOctetStreamUrl));
287 }
288
289 // Test that window.open to a data URL results in an allowed download if the URL
290 // has an unknown mime type.
291 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
292 WindowOpen_UnknownMimeType_Download) {
293 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed(
294 embedded_test_server()->GetURL("/simple_page.html"),
295 GURL(kUnknownMimeTypeUrl));
296 }
297
298 // Test that redirect to a data URL results in an allowed download if the URL
299 // has an unknown mime type.
300 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
301 Redirect_UnknownMimeType_Download) {
302 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed(
303 embedded_test_server()->GetURL("/simple_page.html"),
304 GURL(kUnknownMimeTypeUrl));
305 }
306
307 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest,
308 DirectNavigation_PDF_Allow) {
309 DataUrlNavigationTester(shell()).TestBrowserInitiatedToPDFAllowed();
310 }
311
312 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, WindowOpen_PDF_Block) {
313 DataUrlNavigationTester(shell()).TestWindowOpenBlocked(
314 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl));
315 }
316
317 // Test that a content initiated navigation to a data URL should be blocked if
318 // the data URL has a mime type that will be handled by a plugin (PDF in this
319 // case).
320 IN_PROC_BROWSER_TEST_F(DataUrlNavigationBrowserTest, Redirect_PDF_Block) {
321 DataUrlNavigationTester(shell()).TestRedirectBlocked(
322 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl));
323 }
324
325 // Same as DataUrlNavigationBrowserTest tests, except these tests have browser
326 // side navigation enabled.
327 class DataUrlBrowserSideNavigationBrowserTest : public ContentBrowserTest {
328 public:
329 DataUrlBrowserSideNavigationBrowserTest()
330 : scoped_plugin_register_(PluginService::GetInstance()) {}
331
332 protected:
333 void SetUpCommandLine(base::CommandLine* command_line) override {
334 command_line->AppendSwitch(switches::kEnableBrowserSideNavigation);
335 }
336
337 void SetUpOnMainThread() override {
338 ASSERT_TRUE(embedded_test_server()->Start());
339 }
340
341 private:
342 ScopedPluginRegister scoped_plugin_register_;
343 };
344
345 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
346 BrowserInitiated) {
347 DataUrlNavigationTester(shell()).TestBrowserInitiatedAllowed();
348 }
349
350 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
351 RendererInitiated) {
352 DataUrlNavigationTester(shell()).TestRedirectBlocked(
353 embedded_test_server()->GetURL("/simple_links.html"), GURL(kHtmlUrl));
354 }
355
356 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
357 WindowOpen_Block) {
358 DataUrlNavigationTester(shell()).TestWindowOpenBlocked(
359 embedded_test_server()->GetURL("/simple_page.html"), GURL(kHtmlUrl));
360 }
361
362 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
363 WindowOpen_OctetStream_Download) {
364 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed(
365 embedded_test_server()->GetURL("/simple_page.html"),
366 GURL(kOctetStreamUrl));
367 }
368
369 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
370 Redirect_OctetStream_Download) {
371 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed(
372 embedded_test_server()->GetURL("/simple_page.html"),
373 GURL(kOctetStreamUrl));
374 }
375
376 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
377 WindowOpen_UnknownMimeType_Download) {
378 DataUrlNavigationTester(shell()).TestWindowOpenDownloadAllowed(
379 embedded_test_server()->GetURL("/simple_page.html"),
380 GURL(kUnknownMimeTypeUrl));
381 }
382
383 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
384 Redirect_UnknownMimeType_Download) {
385 DataUrlNavigationTester(shell()).TestRedirectDownloadAllowed(
386 embedded_test_server()->GetURL("/simple_page.html"),
387 GURL(kUnknownMimeTypeUrl));
388 }
389
390 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
391 DirectNavigation_PDF_Allow) {
392 DataUrlNavigationTester(shell()).TestBrowserInitiatedToPDFAllowed();
393 }
394
395 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
396 WindowOpen_PDF_Block) {
397 DataUrlNavigationTester(shell()).TestWindowOpenBlocked(
398 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl));
399 }
400
401 IN_PROC_BROWSER_TEST_F(DataUrlBrowserSideNavigationBrowserTest,
402 Redirect_PDF_Block) {
403 DataUrlNavigationTester(shell()).TestRedirectBlocked(
404 embedded_test_server()->GetURL("/simple_page.html"), GURL(kPdfUrl));
405 }
406
407 } // content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698