Index: chrome/browser/android/spdy_proxy_resource_throttle.cc |
diff --git a/chrome/browser/android/spdy_proxy_resource_throttle.cc b/chrome/browser/android/spdy_proxy_resource_throttle.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..67d5b3c7dc35ead5f1c5ac6ccae423b6050a20d4 |
--- /dev/null |
+++ b/chrome/browser/android/spdy_proxy_resource_throttle.cc |
@@ -0,0 +1,182 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/android/spdy_proxy_resource_throttle.h" |
+ |
+#include "base/logging.h" |
+#include "chrome/browser/browser_process.h" |
+#include "chrome/browser/prerender/prerender_contents.h" |
+#include "chrome/browser/renderer_host/safe_browsing_resource_throttle_factory.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/render_view_host.h" |
+#include "content/public/browser/resource_context.h" |
+#include "content/public/browser/resource_controller.h" |
+#include "content/public/browser/resource_request_info.h" |
+#include "content/public/browser/web_contents.h" |
+#include "net/base/load_flags.h" |
+#include "net/http/http_response_headers.h" |
+#include "net/url_request/redirect_info.h" |
+#include "net/url_request/url_request.h" |
+ |
+#if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE) |
+#include "chrome/browser/profiles/profile_io_data.h" |
+#include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h" |
+#endif |
+ |
+using content::BrowserThread; |
+using content::ResourceThrottle; |
+ |
+// TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more |
+// unit test coverage. |
+// TODO(sgurun) following the comment above, also provide tests for |
+// checking whether the headers are injected correctly and the SPDY proxy |
+// origin is tested properly. |
+ |
+const char* SpdyProxyResourceThrottle::kUnsafeUrlProceedHeader = |
+ "X-Unsafe-Url-Proceed"; |
+ |
+ResourceThrottle* SpdyProxyResourceThrottleFactory::CreateResourceThrottle( |
+ net::URLRequest* request, |
+ content::ResourceContext* resource_context, |
+ content::ResourceType resource_type, |
+ SafeBrowsingService* service) { |
+#if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE) |
+ ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context); |
+ if (io_data->IsOffTheRecord() || |
+ !io_data->IsDataReductionProxyEnabled() || |
+ request->url().SchemeIsSecure()) |
+ return new SafeBrowsingResourceThrottle(request, resource_type, service); |
+#endif |
+ return new SpdyProxyResourceThrottle(request, resource_type, service); |
+} |
+ |
+SpdyProxyResourceThrottle::SpdyProxyResourceThrottle( |
+ net::URLRequest* request, |
+ content::ResourceType resource_type, |
+ SafeBrowsingService* safe_browsing) |
+ : state_(STATE_NONE), |
+ safe_browsing_(safe_browsing), |
+ request_(request), |
+ is_subresource_(resource_type != content::RESOURCE_TYPE_MAIN_FRAME), |
+ is_subframe_(resource_type == content::RESOURCE_TYPE_SUB_FRAME) { |
+} |
+ |
+SpdyProxyResourceThrottle::~SpdyProxyResourceThrottle() { } |
+ |
+void SpdyProxyResourceThrottle::WillRedirectRequest( |
+ const net::RedirectInfo& redirect_info, |
+ bool* defer) { |
+ CHECK(state_ == STATE_NONE); |
+ |
+ // Save the redirect urls for possible malware detail reporting later. |
+ redirect_urls_.push_back(redirect_info.new_url); |
+ |
+ // We need to check the new URL before following the redirect. |
+ SBThreatType threat_type = CheckUrl(); |
+ if (threat_type == SB_THREAT_TYPE_SAFE) |
+ return; |
+ |
+ if (request_->load_flags() & net::LOAD_PREFETCH) { |
+ controller()->Cancel(); |
+ return; |
+ } |
+ const content::ResourceRequestInfo* info = |
+ content::ResourceRequestInfo::ForRequest(request_); |
+ |
+ state_ = STATE_DISPLAYING_BLOCKING_PAGE; |
+ SafeBrowsingUIManager::UnsafeResource unsafe_resource; |
+ unsafe_resource.url = redirect_info.new_url; |
+ unsafe_resource.original_url = request_->original_url(); |
+ unsafe_resource.redirect_urls = redirect_urls_; |
+ unsafe_resource.is_subresource = is_subresource_; |
+ unsafe_resource.is_subframe = is_subframe_; |
+ unsafe_resource.threat_type = threat_type; |
+ unsafe_resource.callback = base::Bind( |
+ &SpdyProxyResourceThrottle::OnBlockingPageComplete, AsWeakPtr()); |
+ unsafe_resource.render_process_host_id = info->GetChildID(); |
+ unsafe_resource.render_view_id = info->GetRouteID(); |
+ |
+ *defer = true; |
+ |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&SpdyProxyResourceThrottle::StartDisplayingBlockingPage, |
+ AsWeakPtr(), |
+ safe_browsing_->ui_manager(), |
+ unsafe_resource)); |
+} |
+ |
+const char* SpdyProxyResourceThrottle::GetNameForLogging() const { |
+ return "SpdyProxyResourceThrottle"; |
+} |
+ |
+// static |
+void SpdyProxyResourceThrottle::StartDisplayingBlockingPage( |
+ const base::WeakPtr<SpdyProxyResourceThrottle>& throttle, |
+ scoped_refptr<SafeBrowsingUIManager> ui_manager, |
+ const SafeBrowsingUIManager::UnsafeResource& resource) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ content::RenderViewHost* rvh = content::RenderViewHost::FromID( |
+ resource.render_process_host_id, resource.render_view_id); |
+ if (rvh) { |
+ content::WebContents* web_contents = |
+ content::WebContents::FromRenderViewHost(rvh); |
+ prerender::PrerenderContents* prerender_contents = |
+ prerender::PrerenderContents::FromWebContents(web_contents); |
+ if (prerender_contents) { |
+ prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING); |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, |
+ FROM_HERE, |
+ base::Bind(resource.callback, false)); |
+ return; |
+ } |
+ } |
+ ui_manager->DisplayBlockingPage(resource); |
+} |
+ |
+// SafeBrowsingService::UrlCheckCallback implementation, called on the IO |
+// thread when the user has decided to proceed with the current request, or |
+// go back. |
+void SpdyProxyResourceThrottle::OnBlockingPageComplete(bool proceed) { |
+ CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE); |
+ state_ = STATE_NONE; |
+ |
+ if (proceed) |
+ ResumeRequest(); |
+ else |
+ controller()->Cancel(); |
+} |
+ |
+SBThreatType SpdyProxyResourceThrottle::CheckUrl() { |
+ SBThreatType result = SB_THREAT_TYPE_SAFE; |
+ |
+ // TODO(sgurun) Check for spdy proxy origin. |
+ if (request_->response_headers() == NULL) |
+ return result; |
+ |
+ if (request_->response_headers()->HasHeader("X-Phishing-Url")) |
+ result = SB_THREAT_TYPE_URL_PHISHING; |
+ else if (request_->response_headers()->HasHeader("X-Malware-Url")) |
+ result = SB_THREAT_TYPE_URL_MALWARE; |
+ |
+ // If safe browsing is disabled and the request is sent to the DRP server, |
+ // we need to break the redirect loop by setting the extra header. |
+ if (result != SB_THREAT_TYPE_SAFE && !safe_browsing_->enabled()) { |
+ request_->SetExtraRequestHeaderByName(kUnsafeUrlProceedHeader, "1", true); |
+ result = SB_THREAT_TYPE_SAFE; |
+ } |
+ |
+ return result; |
+} |
+ |
+void SpdyProxyResourceThrottle::ResumeRequest() { |
+ CHECK(state_ == STATE_NONE); |
+ |
+ // Inject the header before resuming the request. |
+ request_->SetExtraRequestHeaderByName(kUnsafeUrlProceedHeader, "1", true); |
+ controller()->Resume(); |
+} |