1f5bd7785696827a5b999cbbdafd5bc18c68b971
[platform/framework/web/crosswalk.git] / src / components / data_reduction_proxy / browser / data_reduction_proxy_usage_stats.cc
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_usage_stats.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/metrics/histogram.h"
11 #include "base/metrics/sparse_histogram.h"
12 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
13 #include "net/base/net_errors.h"
14 #include "net/proxy/proxy_retry_info.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
20 using base::MessageLoopProxy;
21 using net::HostPortPair;
22 using net::ProxyServer;
23 using net::ProxyService;
24 using net::NetworkChangeNotifier;
25 using net::URLRequest;
26
27 namespace data_reduction_proxy {
28
29 namespace {
30
31 // Records a net error code that resulted in bypassing the data reduction
32 // proxy (|is_primary| is true) or the data reduction proxy fallback.
33 void RecordDataReductionProxyBypassOnNetworkError(
34     bool is_primary,
35     const ProxyServer& proxy_server,
36     int net_error) {
37   if (is_primary) {
38     UMA_HISTOGRAM_SPARSE_SLOWLY(
39         "DataReductionProxy.BypassOnNetworkErrorPrimary",
40         std::abs(net_error));
41     return;
42   }
43   UMA_HISTOGRAM_SPARSE_SLOWLY(
44       "DataReductionProxy.BypassOnNetworkErrorFallback",
45       std::abs(net_error));
46 }
47
48 }  // namespace
49
50 // static
51 void DataReductionProxyUsageStats::RecordDataReductionProxyBypassInfo(
52     bool is_primary,
53     bool bypass_all,
54     const net::ProxyServer& proxy_server,
55     DataReductionProxyBypassType bypass_type) {
56   if (bypass_all) {
57     if (is_primary) {
58       UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BlockTypePrimary",
59                                 bypass_type, BYPASS_EVENT_TYPE_MAX);
60     } else {
61       UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BlockTypeFallback",
62                                 bypass_type, BYPASS_EVENT_TYPE_MAX);
63     }
64   } else {
65     if (is_primary) {
66       UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BypassTypePrimary",
67                                 bypass_type, BYPASS_EVENT_TYPE_MAX);
68     } else {
69       UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BypassTypeFallback",
70                                 bypass_type, BYPASS_EVENT_TYPE_MAX);
71     }
72   }
73 }
74
75 DataReductionProxyUsageStats::DataReductionProxyUsageStats(
76     DataReductionProxyParams* params,
77     MessageLoopProxy* ui_thread_proxy)
78     : data_reduction_proxy_params_(params),
79       last_bypass_type_(BYPASS_EVENT_TYPE_MAX),
80       triggering_request_(true),
81       ui_thread_proxy_(ui_thread_proxy),
82       eligible_num_requests_through_proxy_(0),
83       actual_num_requests_through_proxy_(0),
84       unavailable_(false) {
85   NetworkChangeNotifier::AddNetworkChangeObserver(this);
86 };
87
88 DataReductionProxyUsageStats::~DataReductionProxyUsageStats() {
89   NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
90 };
91
92 void DataReductionProxyUsageStats::OnUrlRequestCompleted(
93     const net::URLRequest* request, bool started) {
94   DCHECK(thread_checker_.CalledOnValidThread());
95
96   if (request->status().status() == net::URLRequestStatus::SUCCESS) {
97     if (data_reduction_proxy_params_->IsDataReductionProxyEligible(request)) {
98       bool was_received_via_proxy =
99           data_reduction_proxy_params_->WasDataReductionProxyUsed(
100               request, NULL);
101       IncrementRequestCounts(was_received_via_proxy);
102     }
103   }
104 }
105
106 void DataReductionProxyUsageStats::OnNetworkChanged(
107     NetworkChangeNotifier::ConnectionType type) {
108   DCHECK(thread_checker_.CalledOnValidThread());
109   ClearRequestCounts();
110 }
111
112 void DataReductionProxyUsageStats::IncrementRequestCounts(
113     bool was_received_via_proxy) {
114   DCHECK(thread_checker_.CalledOnValidThread());
115   if (was_received_via_proxy) {
116     actual_num_requests_through_proxy_++;
117   }
118   eligible_num_requests_through_proxy_++;
119
120   // To account for the case when the proxy works for a little while and then
121   // gets blocked, we reset the counts occasionally.
122   if (eligible_num_requests_through_proxy_ > 50
123       && actual_num_requests_through_proxy_ > 0) {
124     ClearRequestCounts();
125   } else {
126     MaybeNotifyUnavailability();
127   }
128 }
129
130 void DataReductionProxyUsageStats::ClearRequestCounts() {
131   DCHECK(thread_checker_.CalledOnValidThread());
132   eligible_num_requests_through_proxy_ = 0;
133   actual_num_requests_through_proxy_ = 0;
134   MaybeNotifyUnavailability();
135 }
136
137 void DataReductionProxyUsageStats::MaybeNotifyUnavailability() {
138   bool prev_unavailable = unavailable_;
139   unavailable_ = (eligible_num_requests_through_proxy_ > 0 &&
140       actual_num_requests_through_proxy_ == 0);
141   if (prev_unavailable != unavailable_) {
142      ui_thread_proxy_->PostTask(FROM_HERE, base::Bind(
143           &DataReductionProxyUsageStats::NotifyUnavailabilityOnUIThread,
144           base::Unretained(this),
145           unavailable_));
146   }
147 }
148
149 void DataReductionProxyUsageStats::NotifyUnavailabilityOnUIThread(
150     bool unavailable) {
151   DCHECK(ui_thread_proxy_->BelongsToCurrentThread());
152   if (!unavailable_callback_.is_null())
153     unavailable_callback_.Run(unavailable);
154 }
155
156 void DataReductionProxyUsageStats::SetBypassType(
157     DataReductionProxyBypassType type) {
158   last_bypass_type_ = type;
159   triggering_request_ = true;
160 }
161
162 void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
163     net::URLRequest& request,
164     const BooleanPrefMember& data_reduction_proxy_enabled) {
165   int64 content_length = request.received_response_content_length();
166   if (data_reduction_proxy_params_->WasDataReductionProxyUsed(&request, NULL)) {
167     RecordBypassedBytes(last_bypass_type_,
168                         DataReductionProxyUsageStats::NOT_BYPASSED,
169                         content_length);
170     return;
171   }
172
173   if (data_reduction_proxy_enabled.GetValue() &&
174       request.url().SchemeIs(url::kHttpsScheme)) {
175     RecordBypassedBytes(last_bypass_type_,
176                         DataReductionProxyUsageStats::SSL,
177                         content_length);
178     return;
179   }
180
181   if (data_reduction_proxy_enabled.GetValue() &&
182       !data_reduction_proxy_params_->IsDataReductionProxyEligible(&request)) {
183     RecordBypassedBytes(last_bypass_type_,
184                         DataReductionProxyUsageStats::LOCAL_BYPASS_RULES,
185                         content_length);
186     return;
187   }
188
189   if (triggering_request_) {
190     RecordBypassedBytes(last_bypass_type_,
191                         DataReductionProxyUsageStats::TRIGGERING_REQUEST,
192                         content_length);
193     triggering_request_ = false;
194
195     // We only record when audio or video triggers a bypass. We don't care
196     // about audio and video bypassed as collateral damage.
197     std::string mime_type;
198     request.GetMimeType(&mime_type);
199     // MIME types are named by <media-type>/<subtype>. We check to see if the
200     // media type is audio or video.
201     if (mime_type.compare(0, 6, "audio/") == 0  ||
202         mime_type.compare(0, 6, "video/") == 0) {
203       RecordBypassedBytes(last_bypass_type_,
204                           DataReductionProxyUsageStats::AUDIO_VIDEO,
205                           content_length);
206     }
207   }
208
209   if (last_bypass_type_ != BYPASS_EVENT_TYPE_MAX) {
210     RecordBypassedBytes(last_bypass_type_,
211                         DataReductionProxyUsageStats::BYPASSED_BYTES_TYPE_MAX,
212                         content_length);
213     return;
214   }
215
216   if (data_reduction_proxy_params_->
217           AreDataReductionProxiesBypassed(request, NULL)) {
218       RecordBypassedBytes(last_bypass_type_,
219                           DataReductionProxyUsageStats::NETWORK_ERROR,
220                           content_length);
221   }
222 }
223
224 void DataReductionProxyUsageStats::RecordBypassEventHistograms(
225     const net::ProxyServer& bypassed_proxy,
226     int net_error,
227     bool did_fallback) const {
228   DataReductionProxyTypeInfo data_reduction_proxy_info;
229   if (bypassed_proxy.is_valid() && !bypassed_proxy.is_direct() &&
230       data_reduction_proxy_params_->IsDataReductionProxy(
231       bypassed_proxy.host_port_pair(), &data_reduction_proxy_info)) {
232     if (data_reduction_proxy_info.is_ssl)
233       return;
234     if (!data_reduction_proxy_info.is_fallback) {
235       RecordDataReductionProxyBypassInfo(
236           true, false, bypassed_proxy, BYPASS_EVENT_TYPE_NETWORK_ERROR);
237       RecordDataReductionProxyBypassOnNetworkError(
238           true, bypassed_proxy, net_error);
239     } else {
240       RecordDataReductionProxyBypassInfo(
241           false, false, bypassed_proxy, BYPASS_EVENT_TYPE_NETWORK_ERROR);
242       RecordDataReductionProxyBypassOnNetworkError(
243           false, bypassed_proxy, net_error);
244     }
245   }
246 }
247
248 void DataReductionProxyUsageStats::RecordBypassedBytes(
249     DataReductionProxyBypassType bypass_type,
250     DataReductionProxyUsageStats::BypassedBytesType bypassed_bytes_type,
251     int64 content_length) {
252   // Individual histograms are needed to count the bypassed bytes for each
253   // bypass type so that we can see the size of requests. This helps us
254   // remove outliers that would skew the sum of bypassed bytes for each type.
255   switch (bypassed_bytes_type) {
256     case DataReductionProxyUsageStats::NOT_BYPASSED:
257       UMA_HISTOGRAM_COUNTS(
258           "DataReductionProxy.BypassedBytes.NotBypassed", content_length);
259       break;
260     case DataReductionProxyUsageStats::SSL:
261       UMA_HISTOGRAM_COUNTS(
262           "DataReductionProxy.BypassedBytes.SSL", content_length);
263       break;
264     case DataReductionProxyUsageStats::LOCAL_BYPASS_RULES:
265       UMA_HISTOGRAM_COUNTS(
266           "DataReductionProxy.BypassedBytes.LocalBypassRules",
267           content_length);
268       break;
269     case DataReductionProxyUsageStats::AUDIO_VIDEO:
270       if (last_bypass_type_ == BYPASS_EVENT_TYPE_SHORT) {
271         UMA_HISTOGRAM_COUNTS(
272             "DataReductionProxy.BypassedBytes.ShortAudioVideo",
273             content_length);
274       }
275       break;
276     case DataReductionProxyUsageStats::TRIGGERING_REQUEST:
277       switch (bypass_type) {
278         case BYPASS_EVENT_TYPE_SHORT:
279           UMA_HISTOGRAM_COUNTS(
280               "DataReductionProxy.BypassedBytes.ShortTriggeringRequest",
281               content_length);
282           break;
283         case BYPASS_EVENT_TYPE_MEDIUM:
284           UMA_HISTOGRAM_COUNTS(
285               "DataReductionProxy.BypassedBytes.MediumTriggeringRequest",
286               content_length);
287           break;
288         case BYPASS_EVENT_TYPE_LONG:
289           UMA_HISTOGRAM_COUNTS(
290               "DataReductionProxy.BypassedBytes.LongTriggeringRequest",
291               content_length);
292           break;
293         default:
294           break;
295       }
296       break;
297     case DataReductionProxyUsageStats::NETWORK_ERROR:
298       UMA_HISTOGRAM_COUNTS(
299           "DataReductionProxy.BypassedBytes.NetworkErrorOther",
300           content_length);
301       break;
302     case DataReductionProxyUsageStats::BYPASSED_BYTES_TYPE_MAX:
303       switch (bypass_type) {
304         case BYPASS_EVENT_TYPE_CURRENT:
305           UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.Current",
306                                content_length);
307           break;
308         case BYPASS_EVENT_TYPE_SHORT:
309           UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.ShortAll",
310                                content_length);
311           break;
312         case BYPASS_EVENT_TYPE_MEDIUM:
313           UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.MediumAll",
314                                content_length);
315           break;
316         case BYPASS_EVENT_TYPE_LONG:
317           UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.LongAll",
318                                content_length);
319           break;
320         case BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX:
321           UMA_HISTOGRAM_COUNTS(
322               "DataReductionProxy.BypassedBytes.MissingViaHeader4xx",
323               content_length);
324           break;
325         case BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER:
326           UMA_HISTOGRAM_COUNTS(
327               "DataReductionProxy.BypassedBytes.MissingViaHeaderOther",
328               content_length);
329           break;
330         case BYPASS_EVENT_TYPE_MALFORMED_407:
331           UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.Malformed407",
332                                content_length);
333          break;
334         case BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR:
335           UMA_HISTOGRAM_COUNTS(
336               "DataReductionProxy.BypassedBytes."
337               "Status500HttpInternalServerError",
338               content_length);
339           break;
340         case BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY:
341           UMA_HISTOGRAM_COUNTS(
342               "DataReductionProxy.BypassedBytes.Status502HttpBadGateway",
343               content_length);
344           break;
345         case BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE:
346           UMA_HISTOGRAM_COUNTS(
347               "DataReductionProxy.BypassedBytes."
348               "Status503HttpServiceUnavailable",
349               content_length);
350           break;
351         default:
352           break;
353       }
354       break;
355   }
356 }
357
358 }  // namespace data_reduction_proxy
359
360