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