• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_protocol.h"
6 
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"
20 
21 namespace {
SetProxyServerFromGURL(const GURL & gurl,net::ProxyServer * proxy_server)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;
32 }
33 }  // namespace
34 
35 namespace data_reduction_proxy {
36 
MaybeBypassProxyAndPrepareToRetry(const DataReductionProxyParams * data_reduction_proxy_params,net::URLRequest * request,const net::HttpResponseHeaders * original_response_headers,scoped_refptr<net::HttpResponseHeaders> * override_response_headers)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;
48   }
49 
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;
54 
55   if (data_reduction_proxies.first.is_empty())
56     return false;
57 
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;
64   }
65 
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);
72 
73   MarkProxiesAsBadUntil(request,
74                         data_reduction_proxy_info.bypass_duration,
75                         data_reduction_proxy_info.bypass_all,
76                         data_reduction_proxies);
77 
78   // Only retry idempotent methods.
79   if (!IsRequestIdempotent(request))
80     return false;
81 
82   OverrideResponseAsRedirect(request,
83                              original_response_headers,
84                              override_response_headers);
85   return true;
86 }
87 
88 
89 
IsRequestIdempotent(const net::URLRequest * request)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;
100 }
101 
OverrideResponseAsRedirect(net::URLRequest * request,const net::HttpResponseHeaders * original_response_headers,scoped_refptr<net::HttpResponseHeaders> * override_response_headers)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);
109 
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?
120 }
121 
MarkProxiesAsBadUntil(net::URLRequest * request,base::TimeDelta & bypass_duration,bool bypass_all,const std::pair<GURL,GURL> & data_reduction_proxies)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());
142   }
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);
148 
149   proxy_service->MarkProxiesAsBadUntil(proxy_info,
150                                        bypass_duration,
151                                        fallback,
152                                        request->net_log());
153 }
154 
155 }  // namespace data_reduction_proxy
156