1 // Copyright 2015 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/android/spdy_proxy_resource_throttle.h"
7 #include "base/logging.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/prerender/prerender_contents.h"
10 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle_factory.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/render_view_host.h"
13 #include "content/public/browser/resource_context.h"
14 #include "content/public/browser/resource_controller.h"
15 #include "content/public/browser/resource_request_info.h"
16 #include "content/public/browser/web_contents.h"
17 #include "net/base/load_flags.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/url_request/redirect_info.h"
20 #include "net/url_request/url_request.h"
22 #if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE)
23 #include "chrome/browser/profiles/profile_io_data.h"
24 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h"
27 using content::BrowserThread
;
28 using content::ResourceThrottle
;
30 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
31 // unit test coverage.
32 // TODO(sgurun) following the comment above, also provide tests for
33 // checking whether the headers are injected correctly and the SPDY proxy
34 // origin is tested properly.
36 const char* SpdyProxyResourceThrottle::kUnsafeUrlProceedHeader
=
37 "X-Unsafe-Url-Proceed";
39 ResourceThrottle
* SpdyProxyResourceThrottleFactory::CreateResourceThrottle(
40 net::URLRequest
* request
,
41 content::ResourceContext
* resource_context
,
42 content::ResourceType resource_type
,
43 SafeBrowsingService
* service
) {
44 #if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE)
45 ProfileIOData
* io_data
= ProfileIOData::FromResourceContext(resource_context
);
46 if (io_data
->IsOffTheRecord() ||
47 !io_data
->IsDataReductionProxyEnabled() ||
48 request
->url().SchemeIsSecure())
49 return new SafeBrowsingResourceThrottle(request
, resource_type
, service
);
51 return new SpdyProxyResourceThrottle(request
, resource_type
, service
);
54 SpdyProxyResourceThrottle::SpdyProxyResourceThrottle(
55 net::URLRequest
* request
,
56 content::ResourceType resource_type
,
57 SafeBrowsingService
* safe_browsing
)
59 safe_browsing_(safe_browsing
),
61 is_subresource_(resource_type
!= content::RESOURCE_TYPE_MAIN_FRAME
),
62 is_subframe_(resource_type
== content::RESOURCE_TYPE_SUB_FRAME
) {
65 SpdyProxyResourceThrottle::~SpdyProxyResourceThrottle() { }
67 void SpdyProxyResourceThrottle::WillRedirectRequest(
68 const net::RedirectInfo
& redirect_info
,
70 CHECK(state_
== STATE_NONE
);
72 // Save the redirect urls for possible malware detail reporting later.
73 redirect_urls_
.push_back(redirect_info
.new_url
);
75 // We need to check the new URL before following the redirect.
76 SBThreatType threat_type
= CheckUrl();
77 if (threat_type
== SB_THREAT_TYPE_SAFE
)
80 if (request_
->load_flags() & net::LOAD_PREFETCH
) {
81 controller()->Cancel();
84 const content::ResourceRequestInfo
* info
=
85 content::ResourceRequestInfo::ForRequest(request_
);
87 state_
= STATE_DISPLAYING_BLOCKING_PAGE
;
88 SafeBrowsingUIManager::UnsafeResource unsafe_resource
;
89 unsafe_resource
.url
= redirect_info
.new_url
;
90 unsafe_resource
.original_url
= request_
->original_url();
91 unsafe_resource
.redirect_urls
= redirect_urls_
;
92 unsafe_resource
.is_subresource
= is_subresource_
;
93 unsafe_resource
.is_subframe
= is_subframe_
;
94 unsafe_resource
.threat_type
= threat_type
;
95 unsafe_resource
.callback
= base::Bind(
96 &SpdyProxyResourceThrottle::OnBlockingPageComplete
, AsWeakPtr());
97 unsafe_resource
.render_process_host_id
= info
->GetChildID();
98 unsafe_resource
.render_view_id
= info
->GetRouteID();
102 content::BrowserThread::PostTask(
103 content::BrowserThread::UI
,
105 base::Bind(&SpdyProxyResourceThrottle::StartDisplayingBlockingPage
,
107 safe_browsing_
->ui_manager(),
111 const char* SpdyProxyResourceThrottle::GetNameForLogging() const {
112 return "SpdyProxyResourceThrottle";
116 void SpdyProxyResourceThrottle::StartDisplayingBlockingPage(
117 const base::WeakPtr
<SpdyProxyResourceThrottle
>& throttle
,
118 scoped_refptr
<SafeBrowsingUIManager
> ui_manager
,
119 const SafeBrowsingUIManager::UnsafeResource
& resource
) {
120 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
122 content::RenderViewHost
* rvh
= content::RenderViewHost::FromID(
123 resource
.render_process_host_id
, resource
.render_view_id
);
125 content::WebContents
* web_contents
=
126 content::WebContents::FromRenderViewHost(rvh
);
127 prerender::PrerenderContents
* prerender_contents
=
128 prerender::PrerenderContents::FromWebContents(web_contents
);
129 if (prerender_contents
) {
130 prerender_contents
->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING
);
131 content::BrowserThread::PostTask(
132 content::BrowserThread::IO
,
134 base::Bind(resource
.callback
, false));
138 ui_manager
->DisplayBlockingPage(resource
);
141 // SafeBrowsingService::UrlCheckCallback implementation, called on the IO
142 // thread when the user has decided to proceed with the current request, or
144 void SpdyProxyResourceThrottle::OnBlockingPageComplete(bool proceed
) {
145 CHECK(state_
== STATE_DISPLAYING_BLOCKING_PAGE
);
151 controller()->Cancel();
154 SBThreatType
SpdyProxyResourceThrottle::CheckUrl() {
155 SBThreatType result
= SB_THREAT_TYPE_SAFE
;
157 // TODO(sgurun) Check for spdy proxy origin.
158 if (request_
->response_headers() == NULL
)
161 if (request_
->response_headers()->HasHeader("X-Phishing-Url"))
162 result
= SB_THREAT_TYPE_URL_PHISHING
;
163 else if (request_
->response_headers()->HasHeader("X-Malware-Url"))
164 result
= SB_THREAT_TYPE_URL_MALWARE
;
166 // If safe browsing is disabled and the request is sent to the DRP server,
167 // we need to break the redirect loop by setting the extra header.
168 if (result
!= SB_THREAT_TYPE_SAFE
&& !safe_browsing_
->enabled()) {
169 request_
->SetExtraRequestHeaderByName(kUnsafeUrlProceedHeader
, "1", true);
170 result
= SB_THREAT_TYPE_SAFE
;
176 void SpdyProxyResourceThrottle::ResumeRequest() {
177 CHECK(state_
== STATE_NONE
);
179 // Inject the header before resuming the request.
180 request_
->SetExtraRequestHeaderByName(kUnsafeUrlProceedHeader
, "1", true);
181 controller()->Resume();