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