1 // Copyright 2013 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/net/spdyproxy/proxy_advisor.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/stl_util.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/common/pref_names.h"
14 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_params.h"
15 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/request_priority.h"
19 #include "net/http/http_status_code.h"
20 #include "net/proxy/proxy_info.h"
21 #include "net/proxy/proxy_service.h"
22 #include "net/url_request/url_request_context.h"
23 #include "net/url_request/url_request_context_getter.h"
25 // TODO(marq): Remove this class because it is not being used.
27 // Ensure data reduction features are available.
28 #if !defined(OS_ANDROID) && !defined(OS_IOS)
29 #error proxy_advisor should only be included in Android or iOS builds.
32 using content::BrowserThread
;
33 using data_reduction_proxy::DataReductionProxySettings
;
36 const char kOmniboxMotivation
[] = "omnibox";
37 const char kLowThresholdOmniboxMotivation
[] = "low_threshold_omnibox";
38 const char kStartupDNSMotivation
[] = "startup_dns";
39 const char kEarlyLoadMotivation
[] = "early_load";
40 const char kLearnedReferralMotivation
[] = "learned_referral";
41 const char kLowThresholdLearnedReferralMotivation
[] =
42 "low_threshold_learned_referral";
43 const char kSelfReferralMotivation
[] = "self_referral";
44 const char kPageScanMotivation
[] = "page_scan";
46 // Maps a ResolutionMotivation to a string for use in the advisory HEAD
48 const char* MotivationName(
49 chrome_browser_net::UrlInfo::ResolutionMotivation motivation
,
52 case chrome_browser_net::UrlInfo::OMNIBOX_MOTIVATED
:
54 is_preconnect
? kOmniboxMotivation
: kLowThresholdOmniboxMotivation
;
55 case chrome_browser_net::UrlInfo::STARTUP_LIST_MOTIVATED
:
56 return kStartupDNSMotivation
;
57 case chrome_browser_net::UrlInfo::EARLY_LOAD_MOTIVATED
:
58 return kEarlyLoadMotivation
;
59 case chrome_browser_net::UrlInfo::LEARNED_REFERAL_MOTIVATED
:
60 return is_preconnect
?
61 kLearnedReferralMotivation
: kLowThresholdLearnedReferralMotivation
;
62 case chrome_browser_net::UrlInfo::SELF_REFERAL_MOTIVATED
:
63 return kSelfReferralMotivation
;
64 case chrome_browser_net::UrlInfo::PAGE_SCAN_MOTIVATED
:
65 return kPageScanMotivation
;
67 // Other motivations should never be passed to here.
77 ProxyAdvisor::ProxyAdvisor(PrefService
* pref_service
,
78 net::URLRequestContextGetter
* context_getter
)
79 : context_getter_(context_getter
) {
80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
82 // pref_service may be null in mock test subclasses.
84 proxy_pref_member_
.Init(
85 data_reduction_proxy::prefs::kDataReductionProxyEnabled
,
87 base::Bind(&ProxyAdvisor::UpdateProxyState
, base::Unretained(this)));
88 proxy_pref_member_
.MoveToThread(
89 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO
));
93 ProxyAdvisor::~ProxyAdvisor() {
94 STLDeleteElements(&inflight_requests_
);
97 void ProxyAdvisor::OnResponseStarted(net::URLRequest
* request
) {
98 const net::URLRequestStatus
& status(request
->status());
99 if (!status
.is_success()) {
100 DLOG(WARNING
) << "Proxy advisory failed "
101 << "status:" << status
.status()
102 << " error:" << status
.error();
103 } else if (request
->GetResponseCode() != net::HTTP_OK
) {
104 DLOG(WARNING
) << "Proxy advisory status: " << request
->GetResponseCode();
106 RequestComplete(request
);
109 void ProxyAdvisor::OnReadCompleted(net::URLRequest
* request
, int bytes_read
) {
110 // No-op for now, as we don't care yet.
113 void ProxyAdvisor::Advise(
115 chrome_browser_net::UrlInfo::ResolutionMotivation motivation
,
116 bool is_preconnect
) {
117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
119 if (!WouldProxyURL(url
))
122 std::string
motivation_name(MotivationName(motivation
, is_preconnect
));
123 std::string header_value
= motivation_name
+ " " + url
.spec();
124 net::URLRequestContext
* context
= context_getter_
->GetURLRequestContext();
125 data_reduction_proxy::DataReductionProxyParams
params(
126 data_reduction_proxy::DataReductionProxyParams::kAllowed
|
127 data_reduction_proxy::DataReductionProxyParams::kFallbackAllowed
|
128 data_reduction_proxy::DataReductionProxyParams::kPromoAllowed
);
129 std::string endpoint
=
130 params
.origin().spec() + "preconnect";
131 scoped_ptr
<net::URLRequest
> request
= context
->CreateRequest(
132 GURL(endpoint
), net::DEFAULT_PRIORITY
, this, NULL
);
133 request
->set_method("HEAD");
134 request
->SetExtraRequestHeaderByName(
135 "Proxy-Host-Advisory", header_value
, false);
136 request
->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES
|
137 net::LOAD_DO_NOT_SAVE_COOKIES
|
138 net::LOAD_BYPASS_PROXY
|
139 net::LOAD_DISABLE_CACHE
);
140 net::URLRequest
* raw_request
= request
.get();
141 inflight_requests_
.insert(request
.release());
142 raw_request
->Start();
145 // TODO(marq): Move this into DataReductionProxySettings, and add support for
146 // inspecting the current proxy configs -- if ResolveProxy on |url| can be
147 // done synchronously, then this is no longer an approximation.
148 bool ProxyAdvisor::WouldProxyURL(const GURL
& url
) {
149 if (!proxy_pref_member_
.GetValue())
152 if (url
.SchemeIsSecure())
158 void ProxyAdvisor::RequestComplete(net::URLRequest
* request
) {
159 DCHECK_EQ(1u, inflight_requests_
.count(request
));
160 scoped_ptr
<net::URLRequest
> scoped_request_for_deletion(request
);
161 inflight_requests_
.erase(request
);
162 // |scoped_request_for_deletion| will delete |request|
165 void ProxyAdvisor::UpdateProxyState() {
166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
167 // Delete all inflight requests. Each request's destructor will call Cancel().
168 STLDeleteElements(&inflight_requests_
);