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