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