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#ifndef COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_USAGE_STATS_H_
6#define COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_USAGE_STATS_H_
7
8#include "base/callback.h"
9#include "base/message_loop/message_loop_proxy.h"
10#include "base/prefs/pref_member.h"
11#include "base/threading/thread_checker.h"
12#include "components/data_reduction_proxy/browser/data_reduction_proxy_params.h"
13#include "components/data_reduction_proxy/common/data_reduction_proxy_headers.h"
14#include "net/base/host_port_pair.h"
15#include "net/base/network_change_notifier.h"
16#include "net/url_request/url_request.h"
17
18namespace net {
19class HttpResponseHeaders;
20class ProxyConfig;
21class ProxyServer;
22}
23
24namespace data_reduction_proxy {
25
26class DataReductionProxyUsageStats
27    : public net::NetworkChangeNotifier::NetworkChangeObserver {
28 public:
29  // Records a data reduction proxy bypass event as a "BlockType" if
30  // |bypass_all| is true and as a "BypassType" otherwise. Records the event as
31  // "Primary" if |is_primary| is true and "Fallback" otherwise.
32  static void RecordDataReductionProxyBypassInfo(
33      bool is_primary,
34      bool bypass_all,
35      const net::ProxyServer& proxy_server,
36      DataReductionProxyBypassType bypass_type);
37
38  // For the given response |headers| that are expected to include the data
39  // reduction proxy via header, records response code UMA if the data reduction
40  // proxy via header is not present.
41  static void DetectAndRecordMissingViaHeaderResponseCode(
42      bool is_primary,
43      const net::HttpResponseHeaders* headers);
44
45  // MessageLoopProxy instance is owned by io_thread. |params| outlives
46  // this class instance.
47  DataReductionProxyUsageStats(
48      DataReductionProxyParams* params,
49      const scoped_refptr<base::MessageLoopProxy>& ui_thread_proxy);
50  virtual ~DataReductionProxyUsageStats();
51
52  // Sets the callback to be called on the UI thread when the unavailability
53  // status has changed.
54  void set_unavailable_callback(
55      const base::Callback<void(bool)>& unavailable_callback) {
56    unavailable_callback_ = unavailable_callback;
57  }
58
59  // Callback intended to be called from |ChromeNetworkDelegate| when a
60  // request completes. This method is used to gather usage stats.
61  void OnUrlRequestCompleted(const net::URLRequest* request, bool started);
62
63  // Records the last bypass reason to |bypass_type_| and sets
64  // |triggering_request_| to true. A triggering request is the first request to
65  // cause the current bypass.
66  void SetBypassType(DataReductionProxyBypassType type);
67
68  // Records all the data reduction proxy bytes-related histograms for the
69  // completed URLRequest |request|.
70  void RecordBytesHistograms(
71      net::URLRequest* request,
72      const BooleanPrefMember& data_reduction_proxy_enabled,
73      const net::ProxyConfig& data_reduction_proxy_config);
74
75  // Called by |ChromeNetworkDelegate| when a proxy is put into the bad proxy
76  // list. Used to track when the data reduction proxy falls back.
77  void OnProxyFallback(const net::ProxyServer& bypassed_proxy,
78                       int net_error);
79
80 private:
81  friend class DataReductionProxyUsageStatsTest;
82  FRIEND_TEST_ALL_PREFIXES(DataReductionProxyUsageStatsTest,
83                           RecordMissingViaHeaderBytes);
84
85  enum BypassedBytesType {
86    NOT_BYPASSED = 0,         /* Not bypassed. */
87    SSL,                      /* Bypass due to SSL. */
88    LOCAL_BYPASS_RULES,       /* Bypass due to client-side bypass rules. */
89    MANAGED_PROXY_CONFIG,     /* Bypass due to managed config. */
90    AUDIO_VIDEO,              /* Audio/Video bypass. */
91    TRIGGERING_REQUEST,       /* Triggering request bypass. */
92    NETWORK_ERROR,            /* Network error. */
93    BYPASSED_BYTES_TYPE_MAX   /* This must always be last.*/
94  };
95
96  // Given |data_reduction_proxy_enabled|, a |request|, and the
97  // |data_reduction_proxy_config| records the number of bypassed bytes for that
98  // |request| into UMAs based on bypass type. |data_reduction_proxy_enabled|
99  // tells us the state of the kDataReductionProxyEnabled preference.
100  void RecordBypassedBytesHistograms(
101      net::URLRequest* request,
102      const BooleanPrefMember& data_reduction_proxy_enabled,
103      const net::ProxyConfig& data_reduction_proxy_config);
104
105  // Records UMA of the number of response bytes of responses that are expected
106  // to have the data reduction proxy via header, but where the data reduction
107  // proxy via header is not present.
108  void RecordMissingViaHeaderBytes(net::URLRequest* request);
109
110  // NetworkChangeNotifier::NetworkChangeObserver:
111  virtual void OnNetworkChanged(
112      net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
113
114  // Called when request counts change. Resets counts if they exceed thresholds,
115  // and calls MaybeNotifyUnavailability otherwise.
116  void OnRequestCountChanged();
117
118  // Clears request counts unconditionally.
119  void ClearRequestCounts();
120
121  // Checks if the availability status of the data reduction proxy has changed,
122  // and notifies the UIThread via NotifyUnavailabilityOnUIThread if so. The
123  // data reduction proxy is considered unavailable if and only if no requests
124  // went through the proxy but some eligible requests were service by other
125  // routes.
126  void NotifyUnavailabilityIfChanged();
127  void NotifyUnavailabilityOnUIThread(bool unavailable);
128
129  DataReductionProxyParams* data_reduction_proxy_params_;
130  // The last reason for bypass as determined by
131  // MaybeBypassProxyAndPrepareToRetry
132  DataReductionProxyBypassType last_bypass_type_;
133  // True if the last request triggered the current bypass.
134  bool triggering_request_;
135  const scoped_refptr<base::MessageLoopProxy> ui_thread_proxy_;
136
137  // The following 2 fields are used to determine if data reduction proxy is
138  // unreachable. We keep a count of requests which should go through
139  // data request proxy, as well as those which actually do. The proxy is
140  // unreachable if no successful requests are made through it despite a
141  // non-zero number of requests being eligible.
142
143  // Count of successful requests through the data reduction proxy.
144  unsigned long successful_requests_through_proxy_count_;
145
146  // Count of network errors encountered when connecting to a data reduction
147  // proxy.
148  unsigned long proxy_net_errors_count_;
149
150  // Whether or not the data reduction proxy is unavailable.
151  bool unavailable_;
152
153  base::ThreadChecker thread_checker_;
154
155  void RecordBypassedBytes(
156      DataReductionProxyBypassType bypass_type,
157      BypassedBytesType bypassed_bytes_type,
158      int64 content_length);
159
160  // Called when the unavailability status has changed. Runs on the UI thread.
161  base::Callback<void(bool)> unavailable_callback_;
162
163  DISALLOW_COPY_AND_ASSIGN(DataReductionProxyUsageStats);
164};
165
166}  // namespace data_reduction_proxy
167
168#endif  // COMPONENTS_DATA_REDUCTION_PROXY_BROWSER_DATA_REDUCTION_PROXY_USAGE_STATS_H_
169