Moved data reduction proxy header processing out of net
[chromium-blink-merge.git] / components / data_reduction_proxy / browser / data_reduction_proxy_protocol.cc
blob53ece226733e4c12637891abcdb7f1691d877e6b
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"
19 #include "url/gurl.h"
21 namespace {
22 bool SetProxyServerFromGURL(const GURL& gurl,
23 net::ProxyServer* proxy_server) {
24 DCHECK(proxy_server);
25 if (!gurl.SchemeIsHTTPOrHTTPS())
26 return false;
27 *proxy_server = net::ProxyServer(gurl.SchemeIs("http") ?
28 net::ProxyServer::SCHEME_HTTP :
29 net::ProxyServer::SCHEME_HTTPS,
30 net::HostPortPair::FromURL(gurl));
31 return true;
33 } // namespace
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)
43 return false;
44 std::pair<GURL, GURL> data_reduction_proxies;
45 if (!data_reduction_proxy_params->WasDataReductionProxyUsed(
46 request, &data_reduction_proxies)) {
47 return false;
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())
53 return false;
55 if (data_reduction_proxies.first.is_empty())
56 return false;
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) {
63 return false;
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))
80 return false;
82 OverrideResponseAsRedirect(request,
83 original_response_headers,
84 override_response_headers);
85 return true;
90 bool IsRequestIdempotent(const net::URLRequest* request) {
91 DCHECK(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")
98 return true;
99 return false;
102 void OverrideResponseAsRedirect(
103 net::URLRequest* request,
104 const net::HttpResponseHeaders* original_response_headers,
105 scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
106 DCHECK(request);
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,
125 bool bypass_all,
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;
136 if (bypass_all) {
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,
150 bypass_duration,
151 fallback,
152 request->net_log());
155 } // namespace data_reduction_proxy