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