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