protocol_manager.h revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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 CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_MANAGER_H_
6#define CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_MANAGER_H_
7
8// A class that implements Chrome's interface with the SafeBrowsing protocol.
9// The SafeBrowsingProtocolManager handles formatting and making requests of,
10// and handling responses from, Google's SafeBrowsing servers. This class uses
11// The SafeBrowsingProtocolParser class to do the actual parsing.
12
13#include <deque>
14#include <set>
15#include <string>
16#include <vector>
17
18#include "base/gtest_prod_util.h"
19#include "base/hash_tables.h"
20#include "base/scoped_ptr.h"
21#include "base/time.h"
22#include "base/timer.h"
23#include "chrome/browser/safe_browsing/chunk_range.h"
24#include "chrome/browser/safe_browsing/protocol_parser.h"
25#include "chrome/browser/safe_browsing/safe_browsing_service.h"
26#include "chrome/browser/safe_browsing/safe_browsing_util.h"
27#include "chrome/common/net/url_fetcher.h"
28
29class Task;
30class Timer;
31class URLRequestStatus;
32
33#if defined(COMPILER_GCC)
34// Allows us to use URLFetchers in a hash_map with gcc (MSVC is okay without
35// specifying this).
36namespace __gnu_cxx {
37template<>
38struct hash<const URLFetcher*> {
39  size_t operator()(const URLFetcher* fetcher) const {
40    return reinterpret_cast<size_t>(fetcher);
41  }
42};
43}
44#endif
45
46class SafeBrowsingProtocolManager : public URLFetcher::Delegate {
47  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestBackOffTimes);
48  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestChunkStrings);
49  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestGetHashUrl);
50  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest,
51                           TestGetHashBackOffTimes);
52  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestMacKeyUrl);
53  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest,
54                           TestMalwareReportUrl);
55  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestNextChunkUrl);
56  FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestUpdateUrl);
57  friend class SafeBrowsingServiceTest;
58
59 public:
60  // Constructs a SafeBrowsingProtocolManager for |sb_service| that issues
61  // network requests using |request_context_getter|. When |disable_auto_update|
62  // is true, protocol manager won't schedule next update until
63  // ForceScheduleNextUpdate is called.
64  SafeBrowsingProtocolManager(SafeBrowsingService* sb_service,
65                              const std::string& client_name,
66                              const std::string& client_key,
67                              const std::string& wrapped_key,
68                              URLRequestContextGetter* request_context_getter,
69                              const std::string& info_url_prefix,
70                              const std::string& mackey_url_prefix,
71                              bool disable_auto_update);
72  ~SafeBrowsingProtocolManager();
73
74  // Sets up the update schedule and internal state for making periodic requests
75  // of the SafeBrowsing service.
76  void Initialize();
77
78  // URLFetcher::Delegate interface.
79  virtual void OnURLFetchComplete(const URLFetcher* source,
80                                  const GURL& url,
81                                  const URLRequestStatus& status,
82                                  int response_code,
83                                  const ResponseCookies& cookies,
84                                  const std::string& data);
85
86  // API used by the SafeBrowsingService for issuing queries. When the results
87  // are available, SafeBrowsingService::HandleGetHashResults is called.
88  void GetFullHash(SafeBrowsingService::SafeBrowsingCheck* check,
89                   const std::vector<SBPrefix>& prefixes);
90
91  // Forces the start of next update after |next_update_msec| in msec.
92  void ForceScheduleNextUpdate(int next_update_msec);
93
94  bool is_initial_request() const { return initial_request_; }
95
96  // Scheduled update callback.
97  void GetNextUpdate();
98
99  // Called by the SafeBrowsingService when our request for a list of all chunks
100  // for each list is done.  If database_error is true, that means the protocol
101  // manager shouldn't fetch updates since they can't be written to disk.  It
102  // should try again later to open the database.
103  void OnGetChunksComplete(const std::vector<SBListChunkRanges>& list,
104                           bool database_error);
105
106  // Called after the chunks that were parsed were inserted in the database.
107  void OnChunkInserted();
108
109  // The last time we received an update.
110  base::Time last_update() const { return last_update_; }
111
112  // Reports a malware resource to the SafeBrowsing service.
113  void ReportMalware(const GURL& malware_url,
114                     const GURL& page_url,
115                     const GURL& referrer_url);
116
117  // Setter for additional_query_. To make sure the additional_query_ won't
118  // be changed in the middle of an update, caller (e.g.: SafeBrowsingService)
119  // should call this after callbacks triggered in UpdateFinished() or before
120  // IssueUpdateRequest().
121  void set_additional_query(const std::string& query) {
122    additional_query_ = query;
123  }
124  const std::string& additional_query() const {
125    return additional_query_;
126  }
127
128 private:
129  // Internal API for fetching information from the SafeBrowsing servers. The
130  // GetHash requests are higher priority since they can block user requests
131  // so are handled separately.
132  enum SafeBrowsingRequestType {
133    NO_REQUEST = 0,     // No requests in progress
134    UPDATE_REQUEST,   // Request for redirect URLs
135    CHUNK_REQUEST,      // Request for a specific chunk
136    GETKEY_REQUEST      // Update the client's MAC key
137  };
138
139  // Composes a URL using |prefix|, |method| (e.g.: gethash, download,
140  // newkey, report), |client_name| and |version|. When not empty,
141  // |additional_query| is appended to the URL.
142  static std::string ComposeUrl(const std::string& prefix,
143                                const std::string& method,
144                                const std::string& client_name,
145                                const std::string& version,
146                                const std::string& additional_query);
147
148  // Generates Update URL for querying about the latest set of chunk updates.
149  // Append "wrkey=xxx" to the URL when |use_mac| is true.
150  GURL UpdateUrl(bool use_mac) const;
151  // Generates GetHash request URL for retrieving full hashes.
152  // Append "wrkey=xxx" to the URL when |use_mac| is true.
153  GURL GetHashUrl(bool use_mac) const;
154  // Generates new MAC client key request URL.
155  GURL MacKeyUrl() const;
156  // Generates URL for reporting malware pages.
157  GURL MalwareReportUrl(const GURL& malware_url, const GURL& page_url,
158                               const GURL& referrer_url) const;
159  // Composes a ChunkUrl based on input string.
160  GURL NextChunkUrl(const std::string& input) const;
161
162  // Returns the time (in milliseconds) for the next update request. If
163  // 'back_off' is true, the time returned will increment an error count and
164  // return the appriate next time (see ScheduleNextUpdate below).
165  int GetNextUpdateTime(bool back_off);
166
167  // Worker function for calculating GetHash and Update backoff times (in
168  // seconds). 'Multiplier' is doubled for each consecutive error between the
169  // 2nd and 5th, and 'error_count' is incremented with each call.
170  int GetNextBackOffTime(int* error_count, int* multiplier);
171
172  // Manages our update with the next allowable update time. If 'back_off_' is
173  // true, we must decrease the frequency of requests of the SafeBrowsing
174  // service according to section 5 of the protocol specification.
175  // When disable_auto_update_ is set, ScheduleNextUpdate will do nothing.
176  // ForceScheduleNextUpdate has to be called to trigger the update.
177  void ScheduleNextUpdate(bool back_off);
178
179  // Sends a request for a list of chunks we should download to the SafeBrowsing
180  // servers. In order to format this request, we need to send all the chunk
181  // numbers for each list that we have to the server. Getting the chunk numbers
182  // requires a database query (run on the database thread), and the request
183  // is sent upon completion of that query in OnGetChunksComplete.
184  void IssueUpdateRequest();
185
186  // Sends a request for a chunk to the SafeBrowsing servers.
187  void IssueChunkRequest();
188
189  // Gets a key from the SafeBrowsing servers for use with MAC. This should only
190  // be called once per client unless the server directly tells us to update.
191  void IssueKeyRequest();
192
193  // Formats a string returned from the database into:
194  //   "list_name;a:<add_chunk_ranges>:s:<sub_chunk_ranges>:mac\n"
195  static std::string FormatList(const SBListChunkRanges& list, bool use_mac);
196
197  // Runs the protocol parser on received data and update the
198  // SafeBrowsingService with the new content. Returns 'true' on successful
199  // parse, 'false' on error.
200  bool HandleServiceResponse(const GURL& url, const char* data, int length);
201
202  // If the SafeBrowsing service wants us to re-key, we clear our key state and
203  // issue the request.
204  void HandleReKey();
205
206  // Updates internal state for each GetHash response error, assuming that the
207  // current time is |now|.
208  void HandleGetHashError(const base::Time& now);
209
210  // Helper function for update completion.
211  void UpdateFinished(bool success);
212
213  // A callback that runs if we timeout waiting for a response to an update
214  // request. We use this to properly set our update state.
215  void UpdateResponseTimeout();
216
217 private:
218  // Main SafeBrowsing interface object.
219  SafeBrowsingService* sb_service_;
220
221  // Current active request (in case we need to cancel) for updates or chunks
222  // from the SafeBrowsing service. We can only have one of these outstanding
223  // at any given time unlike GetHash requests, which are tracked separately.
224  scoped_ptr<URLFetcher> request_;
225
226  // The kind of request that is currently in progress.
227  SafeBrowsingRequestType request_type_;
228
229  // The number of HTTP response errors, used for request backoff timing.
230  int update_error_count_;
231  int gethash_error_count_;
232
233  // Multipliers which double (max == 8) for each error after the second.
234  int update_back_off_mult_;
235  int gethash_back_off_mult_;
236
237  // Multiplier between 0 and 1 to spread clients over an interval.
238  float back_off_fuzz_;
239
240  // The list for which we are make a request.
241  std::string list_name_;
242
243  // For managing the next earliest time to query the SafeBrowsing servers for
244  // updates.
245  int next_update_sec_;
246  base::OneShotTimer<SafeBrowsingProtocolManager> update_timer_;
247
248  // All chunk requests that need to be made, along with their MAC.
249  std::deque<ChunkUrl> chunk_request_urls_;
250
251  // Map of GetHash requests.
252  typedef base::hash_map<const URLFetcher*,
253                         SafeBrowsingService::SafeBrowsingCheck*> HashRequests;
254  HashRequests hash_requests_;
255
256  // The next scheduled update has special behavior for the first 2 requests.
257  enum UpdateRequestState {
258    FIRST_REQUEST = 0,
259    SECOND_REQUEST,
260    NORMAL_REQUEST
261  };
262  UpdateRequestState update_state_;
263
264  // We'll attempt to get keys once per browser session if we don't already have
265  // them. They are not essential to operation, but provide a layer of
266  // verification.
267  bool initial_request_;
268
269  // True if the service has been given an add/sub chunk but it hasn't been
270  // added to the database yet.
271  bool chunk_pending_to_write_;
272
273  // The keys used for MAC. Empty keys mean we aren't using MAC.
274  std::string client_key_;
275  std::string wrapped_key_;
276
277  // The last time we successfully received an update.
278  base::Time last_update_;
279
280  // While in GetHash backoff, we can't make another GetHash until this time.
281  base::Time next_gethash_time_;
282
283  // Current product version sent in each request.
284  std::string version_;
285
286  // Used for measuring chunk request latency.
287  base::Time chunk_request_start_;
288
289  // Tracks the size of each update (in bytes).
290  int update_size_;
291
292  // Track outstanding malware report fetchers for clean up.
293  std::set<const URLFetcher*> malware_reports_;
294
295  // The safe browsing client name sent in each request.
296  std::string client_name_;
297
298  // A string that is appended to the end of URLs for download, gethash,
299  // newkey, malware report and chunk update requests.
300  std::string additional_query_;
301
302  // The context we use to issue network requests.
303  scoped_refptr<URLRequestContextGetter> request_context_getter_;
304
305  // URL prefix where browser fetches safebrowsing chunk updates, hashes, and
306  // reports malware.
307  std::string info_url_prefix_;
308
309  // URL prefix where browser fetches MAC client key.
310  std::string mackey_url_prefix_;
311
312  // When true, protocol manager will not start an update unless
313  // ForceScheduleNextUpdate() is called. This is set for testing purpose.
314  bool disable_auto_update_;
315
316  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingProtocolManager);
317};
318
319#endif  // CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_MANAGER_H_
320