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