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