blob: 7ab3e90482f8179fdb40cc7cf8b5fc28c7d81977 [file] [log] [blame]
// 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/loader/data_reduction_proxy_resource_throttle_android.h"
#include "base/logging.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prerender/prerender_contents.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/resource_context.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"
using content::BrowserThread;
using content::ResourceThrottle;
using safe_browsing::SafeBrowsingService;
using safe_browsing::SafeBrowsingUIManager;
using safe_browsing::SBThreatType;
// 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.
namespace {
const char kUnsafeUrlProceedHeader[] = "X-Unsafe-Url-Proceed";
} // namespace
// static
DataReductionProxyResourceThrottle*
DataReductionProxyResourceThrottle::MaybeCreate(
net::URLRequest* request,
content::ResourceContext* resource_context,
content::ResourceType resource_type,
SafeBrowsingService* sb_service) {
ProfileIOData* io_data = ProfileIOData::FromResourceContext(resource_context);
// Don't create the throttle if we can't handle the request.
if (io_data->IsOffTheRecord() || !io_data->data_reduction_proxy_io_data() ||
!io_data->data_reduction_proxy_io_data()->IsEnabled() ||
request->url().SchemeIsCryptographic()) {
return nullptr;
}
return new DataReductionProxyResourceThrottle(request, resource_type,
sb_service);
}
DataReductionProxyResourceThrottle::DataReductionProxyResourceThrottle(
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) {
}
DataReductionProxyResourceThrottle::~DataReductionProxyResourceThrottle() { }
void DataReductionProxyResourceThrottle::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 == safe_browsing::SB_THREAT_TYPE_SAFE)
return;
if (request_->load_flags() & net::LOAD_PREFETCH) {
Cancel();
return;
}
const content::ResourceRequestInfo* info =
content::ResourceRequestInfo::ForRequest(request_);
state_ = STATE_DISPLAYING_BLOCKING_PAGE;
security_interstitials::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(
&DataReductionProxyResourceThrottle::OnBlockingPageComplete, AsWeakPtr());
unsafe_resource.callback_thread =
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::IO);
unsafe_resource.web_contents_getter = info->GetWebContentsGetterForRequest();
unsafe_resource.threat_source = safe_browsing::ThreatSource::DATA_SAVER;
*defer = true;
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(
&DataReductionProxyResourceThrottle::StartDisplayingBlockingPage,
AsWeakPtr(), safe_browsing_->ui_manager(), unsafe_resource));
}
const char* DataReductionProxyResourceThrottle::GetNameForLogging() const {
return "DataReductionProxyResourceThrottle";
}
// static
void DataReductionProxyResourceThrottle::StartDisplayingBlockingPage(
const base::WeakPtr<DataReductionProxyResourceThrottle>& throttle,
scoped_refptr<SafeBrowsingUIManager> ui_manager,
const security_interstitials::UnsafeResource& resource) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::WebContents* web_contents = resource.web_contents_getter.Run();
if (web_contents) {
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 DataReductionProxyResourceThrottle::OnBlockingPageComplete(bool proceed) {
CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE);
state_ = STATE_NONE;
if (proceed)
ResumeRequest();
else
Cancel();
}
SBThreatType DataReductionProxyResourceThrottle::CheckUrl() {
SBThreatType result = safe_browsing::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 = safe_browsing::SB_THREAT_TYPE_URL_PHISHING;
else if (request_->response_headers()->HasHeader("X-Malware-Url"))
result = safe_browsing::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 != safe_browsing::SB_THREAT_TYPE_SAFE &&
!safe_browsing_->enabled()) {
request_->SetExtraRequestHeaderByName(kUnsafeUrlProceedHeader, "1", true);
result = safe_browsing::SB_THREAT_TYPE_SAFE;
}
return result;
}
void DataReductionProxyResourceThrottle::ResumeRequest() {
CHECK(state_ == STATE_NONE);
// Inject the header before resuming the request.
request_->SetExtraRequestHeaderByName(kUnsafeUrlProceedHeader, "1", true);
Resume();
}