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