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