Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / renderer_host / chrome_resource_dispatcher_host_delegate.cc
blob5ddf0e8d3de684418977cc47122d768a4a5f362d
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"
7 #include <string>
8 #include <vector>
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/data_reduction_proxy_resource_throttle_android.h"
29 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h"
30 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
31 #include "chrome/browser/signin/chrome_signin_helper.h"
32 #include "chrome/browser/tab_contents/tab_util.h"
33 #include "chrome/browser/ui/login/login_prompt.h"
34 #include "chrome/common/chrome_switches.h"
35 #include "chrome/common/url_constants.h"
36 #include "components/content_settings/core/browser/host_content_settings_map.h"
37 #include "components/google/core/browser/google_util.h"
38 #include "components/variations/net/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/plugin_service.h"
42 #include "content/public/browser/plugin_service_filter.h"
43 #include "content/public/browser/render_process_host.h"
44 #include "content/public/browser/render_view_host.h"
45 #include "content/public/browser/resource_context.h"
46 #include "content/public/browser/resource_dispatcher_host.h"
47 #include "content/public/browser/resource_request_info.h"
48 #include "content/public/browser/service_worker_context.h"
49 #include "content/public/browser/stream_info.h"
50 #include "content/public/browser/web_contents.h"
51 #include "content/public/common/resource_response.h"
52 #include "net/base/load_flags.h"
53 #include "net/base/load_timing_info.h"
54 #include "net/base/request_priority.h"
55 #include "net/http/http_response_headers.h"
56 #include "net/url_request/url_request.h"
58 #if !defined(DISABLE_NACL)
59 #include "chrome/browser/component_updater/pnacl_component_installer.h"
60 #endif
62 #if defined(ENABLE_CONFIGURATION_POLICY)
63 #include "components/policy/core/common/cloud/policy_header_io_helper.h"
64 #endif
66 #if defined(ENABLE_EXTENSIONS)
67 #include "chrome/browser/apps/app_url_redirector.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"
77 #endif
79 #if defined(ENABLE_SUPERVISED_USERS)
80 #include "chrome/browser/supervised_user/supervised_user_resource_throttle.h"
81 #endif
83 #if defined(USE_SYSTEM_PROTOBUF)
84 #include <google/protobuf/repeated_field.h>
85 #else
86 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
87 #endif
89 #if defined(OS_ANDROID)
90 #include "chrome/browser/android/intercept_download_resource_throttle.h"
91 #include "components/navigation_interception/intercept_navigation_delegate.h"
92 #endif
94 #if defined(ENABLE_DATA_REDUCTION_PROXY_DEBUGGING)
95 #include "components/data_reduction_proxy/content/browser/data_reduction_proxy_debug_resource_throttle.h"
96 #endif
98 #if defined(OS_CHROMEOS)
99 #include "chrome/browser/chromeos/login/signin/merge_session_throttle.h"
100 #endif
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;
111 #endif
113 #if defined(OS_ANDROID)
114 using navigation_interception::InterceptNavigationDelegate;
115 #endif
117 namespace {
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,
123 render_view_id);
124 if (!rvh)
125 return;
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);
139 if (!web_contents)
140 return NULL;
142 content::BrowserContext* browser_context = web_contents->GetBrowserContext();
143 if (!browser_context)
144 return NULL;
146 Profile* profile = Profile::FromBrowserContext(browser_context);
147 if (!profile)
148 return NULL;
150 return prerender::PrerenderManagerFactory::GetForProfile(profile);
153 void UpdatePrerenderNetworkBytesCallback(int render_process_id,
154 int render_view_id,
155 int64 bytes) {
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,
177 int render_frame_id,
178 const std::string& extension_id,
179 const std::string& view_id,
180 bool embedded) {
181 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
183 content::WebContents* web_contents =
184 tab_util::GetWebContentsByFrameID(render_process_id, render_frame_id);
185 if (!web_contents)
186 return;
188 // If the request was for a prerender, abort the prerender and do not
189 // continue.
190 prerender::PrerenderContents* prerender_contents =
191 prerender::PrerenderContents::FromWebContents(web_contents);
192 if (prerender_contents) {
193 prerender_contents->Destroy(prerender::FINAL_STATUS_DOWNLOAD);
194 return;
197 Profile* profile =
198 Profile::FromBrowserContext(web_contents->GetBrowserContext());
200 StreamsPrivateAPI* streams_private = StreamsPrivateAPI::Get(profile);
201 if (!streams_private)
202 return;
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)
209 void LaunchURL(
210 const GURL& url,
211 int render_process_id,
212 int render_view_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);
219 if (!web_contents)
220 return;
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();
228 return;
231 ExternalProtocolHandler::LaunchUrlWithDelegate(
232 url,
233 render_process_id,
234 render_view_id,
235 page_transition,
236 has_user_gesture,
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();
249 if (!cus)
250 return;
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";
262 if (crx_id) {
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)
271 } // namespace
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())
278 #endif
280 BrowserThread::PostTask(
281 BrowserThread::IO,
282 FROM_HERE,
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());
291 #endif
294 bool ChromeResourceDispatcherHostDelegate::ShouldBeginRequest(
295 const std::string& method,
296 const GURL& url,
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.
305 if (method != "GET")
306 return false;
308 // If prefetch is disabled, kill the request.
309 if (!prefetch::IsPrefetchEnabled(resource_context))
310 return false;
313 return true;
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);
333 } else {
334 request->SetPriority(net::IDLE);
338 ProfileIOData* io_data = ProfileIOData::FromResourceContext(
339 resource_context);
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));
348 } else {
349 InterceptNavigationDelegate::UpdateUserGestureCarryoverInfo(request);
352 #else
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 #endif
363 #if defined(OS_CHROMEOS)
364 // Check if we need to add merge session throttle. This throttle will postpone
365 // loading of main frames and XHR request.
366 if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME ||
367 resource_type == content::RESOURCE_TYPE_XHR) {
368 // Add interstitial page while merge session process (cookie
369 // reconstruction from OAuth2 refresh token in ChromeOS login) is still in
370 // progress while we are attempting to load a google property.
371 if (!MergeSessionThrottle::AreAllSessionMergedAlready() &&
372 request->url().SchemeIsHTTPOrHTTPS()) {
373 throttles->push_back(new MergeSessionThrottle(request, resource_type));
376 #endif
378 // Don't attempt to append headers to requests that have already started.
379 // TODO(stevet): Remove this once the request ordering issues are resolved
380 // in crbug.com/128048.
381 if (!request->is_pending()) {
382 net::HttpRequestHeaders headers;
383 headers.CopyFrom(request->extra_request_headers());
384 bool is_off_the_record = io_data->IsOffTheRecord();
385 variations::VariationsHttpHeaderProvider::GetInstance()->
386 AppendHeaders(request->url(),
387 is_off_the_record,
388 !is_off_the_record &&
389 io_data->GetMetricsEnabledStateOnIOThread(),
390 &headers);
391 request->SetExtraRequestHeaders(headers);
394 #if defined(ENABLE_CONFIGURATION_POLICY)
395 if (io_data->policy_header_helper())
396 io_data->policy_header_helper()->AddPolicyHeaders(request->url(), request);
397 #endif
399 signin::AppendMirrorRequestHeaderHelper(request, GURL() /* redirect_url */,
400 io_data, info->GetChildID(),
401 info->GetRouteID());
403 AppendStandardResourceThrottles(request,
404 resource_context,
405 resource_type,
406 throttles);
407 #if !defined(DISABLE_NACL)
408 if (!is_prerendering) {
409 AppendComponentUpdaterThrottles(request,
410 resource_context,
411 resource_type,
412 throttles);
414 #endif
416 if (io_data->resource_prefetch_predictor_observer()) {
417 io_data->resource_prefetch_predictor_observer()->OnRequestStarted(
418 request, resource_type, info->GetChildID(), info->GetRenderFrameID());
422 void ChromeResourceDispatcherHostDelegate::DownloadStarting(
423 net::URLRequest* request,
424 content::ResourceContext* resource_context,
425 int child_id,
426 int route_id,
427 int request_id,
428 bool is_content_initiated,
429 bool must_download,
430 ScopedVector<content::ResourceThrottle>* throttles) {
431 BrowserThread::PostTask(
432 BrowserThread::UI, FROM_HERE,
433 base::Bind(&NotifyDownloadInitiatedOnUI, child_id, route_id));
435 // If it's from the web, we don't trust it, so we push the throttle on.
436 if (is_content_initiated) {
437 throttles->push_back(new DownloadResourceThrottle(
438 download_request_limiter_, child_id, route_id, request->url(),
439 request->method()));
440 #if defined(OS_ANDROID)
441 throttles->push_back(
442 new chrome::InterceptDownloadResourceThrottle(
443 request, child_id, route_id, request_id));
444 #endif
447 // If this isn't a new request, we've seen this before and added the standard
448 // resource throttles already so no need to add it again.
449 if (!request->is_pending()) {
450 AppendStandardResourceThrottles(request,
451 resource_context,
452 content::RESOURCE_TYPE_MAIN_FRAME,
453 throttles);
457 ResourceDispatcherHostLoginDelegate*
458 ChromeResourceDispatcherHostDelegate::CreateLoginDelegate(
459 net::AuthChallengeInfo* auth_info, net::URLRequest* request) {
460 return CreateLoginPrompt(auth_info, request);
463 bool ChromeResourceDispatcherHostDelegate::HandleExternalProtocol(
464 const GURL& url,
465 int child_id,
466 int route_id,
467 bool is_main_frame,
468 ui::PageTransition page_transition,
469 bool has_user_gesture) {
470 #if defined(ENABLE_EXTENSIONS)
471 // External protocols are disabled for guests. An exception is made for the
472 // "mailto" protocol, so that pages that utilize it work properly in a
473 // WebView.
474 if (extensions::WebViewRendererState::GetInstance()->IsGuest(child_id) &&
475 !url.SchemeIs(url::kMailToScheme)) {
476 return false;
478 #endif // defined(ENABLE_EXTENSIONS)
480 #if defined(OS_ANDROID)
481 // Main frame external protocols are handled by
482 // InterceptNavigationResourceThrottle.
483 if (is_main_frame)
484 return false;
485 #endif // defined(ANDROID)
487 BrowserThread::PostTask(
488 BrowserThread::UI,
489 FROM_HERE,
490 base::Bind(&LaunchURL, url, child_id, route_id, page_transition,
491 has_user_gesture));
492 return true;
495 void ChromeResourceDispatcherHostDelegate::AppendStandardResourceThrottles(
496 net::URLRequest* request,
497 content::ResourceContext* resource_context,
498 ResourceType resource_type,
499 ScopedVector<content::ResourceThrottle>* throttles) {
500 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
502 // Insert either safe browsing or data reduction proxy throttle at the front
503 // of the list, so one of them gets to decide if the resource is safe.
504 content::ResourceThrottle* first_throttle = NULL;
505 #if defined(OS_ANDROID) && defined(SAFE_BROWSING_SERVICE)
506 first_throttle = DataReductionProxyResourceThrottle::MaybeCreate(
507 request, resource_context, resource_type, safe_browsing_.get());
508 #endif // defined(OS_ANDROID) && defined(SAFE_BROWSING_SERVICE)
510 #if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE)
511 if (!first_throttle && io_data->safe_browsing_enabled()->GetValue()) {
512 first_throttle = SafeBrowsingResourceThrottle::MaybeCreate(
513 request, resource_type, safe_browsing_.get());
515 #endif // defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE)
517 if (first_throttle)
518 throttles->push_back(first_throttle);
520 #if defined(ENABLE_DATA_REDUCTION_PROXY_DEBUGGING)
521 scoped_ptr<content::ResourceThrottle> data_reduction_proxy_throttle =
522 data_reduction_proxy::DataReductionProxyDebugResourceThrottle::
523 MaybeCreate(
524 request, resource_type, io_data->data_reduction_proxy_io_data());
525 if (data_reduction_proxy_throttle)
526 throttles->push_back(data_reduction_proxy_throttle.Pass());
527 #endif
529 #if defined(ENABLE_SUPERVISED_USERS)
530 bool is_subresource_request =
531 resource_type != content::RESOURCE_TYPE_MAIN_FRAME;
532 throttles->push_back(new SupervisedUserResourceThrottle(
533 request, !is_subresource_request,
534 io_data->supervised_user_url_filter()));
535 #endif
537 #if defined(ENABLE_EXTENSIONS)
538 content::ResourceThrottle* wait_for_extensions_init_throttle =
539 user_script_listener_->CreateResourceThrottle(request->url(),
540 resource_type);
541 if (wait_for_extensions_init_throttle)
542 throttles->push_back(wait_for_extensions_init_throttle);
544 extensions::ExtensionThrottleManager* extension_throttle_manager =
545 io_data->GetExtensionThrottleManager();
546 if (extension_throttle_manager) {
547 scoped_ptr<content::ResourceThrottle> extension_throttle =
548 extension_throttle_manager->MaybeCreateThrottle(request);
549 if (extension_throttle)
550 throttles->push_back(extension_throttle.release());
552 #endif
554 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
555 if (info->GetVisibilityState() == blink::WebPageVisibilityStatePrerender) {
556 throttles->push_back(new prerender::PrerenderResourceThrottle(request));
560 bool ChromeResourceDispatcherHostDelegate::ShouldForceDownloadResource(
561 const GURL& url, const std::string& mime_type) {
562 #if defined(ENABLE_EXTENSIONS)
563 // Special-case user scripts to get downloaded instead of viewed.
564 return extensions::UserScript::IsURLUserScript(url, mime_type);
565 #else
566 return false;
567 #endif
570 bool ChromeResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
571 net::URLRequest* request,
572 const base::FilePath& plugin_path,
573 const std::string& mime_type,
574 GURL* origin,
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
585 // the URL request.
586 for (const std::string& extension_id : whitelist) {
587 const Extension* extension =
588 extension_info_map->extensions().GetByID(extension_id);
589 // The white-listed extension may not be installed, so we have to NULL check
590 // |extension|.
591 if (!extension ||
592 (profile_is_off_the_record &&
593 !extension_info_map->IsIncognitoEnabled(extension_id))) {
594 continue;
596 MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
597 if (!handler)
598 continue;
600 // If a plugin path is provided then a stream is being intercepted for the
601 // mimeHandlerPrivate API. Otherwise a stream is being intercepted for the
602 // streamsPrivate API.
603 if (!plugin_path.empty()) {
604 if (handler->HasPlugin() && plugin_path == handler->GetPluginPath()) {
605 StreamTargetInfo target_info;
606 *origin = Extension::GetBaseURLFromExtensionId(extension_id);
607 target_info.extension_id = extension_id;
608 target_info.view_id = base::GenerateGUID();
609 *payload = target_info.view_id;
610 stream_target_info_[request] = target_info;
611 return true;
613 } else {
614 if (!handler->HasPlugin() && handler->CanHandleMIMEType(mime_type)) {
615 StreamTargetInfo target_info;
616 *origin = Extension::GetBaseURLFromExtensionId(extension_id);
617 target_info.extension_id = extension_id;
618 stream_target_info_[request] = target_info;
619 return true;
623 #endif
624 return false;
627 void ChromeResourceDispatcherHostDelegate::OnStreamCreated(
628 net::URLRequest* request,
629 scoped_ptr<content::StreamInfo> stream) {
630 #if defined(ENABLE_EXTENSIONS)
631 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
632 std::map<net::URLRequest*, StreamTargetInfo>::iterator ix =
633 stream_target_info_.find(request);
634 CHECK(ix != stream_target_info_.end());
635 bool embedded = info->GetResourceType() != content::RESOURCE_TYPE_MAIN_FRAME;
636 content::BrowserThread::PostTask(
637 content::BrowserThread::UI, FROM_HERE,
638 base::Bind(&SendExecuteMimeTypeHandlerEvent, base::Passed(&stream),
639 request->GetExpectedContentSize(), info->GetChildID(),
640 info->GetRenderFrameID(), ix->second.extension_id,
641 ix->second.view_id, embedded));
642 stream_target_info_.erase(request);
643 #endif
646 void ChromeResourceDispatcherHostDelegate::OnResponseStarted(
647 net::URLRequest* request,
648 content::ResourceContext* resource_context,
649 content::ResourceResponse* response,
650 IPC::Sender* sender) {
651 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
652 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
654 // See if the response contains the X-Chrome-Manage-Accounts header. If so
655 // show the profile avatar bubble so that user can complete signin/out action
656 // the native UI.
657 signin::ProcessMirrorResponseHeaderIfExists(request, io_data,
658 info->GetChildID(),
659 info->GetRouteID());
661 // Built-in additional protection for the chrome web store origin.
662 #if defined(ENABLE_EXTENSIONS)
663 GURL webstore_url(extension_urls::GetWebstoreLaunchURL());
664 if (request->url().SchemeIsHTTPOrHTTPS() &&
665 request->url().DomainIs(webstore_url.host().c_str())) {
666 net::HttpResponseHeaders* response_headers = request->response_headers();
667 if (response_headers &&
668 !response_headers->HasHeaderValue("x-frame-options", "deny") &&
669 !response_headers->HasHeaderValue("x-frame-options", "sameorigin")) {
670 response_headers->RemoveHeader("x-frame-options");
671 response_headers->AddHeader("x-frame-options: sameorigin");
674 #endif
676 if (io_data->resource_prefetch_predictor_observer())
677 io_data->resource_prefetch_predictor_observer()->OnResponseStarted(request);
679 // Ignores x-frame-options for the chrome signin UI.
680 const std::string request_spec(
681 request->first_party_for_cookies().GetOrigin().spec());
682 #if defined(OS_CHROMEOS)
683 if (request_spec == chrome::kChromeUIOobeURL ||
684 request_spec == chrome::kChromeUIChromeSigninURL) {
685 #else
686 if (request_spec == chrome::kChromeUIChromeSigninURL) {
687 #endif
688 net::HttpResponseHeaders* response_headers = request->response_headers();
689 if (response_headers && response_headers->HasHeader("x-frame-options"))
690 response_headers->RemoveHeader("x-frame-options");
693 mod_pagespeed::RecordMetrics(info->GetResourceType(), request->url(),
694 request->response_headers());
697 void ChromeResourceDispatcherHostDelegate::OnRequestRedirected(
698 const GURL& redirect_url,
699 net::URLRequest* request,
700 content::ResourceContext* resource_context,
701 content::ResourceResponse* response) {
702 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
704 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
706 // In the Mirror world, Chrome should append a X-Chrome-Connected header to
707 // all Gaia requests from a connected profile so Gaia could return a 204
708 // response and let Chrome handle the action with native UI. The only
709 // exception is requests from gaia webview, since the native profile
710 // management UI is built on top of it.
711 signin::AppendMirrorRequestHeaderHelper(
712 request, redirect_url, io_data, info->GetChildID(), info->GetRouteID());
714 if (io_data->resource_prefetch_predictor_observer()) {
715 io_data->resource_prefetch_predictor_observer()->OnRequestRedirected(
716 redirect_url, request);
719 #if defined(ENABLE_CONFIGURATION_POLICY)
720 if (io_data->policy_header_helper())
721 io_data->policy_header_helper()->AddPolicyHeaders(redirect_url, request);
722 #endif
725 // Notification that a request has completed.
726 void ChromeResourceDispatcherHostDelegate::RequestComplete(
727 net::URLRequest* url_request) {
728 // Jump on the UI thread and inform the prerender about the bytes.
729 const ResourceRequestInfo* info =
730 ResourceRequestInfo::ForRequest(url_request);
731 if (url_request && !url_request->was_cached()) {
732 BrowserThread::PostTask(BrowserThread::UI,
733 FROM_HERE,
734 base::Bind(&UpdatePrerenderNetworkBytesCallback,
735 info->GetChildID(),
736 info->GetRouteID(),
737 url_request->GetTotalReceivedBytes()));
741 // static
742 void ChromeResourceDispatcherHostDelegate::
743 SetExternalProtocolHandlerDelegateForTesting(
744 ExternalProtocolHandler::Delegate* delegate) {
745 g_external_protocol_handler_delegate = delegate;