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.
5 #include "chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h"
10 #include "base/base64.h"
11 #include "base/guid.h"
12 #include "base/logging.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/component_updater/component_updater_resource_throttle.h"
16 #include "chrome/browser/content_settings/host_content_settings_map.h"
17 #include "chrome/browser/download/download_request_limiter.h"
18 #include "chrome/browser/download/download_resource_throttle.h"
19 #include "chrome/browser/net/resource_prefetch_predictor_observer.h"
20 #include "chrome/browser/prefetch/prefetch.h"
21 #include "chrome/browser/prerender/prerender_manager.h"
22 #include "chrome/browser/prerender/prerender_manager_factory.h"
23 #include "chrome/browser/prerender/prerender_pending_swap_throttle.h"
24 #include "chrome/browser/prerender/prerender_resource_throttle.h"
25 #include "chrome/browser/prerender/prerender_tracker.h"
26 #include "chrome/browser/prerender/prerender_util.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/profiles/profile_io_data.h"
29 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle_factory.h"
30 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
31 #include "chrome/browser/signin/signin_header_helper.h"
32 #include "chrome/browser/tab_contents/tab_util.h"
33 #include "chrome/browser/ui/login/login_prompt.h"
34 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
35 #include "chrome/common/render_messages.h"
36 #include "chrome/common/url_constants.h"
37 #include "components/google/core/browser/google_util.h"
38 #include "components/variations/variations_http_header_provider.h"
39 #include "content/public/browser/browser_thread.h"
40 #include "content/public/browser/notification_service.h"
41 #include "content/public/browser/render_process_host.h"
42 #include "content/public/browser/render_view_host.h"
43 #include "content/public/browser/resource_context.h"
44 #include "content/public/browser/resource_dispatcher_host.h"
45 #include "content/public/browser/resource_request_info.h"
46 #include "content/public/browser/stream_info.h"
47 #include "content/public/browser/web_contents.h"
48 #include "content/public/common/resource_response.h"
49 #include "net/base/load_flags.h"
50 #include "net/base/load_timing_info.h"
51 #include "net/base/request_priority.h"
52 #include "net/http/http_response_headers.h"
53 #include "net/url_request/url_request.h"
55 #if !defined(DISABLE_NACL)
56 #include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h"
59 #if defined(ENABLE_CONFIGURATION_POLICY)
60 #include "components/policy/core/common/cloud/policy_header_io_helper.h"
63 #if defined(ENABLE_EXTENSIONS)
64 #include "chrome/browser/apps/app_url_redirector.h"
65 #include "chrome/browser/apps/ephemeral_app_throttle.h"
66 #include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
67 #include "chrome/browser/extensions/user_script_listener.h"
68 #include "chrome/common/extensions/manifest_handlers/mime_types_handler.h"
69 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
70 #include "extensions/browser/info_map.h"
71 #include "extensions/common/constants.h"
72 #include "extensions/common/extension_urls.h"
73 #include "extensions/common/user_script.h"
76 #if defined(ENABLE_MANAGED_USERS)
77 #include "chrome/browser/supervised_user/supervised_user_resource_throttle.h"
80 #if defined(USE_SYSTEM_PROTOBUF)
81 #include <google/protobuf/repeated_field.h>
83 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
86 #if defined(OS_ANDROID)
87 #include "chrome/browser/android/intercept_download_resource_throttle.h"
88 #include "chrome/browser/ui/android/infobars/auto_login_prompter.h"
89 #include "components/navigation_interception/intercept_navigation_delegate.h"
92 #if defined(OS_CHROMEOS)
93 #include "chrome/browser/chromeos/login/signin/merge_session_throttle.h"
94 // TODO(oshima): Enable this for other platforms.
95 #include "chrome/browser/renderer_host/offline_resource_throttle.h"
98 using content::BrowserThread
;
99 using content::RenderViewHost
;
100 using content::ResourceDispatcherHostLoginDelegate
;
101 using content::ResourceRequestInfo
;
102 using content::ResourceType
;
104 #if defined(ENABLE_EXTENSIONS)
105 using extensions::Extension
;
106 using extensions::StreamsPrivateAPI
;
109 #if defined(OS_ANDROID)
110 using navigation_interception::InterceptNavigationDelegate
;
115 ExternalProtocolHandler::Delegate
* g_external_protocol_handler_delegate
= NULL
;
117 void NotifyDownloadInitiatedOnUI(int render_process_id
, int render_view_id
) {
118 RenderViewHost
* rvh
= RenderViewHost::FromID(render_process_id
,
123 content::NotificationService::current()->Notify(
124 chrome::NOTIFICATION_DOWNLOAD_INITIATED
,
125 content::Source
<RenderViewHost
>(rvh
),
126 content::NotificationService::NoDetails());
129 prerender::PrerenderManager
* GetPrerenderManager(int render_process_id
,
130 int render_view_id
) {
131 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
133 content::WebContents
* web_contents
=
134 tab_util::GetWebContentsByID(render_process_id
, render_view_id
);
138 content::BrowserContext
* browser_context
= web_contents
->GetBrowserContext();
139 if (!browser_context
)
142 Profile
* profile
= Profile::FromBrowserContext(browser_context
);
146 return prerender::PrerenderManagerFactory::GetForProfile(profile
);
149 void UpdatePrerenderNetworkBytesCallback(int render_process_id
,
152 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
154 content::WebContents
* web_contents
=
155 tab_util::GetWebContentsByID(render_process_id
, render_view_id
);
156 // PrerenderContents::FromWebContents handles the NULL case.
157 prerender::PrerenderContents
* prerender_contents
=
158 prerender::PrerenderContents::FromWebContents(web_contents
);
160 if (prerender_contents
)
161 prerender_contents
->AddNetworkBytes(bytes
);
163 prerender::PrerenderManager
* prerender_manager
=
164 GetPrerenderManager(render_process_id
, render_view_id
);
165 if (prerender_manager
)
166 prerender_manager
->AddProfileNetworkBytesIfEnabled(bytes
);
169 #if defined(ENABLE_EXTENSIONS)
170 void SendExecuteMimeTypeHandlerEvent(scoped_ptr
<content::StreamInfo
> stream
,
171 int64 expected_content_size
,
172 int render_process_id
,
174 const std::string
& extension_id
,
175 const std::string
& view_id
) {
176 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
178 content::WebContents
* web_contents
=
179 tab_util::GetWebContentsByID(render_process_id
, render_view_id
);
183 // If the request was for a prerender, abort the prerender and do not
185 prerender::PrerenderContents
* prerender_contents
=
186 prerender::PrerenderContents::FromWebContents(web_contents
);
187 if (prerender_contents
) {
188 prerender_contents
->Destroy(prerender::FINAL_STATUS_DOWNLOAD
);
193 Profile::FromBrowserContext(web_contents
->GetBrowserContext());
195 StreamsPrivateAPI
* streams_private
= StreamsPrivateAPI::Get(profile
);
196 if (!streams_private
)
198 streams_private
->ExecuteMimeTypeHandler(
199 extension_id
, web_contents
, stream
.Pass(), view_id
,
200 expected_content_size
);
202 #endif // !defined(ENABLE_EXTENSIONS)
204 #if !defined(OS_ANDROID)
205 void LaunchURL(const GURL
& url
, int render_process_id
, int render_view_id
) {
206 // If there is no longer a WebContents, the request may have raced with tab
207 // closing. Don't fire the external request. (It may have been a prerender.)
208 content::WebContents
* web_contents
=
209 tab_util::GetWebContentsByID(render_process_id
, render_view_id
);
213 // Do not launch external requests attached to unswapped prerenders.
214 prerender::PrerenderContents
* prerender_contents
=
215 prerender::PrerenderContents::FromWebContents(web_contents
);
216 if (prerender_contents
) {
217 prerender_contents
->Destroy(prerender::FINAL_STATUS_UNSUPPORTED_SCHEME
);
218 prerender::ReportPrerenderExternalURL();
222 ExternalProtocolHandler::LaunchUrlWithDelegate(
226 g_external_protocol_handler_delegate
);
228 #endif // !defined(OS_ANDROID)
230 #if !defined(DISABLE_NACL)
231 void AppendComponentUpdaterThrottles(
232 net::URLRequest
* request
,
233 content::ResourceContext
* resource_context
,
234 ResourceType resource_type
,
235 ScopedVector
<content::ResourceThrottle
>* throttles
) {
236 const char* crx_id
= NULL
;
237 component_updater::ComponentUpdateService
* cus
=
238 g_browser_process
->component_updater();
241 // Check for PNaCl pexe request.
242 if (resource_type
== content::RESOURCE_TYPE_OBJECT
) {
243 const net::HttpRequestHeaders
& headers
= request
->extra_request_headers();
244 std::string accept_headers
;
245 if (headers
.GetHeader("Accept", &accept_headers
)) {
246 if (accept_headers
.find("application/x-pnacl") != std::string::npos
&&
247 pnacl::NeedsOnDemandUpdate())
248 crx_id
= "hnimpnehoodheedghdeeijklkeaacbdc";
253 // We got a component we need to install, so throttle the resource
254 // until the component is installed.
255 throttles
->push_back(
256 component_updater::GetOnDemandResourceThrottle(cus
, crx_id
));
259 #endif // !defined(DISABLE_NACL)
263 ChromeResourceDispatcherHostDelegate::ChromeResourceDispatcherHostDelegate(
264 prerender::PrerenderTracker
* prerender_tracker
)
265 : download_request_limiter_(g_browser_process
->download_request_limiter()),
266 safe_browsing_(g_browser_process
->safe_browsing_service()),
267 #if defined(ENABLE_EXTENSIONS)
268 user_script_listener_(new extensions::UserScriptListener()),
270 prerender_tracker_(prerender_tracker
) {
273 ChromeResourceDispatcherHostDelegate::~ChromeResourceDispatcherHostDelegate() {
274 #if defined(ENABLE_EXTENSIONS)
275 CHECK(stream_target_info_
.empty());
279 bool ChromeResourceDispatcherHostDelegate::ShouldBeginRequest(
280 const std::string
& method
,
282 ResourceType resource_type
,
283 content::ResourceContext
* resource_context
) {
284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
286 // Handle a PREFETCH resource type. If prefetch is disabled, squelch the
287 // request. Otherwise, do a normal request to warm the cache.
288 if (resource_type
== content::RESOURCE_TYPE_PREFETCH
) {
289 // All PREFETCH requests should be GETs, but be defensive about it.
293 // If prefetch is disabled, kill the request.
294 if (!prefetch::IsPrefetchEnabled(resource_context
))
301 void ChromeResourceDispatcherHostDelegate::RequestBeginning(
302 net::URLRequest
* request
,
303 content::ResourceContext
* resource_context
,
304 content::AppCacheService
* appcache_service
,
305 ResourceType resource_type
,
306 ScopedVector
<content::ResourceThrottle
>* throttles
) {
307 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
308 bool is_prerendering
=
309 info
->GetVisibilityState() == blink::WebPageVisibilityStatePrerender
;
310 if (is_prerendering
) {
311 // Requests with the IGNORE_LIMITS flag set (i.e., sync XHRs)
312 // should remain at MAXIMUM_PRIORITY.
313 if (request
->load_flags() & net::LOAD_IGNORE_LIMITS
) {
314 DCHECK_EQ(request
->priority(), net::MAXIMUM_PRIORITY
);
316 request
->SetPriority(net::IDLE
);
320 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(
323 #if defined(OS_ANDROID)
324 // TODO(davidben): This is insufficient to integrate with prerender properly.
325 // https://crbug.com/370595
326 if (resource_type
== content::RESOURCE_TYPE_MAIN_FRAME
&& !is_prerendering
) {
327 throttles
->push_back(
328 InterceptNavigationDelegate::CreateThrottleFor(request
));
331 if (resource_type
== content::RESOURCE_TYPE_MAIN_FRAME
) {
332 // Redirect some navigations to apps that have registered matching URL
333 // handlers ('url_handlers' in the manifest).
334 content::ResourceThrottle
* url_to_app_throttle
=
335 AppUrlRedirector::MaybeCreateThrottleFor(request
, io_data
);
336 if (url_to_app_throttle
)
337 throttles
->push_back(url_to_app_throttle
);
339 if (!is_prerendering
) {
340 // Experimental: Launch ephemeral apps from search results.
341 content::ResourceThrottle
* ephemeral_app_throttle
=
342 EphemeralAppThrottle::MaybeCreateThrottleForLaunch(
344 if (ephemeral_app_throttle
)
345 throttles
->push_back(ephemeral_app_throttle
);
350 #if defined(OS_CHROMEOS)
351 // Check if we need to add offline throttle. This should be done only
353 if (resource_type
== content::RESOURCE_TYPE_MAIN_FRAME
) {
354 // We check offline first, then check safe browsing so that we still can
355 // block unsafe site after we remove offline page.
356 throttles
->push_back(new OfflineResourceThrottle(request
,
360 // Check if we need to add merge session throttle. This throttle will postpone
361 // loading of main frames and XHR request.
362 if (resource_type
== content::RESOURCE_TYPE_MAIN_FRAME
||
363 resource_type
== content::RESOURCE_TYPE_XHR
) {
364 // Add interstitial page while merge session process (cookie
365 // reconstruction from OAuth2 refresh token in ChromeOS login) is still in
366 // progress while we are attempting to load a google property.
367 if (!MergeSessionThrottle::AreAllSessionMergedAlready() &&
368 request
->url().SchemeIsHTTPOrHTTPS()) {
369 throttles
->push_back(new MergeSessionThrottle(request
, resource_type
));
374 // Don't attempt to append headers to requests that have already started.
375 // TODO(stevet): Remove this once the request ordering issues are resolved
376 // in crbug.com/128048.
377 if (!request
->is_pending()) {
378 net::HttpRequestHeaders headers
;
379 headers
.CopyFrom(request
->extra_request_headers());
380 bool is_off_the_record
= io_data
->IsOffTheRecord();
381 variations::VariationsHttpHeaderProvider::GetInstance()->
382 AppendHeaders(request
->url(),
384 !is_off_the_record
&&
385 io_data
->GetMetricsEnabledStateOnIOThread(),
387 request
->SetExtraRequestHeaders(headers
);
390 #if defined(ENABLE_ONE_CLICK_SIGNIN)
391 AppendChromeSyncGaiaHeader(request
, resource_context
);
394 #if defined(ENABLE_CONFIGURATION_POLICY)
395 if (io_data
->policy_header_helper())
396 io_data
->policy_header_helper()->AddPolicyHeaders(request
->url(), request
);
399 signin::AppendMirrorRequestHeaderIfPossible(
400 request
, GURL() /* redirect_url */, io_data
);
402 AppendStandardResourceThrottles(request
,
406 #if !defined(DISABLE_NACL)
407 if (!is_prerendering
) {
408 AppendComponentUpdaterThrottles(request
,
415 if (io_data
->resource_prefetch_predictor_observer()) {
416 io_data
->resource_prefetch_predictor_observer()->OnRequestStarted(
417 request
, resource_type
, info
->GetChildID(), info
->GetRenderFrameID());
421 void ChromeResourceDispatcherHostDelegate::DownloadStarting(
422 net::URLRequest
* request
,
423 content::ResourceContext
* resource_context
,
427 bool is_content_initiated
,
429 ScopedVector
<content::ResourceThrottle
>* throttles
) {
430 BrowserThread::PostTask(
431 BrowserThread::UI
, FROM_HERE
,
432 base::Bind(&NotifyDownloadInitiatedOnUI
, child_id
, route_id
));
434 // If it's from the web, we don't trust it, so we push the throttle on.
435 if (is_content_initiated
) {
436 throttles
->push_back(
437 new DownloadResourceThrottle(download_request_limiter_
.get(),
442 #if defined(OS_ANDROID)
443 throttles
->push_back(
444 new chrome::InterceptDownloadResourceThrottle(
445 request
, child_id
, route_id
, request_id
));
449 // If this isn't a new request, we've seen this before and added the standard
450 // resource throttles already so no need to add it again.
451 if (!request
->is_pending()) {
452 AppendStandardResourceThrottles(request
,
454 content::RESOURCE_TYPE_MAIN_FRAME
,
459 ResourceDispatcherHostLoginDelegate
*
460 ChromeResourceDispatcherHostDelegate::CreateLoginDelegate(
461 net::AuthChallengeInfo
* auth_info
, net::URLRequest
* request
) {
462 return CreateLoginPrompt(auth_info
, request
);
465 bool ChromeResourceDispatcherHostDelegate::HandleExternalProtocol(
469 #if defined(OS_ANDROID)
470 // Android use a resource throttle to handle external as well as internal
475 #if defined(ENABLE_EXTENSIONS)
476 if (extensions::WebViewRendererState::GetInstance()->IsGuest(child_id
))
479 #endif // defined(ENABLE_EXTENSIONS)
481 BrowserThread::PostTask(BrowserThread::UI
,
483 base::Bind(&LaunchURL
, url
, child_id
, route_id
));
488 void ChromeResourceDispatcherHostDelegate::AppendStandardResourceThrottles(
489 net::URLRequest
* request
,
490 content::ResourceContext
* resource_context
,
491 ResourceType resource_type
,
492 ScopedVector
<content::ResourceThrottle
>* throttles
) {
493 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(resource_context
);
494 #if defined(FULL_SAFE_BROWSING) || defined(MOBILE_SAFE_BROWSING)
495 // Insert safe browsing at the front of the list, so it gets to decide on
497 if (io_data
->safe_browsing_enabled()->GetValue()
498 #if defined(OS_ANDROID)
499 || io_data
->IsDataReductionProxyEnabled()
502 content::ResourceThrottle
* throttle
=
503 SafeBrowsingResourceThrottleFactory::Create(request
,
506 safe_browsing_
.get());
508 throttles
->push_back(throttle
);
512 #if defined(ENABLE_MANAGED_USERS)
513 bool is_subresource_request
=
514 resource_type
!= content::RESOURCE_TYPE_MAIN_FRAME
;
515 throttles
->push_back(new SupervisedUserResourceThrottle(
516 request
, !is_subresource_request
,
517 io_data
->supervised_user_url_filter()));
520 #if defined(ENABLE_EXTENSIONS)
521 content::ResourceThrottle
* throttle
=
522 user_script_listener_
->CreateResourceThrottle(request
->url(),
525 throttles
->push_back(throttle
);
528 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
529 if (info
->GetVisibilityState() == blink::WebPageVisibilityStatePrerender
) {
530 throttles
->push_back(new prerender::PrerenderResourceThrottle(request
));
532 if (prerender_tracker_
->IsPendingSwapRequestOnIOThread(
533 info
->GetChildID(), info
->GetRenderFrameID(), request
->url())) {
534 throttles
->push_back(new prerender::PrerenderPendingSwapThrottle(
535 request
, prerender_tracker_
));
539 #if defined(ENABLE_ONE_CLICK_SIGNIN)
540 void ChromeResourceDispatcherHostDelegate::AppendChromeSyncGaiaHeader(
541 net::URLRequest
* request
,
542 content::ResourceContext
* resource_context
) {
543 static const char kAllowChromeSignIn
[] = "Allow-Chrome-SignIn";
545 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(resource_context
);
546 OneClickSigninHelper::Offer offer
=
547 OneClickSigninHelper::CanOfferOnIOThread(request
, io_data
);
549 case OneClickSigninHelper::CAN_OFFER
:
550 request
->SetExtraRequestHeaderByName(kAllowChromeSignIn
, "1", false);
552 case OneClickSigninHelper::DONT_OFFER
:
553 request
->RemoveRequestHeaderByName(kAllowChromeSignIn
);
555 case OneClickSigninHelper::IGNORE_REQUEST
:
561 bool ChromeResourceDispatcherHostDelegate::ShouldForceDownloadResource(
562 const GURL
& url
, const std::string
& mime_type
) {
563 #if defined(ENABLE_EXTENSIONS)
564 // Special-case user scripts to get downloaded instead of viewed.
565 return extensions::UserScript::IsURLUserScript(url
, mime_type
);
571 bool ChromeResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
572 net::URLRequest
* request
,
573 const std::string
& mime_type
,
575 std::string
* payload
) {
576 #if defined(ENABLE_EXTENSIONS)
577 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
578 ProfileIOData
* io_data
=
579 ProfileIOData::FromResourceContext(info
->GetContext());
580 bool profile_is_off_the_record
= io_data
->IsOffTheRecord();
581 const scoped_refptr
<const extensions::InfoMap
> extension_info_map(
582 io_data
->GetExtensionInfoMap());
583 std::vector
<std::string
> whitelist
= MimeTypesHandler::GetMIMETypeWhitelist();
584 // Go through the white-listed extensions and try to use them to intercept
586 for (size_t i
= 0; i
< whitelist
.size(); ++i
) {
587 const char* extension_id
= whitelist
[i
].c_str();
588 const Extension
* extension
=
589 extension_info_map
->extensions().GetByID(extension_id
);
590 // The white-listed extension may not be installed, so we have to NULL check
593 (profile_is_off_the_record
&&
594 !extension_info_map
->IsIncognitoEnabled(extension_id
))) {
598 MimeTypesHandler
* handler
= MimeTypesHandler::GetHandler(extension
);
599 if (handler
&& handler
->CanHandleMIMEType(mime_type
)) {
600 StreamTargetInfo target_info
;
601 *origin
= Extension::GetBaseURLFromExtensionId(extension_id
);
602 target_info
.extension_id
= extension_id
;
603 if (!handler
->handler_url().empty()) {
604 target_info
.view_id
= base::GenerateGUID();
605 *payload
= origin
->spec() + handler
->handler_url() +
606 "?id=" + target_info
.view_id
;
608 stream_target_info_
[request
] = target_info
;
616 void ChromeResourceDispatcherHostDelegate::OnStreamCreated(
617 net::URLRequest
* request
,
618 scoped_ptr
<content::StreamInfo
> stream
) {
619 #if defined(ENABLE_EXTENSIONS)
620 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
621 std::map
<net::URLRequest
*, StreamTargetInfo
>::iterator ix
=
622 stream_target_info_
.find(request
);
623 CHECK(ix
!= stream_target_info_
.end());
624 content::BrowserThread::PostTask(
625 content::BrowserThread::UI
, FROM_HERE
,
626 base::Bind(&SendExecuteMimeTypeHandlerEvent
, base::Passed(&stream
),
627 request
->GetExpectedContentSize(),
628 info
->GetChildID(), info
->GetRouteID(),
629 ix
->second
.extension_id
, ix
->second
.view_id
));
630 stream_target_info_
.erase(request
);
634 void ChromeResourceDispatcherHostDelegate::OnResponseStarted(
635 net::URLRequest
* request
,
636 content::ResourceContext
* resource_context
,
637 content::ResourceResponse
* response
,
638 IPC::Sender
* sender
) {
639 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
641 #if defined(OS_ANDROID)
642 // See if the response contains the X-Auto-Login header. If so, this was
643 // a request for a login page, and the server is allowing the browser to
644 // suggest auto-login, if available.
645 if (info
->IsMainFrame()) {
646 AutoLoginPrompter::ShowInfoBarIfPossible(request
, info
->GetChildID(),
651 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(resource_context
);
653 #if defined(ENABLE_ONE_CLICK_SIGNIN)
654 // See if the response contains the Google-Accounts-SignIn header. If so,
655 // then the user has just finished signing in, and the server is allowing the
656 // browser to suggest connecting the user's profile to the account.
657 OneClickSigninHelper::ShowInfoBarIfPossible(request
, io_data
,
662 // See if the response contains the X-Chrome-Manage-Accounts header. If so
663 // show the profile avatar bubble so that user can complete signin/out action
665 signin::ProcessMirrorResponseHeaderIfExists(request
, io_data
,
669 // Build in additional protection for the chrome web store origin.
670 #if defined(ENABLE_EXTENSIONS)
671 GURL
webstore_url(extension_urls::GetWebstoreLaunchURL());
672 if (request
->url().DomainIs(webstore_url
.host().c_str())) {
673 net::HttpResponseHeaders
* response_headers
= request
->response_headers();
674 if (!response_headers
->HasHeaderValue("x-frame-options", "deny") &&
675 !response_headers
->HasHeaderValue("x-frame-options", "sameorigin")) {
676 response_headers
->RemoveHeader("x-frame-options");
677 response_headers
->AddHeader("x-frame-options: sameorigin");
682 if (io_data
->resource_prefetch_predictor_observer())
683 io_data
->resource_prefetch_predictor_observer()->OnResponseStarted(request
);
685 // Ignores x-frame-options for the chrome signin UI.
686 const std::string
request_spec(
687 request
->first_party_for_cookies().GetOrigin().spec());
688 #if defined(OS_CHROMEOS)
689 if (request_spec
== chrome::kChromeUIOobeURL
||
690 request_spec
== chrome::kChromeUIChromeSigninURL
) {
692 if (request_spec
== chrome::kChromeUIChromeSigninURL
) {
694 net::HttpResponseHeaders
* response_headers
= request
->response_headers();
695 if (response_headers
&& response_headers
->HasHeader("x-frame-options"))
696 response_headers
->RemoveHeader("x-frame-options");
699 prerender::URLRequestResponseStarted(request
);
702 void ChromeResourceDispatcherHostDelegate::OnRequestRedirected(
703 const GURL
& redirect_url
,
704 net::URLRequest
* request
,
705 content::ResourceContext
* resource_context
,
706 content::ResourceResponse
* response
) {
707 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(resource_context
);
709 #if defined(ENABLE_ONE_CLICK_SIGNIN)
710 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
712 // See if the response contains the Google-Accounts-SignIn header. If so,
713 // then the user has just finished signing in, and the server is allowing the
714 // browser to suggest connecting the user's profile to the account.
715 OneClickSigninHelper::ShowInfoBarIfPossible(request
, io_data
,
718 AppendChromeSyncGaiaHeader(request
, resource_context
);
721 // In the Mirror world, Chrome should append a X-Chrome-Connected header to
722 // all Gaia requests from a connected profile so Gaia could return a 204
723 // response and let Chrome handle the action with native UI. The only
724 // exception is requests from gaia webview, since the native profile
725 // management UI is built on top of it.
726 signin::AppendMirrorRequestHeaderIfPossible(request
, redirect_url
, io_data
);
728 if (io_data
->resource_prefetch_predictor_observer()) {
729 io_data
->resource_prefetch_predictor_observer()->OnRequestRedirected(
730 redirect_url
, request
);
733 #if defined(ENABLE_CONFIGURATION_POLICY)
734 if (io_data
->policy_header_helper())
735 io_data
->policy_header_helper()->AddPolicyHeaders(redirect_url
, request
);
739 // Notification that a request has completed.
740 void ChromeResourceDispatcherHostDelegate::RequestComplete(
741 net::URLRequest
* url_request
) {
742 // Jump on the UI thread and inform the prerender about the bytes.
743 const ResourceRequestInfo
* info
=
744 ResourceRequestInfo::ForRequest(url_request
);
745 if (url_request
&& !url_request
->was_cached()) {
746 BrowserThread::PostTask(BrowserThread::UI
,
748 base::Bind(&UpdatePrerenderNetworkBytesCallback
,
751 url_request
->GetTotalReceivedBytes()));
756 void ChromeResourceDispatcherHostDelegate::
757 SetExternalProtocolHandlerDelegateForTesting(
758 ExternalProtocolHandler::Delegate
* delegate
) {
759 g_external_protocol_handler_delegate
= delegate
;