chrome_resource_dispatcher_host_delegate.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h" 6 7#include <string> 8 9#include "base/base64.h" 10#include "base/logging.h" 11#include "chrome/browser/browser_process.h" 12#include "chrome/browser/chrome_notification_types.h" 13#include "chrome/browser/component_updater/component_updater_service.h" 14#include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h" 15#include "chrome/browser/content_settings/host_content_settings_map.h" 16#include "chrome/browser/download/download_request_limiter.h" 17#include "chrome/browser/download/download_resource_throttle.h" 18#include "chrome/browser/extensions/api/streams_private/streams_private_api.h" 19#include "chrome/browser/extensions/extension_renderer_state.h" 20#include "chrome/browser/extensions/user_script_listener.h" 21#include "chrome/browser/google/google_util.h" 22#include "chrome/browser/metrics/variations/variations_http_header_provider.h" 23#include "chrome/browser/prefetch/prefetch.h" 24#include "chrome/browser/prerender/prerender_manager.h" 25#include "chrome/browser/prerender/prerender_manager_factory.h" 26#include "chrome/browser/prerender/prerender_pending_swap_throttle.h" 27#include "chrome/browser/prerender/prerender_resource_throttle.h" 28#include "chrome/browser/prerender/prerender_tracker.h" 29#include "chrome/browser/prerender/prerender_util.h" 30#include "chrome/browser/profiles/profile.h" 31#include "chrome/browser/profiles/profile_io_data.h" 32#include "chrome/browser/renderer_host/safe_browsing_resource_throttle_factory.h" 33#include "chrome/browser/safe_browsing/safe_browsing_service.h" 34#include "chrome/browser/signin/signin_header_helper.h" 35#include "chrome/browser/tab_contents/tab_util.h" 36#include "chrome/browser/ui/login/login_prompt.h" 37#include "chrome/browser/ui/sync/one_click_signin_helper.h" 38#include "chrome/common/extensions/extension_constants.h" 39#include "chrome/common/extensions/mime_types_handler.h" 40#include "chrome/common/render_messages.h" 41#include "chrome/common/url_constants.h" 42#include "content/public/browser/browser_thread.h" 43#include "content/public/browser/notification_service.h" 44#include "content/public/browser/render_process_host.h" 45#include "content/public/browser/render_view_host.h" 46#include "content/public/browser/resource_context.h" 47#include "content/public/browser/resource_dispatcher_host.h" 48#include "content/public/browser/resource_request_info.h" 49#include "content/public/browser/stream_handle.h" 50#include "content/public/browser/web_contents.h" 51#include "content/public/common/resource_response.h" 52#include "extensions/browser/info_map.h" 53#include "extensions/common/constants.h" 54#include "extensions/common/user_script.h" 55#include "net/base/load_flags.h" 56#include "net/base/load_timing_info.h" 57#include "net/base/request_priority.h" 58#include "net/http/http_response_headers.h" 59#include "net/url_request/url_request.h" 60 61#if defined(ENABLE_CONFIGURATION_POLICY) 62#include "components/policy/core/common/cloud/policy_header_io_helper.h" 63#endif 64 65#if defined(ENABLE_MANAGED_USERS) 66#include "chrome/browser/managed_mode/managed_mode_resource_throttle.h" 67#endif 68 69#if defined(USE_SYSTEM_PROTOBUF) 70#include <google/protobuf/repeated_field.h> 71#else 72#include "third_party/protobuf/src/google/protobuf/repeated_field.h" 73#endif 74 75#if defined(OS_ANDROID) 76#include "chrome/browser/android/intercept_download_resource_throttle.h" 77#include "chrome/browser/ui/android/infobars/auto_login_prompter.h" 78#include "components/navigation_interception/intercept_navigation_delegate.h" 79#else 80#include "chrome/browser/apps/app_url_redirector.h" 81#include "chrome/browser/apps/ephemeral_app_throttle.h" 82#endif 83 84#if defined(OS_CHROMEOS) 85#include "chrome/browser/chromeos/login/merge_session_throttle.h" 86// TODO(oshima): Enable this for other platforms. 87#include "chrome/browser/renderer_host/offline_resource_throttle.h" 88#endif 89 90using content::BrowserThread; 91using content::RenderViewHost; 92using content::ResourceDispatcherHostLoginDelegate; 93using content::ResourceRequestInfo; 94using extensions::Extension; 95using extensions::StreamsPrivateAPI; 96 97#if defined(OS_ANDROID) 98using navigation_interception::InterceptNavigationDelegate; 99#endif 100 101namespace { 102 103ExternalProtocolHandler::Delegate* g_external_protocol_handler_delegate = NULL; 104 105void NotifyDownloadInitiatedOnUI(int render_process_id, int render_view_id) { 106 RenderViewHost* rvh = RenderViewHost::FromID(render_process_id, 107 render_view_id); 108 if (!rvh) 109 return; 110 111 content::NotificationService::current()->Notify( 112 chrome::NOTIFICATION_DOWNLOAD_INITIATED, 113 content::Source<RenderViewHost>(rvh), 114 content::NotificationService::NoDetails()); 115} 116 117prerender::PrerenderManager* GetPrerenderManager(int render_process_id, 118 int render_view_id) { 119 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 120 121 content::WebContents* web_contents = 122 tab_util::GetWebContentsByID(render_process_id, render_view_id); 123 if (!web_contents) 124 return NULL; 125 126 content::BrowserContext* browser_context = web_contents->GetBrowserContext(); 127 if (!browser_context) 128 return NULL; 129 130 Profile* profile = Profile::FromBrowserContext(browser_context); 131 if (!profile) 132 return NULL; 133 134 return prerender::PrerenderManagerFactory::GetForProfile(profile); 135} 136 137void UpdatePrerenderNetworkBytesCallback(int render_process_id, 138 int render_view_id, 139 int64 bytes) { 140 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 141 142 content::WebContents* web_contents = 143 tab_util::GetWebContentsByID(render_process_id, render_view_id); 144 // PrerenderContents::FromWebContents handles the NULL case. 145 prerender::PrerenderContents* prerender_contents = 146 prerender::PrerenderContents::FromWebContents(web_contents); 147 148 if (prerender_contents) 149 prerender_contents->AddNetworkBytes(bytes); 150 151 prerender::PrerenderManager* prerender_manager = 152 GetPrerenderManager(render_process_id, render_view_id); 153 if (prerender_manager) 154 prerender_manager->AddProfileNetworkBytesIfEnabled(bytes); 155} 156 157#if !defined(OS_ANDROID) 158// Goes through the extension's file browser handlers and checks if there is one 159// that can handle the |mime_type|. 160// |extension| must not be NULL. 161bool ExtensionCanHandleMimeType(const Extension* extension, 162 const std::string& mime_type) { 163 MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension); 164 if (!handler) 165 return false; 166 167 return handler->CanHandleMIMEType(mime_type); 168} 169 170void SendExecuteMimeTypeHandlerEvent(scoped_ptr<content::StreamHandle> stream, 171 int64 expected_content_size, 172 int render_process_id, 173 int render_view_id, 174 const std::string& extension_id) { 175 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 176 177 content::WebContents* web_contents = 178 tab_util::GetWebContentsByID(render_process_id, render_view_id); 179 if (!web_contents) 180 return; 181 182 // If the request was for a prerender, abort the prerender and do not 183 // continue. 184 prerender::PrerenderContents* prerender_contents = 185 prerender::PrerenderContents::FromWebContents(web_contents); 186 if (prerender_contents) { 187 prerender_contents->Destroy(prerender::FINAL_STATUS_DOWNLOAD); 188 return; 189 } 190 191 Profile* profile = 192 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 193 194 StreamsPrivateAPI* streams_private = StreamsPrivateAPI::Get(profile); 195 if (!streams_private) 196 return; 197 streams_private->ExecuteMimeTypeHandler( 198 extension_id, web_contents, stream.Pass(), expected_content_size); 199} 200 201void LaunchURL(const GURL& url, int render_process_id, int render_view_id, 202 bool user_gesture) { 203 // If there is no longer a WebContents, the request may have raced with tab 204 // closing. Don't fire the external request. (It may have been a prerender.) 205 content::WebContents* web_contents = 206 tab_util::GetWebContentsByID(render_process_id, render_view_id); 207 if (!web_contents) 208 return; 209 210 // Do not launch external requests attached to unswapped prerenders. 211 prerender::PrerenderContents* prerender_contents = 212 prerender::PrerenderContents::FromWebContents(web_contents); 213 if (prerender_contents) { 214 prerender_contents->Destroy(prerender::FINAL_STATUS_UNSUPPORTED_SCHEME); 215 prerender::ReportPrerenderExternalURL(); 216 return; 217 } 218 219 ExternalProtocolHandler::LaunchUrlWithDelegate( 220 url, render_process_id, render_view_id, 221 g_external_protocol_handler_delegate, 222 user_gesture); 223} 224#endif // !defined(OS_ANDROID) 225 226void AppendComponentUpdaterThrottles( 227 net::URLRequest* request, 228 content::ResourceContext* resource_context, 229 ResourceType::Type resource_type, 230 ScopedVector<content::ResourceThrottle>* throttles) { 231 const char* crx_id = NULL; 232 component_updater::ComponentUpdateService* cus = 233 g_browser_process->component_updater(); 234 if (!cus) 235 return; 236 // Check for PNaCl pexe request. 237 if (resource_type == ResourceType::OBJECT) { 238 const net::HttpRequestHeaders& headers = request->extra_request_headers(); 239 std::string accept_headers; 240 if (headers.GetHeader("Accept", &accept_headers)) { 241 if (accept_headers.find("application/x-pnacl") != std::string::npos && 242 pnacl::NeedsOnDemandUpdate()) 243 crx_id = "hnimpnehoodheedghdeeijklkeaacbdc"; 244 } 245 } 246 247 if (crx_id) { 248 // We got a component we need to install, so throttle the resource 249 // until the component is installed. 250 throttles->push_back(cus->GetOnDemandResourceThrottle(request, crx_id)); 251 } 252} 253 254} // end namespace 255 256ChromeResourceDispatcherHostDelegate::ChromeResourceDispatcherHostDelegate( 257 prerender::PrerenderTracker* prerender_tracker) 258 : download_request_limiter_(g_browser_process->download_request_limiter()), 259 safe_browsing_(g_browser_process->safe_browsing_service()), 260 user_script_listener_(new extensions::UserScriptListener()), 261 prerender_tracker_(prerender_tracker) { 262} 263 264ChromeResourceDispatcherHostDelegate::~ChromeResourceDispatcherHostDelegate() { 265} 266 267bool ChromeResourceDispatcherHostDelegate::ShouldBeginRequest( 268 int child_id, 269 int route_id, 270 const std::string& method, 271 const GURL& url, 272 ResourceType::Type resource_type, 273 content::ResourceContext* resource_context) { 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 275 276 // Handle a PREFETCH resource type. If prefetch is disabled, squelch the 277 // request. Otherwise, do a normal request to warm the cache. 278 if (resource_type == ResourceType::PREFETCH) { 279 // All PREFETCH requests should be GETs, but be defensive about it. 280 if (method != "GET") 281 return false; 282 283 // If prefetch is disabled, kill the request. 284 if (!prefetch::IsPrefetchEnabled(resource_context)) 285 return false; 286 } 287 288 return true; 289} 290 291void ChromeResourceDispatcherHostDelegate::RequestBeginning( 292 net::URLRequest* request, 293 content::ResourceContext* resource_context, 294 appcache::AppCacheService* appcache_service, 295 ResourceType::Type resource_type, 296 int child_id, 297 int route_id, 298 ScopedVector<content::ResourceThrottle>* throttles) { 299 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request); 300 bool is_prerendering = 301 info->GetVisibilityState() == blink::WebPageVisibilityStatePrerender; 302 if (is_prerendering) { 303 // Requests with the IGNORE_LIMITS flag set (i.e., sync XHRs) 304 // should remain at MAXIMUM_PRIORITY. 305 if (request->load_flags() & net::LOAD_IGNORE_LIMITS) { 306 DCHECK_EQ(request->priority(), net::MAXIMUM_PRIORITY); 307 } else { 308 request->SetPriority(net::IDLE); 309 } 310 } 311 312 ProfileIOData* io_data = ProfileIOData::FromResourceContext( 313 resource_context); 314 315 if (!is_prerendering && resource_type == ResourceType::MAIN_FRAME) { 316#if defined(OS_ANDROID) 317 throttles->push_back( 318 InterceptNavigationDelegate::CreateThrottleFor(request)); 319#else 320 // Redirect some navigations to apps that have registered matching URL 321 // handlers ('url_handlers' in the manifest). 322 content::ResourceThrottle* url_to_app_throttle = 323 AppUrlRedirector::MaybeCreateThrottleFor(request, io_data); 324 if (url_to_app_throttle) 325 throttles->push_back(url_to_app_throttle); 326 327 // Experimental: Launch ephemeral apps from search results. 328 content::ResourceThrottle* ephemeral_app_throttle = 329 EphemeralAppThrottle::MaybeCreateThrottleForLaunch( 330 request, io_data); 331 if (ephemeral_app_throttle) 332 throttles->push_back(ephemeral_app_throttle); 333#endif 334 } 335 336#if defined(OS_CHROMEOS) 337 // Check if we need to add offline throttle. This should be done only 338 // for main frames. 339 if (resource_type == ResourceType::MAIN_FRAME) { 340 // We check offline first, then check safe browsing so that we still can 341 // block unsafe site after we remove offline page. 342 throttles->push_back(new OfflineResourceThrottle(request, 343 appcache_service)); 344 } 345 346 // Check if we need to add merge session throttle. This throttle will postpone 347 // loading of main frames and XHR request. 348 if (resource_type == ResourceType::MAIN_FRAME || 349 resource_type == ResourceType::XHR) { 350 // Add interstitial page while merge session process (cookie 351 // reconstruction from OAuth2 refresh token in ChromeOS login) is still in 352 // progress while we are attempting to load a google property. 353 if (!MergeSessionThrottle::AreAllSessionMergedAlready() && 354 request->url().SchemeIsHTTPOrHTTPS()) { 355 throttles->push_back(new MergeSessionThrottle(request, resource_type)); 356 } 357 } 358#endif 359 360 // Don't attempt to append headers to requests that have already started. 361 // TODO(stevet): Remove this once the request ordering issues are resolved 362 // in crbug.com/128048. 363 if (!request->is_pending()) { 364 net::HttpRequestHeaders headers; 365 headers.CopyFrom(request->extra_request_headers()); 366 bool is_off_the_record = io_data->IsOffTheRecord(); 367 chrome_variations::VariationsHttpHeaderProvider::GetInstance()-> 368 AppendHeaders(request->url(), 369 is_off_the_record, 370 !is_off_the_record && 371 io_data->GetMetricsEnabledStateOnIOThread(), 372 &headers); 373 request->SetExtraRequestHeaders(headers); 374 } 375 376#if defined(ENABLE_ONE_CLICK_SIGNIN) 377 AppendChromeSyncGaiaHeader(request, resource_context); 378#endif 379 380#if defined(ENABLE_CONFIGURATION_POLICY) 381 if (io_data->policy_header_helper()) 382 io_data->policy_header_helper()->AddPolicyHeaders(request); 383#endif 384 385 signin::AppendMirrorRequestHeaderIfPossible( 386 request, GURL() /* redirect_url */, 387 io_data, info->GetChildID(), info->GetRouteID()); 388 389 AppendStandardResourceThrottles(request, 390 resource_context, 391 resource_type, 392 throttles); 393 if (!is_prerendering) { 394 AppendComponentUpdaterThrottles(request, 395 resource_context, 396 resource_type, 397 throttles); 398 } 399} 400 401void ChromeResourceDispatcherHostDelegate::DownloadStarting( 402 net::URLRequest* request, 403 content::ResourceContext* resource_context, 404 int child_id, 405 int route_id, 406 int request_id, 407 bool is_content_initiated, 408 bool must_download, 409 ScopedVector<content::ResourceThrottle>* throttles) { 410 BrowserThread::PostTask( 411 BrowserThread::UI, FROM_HERE, 412 base::Bind(&NotifyDownloadInitiatedOnUI, child_id, route_id)); 413 414 // If it's from the web, we don't trust it, so we push the throttle on. 415 if (is_content_initiated) { 416 throttles->push_back( 417 new DownloadResourceThrottle(download_request_limiter_.get(), 418 child_id, 419 route_id, 420 request_id, 421 request->method())); 422#if defined(OS_ANDROID) 423 throttles->push_back( 424 new chrome::InterceptDownloadResourceThrottle( 425 request, child_id, route_id, request_id)); 426#endif 427 } 428 429 // If this isn't a new request, we've seen this before and added the standard 430 // resource throttles already so no need to add it again. 431 if (!request->is_pending()) { 432 AppendStandardResourceThrottles(request, 433 resource_context, 434 ResourceType::MAIN_FRAME, 435 throttles); 436 } 437} 438 439ResourceDispatcherHostLoginDelegate* 440 ChromeResourceDispatcherHostDelegate::CreateLoginDelegate( 441 net::AuthChallengeInfo* auth_info, net::URLRequest* request) { 442 return CreateLoginPrompt(auth_info, request); 443} 444 445bool ChromeResourceDispatcherHostDelegate::HandleExternalProtocol( 446 const GURL& url, 447 int child_id, 448 int route_id, 449 bool initiated_by_user_gesture) { 450#if defined(OS_ANDROID) 451 // Android use a resource throttle to handle external as well as internal 452 // protocols. 453 return false; 454#else 455 456 ExtensionRendererState::WebViewInfo info; 457 if (ExtensionRendererState::GetInstance()->GetWebViewInfo(child_id, 458 route_id, 459 &info)) { 460 return false; 461 } 462 463 BrowserThread::PostTask( 464 BrowserThread::UI, FROM_HERE, 465 base::Bind(&LaunchURL, url, child_id, route_id, 466 initiated_by_user_gesture)); 467 return true; 468#endif 469} 470 471void ChromeResourceDispatcherHostDelegate::AppendStandardResourceThrottles( 472 net::URLRequest* request, 473 content::ResourceContext* resource_context, 474 ResourceType::Type resource_type, 475 ScopedVector<content::ResourceThrottle>* throttles) { 476 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context); 477#if defined(FULL_SAFE_BROWSING) || defined(MOBILE_SAFE_BROWSING) 478 // Insert safe browsing at the front of the list, so it gets to decide on 479 // policies first. 480 if (io_data->safe_browsing_enabled()->GetValue()) { 481 bool is_subresource_request = resource_type != ResourceType::MAIN_FRAME; 482 content::ResourceThrottle* throttle = 483 SafeBrowsingResourceThrottleFactory::Create(request, 484 is_subresource_request, 485 safe_browsing_.get()); 486 if (throttle) 487 throttles->push_back(throttle); 488 } 489#endif 490 491#if defined(ENABLE_MANAGED_USERS) 492 bool is_subresource_request = resource_type != ResourceType::MAIN_FRAME; 493 throttles->push_back(new ManagedModeResourceThrottle( 494 request, !is_subresource_request, 495 io_data->managed_mode_url_filter())); 496#endif 497 498 content::ResourceThrottle* throttle = 499 user_script_listener_->CreateResourceThrottle(request->url(), 500 resource_type); 501 if (throttle) 502 throttles->push_back(throttle); 503 504 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request); 505 if (info->GetVisibilityState() == blink::WebPageVisibilityStatePrerender) { 506 throttles->push_back(new prerender::PrerenderResourceThrottle(request)); 507 } 508 if (prerender_tracker_->IsPendingSwapRequestOnIOThread( 509 info->GetChildID(), info->GetRenderFrameID(), request->url())) { 510 throttles->push_back(new prerender::PrerenderPendingSwapThrottle( 511 request, prerender_tracker_)); 512 } 513} 514 515#if defined(ENABLE_ONE_CLICK_SIGNIN) 516void ChromeResourceDispatcherHostDelegate::AppendChromeSyncGaiaHeader( 517 net::URLRequest* request, 518 content::ResourceContext* resource_context) { 519 static const char kAllowChromeSignIn[] = "Allow-Chrome-SignIn"; 520 521 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context); 522 OneClickSigninHelper::Offer offer = 523 OneClickSigninHelper::CanOfferOnIOThread(request, io_data); 524 switch (offer) { 525 case OneClickSigninHelper::CAN_OFFER: 526 request->SetExtraRequestHeaderByName(kAllowChromeSignIn, "1", false); 527 break; 528 case OneClickSigninHelper::DONT_OFFER: 529 request->RemoveRequestHeaderByName(kAllowChromeSignIn); 530 break; 531 case OneClickSigninHelper::IGNORE_REQUEST: 532 break; 533 } 534} 535#endif 536 537bool ChromeResourceDispatcherHostDelegate::ShouldForceDownloadResource( 538 const GURL& url, const std::string& mime_type) { 539 // Special-case user scripts to get downloaded instead of viewed. 540 return extensions::UserScript::IsURLUserScript(url, mime_type); 541} 542 543bool ChromeResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream( 544 content::ResourceContext* resource_context, 545 const GURL& url, 546 const std::string& mime_type, 547 GURL* origin, 548 std::string* target_id) { 549#if !defined(OS_ANDROID) 550 ProfileIOData* io_data = 551 ProfileIOData::FromResourceContext(resource_context); 552 bool profile_is_off_the_record = io_data->IsOffTheRecord(); 553 const scoped_refptr<const extensions::InfoMap> extension_info_map( 554 io_data->GetExtensionInfoMap()); 555 std::vector<std::string> whitelist = MimeTypesHandler::GetMIMETypeWhitelist(); 556 // Go through the white-listed extensions and try to use them to intercept 557 // the URL request. 558 for (size_t i = 0; i < whitelist.size(); ++i) { 559 const char* extension_id = whitelist[i].c_str(); 560 const Extension* extension = 561 extension_info_map->extensions().GetByID(extension_id); 562 // The white-listed extension may not be installed, so we have to NULL check 563 // |extension|. 564 if (!extension || 565 (profile_is_off_the_record && 566 !extension_info_map->IsIncognitoEnabled(extension_id))) { 567 continue; 568 } 569 570 if (ExtensionCanHandleMimeType(extension, mime_type)) { 571 *origin = Extension::GetBaseURLFromExtensionId(extension_id); 572 *target_id = extension_id; 573 return true; 574 } 575 } 576#endif 577 return false; 578} 579 580void ChromeResourceDispatcherHostDelegate::OnStreamCreated( 581 content::ResourceContext* resource_context, 582 int render_process_id, 583 int render_view_id, 584 const std::string& target_id, 585 scoped_ptr<content::StreamHandle> stream, 586 int64 expected_content_size) { 587#if !defined(OS_ANDROID) 588 content::BrowserThread::PostTask( 589 content::BrowserThread::UI, FROM_HERE, 590 base::Bind(&SendExecuteMimeTypeHandlerEvent, base::Passed(&stream), 591 expected_content_size, render_process_id, render_view_id, 592 target_id)); 593#endif 594} 595 596void ChromeResourceDispatcherHostDelegate::OnResponseStarted( 597 net::URLRequest* request, 598 content::ResourceContext* resource_context, 599 content::ResourceResponse* response, 600 IPC::Sender* sender) { 601 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request); 602 603#if defined(OS_ANDROID) 604 // See if the response contains the X-Auto-Login header. If so, this was 605 // a request for a login page, and the server is allowing the browser to 606 // suggest auto-login, if available. 607 AutoLoginPrompter::ShowInfoBarIfPossible(request, info->GetChildID(), 608 info->GetRouteID()); 609#endif 610 611 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context); 612 613#if defined(ENABLE_ONE_CLICK_SIGNIN) 614 // See if the response contains the Google-Accounts-SignIn header. If so, 615 // then the user has just finished signing in, and the server is allowing the 616 // browser to suggest connecting the user's profile to the account. 617 OneClickSigninHelper::ShowInfoBarIfPossible(request, io_data, 618 info->GetChildID(), 619 info->GetRouteID()); 620#endif 621 622 // See if the response contains the X-Chrome-Manage-Accounts header. If so 623 // show the profile avatar bubble so that user can complete signin/out action 624 // the native UI. 625 signin::ProcessMirrorResponseHeaderIfExists(request, io_data, 626 info->GetChildID(), 627 info->GetRouteID()); 628 629 // Build in additional protection for the chrome web store origin. 630 GURL webstore_url(extension_urls::GetWebstoreLaunchURL()); 631 if (request->url().DomainIs(webstore_url.host().c_str())) { 632 net::HttpResponseHeaders* response_headers = request->response_headers(); 633 if (!response_headers->HasHeaderValue("x-frame-options", "deny") && 634 !response_headers->HasHeaderValue("x-frame-options", "sameorigin")) { 635 response_headers->RemoveHeader("x-frame-options"); 636 response_headers->AddHeader("x-frame-options: sameorigin"); 637 } 638 } 639 640 // Ignores x-frame-options for the chrome signin UI. 641 const std::string request_spec( 642 request->first_party_for_cookies().GetOrigin().spec()); 643#if defined(OS_CHROMEOS) 644 if (request_spec == chrome::kChromeUIOobeURL || 645 request_spec == chrome::kChromeUIChromeSigninURL) { 646#else 647 if (request_spec == chrome::kChromeUIChromeSigninURL) { 648#endif 649 net::HttpResponseHeaders* response_headers = request->response_headers(); 650 if (response_headers->HasHeader("x-frame-options")) 651 response_headers->RemoveHeader("x-frame-options"); 652 } 653 654 prerender::URLRequestResponseStarted(request); 655} 656 657void ChromeResourceDispatcherHostDelegate::OnRequestRedirected( 658 const GURL& redirect_url, 659 net::URLRequest* request, 660 content::ResourceContext* resource_context, 661 content::ResourceResponse* response) { 662 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context); 663 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request); 664 665#if defined(ENABLE_ONE_CLICK_SIGNIN) 666 // See if the response contains the Google-Accounts-SignIn header. If so, 667 // then the user has just finished signing in, and the server is allowing the 668 // browser to suggest connecting the user's profile to the account. 669 OneClickSigninHelper::ShowInfoBarIfPossible(request, io_data, 670 info->GetChildID(), 671 info->GetRouteID()); 672 AppendChromeSyncGaiaHeader(request, resource_context); 673#endif 674 675 // In the Mirror world, Chrome should append a X-Chrome-Connected header to 676 // all Gaia requests from a connected profile so Gaia could return a 204 677 // response and let Chrome handle the action with native UI. The only 678 // exception is requests from gaia webview, since the native profile 679 // management UI is built on top of it. 680 signin::AppendMirrorRequestHeaderIfPossible(request, redirect_url, io_data, 681 info->GetChildID(), info->GetRouteID()); 682} 683 684// Notification that a request has completed. 685void ChromeResourceDispatcherHostDelegate::RequestComplete( 686 net::URLRequest* url_request) { 687 // Jump on the UI thread and inform the prerender about the bytes. 688 const ResourceRequestInfo* info = 689 ResourceRequestInfo::ForRequest(url_request); 690 if (url_request && !url_request->was_cached()) { 691 BrowserThread::PostTask(BrowserThread::UI, 692 FROM_HERE, 693 base::Bind(&UpdatePrerenderNetworkBytesCallback, 694 info->GetChildID(), 695 info->GetRouteID(), 696 url_request->GetTotalReceivedBytes())); 697 } 698} 699 700// static 701void ChromeResourceDispatcherHostDelegate:: 702 SetExternalProtocolHandlerDelegateForTesting( 703 ExternalProtocolHandler::Delegate* delegate) { 704 g_external_protocol_handler_delegate = delegate; 705} 706