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