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.
4
5 #include "chrome/renderer/chrome_content_renderer_client.h"
6
7 #include "base/command_line.h"
8 #include "base/debug/crash_logging.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/path_service.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/common/chrome_content_client.h"
17 #include "chrome/common/chrome_paths.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/content_settings_pattern.h"
20 #include "chrome/common/crash_keys.h"
21 #include "chrome/common/extensions/chrome_extensions_client.h"
22 #include "chrome/common/extensions/extension_constants.h"
23 #include "chrome/common/extensions/extension_process_policy.h"
24 #include "chrome/common/extensions/extension_set.h"
25 #include "chrome/common/localized_error.h"
26 #include "chrome/common/pepper_permission_util.h"
27 #include "chrome/common/render_messages.h"
28 #include "chrome/common/url_constants.h"
29 #include "chrome/renderer/benchmarking_extension.h"
30 #include "chrome/renderer/chrome_render_frame_observer.h"
31 #include "chrome/renderer/chrome_render_process_observer.h"
32 #include "chrome/renderer/chrome_render_view_observer.h"
33 #include "chrome/renderer/content_settings_observer.h"
34 #include "chrome/renderer/extensions/chrome_v8_context.h"
35 #include "chrome/renderer/extensions/chrome_v8_extension.h"
36 #include "chrome/renderer/extensions/dispatcher.h"
37 #include "chrome/renderer/extensions/extension_helper.h"
38 #include "chrome/renderer/extensions/renderer_permissions_policy_delegate.h"
39 #include "chrome/renderer/extensions/resource_request_policy.h"
40 #include "chrome/renderer/external_extension.h"
41 #include "chrome/renderer/loadtimes_extension_bindings.h"
42 #include "chrome/renderer/media/chrome_key_systems.h"
43 #include "chrome/renderer/net/net_error_helper.h"
44 #include "chrome/renderer/net/prescient_networking_dispatcher.h"
45 #include "chrome/renderer/net/renderer_net_predictor.h"
46 #include "chrome/renderer/net_benchmarking_extension.h"
47 #include "chrome/renderer/page_load_histograms.h"
48 #include "chrome/renderer/pepper/pepper_helper.h"
49 #include "chrome/renderer/pepper/ppb_pdf_impl.h"
50 #include "chrome/renderer/playback_extension.h"
51 #include "chrome/renderer/plugins/chrome_plugin_placeholder.h"
52 #include "chrome/renderer/plugins/plugin_uma.h"
53 #include "chrome/renderer/prerender/prerender_dispatcher.h"
54 #include "chrome/renderer/prerender/prerender_helper.h"
55 #include "chrome/renderer/prerender/prerender_media_load_deferrer.h"
56 #include "chrome/renderer/prerender/prerenderer_client.h"
57 #include "chrome/renderer/principals_extension_bindings.h"
58 #include "chrome/renderer/printing/print_web_view_helper.h"
59 #include "chrome/renderer/safe_browsing/malware_dom_details.h"
60 #include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h"
61 #include "chrome/renderer/searchbox/search_bouncer.h"
62 #include "chrome/renderer/searchbox/searchbox.h"
63 #include "chrome/renderer/searchbox/searchbox_extension.h"
64 #include "chrome/renderer/tts_dispatcher.h"
65 #include "chrome/renderer/worker_permission_client_proxy.h"
66 #include "components/autofill/content/renderer/autofill_agent.h"
67 #include "components/autofill/content/renderer/password_autofill_agent.h"
68 #include "components/autofill/content/renderer/password_generation_agent.h"
69 #include "components/autofill/core/common/password_generation_util.h"
70 #include "components/nacl/renderer/ppb_nacl_private_impl.h"
71 #include "components/plugins/renderer/mobile_youtube_plugin.h"
72 #include "components/visitedlink/renderer/visitedlink_slave.h"
73 #include "content/public/common/content_constants.h"
74 #include "content/public/renderer/render_frame.h"
75 #include "content/public/renderer/render_thread.h"
76 #include "content/public/renderer/render_view.h"
77 #include "content/public/renderer/render_view_visitor.h"
78 #include "extensions/common/constants.h"
79 #include "extensions/common/extension.h"
80 #include "extensions/common/extension_urls.h"
81 #include "grit/generated_resources.h"
82 #include "grit/locale_settings.h"
83 #include "grit/renderer_resources.h"
84 #include "ipc/ipc_sync_channel.h"
85 #include "net/base/net_errors.h"
86 #include "ppapi/c/private/ppb_nacl_private.h"
87 #include "ppapi/c/private/ppb_pdf.h"
88 #include "ppapi/shared_impl/ppapi_switches.h"
89 #include "third_party/WebKit/public/platform/WebURL.h"
90 #include "third_party/WebKit/public/platform/WebURLError.h"
91 #include "third_party/WebKit/public/platform/WebURLRequest.h"
92 #include "third_party/WebKit/public/web/WebCache.h"
93 #include "third_party/WebKit/public/web/WebDataSource.h"
94 #include "third_party/WebKit/public/web/WebDocument.h"
95 #include "third_party/WebKit/public/web/WebElement.h"
96 #include "third_party/WebKit/public/web/WebFrame.h"
97 #include "third_party/WebKit/public/web/WebPluginContainer.h"
98 #include "third_party/WebKit/public/web/WebPluginParams.h"
99 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
100 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
101 #include "ui/base/l10n/l10n_util.h"
102 #include "ui/base/layout.h"
103 #include "ui/base/resource/resource_bundle.h"
104 #include "ui/base/webui/jstemplate_builder.h"
105 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
106
107 #if defined(ENABLE_WEBRTC)
108 #include "chrome/renderer/media/webrtc_logging_message_filter.h"
109 #endif
110
111 #if defined(ENABLE_SPELLCHECK)
112 #include "chrome/renderer/spellchecker/spellcheck.h"
113 #include "chrome/renderer/spellchecker/spellcheck_provider.h"
114 #endif
115
116 using autofill::AutofillAgent;
117 using autofill::PasswordAutofillAgent;
118 using autofill::PasswordGenerationAgent;
119 using content::RenderThread;
120 using content::UserMetricsAction;
121 using content::WebPluginInfo;
122 using extensions::Extension;
123 using blink::WebCache;
124 using blink::WebConsoleMessage;
125 using blink::WebDataSource;
126 using blink::WebDocument;
127 using blink::WebFrame;
128 using blink::WebPlugin;
129 using blink::WebPluginParams;
130 using blink::WebSecurityOrigin;
131 using blink::WebSecurityPolicy;
132 using blink::WebString;
133 using blink::WebURL;
134 using blink::WebURLError;
135 using blink::WebURLRequest;
136 using blink::WebURLResponse;
137 using blink::WebVector;
138
139 namespace {
140
141 const char kWebViewTagName[] = "WEBVIEW";
142 const char kAdViewTagName[] = "ADVIEW";
143
144 ChromeContentRendererClient* g_current_client;
145
AppendParams(const std::vector<base::string16> & additional_names,const std::vector<base::string16> & additional_values,WebVector<WebString> * existing_names,WebVector<WebString> * existing_values)146 static void AppendParams(const std::vector<base::string16>& additional_names,
147 const std::vector<base::string16>& additional_values,
148 WebVector<WebString>* existing_names,
149 WebVector<WebString>* existing_values) {
150 DCHECK(additional_names.size() == additional_values.size());
151 DCHECK(existing_names->size() == existing_values->size());
152
153 size_t existing_size = existing_names->size();
154 size_t total_size = existing_size + additional_names.size();
155
156 WebVector<WebString> names(total_size);
157 WebVector<WebString> values(total_size);
158
159 for (size_t i = 0; i < existing_size; ++i) {
160 names[i] = (*existing_names)[i];
161 values[i] = (*existing_values)[i];
162 }
163
164 for (size_t i = 0; i < additional_names.size(); ++i) {
165 names[existing_size + i] = additional_names[i];
166 values[existing_size + i] = additional_values[i];
167 }
168
169 existing_names->swap(names);
170 existing_values->swap(values);
171 }
172
173 #if defined(ENABLE_SPELLCHECK)
174 class SpellCheckReplacer : public content::RenderViewVisitor {
175 public:
SpellCheckReplacer(SpellCheck * spellcheck)176 explicit SpellCheckReplacer(SpellCheck* spellcheck)
177 : spellcheck_(spellcheck) {}
178 virtual bool Visit(content::RenderView* render_view) OVERRIDE;
179
180 private:
181 SpellCheck* spellcheck_; // New shared spellcheck for all views. Weak Ptr.
182 DISALLOW_COPY_AND_ASSIGN(SpellCheckReplacer);
183 };
184
Visit(content::RenderView * render_view)185 bool SpellCheckReplacer::Visit(content::RenderView* render_view) {
186 SpellCheckProvider* provider = SpellCheckProvider::Get(render_view);
187 DCHECK(provider);
188 provider->set_spellcheck(spellcheck_);
189 return true;
190 }
191 #endif
192
193 // For certain sandboxed Pepper plugins, use the JavaScript Content Settings.
ShouldUseJavaScriptSettingForPlugin(const WebPluginInfo & plugin)194 bool ShouldUseJavaScriptSettingForPlugin(const WebPluginInfo& plugin) {
195 if (plugin.type != WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS &&
196 plugin.type != WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS) {
197 return false;
198 }
199
200 // Treat Native Client invocations like JavaScript.
201 if (plugin.name == ASCIIToUTF16(ChromeContentClient::kNaClPluginName))
202 return true;
203
204 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
205 // Treat CDM invocations like JavaScript.
206 if (plugin.name == ASCIIToUTF16(kWidevineCdmDisplayName)) {
207 DCHECK(plugin.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS);
208 return true;
209 }
210 #endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS)
211
212 return false;
213 }
214
215 } // namespace
216
ChromeContentRendererClient()217 ChromeContentRendererClient::ChromeContentRendererClient() {
218 g_current_client = this;
219 }
220
~ChromeContentRendererClient()221 ChromeContentRendererClient::~ChromeContentRendererClient() {
222 g_current_client = NULL;
223 }
224
RenderThreadStarted()225 void ChromeContentRendererClient::RenderThreadStarted() {
226 RenderThread* thread = RenderThread::Get();
227
228 chrome_observer_.reset(new ChromeRenderProcessObserver(this));
229 // ChromeRenderViewTest::SetUp() creates its own ExtensionDispatcher and
230 // injects it using SetExtensionDispatcher(). Don't overwrite it.
231 if (!extension_dispatcher_)
232 extension_dispatcher_.reset(new extensions::Dispatcher());
233 permissions_policy_delegate_.reset(
234 new extensions::RendererPermissionsPolicyDelegate(
235 extension_dispatcher_.get()));
236 prescient_networking_dispatcher_.reset(new PrescientNetworkingDispatcher());
237 net_predictor_.reset(new RendererNetPredictor());
238 #if defined(ENABLE_SPELLCHECK)
239 // ChromeRenderViewTest::SetUp() creates a Spellcheck and injects it using
240 // SetSpellcheck(). Don't overwrite it.
241 if (!spellcheck_) {
242 spellcheck_.reset(new SpellCheck());
243 thread->AddObserver(spellcheck_.get());
244 }
245 #endif
246 visited_link_slave_.reset(new visitedlink::VisitedLinkSlave());
247 #if defined(FULL_SAFE_BROWSING)
248 phishing_classifier_.reset(safe_browsing::PhishingClassifierFilter::Create());
249 #endif
250 prerender_dispatcher_.reset(new prerender::PrerenderDispatcher());
251 #if defined(ENABLE_WEBRTC)
252 webrtc_logging_message_filter_ = new WebRtcLoggingMessageFilter(
253 content::RenderThread::Get()->GetIOMessageLoopProxy());
254 #endif
255 search_bouncer_.reset(new SearchBouncer());
256
257 thread->AddObserver(chrome_observer_.get());
258 thread->AddObserver(extension_dispatcher_.get());
259 #if defined(FULL_SAFE_BROWSING)
260 thread->AddObserver(phishing_classifier_.get());
261 #endif
262 thread->AddObserver(visited_link_slave_.get());
263 thread->AddObserver(prerender_dispatcher_.get());
264 thread->AddObserver(search_bouncer_.get());
265
266 #if defined(ENABLE_WEBRTC)
267 thread->AddFilter(webrtc_logging_message_filter_.get());
268 #endif
269
270 thread->RegisterExtension(extensions_v8::ExternalExtension::Get());
271 thread->RegisterExtension(extensions_v8::LoadTimesExtension::Get());
272
273 CommandLine* command_line = CommandLine::ForCurrentProcess();
274 if (command_line->HasSwitch(switches::kEnableBenchmarking))
275 thread->RegisterExtension(extensions_v8::BenchmarkingExtension::Get());
276 if (command_line->HasSwitch(switches::kEnableNetBenchmarking))
277 thread->RegisterExtension(extensions_v8::NetBenchmarkingExtension::Get());
278 if (command_line->HasSwitch(switches::kInstantProcess))
279 thread->RegisterExtension(extensions_v8::SearchBoxExtension::Get());
280
281 if (command_line->HasSwitch(switches::kPlaybackMode) ||
282 command_line->HasSwitch(switches::kRecordMode) ||
283 command_line->HasSwitch(switches::kNoJsRandomness)) {
284 thread->RegisterExtension(extensions_v8::PlaybackExtension::Get());
285 }
286
287 // TODO(guohui): needs to forward the new-profile-management switch to
288 // renderer processes.
289 if (command_line->HasSwitch(switches::kNewProfileManagement))
290 thread->RegisterExtension(extensions_v8::PrincipalsExtension::Get());
291
292 // chrome:, chrome-search:, and chrome-devtools: pages should not be
293 // accessible by normal content, and should also be unable to script anything
294 // but themselves (to help limit the damage that a corrupt page could cause).
295 WebString chrome_ui_scheme(ASCIIToUTF16(chrome::kChromeUIScheme));
296 WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(chrome_ui_scheme);
297
298 WebString chrome_search_scheme(ASCIIToUTF16(chrome::kChromeSearchScheme));
299 // The Instant process can only display the content but not read it. Other
300 // processes can't display it or read it.
301 if (!command_line->HasSwitch(switches::kInstantProcess))
302 WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(chrome_search_scheme);
303
304 WebString dev_tools_scheme(ASCIIToUTF16(chrome::kChromeDevToolsScheme));
305 WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(dev_tools_scheme);
306
307 #if defined(OS_CHROMEOS)
308 WebString drive_scheme(ASCIIToUTF16(chrome::kDriveScheme));
309 WebSecurityPolicy::registerURLSchemeAsLocal(drive_scheme);
310 #endif
311
312 // chrome: and chrome-search: pages should not be accessible by bookmarklets
313 // or javascript: URLs typed in the omnibox.
314 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
315 chrome_ui_scheme);
316 WebSecurityPolicy::registerURLSchemeAsNotAllowingJavascriptURLs(
317 chrome_search_scheme);
318
319 // chrome:, chrome-search:, and chrome-extension: resources shouldn't trigger
320 // insecure content warnings.
321 WebSecurityPolicy::registerURLSchemeAsSecure(chrome_ui_scheme);
322 WebSecurityPolicy::registerURLSchemeAsSecure(chrome_search_scheme);
323
324 WebString extension_scheme(ASCIIToUTF16(extensions::kExtensionScheme));
325 WebSecurityPolicy::registerURLSchemeAsSecure(extension_scheme);
326
327 // chrome-extension: resources should be allowed to receive CORS requests.
328 WebSecurityPolicy::registerURLSchemeAsCORSEnabled(extension_scheme);
329
330 WebString extension_resource_scheme(
331 ASCIIToUTF16(chrome::kExtensionResourceScheme));
332 WebSecurityPolicy::registerURLSchemeAsSecure(extension_resource_scheme);
333
334 // chrome-extension-resource: resources should be allowed to receive CORS
335 // requests.
336 WebSecurityPolicy::registerURLSchemeAsCORSEnabled(extension_resource_scheme);
337
338 // chrome-extension: resources should bypass Content Security Policy checks
339 // when included in protected resources.
340 WebSecurityPolicy::registerURLSchemeAsBypassingContentSecurityPolicy(
341 extension_scheme);
342 WebSecurityPolicy::registerURLSchemeAsBypassingContentSecurityPolicy(
343 extension_resource_scheme);
344
345 extensions::ExtensionsClient::Set(
346 extensions::ChromeExtensionsClient::GetInstance());
347 }
348
RenderFrameCreated(content::RenderFrame * render_frame)349 void ChromeContentRendererClient::RenderFrameCreated(
350 content::RenderFrame* render_frame) {
351 new ChromeRenderFrameObserver(render_frame);
352 #if defined(ENABLE_PLUGINS)
353 new PepperHelper(render_frame);
354 #endif
355 }
356
RenderViewCreated(content::RenderView * render_view)357 void ChromeContentRendererClient::RenderViewCreated(
358 content::RenderView* render_view) {
359 ContentSettingsObserver* content_settings =
360 new ContentSettingsObserver(render_view, extension_dispatcher_.get());
361 if (chrome_observer_.get()) {
362 content_settings->SetContentSettingRules(
363 chrome_observer_->content_setting_rules());
364 }
365 new extensions::ExtensionHelper(render_view, extension_dispatcher_.get());
366 new PageLoadHistograms(render_view);
367 #if defined(ENABLE_PRINTING)
368 new printing::PrintWebViewHelper(render_view);
369 #endif
370 #if defined(ENABLE_SPELLCHECK)
371 new SpellCheckProvider(render_view, spellcheck_.get());
372 #endif
373 new prerender::PrerendererClient(render_view);
374 #if defined(FULL_SAFE_BROWSING)
375 safe_browsing::MalwareDOMDetails::Create(render_view);
376 #endif
377
378 PasswordAutofillAgent* password_autofill_agent =
379 new PasswordAutofillAgent(render_view);
380 new AutofillAgent(render_view, password_autofill_agent);
381
382 CommandLine* command_line = CommandLine::ForCurrentProcess();
383 if (autofill::password_generation::IsPasswordGenerationEnabled())
384 new PasswordGenerationAgent(render_view);
385 if (command_line->HasSwitch(switches::kInstantProcess))
386 new SearchBox(render_view);
387
388 new ChromeRenderViewObserver(render_view, chrome_observer_.get());
389
390 new NetErrorHelper(render_view);
391 }
392
SetNumberOfViews(int number_of_views)393 void ChromeContentRendererClient::SetNumberOfViews(int number_of_views) {
394 base::debug::SetCrashKeyValue(crash_keys::kNumberOfViews,
395 base::IntToString(number_of_views));
396 }
397
GetSadPluginBitmap()398 SkBitmap* ChromeContentRendererClient::GetSadPluginBitmap() {
399 return const_cast<SkBitmap*>(ResourceBundle::GetSharedInstance().
400 GetImageNamed(IDR_SAD_PLUGIN).ToSkBitmap());
401 }
402
GetSadWebViewBitmap()403 SkBitmap* ChromeContentRendererClient::GetSadWebViewBitmap() {
404 return const_cast<SkBitmap*>(ResourceBundle::GetSharedInstance().
405 GetImageNamed(IDR_SAD_WEBVIEW).ToSkBitmap());
406 }
407
GetDefaultEncoding()408 std::string ChromeContentRendererClient::GetDefaultEncoding() {
409 return l10n_util::GetStringUTF8(IDS_DEFAULT_ENCODING);
410 }
411
GetExtensionByOrigin(const WebSecurityOrigin & origin) const412 const Extension* ChromeContentRendererClient::GetExtensionByOrigin(
413 const WebSecurityOrigin& origin) const {
414 if (!EqualsASCII(origin.protocol(), extensions::kExtensionScheme))
415 return NULL;
416
417 const std::string extension_id = origin.host().utf8().data();
418 return extension_dispatcher_->extensions()->GetByID(extension_id);
419 }
420
OverrideCreatePlugin(content::RenderFrame * render_frame,WebFrame * frame,const WebPluginParams & params,WebPlugin ** plugin)421 bool ChromeContentRendererClient::OverrideCreatePlugin(
422 content::RenderFrame* render_frame,
423 WebFrame* frame,
424 const WebPluginParams& params,
425 WebPlugin** plugin) {
426 std::string orig_mime_type = params.mimeType.utf8();
427 if (orig_mime_type == content::kBrowserPluginMimeType) {
428 if (CommandLine::ForCurrentProcess()->HasSwitch(
429 switches::kEnableBrowserPluginForAllViewTypes))
430 return false;
431 WebDocument document = frame->document();
432 const Extension* extension =
433 GetExtensionByOrigin(document.securityOrigin());
434 if (extension) {
435 const extensions::APIPermission::ID perms[] = {
436 extensions::APIPermission::kWebView,
437 extensions::APIPermission::kAdView
438 };
439 for (size_t i = 0; i < arraysize(perms); ++i) {
440 if (extension->HasAPIPermission(perms[i]))
441 return false;
442 }
443 }
444 }
445
446 ChromeViewHostMsg_GetPluginInfo_Output output;
447 #if defined(ENABLE_PLUGINS)
448 render_frame->Send(new ChromeViewHostMsg_GetPluginInfo(
449 render_frame->GetRoutingID(), GURL(params.url),
450 frame->top()->document().url(), orig_mime_type, &output));
451 #else
452 output.status.value = ChromeViewHostMsg_GetPluginInfo_Status::kNotFound;
453 #endif
454 *plugin = CreatePlugin(render_frame, frame, params, output);
455 return true;
456 }
457
CreatePluginReplacement(content::RenderFrame * render_frame,const base::FilePath & plugin_path)458 WebPlugin* ChromeContentRendererClient::CreatePluginReplacement(
459 content::RenderFrame* render_frame,
460 const base::FilePath& plugin_path) {
461 ChromePluginPlaceholder* placeholder =
462 ChromePluginPlaceholder::CreateErrorPlugin(render_frame, plugin_path);
463 return placeholder->plugin();
464 }
465
DeferMediaLoad(content::RenderFrame * render_frame,const base::Closure & closure)466 void ChromeContentRendererClient::DeferMediaLoad(
467 content::RenderFrame* render_frame,
468 const base::Closure& closure) {
469 #if defined(OS_ANDROID)
470 // Chromium for Android doesn't support prerender yet.
471 closure.Run();
472 return;
473 #else
474 if (!prerender::PrerenderHelper::IsPrerendering(render_frame)) {
475 closure.Run();
476 return;
477 }
478
479 // Lifetime is tied to |render_frame| via content::RenderFrameObserver.
480 new prerender::PrerenderMediaLoadDeferrer(render_frame, closure);
481 #endif
482 }
483
CreatePlugin(content::RenderFrame * render_frame,WebFrame * frame,const WebPluginParams & original_params,const ChromeViewHostMsg_GetPluginInfo_Output & output)484 WebPlugin* ChromeContentRendererClient::CreatePlugin(
485 content::RenderFrame* render_frame,
486 WebFrame* frame,
487 const WebPluginParams& original_params,
488 const ChromeViewHostMsg_GetPluginInfo_Output& output) {
489 const ChromeViewHostMsg_GetPluginInfo_Status& status = output.status;
490 const WebPluginInfo& plugin = output.plugin;
491 const std::string& actual_mime_type = output.actual_mime_type;
492 const base::string16& group_name = output.group_name;
493 const std::string& identifier = output.group_identifier;
494 ChromeViewHostMsg_GetPluginInfo_Status::Value status_value = status.value;
495 GURL url(original_params.url);
496 std::string orig_mime_type = original_params.mimeType.utf8();
497 ChromePluginPlaceholder* placeholder = NULL;
498
499 // If the browser plugin is to be enabled, this should be handled by the
500 // renderer, so the code won't reach here due to the early exit in
501 // OverrideCreatePlugin.
502 if (status_value == ChromeViewHostMsg_GetPluginInfo_Status::kNotFound ||
503 orig_mime_type == content::kBrowserPluginMimeType) {
504 #if defined(OS_ANDROID)
505 if (plugins::MobileYouTubePlugin::IsYouTubeURL(url, orig_mime_type)) {
506 base::StringPiece template_html(
507 ResourceBundle::GetSharedInstance().GetRawDataResource(
508 IDR_MOBILE_YOUTUBE_PLUGIN_HTML));
509 return (new plugins::MobileYouTubePlugin(
510 render_frame,
511 frame,
512 original_params,
513 template_html,
514 GURL(ChromePluginPlaceholder::kPluginPlaceholderDataURL)))
515 ->plugin();
516 }
517 #endif
518 PluginUMAReporter::GetInstance()->ReportPluginMissing(orig_mime_type, url);
519 placeholder = ChromePluginPlaceholder::CreateMissingPlugin(
520 render_frame, frame, original_params);
521 } else {
522 // TODO(bauerb): This should be in content/.
523 WebPluginParams params(original_params);
524 for (size_t i = 0; i < plugin.mime_types.size(); ++i) {
525 if (plugin.mime_types[i].mime_type == actual_mime_type) {
526 AppendParams(plugin.mime_types[i].additional_param_names,
527 plugin.mime_types[i].additional_param_values,
528 ¶ms.attributeNames,
529 ¶ms.attributeValues);
530 break;
531 }
532 }
533 if (params.mimeType.isNull() && (actual_mime_type.size() > 0)) {
534 // Webkit might say that mime type is null while we already know the
535 // actual mime type via ChromeViewHostMsg_GetPluginInfo. In that case
536 // we should use what we know since WebpluginDelegateProxy does some
537 // specific initializations based on this information.
538 params.mimeType = WebString::fromUTF8(actual_mime_type.c_str());
539 }
540
541 // TODO(jam): switch ContentSettingsObserver to RenderFrameObserver.
542 ContentSettingsObserver* observer =
543 ContentSettingsObserver::Get(render_frame->GetRenderView());
544
545 const ContentSettingsType content_type =
546 ShouldUseJavaScriptSettingForPlugin(plugin) ?
547 CONTENT_SETTINGS_TYPE_JAVASCRIPT :
548 CONTENT_SETTINGS_TYPE_PLUGINS;
549
550 if ((status_value ==
551 ChromeViewHostMsg_GetPluginInfo_Status::kUnauthorized ||
552 status_value == ChromeViewHostMsg_GetPluginInfo_Status::kClickToPlay ||
553 status_value == ChromeViewHostMsg_GetPluginInfo_Status::kBlocked) &&
554 observer->IsPluginTemporarilyAllowed(identifier)) {
555 status_value = ChromeViewHostMsg_GetPluginInfo_Status::kAllowed;
556 }
557
558 // Allow full-page plug-ins for click-to-play.
559 if (status_value == ChromeViewHostMsg_GetPluginInfo_Status::kClickToPlay &&
560 !frame->parent() &&
561 !frame->opener() &&
562 frame->document().isPluginDocument()) {
563 status_value = ChromeViewHostMsg_GetPluginInfo_Status::kAllowed;
564 }
565
566 #if defined(USE_AURA) && defined(OS_WIN)
567 // In Aura for Windows we need to check if we can load NPAPI plugins.
568 // For example, if the render view is in the Ash desktop, we should not.
569 if (status_value == ChromeViewHostMsg_GetPluginInfo_Status::kAllowed &&
570 plugin.type == content::WebPluginInfo::PLUGIN_TYPE_NPAPI) {
571 if (observer->AreNPAPIPluginsBlocked())
572 status_value =
573 ChromeViewHostMsg_GetPluginInfo_Status::kNPAPINotSupported;
574 }
575 #endif
576
577 switch (status_value) {
578 case ChromeViewHostMsg_GetPluginInfo_Status::kNotFound: {
579 NOTREACHED();
580 break;
581 }
582 case ChromeViewHostMsg_GetPluginInfo_Status::kAllowed: {
583 const bool is_nacl_plugin =
584 plugin.name == ASCIIToUTF16(ChromeContentClient::kNaClPluginName);
585 const bool is_nacl_mime_type =
586 actual_mime_type == "application/x-nacl";
587 const bool is_pnacl_mime_type =
588 actual_mime_type == "application/x-pnacl";
589 if (is_nacl_plugin || is_nacl_mime_type || is_pnacl_mime_type) {
590 bool is_nacl_unrestricted = false;
591 if (is_nacl_mime_type) {
592 is_nacl_unrestricted =
593 CommandLine::ForCurrentProcess()->HasSwitch(
594 switches::kEnableNaCl);
595 } else if (is_pnacl_mime_type) {
596 is_nacl_unrestricted =
597 !CommandLine::ForCurrentProcess()->HasSwitch(
598 switches::kDisablePnacl);
599 }
600 GURL manifest_url;
601 GURL app_url;
602 if (is_nacl_mime_type || is_pnacl_mime_type) {
603 // Normal NaCl/PNaCl embed. The app URL is the page URL.
604 manifest_url = url;
605 app_url = frame->top()->document().url();
606 } else {
607 // NaCl is being invoked as a content handler. Look up the NaCl
608 // module using the MIME type. The app URL is the manifest URL.
609 manifest_url = GetNaClContentHandlerURL(actual_mime_type, plugin);
610 app_url = manifest_url;
611 }
612 const Extension* extension =
613 g_current_client->extension_dispatcher_->extensions()->
614 GetExtensionOrAppByURL(manifest_url);
615 if (!IsNaClAllowed(manifest_url,
616 app_url,
617 is_nacl_unrestricted,
618 extension,
619 ¶ms)) {
620 WebString error_message;
621 if (is_nacl_mime_type) {
622 error_message =
623 "Only unpacked extensions and apps installed from the Chrome "
624 "Web Store can load NaCl modules without enabling Native "
625 "Client in about:flags.";
626 } else if (is_pnacl_mime_type) {
627 error_message =
628 "Portable Native Client must not be disabled in about:flags.";
629 }
630 frame->addMessageToConsole(
631 WebConsoleMessage(WebConsoleMessage::LevelError,
632 error_message));
633 placeholder = ChromePluginPlaceholder::CreateBlockedPlugin(
634 render_frame,
635 frame,
636 params,
637 plugin,
638 identifier,
639 group_name,
640 IDR_BLOCKED_PLUGIN_HTML,
641 #if defined(OS_CHROMEOS)
642 l10n_util::GetStringUTF16(IDS_NACL_PLUGIN_BLOCKED));
643 #else
644 l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name));
645 #endif
646 break;
647 }
648 }
649
650 // Delay loading plugins if prerendering.
651 // TODO(mmenke): In the case of prerendering, feed into
652 // ChromeContentRendererClient::CreatePlugin instead, to
653 // reduce the chance of future regressions.
654 if (prerender::PrerenderHelper::IsPrerendering(render_frame)) {
655 placeholder = ChromePluginPlaceholder::CreateBlockedPlugin(
656 render_frame,
657 frame,
658 params,
659 plugin,
660 identifier,
661 group_name,
662 IDR_CLICK_TO_PLAY_PLUGIN_HTML,
663 l10n_util::GetStringFUTF16(IDS_PLUGIN_LOAD, group_name));
664 placeholder->set_blocked_for_prerendering(true);
665 placeholder->set_allow_loading(true);
666 break;
667 }
668
669 return render_frame->CreatePlugin(frame, plugin, params);
670 }
671 case ChromeViewHostMsg_GetPluginInfo_Status::kNPAPINotSupported: {
672 RenderThread::Get()->RecordAction(
673 UserMetricsAction("Plugin_NPAPINotSupported"));
674 placeholder = ChromePluginPlaceholder::CreateBlockedPlugin(
675 render_frame,
676 frame,
677 params,
678 plugin,
679 identifier,
680 group_name,
681 IDR_BLOCKED_PLUGIN_HTML,
682 l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_SUPPORTED_METRO));
683 render_frame->Send(new ChromeViewHostMsg_NPAPINotSupported(
684 render_frame->GetRoutingID(), identifier));
685 break;
686 }
687 case ChromeViewHostMsg_GetPluginInfo_Status::kDisabled: {
688 PluginUMAReporter::GetInstance()->ReportPluginDisabled(orig_mime_type,
689 url);
690 placeholder = ChromePluginPlaceholder::CreateBlockedPlugin(
691 render_frame,
692 frame,
693 params,
694 plugin,
695 identifier,
696 group_name,
697 IDR_DISABLED_PLUGIN_HTML,
698 l10n_util::GetStringFUTF16(IDS_PLUGIN_DISABLED, group_name));
699 break;
700 }
701 case ChromeViewHostMsg_GetPluginInfo_Status::kOutdatedBlocked: {
702 #if defined(ENABLE_PLUGIN_INSTALLATION)
703 placeholder = ChromePluginPlaceholder::CreateBlockedPlugin(
704 render_frame,
705 frame,
706 params,
707 plugin,
708 identifier,
709 group_name,
710 IDR_BLOCKED_PLUGIN_HTML,
711 l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED, group_name));
712 placeholder->set_allow_loading(true);
713 render_frame->Send(new ChromeViewHostMsg_BlockedOutdatedPlugin(
714 render_frame->GetRoutingID(), placeholder->CreateRoutingId(),
715 identifier));
716 #else
717 NOTREACHED();
718 #endif
719 break;
720 }
721 case ChromeViewHostMsg_GetPluginInfo_Status::kOutdatedDisallowed: {
722 placeholder = ChromePluginPlaceholder::CreateBlockedPlugin(
723 render_frame,
724 frame,
725 params,
726 plugin,
727 identifier,
728 group_name,
729 IDR_BLOCKED_PLUGIN_HTML,
730 l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED, group_name));
731 break;
732 }
733 case ChromeViewHostMsg_GetPluginInfo_Status::kUnauthorized: {
734 placeholder = ChromePluginPlaceholder::CreateBlockedPlugin(
735 render_frame,
736 frame,
737 params,
738 plugin,
739 identifier,
740 group_name,
741 IDR_BLOCKED_PLUGIN_HTML,
742 l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, group_name));
743 placeholder->set_allow_loading(true);
744 render_frame->Send(new ChromeViewHostMsg_BlockedUnauthorizedPlugin(
745 render_frame->GetRoutingID(),
746 group_name,
747 identifier));
748 break;
749 }
750 case ChromeViewHostMsg_GetPluginInfo_Status::kClickToPlay: {
751 placeholder = ChromePluginPlaceholder::CreateBlockedPlugin(
752 render_frame,
753 frame,
754 params,
755 plugin,
756 identifier,
757 group_name,
758 IDR_CLICK_TO_PLAY_PLUGIN_HTML,
759 l10n_util::GetStringFUTF16(IDS_PLUGIN_LOAD, group_name));
760 placeholder->set_allow_loading(true);
761 RenderThread::Get()->RecordAction(
762 UserMetricsAction("Plugin_ClickToPlay"));
763 observer->DidBlockContentType(content_type);
764 break;
765 }
766 case ChromeViewHostMsg_GetPluginInfo_Status::kBlocked: {
767 placeholder = ChromePluginPlaceholder::CreateBlockedPlugin(
768 render_frame,
769 frame,
770 params,
771 plugin,
772 identifier,
773 group_name,
774 IDR_BLOCKED_PLUGIN_HTML,
775 l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name));
776 placeholder->set_allow_loading(true);
777 RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Blocked"));
778 observer->DidBlockContentType(content_type);
779 break;
780 }
781 }
782 }
783 placeholder->SetStatus(status);
784 return placeholder->plugin();
785 }
786
787 // For NaCl content handling plugins, the NaCl manifest is stored in an
788 // additonal 'nacl' param associated with the MIME type.
789 // static
GetNaClContentHandlerURL(const std::string & actual_mime_type,const content::WebPluginInfo & plugin)790 GURL ChromeContentRendererClient::GetNaClContentHandlerURL(
791 const std::string& actual_mime_type,
792 const content::WebPluginInfo& plugin) {
793 // Look for the manifest URL among the MIME type's additonal parameters.
794 const char* kNaClPluginManifestAttribute = "nacl";
795 base::string16 nacl_attr = ASCIIToUTF16(kNaClPluginManifestAttribute);
796 for (size_t i = 0; i < plugin.mime_types.size(); ++i) {
797 if (plugin.mime_types[i].mime_type == actual_mime_type) {
798 const content::WebPluginMimeType& content_type = plugin.mime_types[i];
799 for (size_t i = 0; i < content_type.additional_param_names.size(); ++i) {
800 if (content_type.additional_param_names[i] == nacl_attr)
801 return GURL(content_type.additional_param_values[i]);
802 }
803 break;
804 }
805 }
806 return GURL();
807 }
808
809 // static
IsNaClAllowed(const GURL & manifest_url,const GURL & app_url,bool is_nacl_unrestricted,const Extension * extension,WebPluginParams * params)810 bool ChromeContentRendererClient::IsNaClAllowed(
811 const GURL& manifest_url,
812 const GURL& app_url,
813 bool is_nacl_unrestricted,
814 const Extension* extension,
815 WebPluginParams* params) {
816 // Temporarily allow these whitelisted apps and WebUIs to use NaCl.
817 std::string app_url_host = app_url.host();
818 std::string manifest_url_path = manifest_url.path();
819
820 bool is_whitelisted_web_ui =
821 app_url.spec() == chrome::kChromeUIAppListStartPageURL;
822
823 bool is_photo_app =
824 // Whitelisted apps must be served over https.
825 app_url.SchemeIs("https") &&
826 manifest_url.SchemeIs("https") &&
827 (EndsWith(app_url_host, "plus.google.com", false) ||
828 EndsWith(app_url_host, "plus.sandbox.google.com", false)) &&
829 manifest_url.DomainIs("ssl.gstatic.com") &&
830 (manifest_url_path.find("s2/oz/nacl/") == 1 ||
831 manifest_url_path.find("photos/nacl/") == 1);
832
833 std::string manifest_fs_host;
834 if (manifest_url.SchemeIsFileSystem() && manifest_url.inner_url()) {
835 manifest_fs_host = manifest_url.inner_url()->host();
836 }
837 bool is_hangouts_app =
838 // Whitelisted apps must be served over secure scheme.
839 app_url.SchemeIs("https") &&
840 manifest_url.SchemeIsSecure() &&
841 manifest_url.SchemeIsFileSystem() &&
842 (EndsWith(app_url_host, "talkgadget.google.com", false) ||
843 EndsWith(app_url_host, "plus.google.com", false) ||
844 EndsWith(app_url_host, "plus.sandbox.google.com", false)) &&
845 // The manifest must be loaded from the host's FileSystem.
846 (manifest_fs_host == app_url_host);
847
848 bool is_whitelisted_app = is_photo_app || is_hangouts_app;
849
850 bool is_extension_from_webstore = extension &&
851 extension->from_webstore();
852
853 bool is_invoked_by_hosted_app = extension &&
854 extension->is_hosted_app() &&
855 extension->web_extent().MatchesURL(app_url);
856
857 // Allow built-in extensions and extensions under development.
858 bool is_extension_unrestricted = extension &&
859 (extension->location() == extensions::Manifest::COMPONENT ||
860 extensions::Manifest::IsUnpackedLocation(extension->location()));
861
862 bool is_invoked_by_extension = app_url.SchemeIs("chrome-extension");
863
864 // The NaCl PDF viewer is always allowed and can use 'Dev' interfaces.
865 bool is_nacl_pdf_viewer =
866 (is_extension_from_webstore &&
867 manifest_url.SchemeIs("chrome-extension") &&
868 manifest_url.host() == "acadkphlmlegjaadjagenfimbpphcgnh");
869
870 // Allow Chrome Web Store extensions, built-in extensions and extensions
871 // under development if the invocation comes from a URL with an extension
872 // scheme. Also allow invocations if they are from whitelisted URLs or
873 // if --enable-nacl is set.
874 bool is_nacl_allowed = is_nacl_unrestricted ||
875 is_whitelisted_web_ui ||
876 is_whitelisted_app ||
877 is_nacl_pdf_viewer ||
878 is_invoked_by_hosted_app ||
879 (is_invoked_by_extension &&
880 (is_extension_from_webstore ||
881 is_extension_unrestricted));
882 if (is_nacl_allowed) {
883 bool app_can_use_dev_interfaces = is_nacl_pdf_viewer;
884 // Make sure that PPAPI 'dev' interfaces aren't available for production
885 // apps unless they're whitelisted.
886 WebString dev_attribute = WebString::fromUTF8("@dev");
887 if ((!is_whitelisted_app && !is_extension_from_webstore) ||
888 app_can_use_dev_interfaces) {
889 // Add the special '@dev' attribute.
890 std::vector<base::string16> param_names;
891 std::vector<base::string16> param_values;
892 param_names.push_back(dev_attribute);
893 param_values.push_back(WebString());
894 AppendParams(
895 param_names,
896 param_values,
897 ¶ms->attributeNames,
898 ¶ms->attributeValues);
899 } else {
900 // If the params somehow contain '@dev', remove it.
901 size_t attribute_count = params->attributeNames.size();
902 for (size_t i = 0; i < attribute_count; ++i) {
903 if (params->attributeNames[i].equals(dev_attribute))
904 params->attributeNames[i] = WebString();
905 }
906 }
907 }
908 return is_nacl_allowed;
909 }
910
HasErrorPage(int http_status_code,std::string * error_domain)911 bool ChromeContentRendererClient::HasErrorPage(int http_status_code,
912 std::string* error_domain) {
913 // Use an internal error page, if we have one for the status code.
914 if (!LocalizedError::HasStrings(LocalizedError::kHttpErrorDomain,
915 http_status_code)) {
916 return false;
917 }
918
919 *error_domain = LocalizedError::kHttpErrorDomain;
920 return true;
921 }
922
ShouldSuppressErrorPage(const GURL & url)923 bool ChromeContentRendererClient::ShouldSuppressErrorPage(const GURL& url) {
924 // Do not flash an error page if the Instant new tab page fails to load.
925 return search_bouncer_.get() && search_bouncer_->IsNewTabPage(url);
926 }
927
GetNavigationErrorStrings(blink::WebFrame * frame,const blink::WebURLRequest & failed_request,const blink::WebURLError & error,const std::string & accept_languages,std::string * error_html,base::string16 * error_description)928 void ChromeContentRendererClient::GetNavigationErrorStrings(
929 blink::WebFrame* frame,
930 const blink::WebURLRequest& failed_request,
931 const blink::WebURLError& error,
932 const std::string& accept_languages,
933 std::string* error_html,
934 base::string16* error_description) {
935 const GURL failed_url = error.unreachableURL;
936 const Extension* extension = NULL;
937
938 if (failed_url.is_valid() &&
939 !failed_url.SchemeIs(extensions::kExtensionScheme)) {
940 extension = extension_dispatcher_->extensions()->GetExtensionOrAppByURL(
941 failed_url);
942 }
943
944 bool is_post = EqualsASCII(failed_request.httpMethod(), "POST");
945
946 if (error_html) {
947 // Use a local error page.
948 int resource_id;
949 base::DictionaryValue error_strings;
950 if (extension && !extension->from_bookmark()) {
951 LocalizedError::GetAppErrorStrings(failed_url, extension, &error_strings);
952
953 // TODO(erikkay): Should we use a different template for different
954 // error messages?
955 resource_id = IDR_ERROR_APP_HTML;
956 } else {
957 const std::string locale = RenderThread::Get()->GetLocale();
958 if (!NetErrorHelper::GetErrorStringsForDnsProbe(
959 frame, error, is_post, locale, accept_languages,
960 &error_strings)) {
961 // In most cases, the NetErrorHelper won't provide DNS-probe-specific
962 // error pages, so fall back to LocalizedError.
963 LocalizedError::GetStrings(error.reason, error.domain.utf8(),
964 error.unreachableURL, is_post, locale,
965 accept_languages, &error_strings);
966 }
967 resource_id = IDR_NET_ERROR_HTML;
968 }
969
970 const base::StringPiece template_html(
971 ResourceBundle::GetSharedInstance().GetRawDataResource(
972 resource_id));
973 if (template_html.empty()) {
974 NOTREACHED() << "unable to load template. ID: " << resource_id;
975 } else {
976 // "t" is the id of the templates root node.
977 *error_html = webui::GetTemplatesHtml(template_html, &error_strings, "t");
978 }
979 }
980
981 if (error_description) {
982 if (!extension)
983 *error_description = LocalizedError::GetErrorDetails(error, is_post);
984 }
985 }
986
RunIdleHandlerWhenWidgetsHidden()987 bool ChromeContentRendererClient::RunIdleHandlerWhenWidgetsHidden() {
988 return !extension_dispatcher_->is_extension_process();
989 }
990
AllowPopup()991 bool ChromeContentRendererClient::AllowPopup() {
992 extensions::ChromeV8Context* current_context =
993 extension_dispatcher_->v8_context_set().GetCurrent();
994 if (!current_context || !current_context->extension())
995 return false;
996 // See http://crbug.com/117446 for the subtlety of this check.
997 switch (current_context->context_type()) {
998 case extensions::Feature::UNSPECIFIED_CONTEXT:
999 case extensions::Feature::WEB_PAGE_CONTEXT:
1000 case extensions::Feature::UNBLESSED_EXTENSION_CONTEXT:
1001 return false;
1002 case extensions::Feature::BLESSED_EXTENSION_CONTEXT:
1003 case extensions::Feature::CONTENT_SCRIPT_CONTEXT:
1004 return true;
1005 case extensions::Feature::BLESSED_WEB_PAGE_CONTEXT:
1006 return !current_context->web_frame()->parent();
1007 }
1008 NOTREACHED();
1009 return false;
1010 }
1011
ShouldFork(WebFrame * frame,const GURL & url,const std::string & http_method,bool is_initial_navigation,bool is_server_redirect,bool * send_referrer)1012 bool ChromeContentRendererClient::ShouldFork(WebFrame* frame,
1013 const GURL& url,
1014 const std::string& http_method,
1015 bool is_initial_navigation,
1016 bool is_server_redirect,
1017 bool* send_referrer) {
1018 DCHECK(!frame->parent());
1019
1020 // If this is the Instant process, fork all navigations originating from the
1021 // renderer. The destination page will then be bucketed back to this Instant
1022 // process if it is an Instant url, or to another process if not. Conversely,
1023 // fork if this is a non-Instant process navigating to an Instant url, so that
1024 // such navigations can also be bucketed into an Instant renderer.
1025 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kInstantProcess) ||
1026 (search_bouncer_.get() && search_bouncer_->ShouldFork(url))) {
1027 *send_referrer = true;
1028 return true;
1029 }
1030
1031 // For now, we skip the rest for POST submissions. This is because
1032 // http://crbug.com/101395 is more likely to cause compatibility issues
1033 // with hosted apps and extensions than WebUI pages. We will remove this
1034 // check when cross-process POST submissions are supported.
1035 if (http_method != "GET")
1036 return false;
1037
1038 // If this is the Signin process, fork all navigations originating from the
1039 // renderer. The destination page will then be bucketed back to this Signin
1040 // process if it is a Signin url, or to another process if not.
1041 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSigninProcess)) {
1042 // We never want to allow non-signin pages to fork-on-POST to a
1043 // signin-related action URL. We'll need to handle this carefully once
1044 // http://crbug.com/101395 is fixed. The CHECK ensures we don't forget.
1045 CHECK_NE(http_method, "POST");
1046 return true;
1047 }
1048
1049 // If |url| matches one of the prerendered URLs, stop this navigation and try
1050 // to swap in the prerendered page on the browser process. If the prerendered
1051 // page no longer exists by the time the OpenURL IPC is handled, a normal
1052 // navigation is attempted.
1053 if (prerender_dispatcher_.get() &&
1054 prerender_dispatcher_->IsPrerenderURL(url)) {
1055 *send_referrer = true;
1056 return true;
1057 }
1058
1059 const ExtensionSet* extensions = extension_dispatcher_->extensions();
1060
1061 // Determine if the new URL is an extension (excluding bookmark apps).
1062 const Extension* new_url_extension = extensions::GetNonBookmarkAppExtension(
1063 *extensions, url);
1064 bool is_extension_url = !!new_url_extension;
1065
1066 // If the navigation would cross an app extent boundary, we also need
1067 // to defer to the browser to ensure process isolation. This is not necessary
1068 // for server redirects, which will be transferred to a new process by the
1069 // browser process when they are ready to commit. It is necessary for client
1070 // redirects, which won't be transferred in the same way.
1071 if (!is_server_redirect &&
1072 CrossesExtensionExtents(frame, url, *extensions, is_extension_url,
1073 is_initial_navigation)) {
1074 // Include the referrer in this case since we're going from a hosted web
1075 // page. (the packaged case is handled previously by the extension
1076 // navigation test)
1077 *send_referrer = true;
1078
1079 const Extension* extension =
1080 extension_dispatcher_->extensions()->GetExtensionOrAppByURL(url);
1081 if (extension && extension->is_app()) {
1082 UMA_HISTOGRAM_ENUMERATION(
1083 extension->is_platform_app() ?
1084 extension_misc::kPlatformAppLaunchHistogram :
1085 extension_misc::kAppLaunchHistogram,
1086 extension_misc::APP_LAUNCH_CONTENT_NAVIGATION,
1087 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
1088 }
1089 return true;
1090 }
1091
1092 // If this is a reload, check whether it has the wrong process type. We
1093 // should send it to the browser if it's an extension URL (e.g., hosted app)
1094 // in a normal process, or if it's a process for an extension that has been
1095 // uninstalled.
1096 if (frame->top()->document().url() == url) {
1097 if (is_extension_url != extension_dispatcher_->is_extension_process())
1098 return true;
1099 }
1100
1101 return false;
1102 }
1103
WillSendRequest(blink::WebFrame * frame,content::PageTransition transition_type,const GURL & url,const GURL & first_party_for_cookies,GURL * new_url)1104 bool ChromeContentRendererClient::WillSendRequest(
1105 blink::WebFrame* frame,
1106 content::PageTransition transition_type,
1107 const GURL& url,
1108 const GURL& first_party_for_cookies,
1109 GURL* new_url) {
1110 // Check whether the request should be allowed. If not allowed, we reset the
1111 // URL to something invalid to prevent the request and cause an error.
1112 if (url.SchemeIs(extensions::kExtensionScheme) &&
1113 !extensions::ResourceRequestPolicy::CanRequestResource(
1114 url,
1115 frame,
1116 transition_type,
1117 extension_dispatcher_->extensions())) {
1118 *new_url = GURL(chrome::kExtensionInvalidRequestURL);
1119 return true;
1120 }
1121
1122 if (url.SchemeIs(chrome::kExtensionResourceScheme) &&
1123 !extensions::ResourceRequestPolicy::CanRequestExtensionResourceScheme(
1124 url,
1125 frame)) {
1126 *new_url = GURL(chrome::kExtensionResourceInvalidRequestURL);
1127 return true;
1128 }
1129
1130 const content::RenderView* render_view =
1131 content::RenderView::FromWebView(frame->view());
1132 SearchBox* search_box = SearchBox::Get(render_view);
1133 if (search_box && url.SchemeIs(chrome::kChromeSearchScheme)) {
1134 if (url.host() == chrome::kChromeUIThumbnailHost)
1135 return search_box->GenerateThumbnailURLFromTransientURL(url, new_url);
1136 else if (url.host() == chrome::kChromeUIFaviconHost)
1137 return search_box->GenerateFaviconURLFromTransientURL(url, new_url);
1138 }
1139
1140 return false;
1141 }
1142
DidCreateScriptContext(WebFrame * frame,v8::Handle<v8::Context> context,int extension_group,int world_id)1143 void ChromeContentRendererClient::DidCreateScriptContext(
1144 WebFrame* frame, v8::Handle<v8::Context> context, int extension_group,
1145 int world_id) {
1146 extension_dispatcher_->DidCreateScriptContext(
1147 frame, context, extension_group, world_id);
1148 }
1149
WillReleaseScriptContext(WebFrame * frame,v8::Handle<v8::Context> context,int world_id)1150 void ChromeContentRendererClient::WillReleaseScriptContext(
1151 WebFrame* frame, v8::Handle<v8::Context> context, int world_id) {
1152 extension_dispatcher_->WillReleaseScriptContext(frame, context, world_id);
1153 }
1154
VisitedLinkHash(const char * canonical_url,size_t length)1155 unsigned long long ChromeContentRendererClient::VisitedLinkHash(
1156 const char* canonical_url, size_t length) {
1157 return visited_link_slave_->ComputeURLFingerprint(canonical_url, length);
1158 }
1159
IsLinkVisited(unsigned long long link_hash)1160 bool ChromeContentRendererClient::IsLinkVisited(unsigned long long link_hash) {
1161 return visited_link_slave_->IsVisited(link_hash);
1162 }
1163
1164 blink::WebPrescientNetworking*
GetPrescientNetworking()1165 ChromeContentRendererClient::GetPrescientNetworking() {
1166 return prescient_networking_dispatcher_.get();
1167 }
1168
ShouldOverridePageVisibilityState(const content::RenderFrame * render_frame,blink::WebPageVisibilityState * override_state)1169 bool ChromeContentRendererClient::ShouldOverridePageVisibilityState(
1170 const content::RenderFrame* render_frame,
1171 blink::WebPageVisibilityState* override_state) {
1172 if (!prerender::PrerenderHelper::IsPrerendering(render_frame))
1173 return false;
1174
1175 *override_state = blink::WebPageVisibilityStatePrerender;
1176 return true;
1177 }
1178
SetExtensionDispatcher(extensions::Dispatcher * extension_dispatcher)1179 void ChromeContentRendererClient::SetExtensionDispatcher(
1180 extensions::Dispatcher* extension_dispatcher) {
1181 extension_dispatcher_.reset(extension_dispatcher);
1182 permissions_policy_delegate_.reset(
1183 new extensions::RendererPermissionsPolicyDelegate(
1184 extension_dispatcher_.get()));
1185 }
1186
CrossesExtensionExtents(WebFrame * frame,const GURL & new_url,const ExtensionSet & extensions,bool is_extension_url,bool is_initial_navigation)1187 bool ChromeContentRendererClient::CrossesExtensionExtents(
1188 WebFrame* frame,
1189 const GURL& new_url,
1190 const ExtensionSet& extensions,
1191 bool is_extension_url,
1192 bool is_initial_navigation) {
1193 GURL old_url(frame->top()->document().url());
1194
1195 // If old_url is still empty and this is an initial navigation, then this is
1196 // a window.open operation. We should look at the opener URL.
1197 if (is_initial_navigation && old_url.is_empty() && frame->opener()) {
1198 // If we're about to open a normal web page from a same-origin opener stuck
1199 // in an extension process, we want to keep it in process to allow the
1200 // opener to script it.
1201 WebDocument opener_document = frame->opener()->document();
1202 WebSecurityOrigin opener = frame->opener()->document().securityOrigin();
1203 bool opener_is_extension_url =
1204 !opener.isUnique() && extensions.GetExtensionOrAppByURL(
1205 opener_document.url()) != NULL;
1206 if (!is_extension_url &&
1207 !opener_is_extension_url &&
1208 extension_dispatcher_->is_extension_process() &&
1209 opener.canRequest(WebURL(new_url)))
1210 return false;
1211
1212 // In all other cases, we want to compare against the top frame's URL (as
1213 // opposed to the opener frame's), since that's what determines the type of
1214 // process. This allows iframes outside an app to open a popup in the app.
1215 old_url = frame->top()->opener()->top()->document().url();
1216 }
1217
1218 // Only consider keeping non-app URLs in an app process if this window
1219 // has an opener (in which case it might be an OAuth popup that tries to
1220 // script an iframe within the app).
1221 bool should_consider_workaround = !!frame->opener();
1222
1223 return extensions::CrossesExtensionProcessBoundary(
1224 extensions, old_url, new_url, should_consider_workaround);
1225 }
1226
1227 #if defined(ENABLE_SPELLCHECK)
SetSpellcheck(SpellCheck * spellcheck)1228 void ChromeContentRendererClient::SetSpellcheck(SpellCheck* spellcheck) {
1229 RenderThread* thread = RenderThread::Get();
1230 if (spellcheck_.get() && thread)
1231 thread->RemoveObserver(spellcheck_.get());
1232 spellcheck_.reset(spellcheck);
1233 SpellCheckReplacer replacer(spellcheck_.get());
1234 content::RenderView::ForEach(&replacer);
1235 if (thread)
1236 thread->AddObserver(spellcheck_.get());
1237 }
1238 #endif
1239
OnPurgeMemory()1240 void ChromeContentRendererClient::OnPurgeMemory() {
1241 #if defined(ENABLE_SPELLCHECK)
1242 DVLOG(1) << "Resetting spellcheck in renderer client";
1243 SetSpellcheck(new SpellCheck());
1244 #endif
1245 }
1246
IsAdblockInstalled()1247 bool ChromeContentRendererClient::IsAdblockInstalled() {
1248 return g_current_client->extension_dispatcher_->extensions()->Contains(
1249 "gighmmpiobklfepjocnamgkkbiglidom");
1250 }
1251
IsAdblockPlusInstalled()1252 bool ChromeContentRendererClient::IsAdblockPlusInstalled() {
1253 return g_current_client->extension_dispatcher_->extensions()->Contains(
1254 "cfhdojbkjhnklbpkdaibdccddilifddb");
1255 }
1256
IsAdblockWithWebRequestInstalled()1257 bool ChromeContentRendererClient::IsAdblockWithWebRequestInstalled() {
1258 return g_current_client->extension_dispatcher_->
1259 IsAdblockWithWebRequestInstalled();
1260 }
1261
IsAdblockPlusWithWebRequestInstalled()1262 bool ChromeContentRendererClient::IsAdblockPlusWithWebRequestInstalled() {
1263 return g_current_client->extension_dispatcher_->
1264 IsAdblockPlusWithWebRequestInstalled();
1265 }
1266
IsOtherExtensionWithWebRequestInstalled()1267 bool ChromeContentRendererClient::IsOtherExtensionWithWebRequestInstalled() {
1268 return g_current_client->extension_dispatcher_->
1269 IsOtherExtensionWithWebRequestInstalled();
1270 }
1271
CreatePPAPIInterface(const std::string & interface_name)1272 const void* ChromeContentRendererClient::CreatePPAPIInterface(
1273 const std::string& interface_name) {
1274 #if defined(ENABLE_PLUGINS)
1275 #if !defined(DISABLE_NACL)
1276 if (interface_name == PPB_NACL_PRIVATE_INTERFACE)
1277 return nacl::GetNaClPrivateInterface();
1278 #endif // DISABLE_NACL
1279 if (interface_name == PPB_PDF_INTERFACE)
1280 return PPB_PDF_Impl::GetInterface();
1281 #endif
1282 return NULL;
1283 }
1284
IsExternalPepperPlugin(const std::string & module_name)1285 bool ChromeContentRendererClient::IsExternalPepperPlugin(
1286 const std::string& module_name) {
1287 // TODO(bbudge) remove this when the trusted NaCl plugin has been removed.
1288 // We must defer certain plugin events for NaCl instances since we switch
1289 // from the in-process to the out-of-process proxy after instantiating them.
1290 return module_name == "Native Client";
1291 }
1292
1293 blink::WebSpeechSynthesizer*
OverrideSpeechSynthesizer(blink::WebSpeechSynthesizerClient * client)1294 ChromeContentRendererClient::OverrideSpeechSynthesizer(
1295 blink::WebSpeechSynthesizerClient* client) {
1296 return new TtsDispatcher(client);
1297 }
1298
AllowBrowserPlugin(blink::WebPluginContainer * container)1299 bool ChromeContentRendererClient::AllowBrowserPlugin(
1300 blink::WebPluginContainer* container) {
1301 if (CommandLine::ForCurrentProcess()->HasSwitch(
1302 switches::kEnableBrowserPluginForAllViewTypes))
1303 return true;
1304
1305 // If this |BrowserPlugin| <object> in the |container| is not inside a
1306 // <webview>/<adview> shadowHost, we disable instantiating this plugin. This
1307 // is to discourage and prevent developers from accidentally attaching
1308 // <object> directly in apps.
1309 //
1310 // Note that this check below does *not* ensure any security, it is still
1311 // possible to bypass this check.
1312 // TODO(lazyboy): http://crbug.com/178663, Ensure we properly disallow
1313 // instantiating BrowserPlugin outside of the <webview>/<adview> shim.
1314 if (container->element().isNull())
1315 return false;
1316
1317 if (container->element().shadowHost().isNull())
1318 return false;
1319
1320 WebString tag_name = container->element().shadowHost().tagName();
1321 return tag_name.equals(WebString::fromUTF8(kWebViewTagName)) ||
1322 tag_name.equals(WebString::fromUTF8(kAdViewTagName));
1323 }
1324
AllowPepperMediaStreamAPI(const GURL & url)1325 bool ChromeContentRendererClient::AllowPepperMediaStreamAPI(
1326 const GURL& url) {
1327 #if !defined(OS_ANDROID)
1328 // Allow only the Hangouts app to use the MediaStream APIs. It's OK to check
1329 // the whitelist in the renderer, since we're only preventing access until
1330 // these APIs are public and stable.
1331 std::string url_host = url.host();
1332 if (url.SchemeIs("https") &&
1333 (EndsWith(url_host, "talkgadget.google.com", false) ||
1334 EndsWith(url_host, "plus.google.com", false) ||
1335 EndsWith(url_host, "plus.sandbox.google.com", false)) &&
1336 StartsWithASCII(url.path(), "/hangouts/", false)) {
1337 return true;
1338 }
1339 // Allow access for tests.
1340 if (CommandLine::ForCurrentProcess()->HasSwitch(
1341 switches::kEnablePepperTesting)) {
1342 return true;
1343 }
1344 #endif // !defined(OS_ANDROID)
1345 return false;
1346 }
1347
AddKeySystems(std::vector<content::KeySystemInfo> * key_systems)1348 void ChromeContentRendererClient::AddKeySystems(
1349 std::vector<content::KeySystemInfo>* key_systems) {
1350 AddChromeKeySystems(key_systems);
1351 }
1352
ShouldReportDetailedMessageForSource(const base::string16 & source) const1353 bool ChromeContentRendererClient::ShouldReportDetailedMessageForSource(
1354 const base::string16& source) const {
1355 return extensions::IsSourceFromAnExtension(source);
1356 }
1357
ShouldEnableSiteIsolationPolicy() const1358 bool ChromeContentRendererClient::ShouldEnableSiteIsolationPolicy() const {
1359 // SiteIsolationPolicy is off by default. We would like to activate cross-site
1360 // document blocking (for UMA data collection) for normal renderer processes
1361 // running a normal web page from the Internet. We only turn on
1362 // SiteIsolationPolicy for a renderer process that does not have the extension
1363 // flag on.
1364 CommandLine* command_line = CommandLine::ForCurrentProcess();
1365 return !command_line->HasSwitch(switches::kExtensionProcess);
1366 }
1367
1368 blink::WebWorkerPermissionClientProxy*
CreateWorkerPermissionClientProxy(content::RenderView * render_view,blink::WebFrame * frame)1369 ChromeContentRendererClient::CreateWorkerPermissionClientProxy(
1370 content::RenderView* render_view,
1371 blink::WebFrame* frame) {
1372 return new WorkerPermissionClientProxy(render_view, frame);
1373 }
1374