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"
22 bool SetProxyServerFromGURL(const GURL
& gurl
,
23 net::ProxyServer
* proxy_server
) {
25 if (!gurl
.SchemeIsHTTPOrHTTPS())
27 *proxy_server
= net::ProxyServer(gurl
.SchemeIs("http") ?
28 net::ProxyServer::SCHEME_HTTP
:
29 net::ProxyServer::SCHEME_HTTPS
,
30 net::HostPortPair::FromURL(gurl
));
35 namespace data_reduction_proxy
{
37 bool MaybeBypassProxyAndPrepareToRetry(
38 const DataReductionProxyParams
* data_reduction_proxy_params
,
39 net::URLRequest
* request
,
40 const net::HttpResponseHeaders
* original_response_headers
,
41 scoped_refptr
<net::HttpResponseHeaders
>* override_response_headers
) {
42 if (!data_reduction_proxy_params
)
44 std::pair
<GURL
, GURL
> data_reduction_proxies
;
45 if (!data_reduction_proxy_params
->WasDataReductionProxyUsed(
46 request
, &data_reduction_proxies
)) {
50 // Empty implies either that the request was served from cache or that
51 // request was served directly from the origin.
52 if (request
->proxy_server().IsEmpty())
55 if (data_reduction_proxies
.first
.is_empty())
58 DataReductionProxyInfo data_reduction_proxy_info
;
59 net::ProxyService::DataReductionProxyBypassEventType bypass_type
=
60 GetDataReductionProxyBypassEventType(
61 original_response_headers
, &data_reduction_proxy_info
);
62 if (bypass_type
== net::ProxyService::BYPASS_EVENT_TYPE_MAX
) {
66 DCHECK(request
->context());
67 DCHECK(request
->context()->proxy_service());
68 net::ProxyServer proxy_server
;
69 SetProxyServerFromGURL(data_reduction_proxies
.first
, &proxy_server
);
70 request
->context()->proxy_service()->RecordDataReductionProxyBypassInfo(
71 !data_reduction_proxies
.second
.is_empty(), proxy_server
, bypass_type
);
73 MarkProxiesAsBadUntil(request
,
74 data_reduction_proxy_info
.bypass_duration
,
75 data_reduction_proxy_info
.bypass_all
,
76 data_reduction_proxies
);
78 // Only retry idempotent methods.
79 if (!IsRequestIdempotent(request
))
82 OverrideResponseAsRedirect(request
,
83 original_response_headers
,
84 override_response_headers
);
90 bool IsRequestIdempotent(const net::URLRequest
* request
) {
92 if (request
->method() == "GET" ||
93 request
->method() == "OPTIONS" ||
94 request
->method() == "HEAD" ||
95 request
->method() == "PUT" ||
96 request
->method() == "DELETE" ||
97 request
->method() == "TRACE")
102 void OverrideResponseAsRedirect(
103 net::URLRequest
* request
,
104 const net::HttpResponseHeaders
* original_response_headers
,
105 scoped_refptr
<net::HttpResponseHeaders
>* override_response_headers
) {
107 DCHECK(original_response_headers
);
108 DCHECK(override_response_headers
->get() == NULL
);
110 request
->SetLoadFlags(request
->load_flags() |
111 net::LOAD_DISABLE_CACHE
|
112 net::LOAD_BYPASS_PROXY
);
113 *override_response_headers
= new net::HttpResponseHeaders(
114 original_response_headers
->raw_headers());
115 (*override_response_headers
)->ReplaceStatusLine("HTTP/1.1 302 Found");
116 (*override_response_headers
)->RemoveHeader("Location");
117 (*override_response_headers
)->AddHeader("Location: " +
118 request
->url().spec());
119 // TODO(bengr): Should we pop_back the request->url_chain?
122 void MarkProxiesAsBadUntil(
123 net::URLRequest
* request
,
124 base::TimeDelta
& bypass_duration
,
126 const std::pair
<GURL
, GURL
>& data_reduction_proxies
) {
127 DCHECK(!data_reduction_proxies
.first
.is_empty());
128 // Synthesize a suitable |ProxyInfo| to add the proxies to the
129 // |ProxyRetryInfoMap| of the proxy service.
130 net::ProxyList proxy_list
;
131 net::ProxyServer primary
;
132 SetProxyServerFromGURL(data_reduction_proxies
.first
, &primary
);
133 if (primary
.is_valid())
134 proxy_list
.AddProxyServer(primary
);
135 net::ProxyServer fallback
;
137 if (!data_reduction_proxies
.second
.is_empty())
138 SetProxyServerFromGURL(data_reduction_proxies
.second
, &fallback
);
139 if (fallback
.is_valid())
140 proxy_list
.AddProxyServer(fallback
);
141 proxy_list
.AddProxyServer(net::ProxyServer::Direct());
143 net::ProxyInfo proxy_info
;
144 proxy_info
.UseProxyList(proxy_list
);
145 DCHECK(request
->context());
146 net::ProxyService
* proxy_service
= request
->context()->proxy_service();
147 DCHECK(proxy_service
);
149 proxy_service
->MarkProxiesAsBadUntil(proxy_info
,
155 } // namespace data_reduction_proxy