Fix build break
[chromium-blink-merge.git] / chrome / browser / renderer_host / chrome_resource_dispatcher_host_delegate.cc
blob1cbba37d315b5ebae1338d58e5d12b5d3a048eca
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h"
7 #include <string>
9 #include "base/base64.h"
10 #include "base/logging.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/content_settings/host_content_settings_map.h"
13 #include "chrome/browser/download/download_request_limiter.h"
14 #include "chrome/browser/download/download_resource_throttle.h"
15 #include "chrome/browser/download/download_util.h"
16 #include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
17 #include "chrome/browser/extensions/extension_info_map.h"
18 #include "chrome/browser/extensions/user_script_listener.h"
19 #include "chrome/browser/external_protocol/external_protocol_handler.h"
20 #include "chrome/browser/google/google_util.h"
21 #include "chrome/browser/metrics/variations/variations_http_header_provider.h"
22 #include "chrome/browser/net/resource_prefetch_predictor_observer.h"
23 #include "chrome/browser/prerender/prerender_manager.h"
24 #include "chrome/browser/prerender/prerender_tracker.h"
25 #include "chrome/browser/prerender/prerender_util.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/browser/profiles/profile_io_data.h"
28 #include "chrome/browser/renderer_host/chrome_url_request_user_data.h"
29 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle_factory.h"
30 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
31 #include "chrome/browser/ui/auto_login_prompter.h"
32 #include "chrome/browser/ui/login/login_prompt.h"
33 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
34 #include "chrome/common/chrome_notification_types.h"
35 #include "chrome/common/extensions/mime_types_handler.h"
36 #include "chrome/common/extensions/user_script.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 "net/base/load_flags.h"
48 #include "net/base/load_timing_info.h"
49 #include "net/http/http_response_headers.h"
50 #include "net/ssl/ssl_config_service.h"
51 #include "net/url_request/url_request.h"
53 #if defined(ENABLE_MANAGED_USERS)
54 #include "chrome/browser/managed_mode/managed_mode_resource_throttle.h"
55 #endif
57 #if defined(USE_SYSTEM_PROTOBUF)
58 #include <google/protobuf/repeated_field.h>
59 #else
60 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
61 #endif
63 #if defined(OS_ANDROID)
64 #include "chrome/browser/android/intercept_download_resource_throttle.h"
65 #include "components/navigation_interception/intercept_navigation_delegate.h"
66 #endif
68 #if defined(OS_CHROMEOS)
69 #include "chrome/browser/chromeos/login/merge_session_throttle.h"
70 // TODO(oshima): Enable this for other platforms.
71 #include "chrome/browser/renderer_host/offline_resource_throttle.h"
72 #endif
74 using content::BrowserThread;
75 using content::RenderViewHost;
76 using content::ResourceDispatcherHostLoginDelegate;
77 using content::ResourceRequestInfo;
78 using extensions::Extension;
79 using extensions::StreamsPrivateAPI;
81 namespace {
83 void NotifyDownloadInitiatedOnUI(int render_process_id, int render_view_id) {
84 RenderViewHost* rvh = RenderViewHost::FromID(render_process_id,
85 render_view_id);
86 if (!rvh)
87 return;
89 content::NotificationService::current()->Notify(
90 chrome::NOTIFICATION_DOWNLOAD_INITIATED,
91 content::Source<RenderViewHost>(rvh),
92 content::NotificationService::NoDetails());
95 // Goes through the extension's file browser handlers and checks if there is one
96 // that can handle the |mime_type|.
97 // |extension| must not be NULL.
98 bool ExtensionCanHandleMimeType(const Extension* extension,
99 const std::string& mime_type) {
100 MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
101 if (!handler)
102 return false;
104 return handler->CanHandleMIMEType(mime_type);
107 void SendExecuteMimeTypeHandlerEvent(scoped_ptr<content::StreamHandle> stream,
108 int render_process_id,
109 int render_view_id,
110 const std::string& extension_id) {
111 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
113 content::RenderViewHost* render_view_host =
114 content::RenderViewHost::FromID(render_process_id, render_view_id);
115 if (!render_view_host)
116 return;
118 content::WebContents* web_contents =
119 content::WebContents::FromRenderViewHost(render_view_host);
120 if (!web_contents)
121 return;
123 content::BrowserContext* browser_context = web_contents->GetBrowserContext();
124 if (!browser_context)
125 return;
127 Profile* profile = Profile::FromBrowserContext(browser_context);
128 if (!profile)
129 return;
131 StreamsPrivateAPI* streams_private = StreamsPrivateAPI::Get(profile);
132 if (!streams_private)
133 return;
134 streams_private->ExecuteMimeTypeHandler(
135 extension_id, web_contents, stream.Pass());
138 } // end namespace
140 ChromeResourceDispatcherHostDelegate::ChromeResourceDispatcherHostDelegate(
141 prerender::PrerenderTracker* prerender_tracker)
142 : download_request_limiter_(g_browser_process->download_request_limiter()),
143 safe_browsing_(g_browser_process->safe_browsing_service()),
144 user_script_listener_(new extensions::UserScriptListener()),
145 prerender_tracker_(prerender_tracker) {
148 ChromeResourceDispatcherHostDelegate::~ChromeResourceDispatcherHostDelegate() {
151 bool ChromeResourceDispatcherHostDelegate::ShouldBeginRequest(
152 int child_id,
153 int route_id,
154 const std::string& method,
155 const GURL& url,
156 ResourceType::Type resource_type,
157 content::ResourceContext* resource_context,
158 const content::Referrer& referrer) {
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
161 // Handle a PREFETCH resource type. If prefetch is disabled, squelch the
162 // request. Otherwise, do a normal request to warm the cache.
163 if (resource_type == ResourceType::PREFETCH) {
164 // All PREFETCH requests should be GETs, but be defensive about it.
165 if (method != "GET")
166 return false;
168 // If prefetch is disabled, kill the request.
169 if (!prerender::PrerenderManager::IsPrefetchEnabled())
170 return false;
173 // Abort any prerenders that spawn requests that use invalid HTTP methods
174 // or invalid schemes.
175 if (prerender_tracker_->IsPrerenderingOnIOThread(child_id, route_id)) {
176 if (!prerender::PrerenderManager::IsValidHttpMethod(method)) {
177 prerender_tracker_->TryCancelOnIOThread(
178 child_id, route_id, prerender::FINAL_STATUS_INVALID_HTTP_METHOD);
179 return false;
181 if (!prerender::PrerenderManager::DoesURLHaveValidScheme(url)) {
182 prerender_tracker_->TryCancelOnIOThread(
183 child_id, route_id, prerender::FINAL_STATUS_UNSUPPORTED_SCHEME);
184 return false;
188 return true;
191 void ChromeResourceDispatcherHostDelegate::RequestBeginning(
192 net::URLRequest* request,
193 content::ResourceContext* resource_context,
194 appcache::AppCacheService* appcache_service,
195 ResourceType::Type resource_type,
196 int child_id,
197 int route_id,
198 bool is_continuation_of_transferred_request,
199 ScopedVector<content::ResourceThrottle>* throttles) {
200 if (is_continuation_of_transferred_request)
201 ChromeURLRequestUserData::Delete(request);
203 ChromeURLRequestUserData* user_data =
204 ChromeURLRequestUserData::Create(request);
205 bool is_prerendering = prerender_tracker_->IsPrerenderingOnIOThread(
206 child_id, route_id);
207 if (is_prerendering) {
208 user_data->set_is_prerender(true);
209 request->SetPriority(net::IDLE);
212 #if defined(OS_ANDROID)
213 if (!is_prerendering && resource_type == ResourceType::MAIN_FRAME) {
214 throttles->push_back(
215 components::InterceptNavigationDelegate::CreateThrottleFor(request));
217 #endif
218 #if defined(OS_CHROMEOS)
219 if (resource_type == ResourceType::MAIN_FRAME) {
220 // We check offline first, then check safe browsing so that we still can
221 // block unsafe site after we remove offline page.
222 throttles->push_back(new OfflineResourceThrottle(
223 child_id, route_id, request, appcache_service));
224 // Add interstitial page while merge session process (cookie
225 // reconstruction from OAuth2 refresh token in ChromeOS login) is still in
226 // progress while we are attempting to load a google property.
227 throttles->push_back(new MergeSessionThrottle(
228 child_id, route_id, request));
230 #endif
232 // Don't attempt to append headers to requests that have already started.
233 // TODO(stevet): Remove this once the request ordering issues are resolved
234 // in crbug.com/128048.
235 if (!request->is_pending()) {
236 net::HttpRequestHeaders headers;
237 headers.CopyFrom(request->extra_request_headers());
238 ProfileIOData* io_data = ProfileIOData::FromResourceContext(
239 resource_context);
240 bool incognito = io_data->is_incognito();
241 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->
242 AppendHeaders(request->url(),
243 incognito,
244 !incognito && io_data->GetMetricsEnabledStateOnIOThread(),
245 &headers);
246 request->SetExtraRequestHeaders(headers);
249 #if defined(ENABLE_ONE_CLICK_SIGNIN)
250 AppendChromeSyncGaiaHeader(request, resource_context);
251 #endif
253 AppendStandardResourceThrottles(request,
254 resource_context,
255 child_id,
256 route_id,
257 resource_type,
258 throttles);
260 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
261 if (io_data->resource_prefetch_predictor_observer()) {
262 io_data->resource_prefetch_predictor_observer()->OnRequestStarted(
263 request, resource_type, child_id, route_id);
267 void ChromeResourceDispatcherHostDelegate::DownloadStarting(
268 net::URLRequest* request,
269 content::ResourceContext* resource_context,
270 int child_id,
271 int route_id,
272 int request_id,
273 bool is_content_initiated,
274 bool must_download,
275 ScopedVector<content::ResourceThrottle>* throttles) {
276 BrowserThread::PostTask(
277 BrowserThread::UI, FROM_HERE,
278 base::Bind(&NotifyDownloadInitiatedOnUI, child_id, route_id));
280 // If it's from the web, we don't trust it, so we push the throttle on.
281 if (is_content_initiated) {
282 throttles->push_back(new DownloadResourceThrottle(
283 download_request_limiter_, child_id, route_id, request_id,
284 request->method()));
285 #if defined(OS_ANDROID)
286 throttles->push_back(
287 new chrome::InterceptDownloadResourceThrottle(
288 request, child_id, route_id, request_id));
289 #endif
292 // If this isn't a new request, we've seen this before and added the standard
293 // resource throttles already so no need to add it again.
294 if (!request->is_pending()) {
295 AppendStandardResourceThrottles(request,
296 resource_context,
297 child_id,
298 route_id,
299 ResourceType::MAIN_FRAME,
300 throttles);
304 bool ChromeResourceDispatcherHostDelegate::AcceptSSLClientCertificateRequest(
305 net::URLRequest* request, net::SSLCertRequestInfo* cert_request_info) {
306 if (request->load_flags() & net::LOAD_PREFETCH)
307 return false;
309 ChromeURLRequestUserData* user_data = ChromeURLRequestUserData::Get(request);
310 if (user_data && user_data->is_prerender()) {
311 int child_id, route_id;
312 if (ResourceRequestInfo::ForRequest(request)->GetAssociatedRenderView(
313 &child_id, &route_id)) {
314 if (prerender_tracker_->TryCancel(
315 child_id, route_id,
316 prerender::FINAL_STATUS_SSL_CLIENT_CERTIFICATE_REQUESTED)) {
317 return false;
322 return true;
325 bool ChromeResourceDispatcherHostDelegate::AcceptAuthRequest(
326 net::URLRequest* request,
327 net::AuthChallengeInfo* auth_info) {
328 ChromeURLRequestUserData* user_data = ChromeURLRequestUserData::Get(request);
329 if (!user_data || !user_data->is_prerender())
330 return true;
332 int child_id, route_id;
333 if (!ResourceRequestInfo::ForRequest(request)->GetAssociatedRenderView(
334 &child_id, &route_id)) {
335 NOTREACHED();
336 return true;
339 if (!prerender_tracker_->TryCancelOnIOThread(
340 child_id, route_id, prerender::FINAL_STATUS_AUTH_NEEDED)) {
341 return true;
344 return false;
347 ResourceDispatcherHostLoginDelegate*
348 ChromeResourceDispatcherHostDelegate::CreateLoginDelegate(
349 net::AuthChallengeInfo* auth_info, net::URLRequest* request) {
350 return CreateLoginPrompt(auth_info, request);
353 bool ChromeResourceDispatcherHostDelegate::HandleExternalProtocol(
354 const GURL& url, int child_id, int route_id) {
355 #if defined(OS_ANDROID)
356 // Android use a resource throttle to handle external as well as internal
357 // protocols.
358 return false;
359 #else
361 if (prerender_tracker_->IsPrerenderingOnIOThread(child_id, route_id)) {
362 prerender_tracker_->TryCancel(
363 child_id, route_id, prerender::FINAL_STATUS_UNSUPPORTED_SCHEME);
364 return false;
367 BrowserThread::PostTask(
368 BrowserThread::UI, FROM_HERE,
369 base::Bind(&ExternalProtocolHandler::LaunchUrl, url, child_id, route_id));
370 return true;
371 #endif
374 void ChromeResourceDispatcherHostDelegate::AppendStandardResourceThrottles(
375 net::URLRequest* request,
376 content::ResourceContext* resource_context,
377 int child_id,
378 int route_id,
379 ResourceType::Type resource_type,
380 ScopedVector<content::ResourceThrottle>* throttles) {
381 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
382 #if defined(FULL_SAFE_BROWSING) || defined(MOBILE_SAFE_BROWSING)
383 // Insert safe browsing at the front of the list, so it gets to decide on
384 // policies first.
385 if (io_data->safe_browsing_enabled()->GetValue()) {
386 bool is_subresource_request = resource_type != ResourceType::MAIN_FRAME;
387 content::ResourceThrottle* throttle =
388 SafeBrowsingResourceThrottleFactory::Create(request, child_id, route_id,
389 is_subresource_request, safe_browsing_);
390 if (throttle)
391 throttles->push_back(throttle);
393 #endif
395 #if defined(ENABLE_MANAGED_USERS)
396 bool is_subresource_request = resource_type != ResourceType::MAIN_FRAME;
397 throttles->push_back(new ManagedModeResourceThrottle(
398 request, child_id, route_id, !is_subresource_request,
399 io_data->managed_mode_url_filter()));
400 #endif
402 content::ResourceThrottle* throttle =
403 user_script_listener_->CreateResourceThrottle(request->url(),
404 resource_type);
405 if (throttle)
406 throttles->push_back(throttle);
409 #if defined(ENABLE_ONE_CLICK_SIGNIN)
410 void ChromeResourceDispatcherHostDelegate::AppendChromeSyncGaiaHeader(
411 net::URLRequest* request,
412 content::ResourceContext* resource_context) {
413 static const char kAllowChromeSignIn[] = "Allow-Chrome-SignIn";
415 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
416 OneClickSigninHelper::Offer offer =
417 OneClickSigninHelper::CanOfferOnIOThread(request, io_data);
418 switch (offer) {
419 case OneClickSigninHelper::CAN_OFFER:
420 request->SetExtraRequestHeaderByName(kAllowChromeSignIn, "1", false);
421 break;
422 case OneClickSigninHelper::DONT_OFFER:
423 request->RemoveRequestHeaderByName(kAllowChromeSignIn);
424 break;
425 case OneClickSigninHelper::IGNORE_REQUEST:
426 break;
429 #endif
431 bool ChromeResourceDispatcherHostDelegate::ShouldForceDownloadResource(
432 const GURL& url, const std::string& mime_type) {
433 // Special-case user scripts to get downloaded instead of viewed.
434 return extensions::UserScript::IsURLUserScript(url, mime_type);
437 bool ChromeResourceDispatcherHostDelegate::ShouldInterceptResourceAsStream(
438 content::ResourceContext* resource_context,
439 const GURL& url,
440 const std::string& mime_type,
441 GURL* security_origin,
442 std::string* target_id) {
443 #if !defined(OS_ANDROID)
444 ProfileIOData* io_data =
445 ProfileIOData::FromResourceContext(resource_context);
446 bool profile_is_incognito = io_data->is_incognito();
447 const scoped_refptr<const ExtensionInfoMap> extension_info_map(
448 io_data->GetExtensionInfoMap());
449 std::vector<std::string> whitelist = MimeTypesHandler::GetMIMETypeWhitelist();
450 // Go through the white-listed extensions and try to use them to intercept
451 // the URL request.
452 for (size_t i = 0; i < whitelist.size(); ++i) {
453 const char* extension_id = whitelist[i].c_str();
454 const Extension* extension =
455 extension_info_map->extensions().GetByID(extension_id);
456 // The white-listed extension may not be installed, so we have to NULL check
457 // |extension|.
458 if (!extension ||
459 (profile_is_incognito &&
460 !extension_info_map->IsIncognitoEnabled(extension_id))) {
461 continue;
464 if (ExtensionCanHandleMimeType(extension, mime_type)) {
465 *security_origin = Extension::GetBaseURLFromExtensionId(extension_id);
466 *target_id = extension_id;
467 return true;
470 #endif
471 return false;
474 void ChromeResourceDispatcherHostDelegate::OnStreamCreated(
475 content::ResourceContext* resource_context,
476 int render_process_id,
477 int render_view_id,
478 const std::string& target_id,
479 scoped_ptr<content::StreamHandle> stream) {
480 #if !defined(OS_ANDROID)
481 content::BrowserThread::PostTask(
482 content::BrowserThread::UI, FROM_HERE,
483 base::Bind(&SendExecuteMimeTypeHandlerEvent, base::Passed(&stream),
484 render_process_id, render_view_id,
485 target_id));
486 #endif
489 void ChromeResourceDispatcherHostDelegate::OnResponseStarted(
490 net::URLRequest* request,
491 content::ResourceContext* resource_context,
492 content::ResourceResponse* response,
493 IPC::Sender* sender) {
494 // TODO(mmenke): Figure out if LOAD_ENABLE_LOAD_TIMING is safe to remove.
495 if (request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING)
496 request->GetLoadTimingInfo(&response->head.load_timing);
498 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
500 if (request->url().SchemeIsSecure()) {
501 const net::URLRequestContext* context = request->context();
502 net::TransportSecurityState* state = context->transport_security_state();
503 if (state) {
504 net::TransportSecurityState::DomainState domain_state;
505 bool has_sni = net::SSLConfigService::IsSNIAvailable(
506 context->ssl_config_service());
507 if (state->GetDomainState(request->url().host(), has_sni,
508 &domain_state) &&
509 domain_state.ShouldUpgradeToSSL()) {
510 sender->Send(new ChromeViewMsg_AddStrictSecurityHost(
511 info->GetRouteID(), request->url().host()));
516 // See if the response contains the X-Auto-Login header. If so, this was
517 // a request for a login page, and the server is allowing the browser to
518 // suggest auto-login, if available.
519 AutoLoginPrompter::ShowInfoBarIfPossible(request, info->GetChildID(),
520 info->GetRouteID());
522 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
524 #if defined(ENABLE_ONE_CLICK_SIGNIN)
525 // See if the response contains the Google-Accounts-SignIn header. If so,
526 // then the user has just finished signing in, and the server is allowing the
527 // browser to suggest connecting the user's profile to the account.
528 OneClickSigninHelper::ShowInfoBarIfPossible(request, io_data,
529 info->GetChildID(),
530 info->GetRouteID());
531 #endif
533 // Build in additional protection for the chrome web store origin.
534 GURL webstore_url(extension_urls::GetWebstoreLaunchURL());
535 if (request->url().DomainIs(webstore_url.host().c_str())) {
536 net::HttpResponseHeaders* response_headers = request->response_headers();
537 if (!response_headers->HasHeaderValue("x-frame-options", "deny") &&
538 !response_headers->HasHeaderValue("x-frame-options", "sameorigin")) {
539 response_headers->RemoveHeader("x-frame-options");
540 response_headers->AddHeader("x-frame-options: sameorigin");
544 if (io_data->resource_prefetch_predictor_observer())
545 io_data->resource_prefetch_predictor_observer()->OnResponseStarted(request);
547 prerender::URLRequestResponseStarted(request);
550 void ChromeResourceDispatcherHostDelegate::OnRequestRedirected(
551 const GURL& redirect_url,
552 net::URLRequest* request,
553 content::ResourceContext* resource_context,
554 content::ResourceResponse* response) {
555 // TODO(mmenke): Figure out if LOAD_ENABLE_LOAD_TIMING is safe to remove.
556 if (request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING)
557 request->GetLoadTimingInfo(&response->head.load_timing);
559 ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
561 #if defined(ENABLE_ONE_CLICK_SIGNIN)
562 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
564 // See if the response contains the Google-Accounts-SignIn header. If so,
565 // then the user has just finished signing in, and the server is allowing the
566 // browser to suggest connecting the user's profile to the account.
567 OneClickSigninHelper::ShowInfoBarIfPossible(request, io_data,
568 info->GetChildID(),
569 info->GetRouteID());
570 AppendChromeSyncGaiaHeader(request, resource_context);
571 #endif
573 if (io_data->resource_prefetch_predictor_observer()) {
574 io_data->resource_prefetch_predictor_observer()->OnRequestRedirected(
575 redirect_url, request);
578 int child_id, route_id;
579 if (!prerender::PrerenderManager::DoesURLHaveValidScheme(redirect_url) &&
580 ResourceRequestInfo::ForRequest(request)->GetAssociatedRenderView(
581 &child_id, &route_id) &&
582 prerender_tracker_->IsPrerenderingOnIOThread(child_id, route_id)) {
583 prerender_tracker_->TryCancel(
584 child_id, route_id, prerender::FINAL_STATUS_UNSUPPORTED_SCHEME);
585 request->Cancel();