1 // Copyright 2014 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 "components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/time/time.h"
9 #include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
10 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
11 #include "net/base/load_flags.h"
12 #include "net/http/http_response_headers.h"
13 #include "net/proxy/proxy_info.h"
14 #include "net/proxy/proxy_list.h"
15 #include "net/proxy/proxy_server.h"
16 #include "net/proxy/proxy_service.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_context.h"
23 bool SetProxyServerFromGURL(const GURL
& gurl
,
24 net::ProxyServer
* proxy_server
) {
26 if (!gurl
.SchemeIsHTTPOrHTTPS())
28 *proxy_server
= net::ProxyServer(gurl
.SchemeIs("http") ?
29 net::ProxyServer::SCHEME_HTTP
:
30 net::ProxyServer::SCHEME_HTTPS
,
31 net::HostPortPair::FromURL(gurl
));
37 namespace data_reduction_proxy
{
39 bool MaybeBypassProxyAndPrepareToRetry(
40 const DataReductionProxyParams
* data_reduction_proxy_params
,
41 net::URLRequest
* request
,
42 const net::HttpResponseHeaders
* original_response_headers
,
43 scoped_refptr
<net::HttpResponseHeaders
>* override_response_headers
,
44 net::ProxyService::DataReductionProxyBypassType
* proxy_bypass_type
) {
45 if (!data_reduction_proxy_params
)
47 std::pair
<GURL
, GURL
> data_reduction_proxies
;
48 if (!data_reduction_proxy_params
->WasDataReductionProxyUsed(
49 request
, &data_reduction_proxies
)) {
53 // Empty implies either that the request was served from cache or that
54 // request was served directly from the origin.
55 if (request
->proxy_server().IsEmpty())
58 if (data_reduction_proxies
.first
.is_empty())
61 DataReductionProxyInfo data_reduction_proxy_info
;
62 net::ProxyService::DataReductionProxyBypassType bypass_type
=
63 GetDataReductionProxyBypassType(original_response_headers
,
64 &data_reduction_proxy_info
);
65 if (proxy_bypass_type
)
66 *proxy_bypass_type
= bypass_type
;
67 if (bypass_type
== net::ProxyService::BYPASS_EVENT_TYPE_MAX
)
70 DCHECK(request
->context());
71 DCHECK(request
->context()->proxy_service());
72 net::ProxyServer proxy_server
;
73 SetProxyServerFromGURL(data_reduction_proxies
.first
, &proxy_server
);
74 request
->context()->proxy_service()->RecordDataReductionProxyBypassInfo(
75 !data_reduction_proxies
.second
.is_empty(),
76 data_reduction_proxy_info
.bypass_all
,
80 MarkProxiesAsBadUntil(request
,
81 data_reduction_proxy_info
.bypass_duration
,
82 data_reduction_proxy_info
.bypass_all
,
83 data_reduction_proxies
);
85 // Only retry idempotent methods.
86 if (!IsRequestIdempotent(request
))
89 OverrideResponseAsRedirect(request
,
90 original_response_headers
,
91 override_response_headers
);
95 void OnResolveProxyHandler(const GURL
& url
,
97 const DataReductionProxyParams
* params
,
98 net::ProxyInfo
* result
) {
99 if ((load_flags
& net::LOAD_BYPASS_DATA_REDUCTION_PROXY
) &&
100 DataReductionProxyParams::IsIncludedInCriticalPathBypassFieldTrial() &&
101 !result
->is_empty() &&
102 !result
->is_direct() &&
104 params
->IsDataReductionProxy(
105 result
->proxy_server().host_port_pair(), NULL
)) {
110 bool IsRequestIdempotent(const net::URLRequest
* request
) {
112 if (request
->method() == "GET" ||
113 request
->method() == "OPTIONS" ||
114 request
->method() == "HEAD" ||
115 request
->method() == "PUT" ||
116 request
->method() == "DELETE" ||
117 request
->method() == "TRACE")
122 void OverrideResponseAsRedirect(
123 net::URLRequest
* request
,
124 const net::HttpResponseHeaders
* original_response_headers
,
125 scoped_refptr
<net::HttpResponseHeaders
>* override_response_headers
) {
127 DCHECK(original_response_headers
);
128 DCHECK(override_response_headers
->get() == NULL
);
130 request
->SetLoadFlags(request
->load_flags() |
131 net::LOAD_DISABLE_CACHE
|
132 net::LOAD_BYPASS_PROXY
);
133 *override_response_headers
= new net::HttpResponseHeaders(
134 original_response_headers
->raw_headers());
135 (*override_response_headers
)->ReplaceStatusLine("HTTP/1.1 302 Found");
136 (*override_response_headers
)->RemoveHeader("Location");
137 (*override_response_headers
)->AddHeader("Location: " +
138 request
->url().spec());
139 // TODO(bengr): Should we pop_back the request->url_chain?
142 void MarkProxiesAsBadUntil(
143 net::URLRequest
* request
,
144 base::TimeDelta
& bypass_duration
,
146 const std::pair
<GURL
, GURL
>& data_reduction_proxies
) {
147 DCHECK(!data_reduction_proxies
.first
.is_empty());
148 // Synthesize a suitable |ProxyInfo| to add the proxies to the
149 // |ProxyRetryInfoMap| of the proxy service.
150 net::ProxyList proxy_list
;
151 net::ProxyServer primary
;
152 SetProxyServerFromGURL(data_reduction_proxies
.first
, &primary
);
153 if (primary
.is_valid())
154 proxy_list
.AddProxyServer(primary
);
155 net::ProxyServer fallback
;
157 if (!data_reduction_proxies
.second
.is_empty())
158 SetProxyServerFromGURL(data_reduction_proxies
.second
, &fallback
);
159 if (fallback
.is_valid())
160 proxy_list
.AddProxyServer(fallback
);
161 proxy_list
.AddProxyServer(net::ProxyServer::Direct());
163 net::ProxyInfo proxy_info
;
164 proxy_info
.UseProxyList(proxy_list
);
165 DCHECK(request
->context());
166 net::ProxyService
* proxy_service
= request
->context()->proxy_service();
167 DCHECK(proxy_service
);
169 proxy_service
->MarkProxiesAsBadUntil(proxy_info
,
175 } // namespace data_reduction_proxy