Home | History | Annotate | Download | only in renderer
      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 
    144 using autofill::AutofillAgent;
    145 using autofill::PasswordAutofillAgent;
    146 using autofill::PasswordGenerationAgent;
    147 using base::ASCIIToUTF16;
    148 using base::UserMetricsAction;
    149 using content::RenderThread;
    150 using content::WebPluginInfo;
    151 using extensions::Extension;
    152 using blink::WebCache;
    153 using blink::WebConsoleMessage;
    154 using blink::WebDataSource;
    155 using blink::WebDocument;
    156 using blink::WebFrame;
    157 using blink::WebLocalFrame;
    158 using blink::WebPlugin;
    159 using blink::WebPluginParams;
    160 using blink::WebSecurityOrigin;
    161 using blink::WebSecurityPolicy;
    162 using blink::WebString;
    163 using blink::WebURL;
    164 using blink::WebURLError;
    165 using blink::WebURLRequest;
    166 using blink::WebURLResponse;
    167 using blink::WebVector;
    168 
    169 namespace {
    170 
    171 ChromeContentRendererClient* g_current_client;
    172 
    173 #if defined(ENABLE_PLUGINS)
    174 const char* const kPredefinedAllowedCompositorOrigins[] = {
    175   "6EAED1924DB611B6EEF2A664BD077BE7EAD33B8F",  // see crbug.com/383937
    176   "4EB74897CB187C7633357C2FE832E0AD6A44883A"   // see crbug.com/383937
    177 };
    178 
    179 const char* const kPredefinedAllowedVideoDecodeOrigins[] = {
    180   "6EAED1924DB611B6EEF2A664BD077BE7EAD33B8F",  // see crbug.com/383937
    181   "4EB74897CB187C7633357C2FE832E0AD6A44883A"   // see crbug.com/383937
    182 };
    183 #endif
    184 
    185 static 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)
    213 class 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 
    224 bool 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.
    233 bool 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)
    257 void 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 
    268 ChromeContentRendererClient::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 
    286 ChromeContentRendererClient::~ChromeContentRendererClient() {
    287   g_current_client = NULL;
    288 }
    289 
    290 void 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 
    442 void 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 
    490 void 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 
    525 void ChromeContentRendererClient::SetNumberOfViews(int number_of_views) {
    526   base::debug::SetCrashKeyValue(crash_keys::kNumberOfViews,
    527                                 base::IntToString(number_of_views));
    528 }
    529 
    530 SkBitmap* ChromeContentRendererClient::GetSadPluginBitmap() {
    531   return const_cast<SkBitmap*>(ResourceBundle::GetSharedInstance().
    532       GetImageNamed(IDR_SAD_PLUGIN).ToSkBitmap());
    533 }
    534 
    535 SkBitmap* ChromeContentRendererClient::GetSadWebViewBitmap() {
    536   return const_cast<SkBitmap*>(ResourceBundle::GetSharedInstance().
    537       GetImageNamed(IDR_SAD_WEBVIEW).ToSkBitmap());
    538 }
    539 
    540 #if defined(ENABLE_EXTENSIONS)
    541 const 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 
    551 bool 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 
    584 WebPlugin* 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 
    592 void 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 
    610 WebPlugin* 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
    940 GURL 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
    960 bool 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 
   1061 bool 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 
   1073 bool 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 
   1091 void 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 
   1149 bool ChromeContentRendererClient::RunIdleHandlerWhenWidgetsHidden() {
   1150 #if defined(ENABLE_EXTENSIONS)
   1151   return !extension_dispatcher_->is_extension_process();
   1152 #else
   1153   return true;
   1154 #endif
   1155 }
   1156 
   1157 bool 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 
   1181 bool 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 
   1276 bool 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 
   1317 void 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 
   1326 unsigned long long ChromeContentRendererClient::VisitedLinkHash(
   1327     const char* canonical_url, size_t length) {
   1328   return visited_link_slave_->ComputeURLFingerprint(canonical_url, length);
   1329 }
   1330 
   1331 bool ChromeContentRendererClient::IsLinkVisited(unsigned long long link_hash) {
   1332   return visited_link_slave_->IsVisited(link_hash);
   1333 }
   1334 
   1335 blink::WebPrescientNetworking*
   1336 ChromeContentRendererClient::GetPrescientNetworking() {
   1337   return prescient_networking_dispatcher_.get();
   1338 }
   1339 
   1340 bool 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)
   1351 void 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 
   1359 extensions::Dispatcher*
   1360 ChromeContentRendererClient::GetExtensionDispatcherForTest() {
   1361   return extension_dispatcher_.get();
   1362 }
   1363 
   1364 bool 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)
   1406 void 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
   1419 bool 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 
   1428 const 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 
   1441 bool 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)
   1450 bool 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 
   1459 blink::WebSpeechSynthesizer*
   1460 ChromeContentRendererClient::OverrideSpeechSynthesizer(
   1461     blink::WebSpeechSynthesizerClient* client) {
   1462   return new TtsDispatcher(client);
   1463 }
   1464 
   1465 bool 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 
   1488 void ChromeContentRendererClient::AddKeySystems(
   1489     std::vector<content::KeySystemInfo>* key_systems) {
   1490   AddChromeKeySystems(key_systems);
   1491 }
   1492 
   1493 bool ChromeContentRendererClient::ShouldReportDetailedMessageForSource(
   1494     const base::string16& source) const {
   1495   return extensions::IsSourceFromAnExtension(source);
   1496 }
   1497 
   1498 bool 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 
   1508 blink::WebWorkerPermissionClientProxy*
   1509 ChromeContentRendererClient::CreateWorkerPermissionClientProxy(
   1510     content::RenderFrame* render_frame,
   1511     blink::WebFrame* frame) {
   1512   return new WorkerPermissionClientProxy(render_frame, frame);
   1513 }
   1514 
   1515 bool 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 
   1533 bool 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 
   1549 bool 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 
   1566 content::BrowserPluginDelegate*
   1567 ChromeContentRendererClient::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