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/download/download_request_limiter.h"
17 #include "chrome/browser/download/download_resource_throttle.h"
18 #include "chrome/browser/mod_pagespeed/mod_pagespeed_metrics.h"
19 #include "chrome/browser/net/resource_prefetch_predictor_observer.h"
20 #include "chrome/browser/plugins/plugin_prefs.h"
21 #include "chrome/browser/prefetch/prefetch.h"
22 #include "chrome/browser/prerender/prerender_manager.h"
23 #include "chrome/browser/prerender/prerender_manager_factory.h"
24 #include "chrome/browser/prerender/prerender_resource_throttle.h"
25 #include "chrome/browser/prerender/prerender_util.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/profiles/profile_io_data.h"
28 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle_factory.h"
29 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
30 #include "chrome/browser/signin/chrome_signin_helper.h"
31 #include "chrome/browser/tab_contents/tab_util.h"
32 #include "chrome/browser/ui/login/login_prompt.h"
33 #include "chrome/common/chrome_switches.h"
34 #include "chrome/common/url_constants.h"
35 #include "components/content_settings/core/browser/host_content_settings_map.h"
36 #include "components/google/core/browser/google_util.h"
37 #include "components/variations/net/variations_http_header_provider.h"
38 #include "content/public/browser/browser_thread.h"
39 #include "content/public/browser/notification_service.h"
40 #include "content/public/browser/plugin_service.h"
41 #include "content/public/browser/plugin_service_filter.h"
42 #include "content/public/browser/render_process_host.h"
43 #include "content/public/browser/render_view_host.h"
44 #include "content/public/browser/resource_context.h"
45 #include "content/public/browser/resource_dispatcher_host.h"
46 #include "content/public/browser/resource_request_info.h"
47 #include "content/public/browser/service_worker_context.h"
48 #include "content/public/browser/stream_info.h"
49 #include "content/public/browser/web_contents.h"
50 #include "content/public/common/resource_response.h"
51 #include "net/base/load_flags.h"
52 #include "net/base/load_timing_info.h"
53 #include "net/base/request_priority.h"
54 #include "net/http/http_response_headers.h"
55 #include "net/url_request/url_request.h"
57 #if !defined(DISABLE_NACL)
58 #include "chrome/browser/component_updater/pnacl_component_installer.h"
61 #if defined(ENABLE_CONFIGURATION_POLICY)
62 #include "components/policy/core/common/cloud/policy_header_io_helper.h"
65 #if defined(ENABLE_EXTENSIONS)
66 #include "chrome/browser/apps/app_url_redirector.h"
67 #include "chrome/browser/apps/ephemeral_app_throttle.h"
68 #include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
69 #include "chrome/browser/extensions/user_script_listener.h"
70 #include "extensions/browser/extension_throttle_manager.h"
71 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
72 #include "extensions/browser/info_map.h"
73 #include "extensions/common/constants.h"
74 #include "extensions/common/extension_urls.h"
75 #include "extensions/common/manifest_handlers/mime_types_handler.h"
76 #include "extensions/common/user_script.h"
79 #if defined(ENABLE_SUPERVISED_USERS)
80 #include "chrome/browser/supervised_user/supervised_user_resource_throttle.h"
83 #if defined(USE_SYSTEM_PROTOBUF)
84 #include <google/protobuf/repeated_field.h>
86 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
89 #if defined(OS_ANDROID)
90 #include "chrome/browser/android/intercept_download_resource_throttle.h"
91 #include "components/navigation_interception/intercept_navigation_delegate.h"
94 #if defined(ENABLE_DATA_REDUCTION_PROXY_DEBUGGING)
95 #include "components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_resource_throttle.h"
98 #if defined(OS_CHROMEOS)
99 #include "chrome/browser/chromeos/login/signin/merge_session_throttle.h"
102 using content::BrowserThread
;
103 using content::RenderViewHost
;
104 using content::ResourceDispatcherHostLoginDelegate
;
105 using content::ResourceRequestInfo
;
106 using content::ResourceType
;
108 #if defined(ENABLE_EXTENSIONS)
109 using extensions::Extension
;
110 using extensions::StreamsPrivateAPI
;
113 #if defined(OS_ANDROID)
114 using navigation_interception::InterceptNavigationDelegate
;
119 ExternalProtocolHandler::Delegate
* g_external_protocol_handler_delegate
= NULL
;
121 void NotifyDownloadInitiatedOnUI(int render_process_id
, int render_view_id
) {
122 RenderViewHost
* rvh
= RenderViewHost::FromID(render_process_id
,
127 content::NotificationService::current()->Notify(
128 chrome::NOTIFICATION_DOWNLOAD_INITIATED
,
129 content::Source
<RenderViewHost
>(rvh
),
130 content::NotificationService::NoDetails());
133 prerender::PrerenderManager
* GetPrerenderManager(int render_process_id
,
134 int render_view_id
) {
135 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
137 content::WebContents
* web_contents
=
138 tab_util::GetWebContentsByID(render_process_id
, render_view_id
);
142 content::BrowserContext
* browser_context
= web_contents
->GetBrowserContext();
143 if (!browser_context
)
146 Profile
* profile
= Profile::FromBrowserContext(browser_context
);
150 return prerender::PrerenderManagerFactory::GetForProfile(profile
);
153 void UpdatePrerenderNetworkBytesCallback(int render_process_id
,
156 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
158 content::WebContents
* web_contents
=
159 tab_util::GetWebContentsByID(render_process_id
, render_view_id
);
160 // PrerenderContents::FromWebContents handles the NULL case.
161 prerender::PrerenderContents
* prerender_contents
=
162 prerender::PrerenderContents::FromWebContents(web_contents
);
164 if (prerender_contents
)
165 prerender_contents
->AddNetworkBytes(bytes
);
167 prerender::PrerenderManager
* prerender_manager
=
168 GetPrerenderManager(render_process_id
, render_view_id
);
169 if (prerender_manager
)
170 prerender_manager
->AddProfileNetworkBytesIfEnabled(bytes
);
173 #if defined(ENABLE_EXTENSIONS)
174 void SendExecuteMimeTypeHandlerEvent(scoped_ptr
<content::StreamInfo
> stream
,
175 int64 expected_content_size
,
176 int render_process_id
,
178 const std::string
& extension_id
,
179 const std::string
& view_id
,
181 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
183 content::WebContents
* web_contents
=
184 tab_util::GetWebContentsByFrameID(render_process_id
, render_frame_id
);
188 // If the request was for a prerender, abort the prerender and do not
190 prerender::PrerenderContents
* prerender_contents
=
191 prerender::PrerenderContents::FromWebContents(web_contents
);
192 if (prerender_contents
) {
193 prerender_contents
->Destroy(prerender::FINAL_STATUS_DOWNLOAD
);
198 Profile::FromBrowserContext(web_contents
->GetBrowserContext());
200 StreamsPrivateAPI
* streams_private
= StreamsPrivateAPI::Get(profile
);
201 if (!streams_private
)
203 streams_private
->ExecuteMimeTypeHandler(
204 extension_id
, web_contents
, stream
.Pass(), view_id
, expected_content_size
,
205 embedded
, render_process_id
, render_frame_id
);
207 #endif // !defined(ENABLE_EXTENSIONS)
211 int render_process_id
,
213 ui::PageTransition page_transition
,
214 bool has_user_gesture
) {
215 // If there is no longer a WebContents, the request may have raced with tab
216 // closing. Don't fire the external request. (It may have been a prerender.)
217 content::WebContents
* web_contents
=
218 tab_util::GetWebContentsByID(render_process_id
, render_view_id
);
222 // Do not launch external requests attached to unswapped prerenders.
223 prerender::PrerenderContents
* prerender_contents
=
224 prerender::PrerenderContents::FromWebContents(web_contents
);
225 if (prerender_contents
) {
226 prerender_contents
->Destroy(prerender::FINAL_STATUS_UNSUPPORTED_SCHEME
);
227 prerender::ReportPrerenderExternalURL();
231 ExternalProtocolHandler::LaunchUrlWithDelegate(
237 g_external_protocol_handler_delegate
);
240 #if !defined(DISABLE_NACL)
241 void AppendComponentUpdaterThrottles(
242 net::URLRequest
* request
,
243 content::ResourceContext
* resource_context
,
244 ResourceType resource_type
,
245 ScopedVector
<content::ResourceThrottle
>* throttles
) {
246 const char* crx_id
= NULL
;
247 component_updater::ComponentUpdateService
* cus
=
248 g_browser_process
->component_updater();
251 // Check for PNaCl pexe request.
252 if (resource_type
== content::RESOURCE_TYPE_OBJECT
) {
253 const net::HttpRequestHeaders
& headers
= request
->extra_request_headers();
254 std::string accept_headers
;
255 if (headers
.GetHeader("Accept", &accept_headers
)) {
256 if (accept_headers
.find("application/x-pnacl") != std::string::npos
&&
257 pnacl::NeedsOnDemandUpdate())
258 crx_id
= "hnimpnehoodheedghdeeijklkeaacbdc";
263 // We got a component we need to install, so throttle the resource
264 // until the component is installed.
265 throttles
->push_back(
266 component_updater::GetOnDemandResourceThrottle(cus
, crx_id
));
269 #endif // !defined(DISABLE_NACL)
273 ChromeResourceDispatcherHostDelegate::ChromeResourceDispatcherHostDelegate()
274 : download_request_limiter_(g_browser_process
->download_request_limiter()),
275 safe_browsing_(g_browser_process
->safe_browsing_service())
276 #if defined(ENABLE_EXTENSIONS)
277 , user_script_listener_(new extensions::UserScriptListener())
280 BrowserThread::PostTask(
283 base::Bind(content::ServiceWorkerContext::AddExcludedHeadersForFetchEvent
,
284 variations::VariationsHttpHeaderProvider::GetInstance()
285 ->GetVariationHeaderNames()));
288 ChromeResourceDispatcherHostDelegate::~ChromeResourceDispatcherHostDelegate() {
289 #if defined(ENABLE_EXTENSIONS)
290 CHECK(stream_target_info_
.empty());
294 bool ChromeResourceDispatcherHostDelegate::ShouldBeginRequest(
295 const std::string
& method
,
297 ResourceType resource_type
,
298 content::ResourceContext
* resource_context
) {
299 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
301 // Handle a PREFETCH resource type. If prefetch is disabled, squelch the
302 // request. Otherwise, do a normal request to warm the cache.
303 if (resource_type
== content::RESOURCE_TYPE_PREFETCH
) {
304 // All PREFETCH requests should be GETs, but be defensive about it.
308 // If prefetch is disabled, kill the request.
309 if (!prefetch::IsPrefetchEnabled(resource_context
))
316 void ChromeResourceDispatcherHostDelegate::RequestBeginning(
317 net::URLRequest
* request
,
318 content::ResourceContext
* resource_context
,
319 content::AppCacheService
* appcache_service
,
320 ResourceType resource_type
,
321 ScopedVector
<content::ResourceThrottle
>* throttles
) {
322 if (safe_browsing_
.get())
323 safe_browsing_
->OnResourceRequest(request
);
325 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
326 bool is_prerendering
=
327 info
->GetVisibilityState() == blink::WebPageVisibilityStatePrerender
;
328 if (is_prerendering
) {
329 // Requests with the IGNORE_LIMITS flag set (i.e., sync XHRs)
330 // should remain at MAXIMUM_PRIORITY.
331 if (request
->load_flags() & net::LOAD_IGNORE_LIMITS
) {
332 DCHECK_EQ(request
->priority(), net::MAXIMUM_PRIORITY
);
334 request
->SetPriority(net::IDLE
);
338 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(
341 #if defined(OS_ANDROID)
342 // TODO(davidben): This is insufficient to integrate with prerender properly.
343 // https://crbug.com/370595
344 if (!is_prerendering
) {
345 if (resource_type
== content::RESOURCE_TYPE_MAIN_FRAME
) {
346 throttles
->push_back(
347 InterceptNavigationDelegate::CreateThrottleFor(request
));
349 InterceptNavigationDelegate::UpdateUserGestureCarryoverInfo(request
);
353 if (resource_type
== content::RESOURCE_TYPE_MAIN_FRAME
) {
354 // Redirect some navigations to apps that have registered matching URL
355 // handlers ('url_handlers' in the manifest).
356 content::ResourceThrottle
* url_to_app_throttle
=
357 AppUrlRedirector::MaybeCreateThrottleFor(request
, io_data
);
358 if (url_to_app_throttle
)
359 throttles
->push_back(url_to_app_throttle
);
361 if (!is_prerendering
) {
362 // Experimental: Launch ephemeral apps from search results.
363 content::ResourceThrottle
* ephemeral_app_throttle
=
364 EphemeralAppThrottle::MaybeCreateThrottleForLaunch(
366 if (ephemeral_app_throttle
)
367 throttles
->push_back(ephemeral_app_throttle
);
372 #if defined(OS_CHROMEOS)
373 // Check if we need to add merge session throttle. This throttle will postpone
374 // loading of main frames and XHR request.
375 if (resource_type
== content::RESOURCE_TYPE_MAIN_FRAME
||
376 resource_type
== content::RESOURCE_TYPE_XHR
) {
377 // Add interstitial page while merge session process (cookie
378 // reconstruction from OAuth2 refresh token in ChromeOS login) is still in
379 // progress while we are attempting to load a google property.
380 if (!MergeSessionThrottle::AreAllSessionMergedAlready() &&
381 request
->url().SchemeIsHTTPOrHTTPS()) {
382 throttles
->push_back(new MergeSessionThrottle(request
, resource_type
));
387 // Don't attempt to append headers to requests that have already started.
388 // TODO(stevet): Remove this once the request ordering issues are resolved
389 // in crbug.com/128048.
390 if (!request
->is_pending()) {
391 net::HttpRequestHeaders headers
;
392 headers
.CopyFrom(request
->extra_request_headers());
393 bool is_off_the_record
= io_data
->IsOffTheRecord();
394 variations::VariationsHttpHeaderProvider::GetInstance()->
395 AppendHeaders(request
->url(),
397 !is_off_the_record
&&
398 io_data
->GetMetricsEnabledStateOnIOThread(),
400 request
->SetExtraRequestHeaders(headers
);
403 #if defined(ENABLE_CONFIGURATION_POLICY)
404 if (io_data
->policy_header_helper())
405 io_data
->policy_header_helper()->AddPolicyHeaders(request
->url(), request
);
408 signin::AppendMirrorRequestHeaderHelper(request
, GURL() /* redirect_url */,
409 io_data
, info
->GetChildID(),
412 AppendStandardResourceThrottles(request
,
416 #if !defined(DISABLE_NACL)
417 if (!is_prerendering
) {
418 AppendComponentUpdaterThrottles(request
,
425 if (io_data
->resource_prefetch_predictor_observer()) {
426 io_data
->resource_prefetch_predictor_observer()->OnRequestStarted(
427 request
, resource_type
, info
->GetChildID(), info
->GetRenderFrameID());
431 void ChromeResourceDispatcherHostDelegate::DownloadStarting(
432 net::URLRequest
* request
,
433 content::ResourceContext
* resource_context
,
437 bool is_content_initiated
,
439 ScopedVector
<content::ResourceThrottle
>* throttles
) {
440 BrowserThread::PostTask(
441 BrowserThread::UI
, FROM_HERE
,
442 base::Bind(&NotifyDownloadInitiatedOnUI
, child_id
, route_id
));
444 // If it's from the web, we don't trust it, so we push the throttle on.
445 if (is_content_initiated
) {
446 throttles
->push_back(new DownloadResourceThrottle(
447 download_request_limiter_
, child_id
, route_id
, request
->url(),
449 #if defined(OS_ANDROID)
450 throttles
->push_back(
451 new chrome::InterceptDownloadResourceThrottle(
452 request
, child_id
, route_id
, request_id
));
456 // If this isn't a new request, we've seen this before and added the standard
457 // resource throttles already so no need to add it again.
458 if (!request
->is_pending()) {
459 AppendStandardResourceThrottles(request
,
461 content::RESOURCE_TYPE_MAIN_FRAME
,
466 ResourceDispatcherHostLoginDelegate
*
467 ChromeResourceDispatcherHostDelegate::CreateLoginDelegate(
468 net::AuthChallengeInfo
* auth_info
, net::URLRequest
* request
) {
469 return CreateLoginPrompt(auth_info
, request
);
472 bool ChromeResourceDispatcherHostDelegate::HandleExternalProtocol(
477 ui::PageTransition page_transition
,
478 bool has_user_gesture
) {
479 #if defined(ENABLE_EXTENSIONS)
480 // External protocols are disabled for guests. An exception is made for the
481 // "mailto" protocol, so that pages that utilize it work properly in a
483 if (extensions::WebViewRendererState::GetInstance()->IsGuest(child_id
) &&
484 !url
.SchemeIs(url::kMailToScheme
)) {
487 #endif // defined(ENABLE_EXTENSIONS)
489 #if defined(OS_ANDROID)
490 // Main frame external protocols are handled by
491 // InterceptNavigationResourceThrottle.
494 #endif // defined(ANDROID)
496 BrowserThread::PostTask(
499 base::Bind(&LaunchURL
, url
, child_id
, route_id
, page_transition
,
504 void ChromeResourceDispatcherHostDelegate::AppendStandardResourceThrottles(
505 net::URLRequest
* request
,
506 content::ResourceContext
* resource_context
,
507 ResourceType resource_type
,
508 ScopedVector
<content::ResourceThrottle
>* throttles
) {
509 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(resource_context
);
510 #if defined(SAFE_BROWSING_SERVICE)
511 // Insert safe browsing at the front of the list, so it gets to decide on
513 if (io_data
->safe_browsing_enabled()->GetValue()
514 #if defined(OS_ANDROID)
515 || io_data
->IsDataReductionProxyEnabled()
518 content::ResourceThrottle
* throttle
=
519 SafeBrowsingResourceThrottleFactory::Create(request
,
522 safe_browsing_
.get());
524 throttles
->push_back(throttle
);
528 #if defined(ENABLE_DATA_REDUCTION_PROXY_DEBUGGING)
529 scoped_ptr
<content::ResourceThrottle
> data_reduction_proxy_throttle
=
530 data_reduction_proxy::DataReductionProxyDebugResourceThrottle::
532 request
, resource_type
, io_data
->data_reduction_proxy_io_data());
533 if (data_reduction_proxy_throttle
)
534 throttles
->push_back(data_reduction_proxy_throttle
.Pass());
537 #if defined(ENABLE_SUPERVISED_USERS)
538 bool is_subresource_request
=
539 resource_type
!= content::RESOURCE_TYPE_MAIN_FRAME
;
540 throttles
->push_back(new SupervisedUserResourceThrottle(
541 request
, !is_subresource_request
,
542 io_data
->supervised_user_url_filter()));
545 #if defined(ENABLE_EXTENSIONS)
546 content::ResourceThrottle
* wait_for_extensions_init_throttle
=
547 user_script_listener_
->CreateResourceThrottle(request
->url(),
549 if (wait_for_extensions_init_throttle
)
550 throttles
->push_back(wait_for_extensions_init_throttle
);
552 extensions::ExtensionThrottleManager
* extension_throttle_manager
=
553 io_data
->GetExtensionThrottleManager();
554 if (extension_throttle_manager
) {
555 scoped_ptr
<content::ResourceThrottle
> extension_throttle
=
556 extension_throttle_manager
->MaybeCreateThrottle(request
);
557 if (extension_throttle
)
558 throttles
->push_back(extension_throttle
.release());
562 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
563 if (info
->GetVisibilityState() == blink::WebPageVisibilityStatePrerender
) {
564 throttles
->push_back(new prerender::PrerenderResourceThrottle(request
));
568 bool ChromeResourceDispatcherHostDelegate::ShouldForceDownloadResource(
569 const GURL
& url
, const std::string
& mime_type
) {
570 #if defined(ENABLE_EXTENSIONS)
571 // Special-case user scripts to get downloaded instead of viewed.
572 return extensions::UserScript::IsURLUserScript(url
, mime_type
);
578 bool ChromeResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
579 net::URLRequest
* request
,
580 const base::FilePath
& plugin_path
,
581 const std::string
& mime_type
,
583 std::string
* payload
) {
584 #if defined(ENABLE_EXTENSIONS)
585 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
586 ProfileIOData
* io_data
=
587 ProfileIOData::FromResourceContext(info
->GetContext());
588 bool profile_is_off_the_record
= io_data
->IsOffTheRecord();
589 const scoped_refptr
<const extensions::InfoMap
> extension_info_map(
590 io_data
->GetExtensionInfoMap());
591 std::vector
<std::string
> whitelist
= MimeTypesHandler::GetMIMETypeWhitelist();
592 // Go through the white-listed extensions and try to use them to intercept
594 for (const std::string
& extension_id
: whitelist
) {
595 const Extension
* extension
=
596 extension_info_map
->extensions().GetByID(extension_id
);
597 // The white-listed extension may not be installed, so we have to NULL check
600 (profile_is_off_the_record
&&
601 !extension_info_map
->IsIncognitoEnabled(extension_id
))) {
604 MimeTypesHandler
* handler
= MimeTypesHandler::GetHandler(extension
);
608 // If a plugin path is provided then a stream is being intercepted for the
609 // mimeHandlerPrivate API. Otherwise a stream is being intercepted for the
610 // streamsPrivate API.
611 if (!plugin_path
.empty()) {
612 if (handler
->HasPlugin() && plugin_path
== handler
->GetPluginPath()) {
613 StreamTargetInfo target_info
;
614 *origin
= Extension::GetBaseURLFromExtensionId(extension_id
);
615 target_info
.extension_id
= extension_id
;
616 target_info
.view_id
= base::GenerateGUID();
617 *payload
= target_info
.view_id
;
618 stream_target_info_
[request
] = target_info
;
622 if (!handler
->HasPlugin() && handler
->CanHandleMIMEType(mime_type
)) {
623 StreamTargetInfo target_info
;
624 *origin
= Extension::GetBaseURLFromExtensionId(extension_id
);
625 target_info
.extension_id
= extension_id
;
626 stream_target_info_
[request
] = target_info
;
635 void ChromeResourceDispatcherHostDelegate::OnStreamCreated(
636 net::URLRequest
* request
,
637 scoped_ptr
<content::StreamInfo
> stream
) {
638 #if defined(ENABLE_EXTENSIONS)
639 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
640 std::map
<net::URLRequest
*, StreamTargetInfo
>::iterator ix
=
641 stream_target_info_
.find(request
);
642 CHECK(ix
!= stream_target_info_
.end());
643 bool embedded
= info
->GetResourceType() != content::RESOURCE_TYPE_MAIN_FRAME
;
644 content::BrowserThread::PostTask(
645 content::BrowserThread::UI
, FROM_HERE
,
646 base::Bind(&SendExecuteMimeTypeHandlerEvent
, base::Passed(&stream
),
647 request
->GetExpectedContentSize(), info
->GetChildID(),
648 info
->GetRenderFrameID(), ix
->second
.extension_id
,
649 ix
->second
.view_id
, embedded
));
650 stream_target_info_
.erase(request
);
654 void ChromeResourceDispatcherHostDelegate::OnResponseStarted(
655 net::URLRequest
* request
,
656 content::ResourceContext
* resource_context
,
657 content::ResourceResponse
* response
,
658 IPC::Sender
* sender
) {
659 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
660 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(resource_context
);
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 // Built-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().SchemeIsHTTPOrHTTPS() &&
673 request
->url().DomainIs(webstore_url
.host().c_str())) {
674 net::HttpResponseHeaders
* response_headers
= request
->response_headers();
675 if (response_headers
&&
676 !response_headers
->HasHeaderValue("x-frame-options", "deny") &&
677 !response_headers
->HasHeaderValue("x-frame-options", "sameorigin")) {
678 response_headers
->RemoveHeader("x-frame-options");
679 response_headers
->AddHeader("x-frame-options: sameorigin");
684 if (io_data
->resource_prefetch_predictor_observer())
685 io_data
->resource_prefetch_predictor_observer()->OnResponseStarted(request
);
687 // Ignores x-frame-options for the chrome signin UI.
688 const std::string
request_spec(
689 request
->first_party_for_cookies().GetOrigin().spec());
690 #if defined(OS_CHROMEOS)
691 if (request_spec
== chrome::kChromeUIOobeURL
||
692 request_spec
== chrome::kChromeUIChromeSigninURL
) {
694 if (request_spec
== chrome::kChromeUIChromeSigninURL
) {
696 net::HttpResponseHeaders
* response_headers
= request
->response_headers();
697 if (response_headers
&& response_headers
->HasHeader("x-frame-options"))
698 response_headers
->RemoveHeader("x-frame-options");
701 mod_pagespeed::RecordMetrics(info
->GetResourceType(), request
->url(),
702 request
->response_headers());
705 void ChromeResourceDispatcherHostDelegate::OnRequestRedirected(
706 const GURL
& redirect_url
,
707 net::URLRequest
* request
,
708 content::ResourceContext
* resource_context
,
709 content::ResourceResponse
* response
) {
710 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(resource_context
);
712 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(request
);
714 // In the Mirror world, Chrome should append a X-Chrome-Connected header to
715 // all Gaia requests from a connected profile so Gaia could return a 204
716 // response and let Chrome handle the action with native UI. The only
717 // exception is requests from gaia webview, since the native profile
718 // management UI is built on top of it.
719 signin::AppendMirrorRequestHeaderHelper(
720 request
, redirect_url
, io_data
, info
->GetChildID(), info
->GetRouteID());
722 if (io_data
->resource_prefetch_predictor_observer()) {
723 io_data
->resource_prefetch_predictor_observer()->OnRequestRedirected(
724 redirect_url
, request
);
727 #if defined(ENABLE_CONFIGURATION_POLICY)
728 if (io_data
->policy_header_helper())
729 io_data
->policy_header_helper()->AddPolicyHeaders(redirect_url
, request
);
733 // Notification that a request has completed.
734 void ChromeResourceDispatcherHostDelegate::RequestComplete(
735 net::URLRequest
* url_request
) {
736 // Jump on the UI thread and inform the prerender about the bytes.
737 const ResourceRequestInfo
* info
=
738 ResourceRequestInfo::ForRequest(url_request
);
739 if (url_request
&& !url_request
->was_cached()) {
740 BrowserThread::PostTask(BrowserThread::UI
,
742 base::Bind(&UpdatePrerenderNetworkBytesCallback
,
745 url_request
->GetTotalReceivedBytes()));
750 void ChromeResourceDispatcherHostDelegate::
751 SetExternalProtocolHandlerDelegateForTesting(
752 ExternalProtocolHandler::Delegate
* delegate
) {
753 g_external_protocol_handler_delegate
= delegate
;