Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: components/data_reduction_proxy/core/browser/data_reduction_proxy_usage_stats.cc

Issue 956223002: Rename DataReductionProxyUsageStats to DataReductionProxyBypassStats (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: nits Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/core/browser/data_reduction_proxy_usag e_stats.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/metrics/histogram.h"
10 #include "base/metrics/sparse_histogram.h"
11 #include "base/prefs/pref_member.h"
12 #include "base/single_thread_task_runner.h"
13 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_conf ig.h"
14 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_tamp er_detection.h"
15 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_heade rs.h"
16 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_param s.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/net_errors.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/http/http_status_code.h"
21 #include "net/proxy/proxy_server.h"
22 #include "net/proxy/proxy_service.h"
23 #include "net/url_request/url_request.h"
24 #include "net/url_request/url_request_context.h"
25
26 using base::MessageLoopProxy;
27 using net::HostPortPair;
28 using net::ProxyServer;
29 using net::ProxyService;
30 using net::NetworkChangeNotifier;
31 using net::URLRequest;
32
33 namespace data_reduction_proxy {
34
35 namespace {
36
37 const int kMinFailedRequestsWhenUnavailable = 1;
38 const int kMaxSuccessfulRequestsWhenUnavailable = 0;
39 const int kMaxFailedRequestsBeforeReset = 3;
40
41 // Records a net error code that resulted in bypassing the data reduction
42 // proxy (|is_primary| is true) or the data reduction proxy fallback.
43 void RecordDataReductionProxyBypassOnNetworkError(
44 bool is_primary,
45 const ProxyServer& proxy_server,
46 int net_error) {
47 if (is_primary) {
48 UMA_HISTOGRAM_SPARSE_SLOWLY(
49 "DataReductionProxy.BypassOnNetworkErrorPrimary",
50 std::abs(net_error));
51 return;
52 }
53 UMA_HISTOGRAM_SPARSE_SLOWLY(
54 "DataReductionProxy.BypassOnNetworkErrorFallback",
55 std::abs(net_error));
56 }
57
58 } // namespace
59
60 // static
61 void DataReductionProxyUsageStats::RecordDataReductionProxyBypassInfo(
62 bool is_primary,
63 bool bypass_all,
64 const net::ProxyServer& proxy_server,
65 DataReductionProxyBypassType bypass_type) {
66 if (bypass_all) {
67 if (is_primary) {
68 UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BlockTypePrimary",
69 bypass_type, BYPASS_EVENT_TYPE_MAX);
70 } else {
71 UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BlockTypeFallback",
72 bypass_type, BYPASS_EVENT_TYPE_MAX);
73 }
74 } else {
75 if (is_primary) {
76 UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BypassTypePrimary",
77 bypass_type, BYPASS_EVENT_TYPE_MAX);
78 } else {
79 UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.BypassTypeFallback",
80 bypass_type, BYPASS_EVENT_TYPE_MAX);
81 }
82 }
83 }
84
85 // static
86 void DataReductionProxyUsageStats::DetectAndRecordMissingViaHeaderResponseCode(
87 bool is_primary,
88 const net::HttpResponseHeaders* headers) {
89 if (HasDataReductionProxyViaHeader(headers, NULL)) {
90 // The data reduction proxy via header is present, so don't record anything.
91 return;
92 }
93
94 if (is_primary) {
95 UMA_HISTOGRAM_SPARSE_SLOWLY(
96 "DataReductionProxy.MissingViaHeader.ResponseCode.Primary",
97 headers->response_code());
98 } else {
99 UMA_HISTOGRAM_SPARSE_SLOWLY(
100 "DataReductionProxy.MissingViaHeader.ResponseCode.Fallback",
101 headers->response_code());
102 }
103 }
104
105 DataReductionProxyUsageStats::DataReductionProxyUsageStats(
106 DataReductionProxyConfig* config,
107 UnreachableCallback unreachable_callback,
108 const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner)
109 : data_reduction_proxy_config_(config),
110 unreachable_callback_(unreachable_callback),
111 last_bypass_type_(BYPASS_EVENT_TYPE_MAX),
112 triggering_request_(true),
113 ui_task_runner_(ui_task_runner),
114 successful_requests_through_proxy_count_(0),
115 proxy_net_errors_count_(0),
116 unavailable_(false) {
117 DCHECK(config);
118 NetworkChangeNotifier::AddNetworkChangeObserver(this);
119 };
120
121 DataReductionProxyUsageStats::~DataReductionProxyUsageStats() {
122 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
123 };
124
125 void DataReductionProxyUsageStats::OnUrlRequestCompleted(
126 const net::URLRequest* request, bool started) {
127 DCHECK(thread_checker_.CalledOnValidThread());
128
129 DataReductionProxyTypeInfo proxy_info;
130 // Ignore requests that did not use the data reduction proxy. The check for
131 // LOAD_BYPASS_PROXY is necessary because the proxy_server() in the |request|
132 // might still be set to the data reduction proxy if |request| was retried
133 // over direct and a network error occurred while retrying it.
134 if (data_reduction_proxy_config_->WasDataReductionProxyUsed(request,
135 &proxy_info) &&
136 (request->load_flags() & net::LOAD_BYPASS_PROXY) == 0) {
137 if (request->status().status() == net::URLRequestStatus::SUCCESS) {
138 successful_requests_through_proxy_count_++;
139 NotifyUnavailabilityIfChanged();
140 }
141
142 // Report any network errors that occurred for this request, including OK
143 // and ABORTED.
144 if (!proxy_info.is_fallback) {
145 UMA_HISTOGRAM_SPARSE_SLOWLY(
146 "DataReductionProxy.RequestCompletionErrorCodes.Primary",
147 std::abs(request->status().error()));
148 if (request->load_flags() & net::LOAD_MAIN_FRAME) {
149 UMA_HISTOGRAM_SPARSE_SLOWLY(
150 "DataReductionProxy.RequestCompletionErrorCodes.MainFrame.Primary",
151 std::abs(request->status().error()));
152 }
153 } else {
154 UMA_HISTOGRAM_SPARSE_SLOWLY(
155 "DataReductionProxy.RequestCompletionErrorCodes.Fallback",
156 std::abs(request->status().error()));
157 if (request->load_flags() & net::LOAD_MAIN_FRAME) {
158 UMA_HISTOGRAM_SPARSE_SLOWLY(
159 "DataReductionProxy.RequestCompletionErrorCodes.MainFrame.Fallback",
160 std::abs(request->status().error()));
161 }
162 }
163 }
164 }
165
166 void DataReductionProxyUsageStats::SetBypassType(
167 DataReductionProxyBypassType type) {
168 last_bypass_type_ = type;
169 triggering_request_ = true;
170 }
171
172 DataReductionProxyBypassType
173 DataReductionProxyUsageStats::GetBypassType() const {
174 return last_bypass_type_;
175 }
176
177 void DataReductionProxyUsageStats::RecordBytesHistograms(
178 const net::URLRequest& request,
179 const BooleanPrefMember& data_reduction_proxy_enabled,
180 const net::ProxyConfig& data_reduction_proxy_config) {
181 RecordBypassedBytesHistograms(request, data_reduction_proxy_enabled,
182 data_reduction_proxy_config);
183 RecordMissingViaHeaderBytes(request);
184 }
185
186 void DataReductionProxyUsageStats::OnProxyFallback(
187 const net::ProxyServer& bypassed_proxy,
188 int net_error) {
189 DataReductionProxyTypeInfo data_reduction_proxy_info;
190 if (bypassed_proxy.is_valid() && !bypassed_proxy.is_direct() &&
191 data_reduction_proxy_config_->IsDataReductionProxy(
192 bypassed_proxy.host_port_pair(), &data_reduction_proxy_info)) {
193 if (data_reduction_proxy_info.is_ssl)
194 return;
195
196 proxy_net_errors_count_++;
197
198 // To account for the case when the proxy is reachable for sometime, and
199 // then gets blocked, we reset counts when number of errors exceed
200 // the threshold.
201 if (proxy_net_errors_count_ >= kMaxFailedRequestsBeforeReset &&
202 successful_requests_through_proxy_count_ >
203 kMaxSuccessfulRequestsWhenUnavailable) {
204 ClearRequestCounts();
205 } else {
206 NotifyUnavailabilityIfChanged();
207 }
208
209 if (!data_reduction_proxy_info.is_fallback) {
210 RecordDataReductionProxyBypassInfo(
211 true, false, bypassed_proxy, BYPASS_EVENT_TYPE_NETWORK_ERROR);
212 RecordDataReductionProxyBypassOnNetworkError(
213 true, bypassed_proxy, net_error);
214 } else {
215 RecordDataReductionProxyBypassInfo(
216 false, false, bypassed_proxy, BYPASS_EVENT_TYPE_NETWORK_ERROR);
217 RecordDataReductionProxyBypassOnNetworkError(
218 false, bypassed_proxy, net_error);
219 }
220 }
221 }
222
223 void DataReductionProxyUsageStats::OnConnectComplete(
224 const net::HostPortPair& proxy_server,
225 int net_error) {
226 if (data_reduction_proxy_config_->IsDataReductionProxy(proxy_server, NULL)) {
227 UMA_HISTOGRAM_SPARSE_SLOWLY(
228 "DataReductionProxy.HTTPConnectCompleted",
229 std::abs(net_error));
230 }
231 }
232
233 void DataReductionProxyUsageStats::RecordBypassedBytesHistograms(
234 const net::URLRequest& request,
235 const BooleanPrefMember& data_reduction_proxy_enabled,
236 const net::ProxyConfig& data_reduction_proxy_config) {
237 int64 content_length = request.received_response_content_length();
238
239 // Only record histograms when the data reduction proxy is enabled.
240 if (!data_reduction_proxy_enabled.GetValue())
241 return;
242
243 // TODO(bengr): Add histogram(s) for byte counts of unsupported schemes, e.g.,
244 // ws and wss.
245 if (!request.url().SchemeIsHTTPOrHTTPS())
246 return;
247
248 DataReductionProxyTypeInfo data_reduction_proxy_type_info;
249 if (data_reduction_proxy_config_->WasDataReductionProxyUsed(
250 &request, &data_reduction_proxy_type_info)) {
251 RecordBypassedBytes(last_bypass_type_,
252 DataReductionProxyUsageStats::NOT_BYPASSED,
253 content_length);
254
255 // If non-empty, |proxy_server.first| is the proxy that this request used.
256 const net::ProxyServer& first =
257 data_reduction_proxy_type_info.proxy_servers.first;
258 if (first.is_valid() && !first.host_port_pair().IsEmpty()) {
259 DataReductionProxyTamperDetection::DetectAndReport(
260 request.response_info().headers.get(),
261 first.is_https() || first.is_quic(), content_length);
262 }
263 return;
264 }
265
266 if (request.url().SchemeIs(url::kHttpsScheme)) {
267 RecordBypassedBytes(last_bypass_type_,
268 DataReductionProxyUsageStats::SSL,
269 content_length);
270 return;
271 }
272
273 // Now that the data reduction proxy is a best effort proxy, if the effective
274 // proxy configuration resolves to anything other than direct:// for a URL,
275 // the data reduction proxy will not be used.
276 DCHECK(!data_reduction_proxy_type_info.proxy_servers.first.is_valid());
277 if (!request.proxy_server().IsEmpty()) {
278 RecordBypassedBytes(last_bypass_type_,
279 DataReductionProxyUsageStats::PROXY_OVERRIDDEN,
280 content_length);
281 return;
282 }
283
284 if (data_reduction_proxy_config_->IsBypassedByDataReductionProxyLocalRules(
285 request, data_reduction_proxy_config)) {
286 RecordBypassedBytes(last_bypass_type_,
287 DataReductionProxyUsageStats::LOCAL_BYPASS_RULES,
288 content_length);
289 return;
290 }
291
292 // Only record separate triggering request UMA for short, medium, and long
293 // bypass events.
294 if (triggering_request_ &&
295 (last_bypass_type_ == BYPASS_EVENT_TYPE_SHORT ||
296 last_bypass_type_ == BYPASS_EVENT_TYPE_MEDIUM ||
297 last_bypass_type_ == BYPASS_EVENT_TYPE_LONG)) {
298 std::string mime_type;
299 request.GetMimeType(&mime_type);
300 // MIME types are named by <media-type>/<subtype>. Check to see if the
301 // media type is audio or video. Only record when triggered by short bypass,
302 // there isn't an audio or video bucket for medium or long bypasses.
303 if (last_bypass_type_ == BYPASS_EVENT_TYPE_SHORT &&
304 (mime_type.compare(0, 6, "audio/") == 0 ||
305 mime_type.compare(0, 6, "video/") == 0)) {
306 RecordBypassedBytes(last_bypass_type_,
307 DataReductionProxyUsageStats::AUDIO_VIDEO,
308 content_length);
309 return;
310 }
311
312 RecordBypassedBytes(last_bypass_type_,
313 DataReductionProxyUsageStats::TRIGGERING_REQUEST,
314 content_length);
315 triggering_request_ = false;
316 return;
317 }
318
319 if (last_bypass_type_ != BYPASS_EVENT_TYPE_MAX) {
320 RecordBypassedBytes(last_bypass_type_,
321 DataReductionProxyUsageStats::BYPASSED_BYTES_TYPE_MAX,
322 content_length);
323 return;
324 }
325
326 if (data_reduction_proxy_config_->AreDataReductionProxiesBypassed(
327 request, data_reduction_proxy_config, NULL)) {
328 RecordBypassedBytes(last_bypass_type_,
329 DataReductionProxyUsageStats::NETWORK_ERROR,
330 content_length);
331 }
332 }
333
334 void DataReductionProxyUsageStats::RecordMissingViaHeaderBytes(
335 const URLRequest& request) {
336 // Responses that were served from cache should have been filtered out
337 // already.
338 DCHECK(!request.was_cached());
339
340 if (!data_reduction_proxy_config_->WasDataReductionProxyUsed(&request,
341 NULL) ||
342 HasDataReductionProxyViaHeader(request.response_headers(), NULL)) {
343 // Only track requests that used the data reduction proxy and had responses
344 // that were missing the data reduction proxy via header.
345 return;
346 }
347
348 if (request.GetResponseCode() >= net::HTTP_BAD_REQUEST &&
349 request.GetResponseCode() < net::HTTP_INTERNAL_SERVER_ERROR) {
350 // Track 4xx responses that are missing via headers separately.
351 UMA_HISTOGRAM_COUNTS("DataReductionProxy.MissingViaHeader.Bytes.4xx",
352 request.received_response_content_length());
353 } else {
354 UMA_HISTOGRAM_COUNTS("DataReductionProxy.MissingViaHeader.Bytes.Other",
355 request.received_response_content_length());
356 }
357 }
358
359 void DataReductionProxyUsageStats::OnNetworkChanged(
360 NetworkChangeNotifier::ConnectionType type) {
361 DCHECK(thread_checker_.CalledOnValidThread());
362 ClearRequestCounts();
363 }
364
365 void DataReductionProxyUsageStats::ClearRequestCounts() {
366 DCHECK(thread_checker_.CalledOnValidThread());
367 successful_requests_through_proxy_count_ = 0;
368 proxy_net_errors_count_ = 0;
369 }
370
371 void DataReductionProxyUsageStats::NotifyUnavailabilityIfChanged() {
372 bool prev_unavailable = unavailable_;
373 unavailable_ =
374 (proxy_net_errors_count_ >= kMinFailedRequestsWhenUnavailable &&
375 successful_requests_through_proxy_count_ <=
376 kMaxSuccessfulRequestsWhenUnavailable);
377 if (prev_unavailable != unavailable_) {
378 ui_task_runner_->PostTask(FROM_HERE, base::Bind(
379 &DataReductionProxyUsageStats::NotifyUnavailabilityOnUIThread,
380 base::Unretained(this),
381 unavailable_));
382 }
383 }
384
385 void DataReductionProxyUsageStats::NotifyUnavailabilityOnUIThread(
386 bool unavailable) {
387 DCHECK(ui_task_runner_->BelongsToCurrentThread());
388 unreachable_callback_.Run(unavailable);
389 }
390
391 void DataReductionProxyUsageStats::RecordBypassedBytes(
392 DataReductionProxyBypassType bypass_type,
393 DataReductionProxyUsageStats::BypassedBytesType bypassed_bytes_type,
394 int64 content_length) {
395 // Individual histograms are needed to count the bypassed bytes for each
396 // bypass type so that we can see the size of requests. This helps us
397 // remove outliers that would skew the sum of bypassed bytes for each type.
398 switch (bypassed_bytes_type) {
399 case DataReductionProxyUsageStats::NOT_BYPASSED:
400 UMA_HISTOGRAM_COUNTS(
401 "DataReductionProxy.BypassedBytes.NotBypassed", content_length);
402 break;
403 case DataReductionProxyUsageStats::SSL:
404 UMA_HISTOGRAM_COUNTS(
405 "DataReductionProxy.BypassedBytes.SSL", content_length);
406 break;
407 case DataReductionProxyUsageStats::LOCAL_BYPASS_RULES:
408 UMA_HISTOGRAM_COUNTS(
409 "DataReductionProxy.BypassedBytes.LocalBypassRules",
410 content_length);
411 break;
412 case DataReductionProxyUsageStats::PROXY_OVERRIDDEN:
413 UMA_HISTOGRAM_COUNTS(
414 "DataReductionProxy.BypassedBytes.ProxyOverridden",
415 content_length);
416 break;
417 case DataReductionProxyUsageStats::AUDIO_VIDEO:
418 if (last_bypass_type_ == BYPASS_EVENT_TYPE_SHORT) {
419 UMA_HISTOGRAM_COUNTS(
420 "DataReductionProxy.BypassedBytes.ShortAudioVideo",
421 content_length);
422 }
423 break;
424 case DataReductionProxyUsageStats::TRIGGERING_REQUEST:
425 switch (bypass_type) {
426 case BYPASS_EVENT_TYPE_SHORT:
427 UMA_HISTOGRAM_COUNTS(
428 "DataReductionProxy.BypassedBytes.ShortTriggeringRequest",
429 content_length);
430 break;
431 case BYPASS_EVENT_TYPE_MEDIUM:
432 UMA_HISTOGRAM_COUNTS(
433 "DataReductionProxy.BypassedBytes.MediumTriggeringRequest",
434 content_length);
435 break;
436 case BYPASS_EVENT_TYPE_LONG:
437 UMA_HISTOGRAM_COUNTS(
438 "DataReductionProxy.BypassedBytes.LongTriggeringRequest",
439 content_length);
440 break;
441 default:
442 break;
443 }
444 break;
445 case DataReductionProxyUsageStats::NETWORK_ERROR:
446 UMA_HISTOGRAM_COUNTS(
447 "DataReductionProxy.BypassedBytes.NetworkErrorOther",
448 content_length);
449 break;
450 case DataReductionProxyUsageStats::BYPASSED_BYTES_TYPE_MAX:
451 switch (bypass_type) {
452 case BYPASS_EVENT_TYPE_CURRENT:
453 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.Current",
454 content_length);
455 break;
456 case BYPASS_EVENT_TYPE_SHORT:
457 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.ShortAll",
458 content_length);
459 break;
460 case BYPASS_EVENT_TYPE_MEDIUM:
461 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.MediumAll",
462 content_length);
463 break;
464 case BYPASS_EVENT_TYPE_LONG:
465 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.LongAll",
466 content_length);
467 break;
468 case BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX:
469 UMA_HISTOGRAM_COUNTS(
470 "DataReductionProxy.BypassedBytes.MissingViaHeader4xx",
471 content_length);
472 break;
473 case BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER:
474 UMA_HISTOGRAM_COUNTS(
475 "DataReductionProxy.BypassedBytes.MissingViaHeaderOther",
476 content_length);
477 break;
478 case BYPASS_EVENT_TYPE_MALFORMED_407:
479 UMA_HISTOGRAM_COUNTS("DataReductionProxy.BypassedBytes.Malformed407",
480 content_length);
481 break;
482 case BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR:
483 UMA_HISTOGRAM_COUNTS(
484 "DataReductionProxy.BypassedBytes."
485 "Status500HttpInternalServerError",
486 content_length);
487 break;
488 case BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY:
489 UMA_HISTOGRAM_COUNTS(
490 "DataReductionProxy.BypassedBytes.Status502HttpBadGateway",
491 content_length);
492 break;
493 case BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE:
494 UMA_HISTOGRAM_COUNTS(
495 "DataReductionProxy.BypassedBytes."
496 "Status503HttpServiceUnavailable",
497 content_length);
498 break;
499 default:
500 break;
501 }
502 break;
503 }
504 }
505
506 } // namespace data_reduction_proxy
507
508
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698