1 // Copyright (c) 2012 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.
5 #include "chrome/renderer/chrome_content_renderer_client.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/renderer/searchbox/search_bouncer.h"
11 #include "content/public/common/webplugininfo.h"
12 #include "extensions/common/extension.h"
13 #include "extensions/common/extension_builder.h"
14 #include "extensions/common/manifest_constants.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/WebKit/public/platform/WebString.h"
17 #include "third_party/WebKit/public/platform/WebVector.h"
18 #include "third_party/WebKit/public/web/WebPluginParams.h"
21 using blink::WebPluginParams
;
22 using blink::WebString
;
23 using blink::WebVector
;
24 using content::WebPluginInfo
;
25 using content::WebPluginMimeType
;
28 const bool kNaClRestricted
= false;
29 const bool kNaClUnrestricted
= true;
30 const bool kExtensionRestricted
= false;
31 const bool kExtensionUnrestricted
= true;
32 const bool kExtensionNotFromWebStore
= false;
33 const bool kExtensionFromWebStore
= true;
34 const bool kNotHostedApp
= false;
35 const bool kHostedApp
= true;
37 const char kExtensionUrl
[] = "chrome-extension://extension_id/background.html";
39 const char kPhotosAppURL1
[] = "https://foo.plus.google.com";
40 const char kPhotosAppURL2
[] = "https://foo.plus.sandbox.google.com";
41 const char kPhotosManifestURL1
[] = "https://ssl.gstatic.com/s2/oz/nacl/foo";
42 const char kPhotosManifestURL2
[] = "https://ssl.gstatic.com/photos/nacl/foo";
44 const char kChatAppURL1
[] = "https://foo.talkgadget.google.com/hangouts/foo";
45 const char kChatAppURL2
[] = "https://foo.plus.google.com/hangouts/foo";
46 const char kChatAppURL3
[] = "https://foo.plus.sandbox.google.com/hangouts/foo";
47 const char kChatManifestFS1
[] =
48 "filesystem:https://foo.talkgadget.google.com/foo";
49 const char kChatManifestFS2
[] = "filesystem:https://foo.plus.google.com/foo";
50 const char kChatManifestFS3
[] =
51 "filesystem:https://foo.plus.sandbox.google.com/foo";
53 bool AllowsDevInterfaces(const WebPluginParams
& params
) {
54 for (size_t i
= 0; i
< params
.attributeNames
.size(); ++i
) {
55 if (params
.attributeNames
[i
] == WebString::fromUTF8("@dev"))
61 void AddFakeDevAttribute(WebPluginParams
* params
) {
62 WebVector
<WebString
> names(static_cast<size_t>(1));
63 WebVector
<WebString
> values(static_cast<size_t>(1));
64 names
[0] = WebString::fromUTF8("@dev");
65 values
[0] = WebString();
66 params
->attributeNames
.swap(names
);
67 params
->attributeValues
.swap(values
);
70 void AddContentTypeHandler(content::WebPluginInfo
* info
,
71 const char* mime_type
,
72 const char* manifest_url
) {
73 content::WebPluginMimeType mime_type_info
;
74 mime_type_info
.mime_type
= mime_type
;
75 mime_type_info
.additional_param_names
.push_back(base::UTF8ToUTF16("nacl"));
76 mime_type_info
.additional_param_values
.push_back(
77 base::UTF8ToUTF16(manifest_url
));
78 info
->mime_types
.push_back(mime_type_info
);
82 typedef testing::Test ChromeContentRendererClientTest
;
85 scoped_refptr
<const extensions::Extension
> CreateTestExtension(
86 bool is_unrestricted
, bool is_from_webstore
, bool is_hosted_app
,
87 const std::string
& app_url
) {
88 extensions::Manifest::Location location
= is_unrestricted
?
89 extensions::Manifest::UNPACKED
:
90 extensions::Manifest::INTERNAL
;
91 int flags
= is_from_webstore
?
92 extensions::Extension::FROM_WEBSTORE
:
93 extensions::Extension::NO_FLAGS
;
95 base::DictionaryValue manifest
;
96 manifest
.SetString("name", "NaCl Extension");
97 manifest
.SetString("version", "1");
98 manifest
.SetInteger("manifest_version", 2);
100 base::ListValue
* url_list
= new base::ListValue();
101 url_list
->Append(base::Value::CreateStringValue(app_url
));
102 manifest
.Set(extensions::manifest_keys::kWebURLs
, url_list
);
103 manifest
.SetString(extensions::manifest_keys::kLaunchWebURL
, app_url
);
106 return extensions::Extension::Create(base::FilePath(), location
, manifest
,
110 scoped_refptr
<const extensions::Extension
> CreateExtension(
111 bool is_unrestricted
, bool is_from_webstore
) {
112 return CreateTestExtension(
113 is_unrestricted
, is_from_webstore
, kNotHostedApp
, std::string());
116 scoped_refptr
<const extensions::Extension
> CreateHostedApp(
117 bool is_unrestricted
, bool is_from_webstore
, const std::string
& app_url
) {
118 return CreateTestExtension(is_unrestricted
, is_from_webstore
, kHostedApp
,
122 TEST_F(ChromeContentRendererClientTest
, NaClRestriction
) {
123 // Unknown content types have no NaCl module.
127 ChromeContentRendererClient::GetNaClContentHandlerURL(
128 "application/x-foo", info
));
130 // Known content types have a NaCl module.
133 AddContentTypeHandler(&info
, "application/x-foo", "www.foo.com");
134 EXPECT_EQ(GURL("www.foo.com"),
135 ChromeContentRendererClient::GetNaClContentHandlerURL(
136 "application/x-foo", info
));
138 // --enable-nacl allows all NaCl apps, with 'dev' interfaces.
140 WebPluginParams params
;
141 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
145 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
147 EXPECT_TRUE(AllowsDevInterfaces(params
));
149 // Unrestricted extensions are allowed without --enable-nacl, with 'dev'
150 // interfaces if called from an extension url.
152 WebPluginParams params
;
153 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
157 CreateExtension(kExtensionUnrestricted
, kExtensionNotFromWebStore
)
160 EXPECT_TRUE(AllowsDevInterfaces(params
));
162 // CWS extensions are allowed without --enable-nacl, without 'dev'
163 // interfaces if called from an extension url.
165 WebPluginParams params
;
166 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
170 CreateExtension(kExtensionRestricted
, kExtensionFromWebStore
).get(),
172 EXPECT_FALSE(AllowsDevInterfaces(params
));
174 // CWS extensions can't get 'dev' interfaces with --enable-nacl.
176 WebPluginParams params
;
177 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
181 CreateExtension(kExtensionRestricted
, kExtensionFromWebStore
).get(),
183 EXPECT_FALSE(AllowsDevInterfaces(params
));
185 // CWS extensions can't get 'dev' interfaces by injecting a fake
188 WebPluginParams params
;
189 AddFakeDevAttribute(¶ms
);
190 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
194 CreateExtension(kExtensionRestricted
, kExtensionFromWebStore
).get(),
196 EXPECT_FALSE(AllowsDevInterfaces(params
));
198 // The NaCl PDF extension is allowed without --enable-nacl, with 'dev'
199 // interfaces, from all URLs.
201 WebPluginParams params
;
202 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
203 GURL("chrome-extension://acadkphlmlegjaadjagenfimbpphcgnh"),
206 CreateExtension(kExtensionRestricted
, kExtensionFromWebStore
).get(),
208 EXPECT_TRUE(AllowsDevInterfaces(params
));
210 // Whitelisted URLs are allowed without --enable-nacl, without 'dev'
211 // interfaces. There is a whitelist for the app URL and the manifest URL.
213 WebPluginParams params
;
214 // Whitelisted Photos app is allowed (two app URLs, two manifest URLs)
215 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
216 GURL(kPhotosManifestURL1
),
217 GURL(kPhotosAppURL1
),
219 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
221 EXPECT_FALSE(AllowsDevInterfaces(params
));
222 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
223 GURL(kPhotosManifestURL1
),
224 GURL(kPhotosAppURL2
),
226 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
228 EXPECT_FALSE(AllowsDevInterfaces(params
));
229 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
230 GURL(kPhotosManifestURL2
),
231 GURL(kPhotosAppURL1
),
233 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
235 EXPECT_FALSE(AllowsDevInterfaces(params
));
236 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
237 GURL(kPhotosManifestURL2
),
238 GURL(kPhotosAppURL2
),
240 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
242 EXPECT_FALSE(AllowsDevInterfaces(params
));
243 // Whitelisted Chat app is allowed.
244 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
245 GURL(kChatManifestFS1
),
248 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
250 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
251 GURL(kChatManifestFS2
),
254 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
256 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
257 GURL(kChatManifestFS3
),
260 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
263 // Whitelisted manifest URL, bad app URLs, NOT allowed.
264 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
265 GURL(kPhotosManifestURL1
),
266 GURL("http://plus.google.com/foo"), // http scheme
268 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
270 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
271 GURL(kPhotosManifestURL1
),
272 GURL("http://plus.sandbox.google.com/foo"), // http scheme
274 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
276 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
277 GURL(kPhotosManifestURL1
),
278 GURL("https://plus.google.evil.com/foo"), // bad host
280 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
282 // Whitelisted app URL, bad manifest URL, NOT allowed.
283 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
284 GURL("http://ssl.gstatic.com/s2/oz/nacl/foo"), // http scheme
285 GURL(kPhotosAppURL1
),
287 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
289 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
290 GURL("https://ssl.gstatic.evil.com/s2/oz/nacl/foo"), // bad host
291 GURL(kPhotosAppURL1
),
293 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
295 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
296 GURL("https://ssl.gstatic.com/wrong/s2/oz/nacl/foo"), // bad path
297 GURL(kPhotosAppURL1
),
299 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
302 // Whitelisted URLs can't get 'dev' interfaces with --enable-nacl.
304 WebPluginParams params
;
305 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
306 GURL(kPhotosManifestURL1
),
307 GURL(kPhotosAppURL1
),
309 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
311 EXPECT_FALSE(AllowsDevInterfaces(params
));
313 // Whitelisted URLs can't get 'dev' interfaces by injecting a fake
316 WebPluginParams params
;
317 AddFakeDevAttribute(¶ms
);
318 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
319 GURL(kPhotosManifestURL1
),
320 GURL(kPhotosAppURL1
),
322 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
324 EXPECT_FALSE(AllowsDevInterfaces(params
));
326 // Non-whitelisted URLs are blocked without --enable-nacl.
328 WebPluginParams params
;
329 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
331 GURL("https://plus.google.com.evil.com/foo1"),
333 CreateExtension(kExtensionRestricted
, kExtensionNotFromWebStore
).get(),
335 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
337 GURL("https://plus.google.com.evil.com/foo2"),
339 CreateExtension(kExtensionRestricted
, kExtensionFromWebStore
).get(),
341 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
343 GURL("https://talkgadget.google.com.evil.com/foo3"),
345 CreateExtension(kExtensionUnrestricted
, kExtensionNotFromWebStore
)
348 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
350 GURL("https://talkgadget.google.com.evil.com/foo4"),
352 CreateExtension(kExtensionUnrestricted
, kExtensionFromWebStore
).get(),
355 // Non chrome-extension:// URLs belonging to hosted apps are allowed.
357 WebPluginParams params
;
358 EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
360 GURL("http://example.com/test.html"),
362 CreateHostedApp(kExtensionRestricted
,
363 kExtensionNotFromWebStore
,
364 "http://example.com/").get(),
366 EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
368 GURL("http://example.evil.com/test.html"),
370 CreateHostedApp(kExtensionRestricted
,
371 kExtensionNotFromWebStore
,
372 "http://example.com/").get(),
377 TEST_F(ChromeContentRendererClientTest
, AllowPepperMediaStreamAPI
) {
378 ChromeContentRendererClient test
;
379 #if !defined(OS_ANDROID)
380 EXPECT_TRUE(test
.AllowPepperMediaStreamAPI(GURL(kChatAppURL1
)));
381 EXPECT_TRUE(test
.AllowPepperMediaStreamAPI(GURL(kChatAppURL2
)));
382 EXPECT_TRUE(test
.AllowPepperMediaStreamAPI(GURL(kChatAppURL3
)));
384 EXPECT_FALSE(test
.AllowPepperMediaStreamAPI(GURL(kChatAppURL1
)));
385 EXPECT_FALSE(test
.AllowPepperMediaStreamAPI(GURL(kChatAppURL2
)));
386 EXPECT_FALSE(test
.AllowPepperMediaStreamAPI(GURL(kChatAppURL3
)));
388 EXPECT_FALSE(test
.AllowPepperMediaStreamAPI(
389 GURL("http://talkgadget.google.com/hangouts/foo")));
390 EXPECT_FALSE(test
.AllowPepperMediaStreamAPI(
391 GURL("https://talkgadget.evil.com/hangouts/foo")));
394 TEST_F(ChromeContentRendererClientTest
, ShouldSuppressErrorPage
) {
395 ChromeContentRendererClient client
;
396 client
.search_bouncer_
.reset(new SearchBouncer
);
397 client
.search_bouncer_
->OnSetSearchURLs(
398 std::vector
<GURL
>(), GURL("http://example.com/n"));
399 EXPECT_FALSE(client
.ShouldSuppressErrorPage(NULL
,
400 GURL("http://example.com")));
401 EXPECT_TRUE(client
.ShouldSuppressErrorPage(NULL
,
402 GURL("http://example.com/n")));