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