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 116using autofill::AutofillAgent; 117using autofill::PasswordAutofillAgent; 118using autofill::PasswordGenerationAgent; 119using content::RenderThread; 120using content::UserMetricsAction; 121using content::WebPluginInfo; 122using extensions::Extension; 123using blink::WebCache; 124using blink::WebConsoleMessage; 125using blink::WebDataSource; 126using blink::WebDocument; 127using blink::WebFrame; 128using blink::WebPlugin; 129using blink::WebPluginParams; 130using blink::WebSecurityOrigin; 131using blink::WebSecurityPolicy; 132using blink::WebString; 133using blink::WebURL; 134using blink::WebURLError; 135using blink::WebURLRequest; 136using blink::WebURLResponse; 137using blink::WebVector; 138 139namespace { 140 141const char kWebViewTagName[] = "WEBVIEW"; 142const char kAdViewTagName[] = "ADVIEW"; 143 144ChromeContentRendererClient* g_current_client; 145 146static 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) 174class SpellCheckReplacer : public content::RenderViewVisitor { 175 public: 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 185bool 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. 194bool 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 217ChromeContentRendererClient::ChromeContentRendererClient() { 218 g_current_client = this; 219} 220 221ChromeContentRendererClient::~ChromeContentRendererClient() { 222 g_current_client = NULL; 223} 224 225void 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 349void 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 357void 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 393void ChromeContentRendererClient::SetNumberOfViews(int number_of_views) { 394 base::debug::SetCrashKeyValue(crash_keys::kNumberOfViews, 395 base::IntToString(number_of_views)); 396} 397 398SkBitmap* ChromeContentRendererClient::GetSadPluginBitmap() { 399 return const_cast<SkBitmap*>(ResourceBundle::GetSharedInstance(). 400 GetImageNamed(IDR_SAD_PLUGIN).ToSkBitmap()); 401} 402 403SkBitmap* ChromeContentRendererClient::GetSadWebViewBitmap() { 404 return const_cast<SkBitmap*>(ResourceBundle::GetSharedInstance(). 405 GetImageNamed(IDR_SAD_WEBVIEW).ToSkBitmap()); 406} 407 408std::string ChromeContentRendererClient::GetDefaultEncoding() { 409 return l10n_util::GetStringUTF8(IDS_DEFAULT_ENCODING); 410} 411 412const 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 421bool 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 458WebPlugin* 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 466void 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 484WebPlugin* 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 ¶ms.attributeNames, 529 ¶ms.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 ¶ms)) { 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 790GURL 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 810bool 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 ¶ms->attributeNames, 898 ¶ms->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 911bool 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 923bool 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 928void 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 987bool ChromeContentRendererClient::RunIdleHandlerWhenWidgetsHidden() { 988 return !extension_dispatcher_->is_extension_process(); 989} 990 991bool 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 1012bool 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 1104bool 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 1143void 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 1150void ChromeContentRendererClient::WillReleaseScriptContext( 1151 WebFrame* frame, v8::Handle<v8::Context> context, int world_id) { 1152 extension_dispatcher_->WillReleaseScriptContext(frame, context, world_id); 1153} 1154 1155unsigned long long ChromeContentRendererClient::VisitedLinkHash( 1156 const char* canonical_url, size_t length) { 1157 return visited_link_slave_->ComputeURLFingerprint(canonical_url, length); 1158} 1159 1160bool ChromeContentRendererClient::IsLinkVisited(unsigned long long link_hash) { 1161 return visited_link_slave_->IsVisited(link_hash); 1162} 1163 1164blink::WebPrescientNetworking* 1165ChromeContentRendererClient::GetPrescientNetworking() { 1166 return prescient_networking_dispatcher_.get(); 1167} 1168 1169bool 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 1179void 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 1187bool 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) 1228void 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 1240void ChromeContentRendererClient::OnPurgeMemory() { 1241#if defined(ENABLE_SPELLCHECK) 1242 DVLOG(1) << "Resetting spellcheck in renderer client"; 1243 SetSpellcheck(new SpellCheck()); 1244#endif 1245} 1246 1247bool ChromeContentRendererClient::IsAdblockInstalled() { 1248 return g_current_client->extension_dispatcher_->extensions()->Contains( 1249 "gighmmpiobklfepjocnamgkkbiglidom"); 1250} 1251 1252bool ChromeContentRendererClient::IsAdblockPlusInstalled() { 1253 return g_current_client->extension_dispatcher_->extensions()->Contains( 1254 "cfhdojbkjhnklbpkdaibdccddilifddb"); 1255} 1256 1257bool ChromeContentRendererClient::IsAdblockWithWebRequestInstalled() { 1258 return g_current_client->extension_dispatcher_-> 1259 IsAdblockWithWebRequestInstalled(); 1260} 1261 1262bool ChromeContentRendererClient::IsAdblockPlusWithWebRequestInstalled() { 1263 return g_current_client->extension_dispatcher_-> 1264 IsAdblockPlusWithWebRequestInstalled(); 1265} 1266 1267bool ChromeContentRendererClient::IsOtherExtensionWithWebRequestInstalled() { 1268 return g_current_client->extension_dispatcher_-> 1269 IsOtherExtensionWithWebRequestInstalled(); 1270} 1271 1272const 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 1285bool 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 1293blink::WebSpeechSynthesizer* 1294ChromeContentRendererClient::OverrideSpeechSynthesizer( 1295 blink::WebSpeechSynthesizerClient* client) { 1296 return new TtsDispatcher(client); 1297} 1298 1299bool 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 1325bool 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 1348void ChromeContentRendererClient::AddKeySystems( 1349 std::vector<content::KeySystemInfo>* key_systems) { 1350 AddChromeKeySystems(key_systems); 1351} 1352 1353bool ChromeContentRendererClient::ShouldReportDetailedMessageForSource( 1354 const base::string16& source) const { 1355 return extensions::IsSourceFromAnExtension(source); 1356} 1357 1358bool 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 1368blink::WebWorkerPermissionClientProxy* 1369ChromeContentRendererClient::CreateWorkerPermissionClientProxy( 1370 content::RenderView* render_view, 1371 blink::WebFrame* frame) { 1372 return new WorkerPermissionClientProxy(render_view, frame); 1373} 1374