1 // Copyright (c) 2012 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.
5 #ifndef CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_MANAGER_H_
6 #define CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_MANAGER_H_
8 // A class that implements Chrome's interface with the SafeBrowsing protocol.
9 // See https://developers.google.com/safe-browsing/developers_guide_v2 for
12 // The SafeBrowsingProtocolManager handles formatting and making requests of,
13 // and handling responses from, Google's SafeBrowsing servers. This class uses
14 // The SafeBrowsingProtocolParser class to do the actual parsing.
21 #include "base/containers/hash_tables.h"
22 #include "base/gtest_prod_util.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "base/threading/non_thread_safe.h"
25 #include "base/time/time.h"
26 #include "base/timer/timer.h"
27 #include "chrome/browser/safe_browsing/chunk_range.h"
28 #include "chrome/browser/safe_browsing/protocol_manager_helper.h"
29 #include "chrome/browser/safe_browsing/protocol_parser.h"
30 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
31 #include "net/url_request/url_fetcher_delegate.h"
32 #include "net/url_request/url_request_status.h"
37 class URLRequestContextGetter
;
40 class SBProtocolManagerFactory
;
41 class SafeBrowsingProtocolManagerDelegate
;
43 class SafeBrowsingProtocolManager
: public net::URLFetcherDelegate
,
44 public base::NonThreadSafe
{
46 // FullHashCallback is invoked when GetFullHash completes.
48 // - The vector of full hash results. If empty, indicates that there
49 // were no matches, and that the resource is safe.
50 // - The cache lifetime of the result. A lifetime of 0 indicates the results
51 // should not be cached.
52 typedef base::Callback
<void(const std::vector
<SBFullHashResult
>&,
53 const base::TimeDelta
&)> FullHashCallback
;
55 ~SafeBrowsingProtocolManager() override
;
57 // Makes the passed |factory| the factory used to instantiate
58 // a SafeBrowsingService. Useful for tests.
59 static void RegisterFactory(SBProtocolManagerFactory
* factory
) {
63 // Create an instance of the safe browsing protocol manager.
64 static SafeBrowsingProtocolManager
* Create(
65 SafeBrowsingProtocolManagerDelegate
* delegate
,
66 net::URLRequestContextGetter
* request_context_getter
,
67 const SafeBrowsingProtocolConfig
& config
);
69 // Sets up the update schedule and internal state for making periodic requests
70 // of the Safebrowsing servers.
71 virtual void Initialize();
73 // net::URLFetcherDelegate interface.
74 void OnURLFetchComplete(const net::URLFetcher
* source
) override
;
76 // Retrieve the full hash for a set of prefixes, and invoke the callback
77 // argument when the results are retrieved. The callback may be invoked
79 virtual void GetFullHash(const std::vector
<SBPrefix
>& prefixes
,
80 FullHashCallback callback
,
82 bool is_extended_reporting
);
84 // Forces the start of next update after |interval| time.
85 void ForceScheduleNextUpdate(base::TimeDelta interval
);
87 // Scheduled update callback.
90 // Called by the SafeBrowsingService when our request for a list of all chunks
91 // for each list is done. If database_error is true, that means the protocol
92 // manager shouldn't fetch updates since they can't be written to disk. It
93 // should try again later to open the database.
94 void OnGetChunksComplete(const std::vector
<SBListChunkRanges
>& list
,
96 bool is_extended_reporting
);
98 // The last time we received an update.
99 base::Time
last_update() const { return last_update_
; }
101 // Setter for additional_query_. To make sure the additional_query_ won't
102 // be changed in the middle of an update, caller (e.g.: SafeBrowsingService)
103 // should call this after callbacks triggered in UpdateFinished() or before
104 // IssueUpdateRequest().
105 void set_additional_query(const std::string
& query
) {
106 additional_query_
= query
;
108 const std::string
& additional_query() const {
109 return additional_query_
;
112 // Enumerate failures for histogramming purposes. DO NOT CHANGE THE
113 // ORDERING OF THESE VALUES.
115 // 200 response code means that the server recognized the hash
116 // prefix, while 204 is an empty response indicating that the
117 // server did not recognize it.
121 // Subset of successful responses which returned no full hashes.
122 // This includes the STATUS_204 case, and the *_ERROR cases.
123 GET_HASH_FULL_HASH_EMPTY
,
125 // Subset of successful responses for which one or more of the
126 // full hashes matched (should lead to an interstitial).
127 GET_HASH_FULL_HASH_HIT
,
129 // Subset of successful responses which weren't empty and have no
130 // matches. It means that there was a prefix collision which was
131 // cleared up by the full hashes.
132 GET_HASH_FULL_HASH_MISS
,
134 // Subset of successful responses where the response body wasn't parsable.
135 GET_HASH_PARSE_ERROR
,
137 // Gethash request failed (network error).
138 GET_HASH_NETWORK_ERROR
,
140 // Gethash request returned HTTP result code other than 200 or 204.
143 // Gethash attempted during error backoff, no request sent.
144 GET_HASH_BACKOFF_ERROR
,
146 // Memory space for histograms is determined by the max. ALWAYS
147 // ADD NEW VALUES BEFORE THIS ONE.
151 // Record a GetHash result. |is_download| indicates if the get
152 // hash is triggered by download related lookup.
153 static void RecordGetHashResult(bool is_download
,
154 ResultType result_type
);
156 // Record HTTP response code when there's no error in fetching an HTTP
157 // request, and the error code, when there is.
158 // |metric_name| is the name of the UMA metric to record the response code or
159 // error code against, |status| represents the status of the HTTP request, and
160 // |response code| represents the HTTP response code received from the server.
161 static void RecordHttpResponseOrErrorCode(
162 const char* metric_name
, const net::URLRequestStatus
& status
,
165 // Returns whether another update is currently scheduled.
166 bool IsUpdateScheduled() const;
168 // Called when app changes status of foreground or background.
169 void SetAppInForeground(bool foreground
) {
170 app_in_foreground_
= foreground
;
174 // Constructs a SafeBrowsingProtocolManager for |delegate| that issues
175 // network requests using |request_context_getter|.
176 SafeBrowsingProtocolManager(
177 SafeBrowsingProtocolManagerDelegate
* delegate
,
178 net::URLRequestContextGetter
* request_context_getter
,
179 const SafeBrowsingProtocolConfig
& config
);
182 FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest
, TestBackOffTimes
);
183 FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest
, TestChunkStrings
);
184 FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest
, TestGetHashUrl
);
185 FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest
,
186 TestGetHashBackOffTimes
);
187 FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest
, TestNextChunkUrl
);
188 FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest
, TestUpdateUrl
);
189 friend class SafeBrowsingServerTest
;
190 friend class SBProtocolManagerFactoryImpl
;
192 // Internal API for fetching information from the SafeBrowsing servers. The
193 // GetHash requests are higher priority since they can block user requests
194 // so are handled separately.
195 enum SafeBrowsingRequestType
{
196 NO_REQUEST
= 0, // No requests in progress
197 UPDATE_REQUEST
, // Request for redirect URLs
198 BACKUP_UPDATE_REQUEST
, // Request for redirect URLs to a backup URL.
199 CHUNK_REQUEST
, // Request for a specific chunk
202 // Which type of backup update request is being used.
203 enum BackupUpdateReason
{
204 BACKUP_UPDATE_REASON_CONNECT
,
205 BACKUP_UPDATE_REASON_HTTP
,
206 BACKUP_UPDATE_REASON_NETWORK
,
207 BACKUP_UPDATE_REASON_MAX
,
210 // Generates Update URL for querying about the latest set of chunk updates.
211 GURL
UpdateUrl(bool is_extended_reporting
) const;
213 // Generates backup Update URL for querying about the latest set of chunk
214 // updates. |url_prefix| is the base prefix to use.
215 GURL
BackupUpdateUrl(BackupUpdateReason reason
) const;
217 // Generates GetHash request URL for retrieving full hashes.
218 GURL
GetHashUrl(bool is_extended_reporting
) const;
219 // Generates URL for reporting safe browsing hits for UMA users.
221 // Composes a ChunkUrl based on input string.
222 GURL
NextChunkUrl(const std::string
& input
) const;
224 // Returns the time for the next update request. If |back_off| is true,
225 // the time returned will increment an error count and return the appriate
226 // next time (see ScheduleNextUpdate below).
227 base::TimeDelta
GetNextUpdateInterval(bool back_off
);
229 // Worker function for calculating GetHash and Update backoff times (in
230 // seconds). |multiplier| is doubled for each consecutive error between the
231 // 2nd and 5th, and |error_count| is incremented with each call.
232 base::TimeDelta
GetNextBackOffInterval(size_t* error_count
,
233 size_t* multiplier
) const;
235 // Manages our update with the next allowable update time. If 'back_off_' is
236 // true, we must decrease the frequency of requests of the SafeBrowsing
237 // service according to section 5 of the protocol specification.
238 // When disable_auto_update_ is set, ScheduleNextUpdate will do nothing.
239 // ForceScheduleNextUpdate has to be called to trigger the update.
240 void ScheduleNextUpdate(bool back_off
);
242 // Sends a request for a list of chunks we should download to the SafeBrowsing
243 // servers. In order to format this request, we need to send all the chunk
244 // numbers for each list that we have to the server. Getting the chunk numbers
245 // requires a database query (run on the database thread), and the request
246 // is sent upon completion of that query in OnGetChunksComplete.
247 void IssueUpdateRequest();
249 // Sends a backup request for a list of chunks to download, when the primary
250 // update request failed. |reason| specifies why the backup is needed. Unlike
251 // the primary IssueUpdateRequest, this does not need to hit the local
252 // SafeBrowsing database since the existing chunk numbers are remembered from
253 // the primary update request. Returns whether the backup request was issued -
254 // this may be false in cases where there is not a prefix specified.
255 bool IssueBackupUpdateRequest(BackupUpdateReason reason
);
257 // Sends a request for a chunk to the SafeBrowsing servers.
258 void IssueChunkRequest();
260 // Runs the protocol parser on received data and update the
261 // SafeBrowsingService with the new content. Returns 'true' on successful
262 // parse, 'false' on error.
263 bool HandleServiceResponse(const GURL
& url
, const char* data
, size_t length
);
265 // Updates internal state for each GetHash response error, assuming that the
266 // current time is |now|.
267 void HandleGetHashError(const base::Time
& now
);
269 // Helper function for update completion.
270 void UpdateFinished(bool success
);
271 void UpdateFinished(bool success
, bool back_off
);
273 // A callback that runs if we timeout waiting for a response to an update
274 // request. We use this to properly set our update state.
275 void UpdateResponseTimeout();
277 // Called after the chunks are added to the database.
278 void OnAddChunksComplete();
281 // Map of GetHash requests to parameters which created it.
282 struct FullHashDetails
{
284 FullHashDetails(FullHashCallback callback
, bool is_download
);
287 FullHashCallback callback
;
290 typedef base::hash_map
<const net::URLFetcher
*, FullHashDetails
> HashRequests
;
292 // The factory that controls the creation of SafeBrowsingProtocolManager.
293 // This is used by tests.
294 static SBProtocolManagerFactory
* factory_
;
297 SafeBrowsingProtocolManagerDelegate
* delegate_
;
299 // Current active request (in case we need to cancel) for updates or chunks
300 // from the SafeBrowsing service. We can only have one of these outstanding
301 // at any given time unlike GetHash requests, which are tracked separately.
302 scoped_ptr
<net::URLFetcher
> request_
;
304 // The kind of request that is currently in progress.
305 SafeBrowsingRequestType request_type_
;
307 // The number of HTTP response errors, used for request backoff timing.
308 size_t update_error_count_
;
309 size_t gethash_error_count_
;
311 // Multipliers which double (max == 8) for each error after the second.
312 size_t update_back_off_mult_
;
313 size_t gethash_back_off_mult_
;
315 // Multiplier between 0 and 1 to spread clients over an interval.
316 float back_off_fuzz_
;
318 // The list for which we are make a request.
319 std::string list_name_
;
321 // For managing the next earliest time to query the SafeBrowsing servers for
323 base::TimeDelta next_update_interval_
;
324 base::OneShotTimer
<SafeBrowsingProtocolManager
> update_timer_
;
326 // timeout_timer_ is used to interrupt update requests which are taking
328 base::OneShotTimer
<SafeBrowsingProtocolManager
> timeout_timer_
;
330 // All chunk requests that need to be made.
331 std::deque
<ChunkUrl
> chunk_request_urls_
;
333 HashRequests hash_requests_
;
335 // The next scheduled update has special behavior for the first 2 requests.
336 enum UpdateRequestState
{
341 UpdateRequestState update_state_
;
343 // True if the service has been given an add/sub chunk but it hasn't been
344 // added to the database yet.
345 bool chunk_pending_to_write_
;
347 // The last time we successfully received an update.
348 base::Time last_update_
;
350 // While in GetHash backoff, we can't make another GetHash until this time.
351 base::Time next_gethash_time_
;
353 // Current product version sent in each request.
354 std::string version_
;
356 // Used for measuring chunk request latency.
357 base::Time chunk_request_start_
;
359 // Tracks the size of each update (in bytes).
362 // The safe browsing client name sent in each request.
363 std::string client_name_
;
365 // A string that is appended to the end of URLs for download, gethash,
366 // safebrowsing hits and chunk update requests.
367 std::string additional_query_
;
369 // The context we use to issue network requests.
370 scoped_refptr
<net::URLRequestContextGetter
> request_context_getter_
;
372 // URL prefix where browser fetches safebrowsing chunk updates, and hashes.
373 std::string url_prefix_
;
375 // Backup URL prefixes for updates.
376 std::string backup_url_prefixes_
[BACKUP_UPDATE_REASON_MAX
];
378 // The current reason why the backup update request is happening.
379 BackupUpdateReason backup_update_reason_
;
381 // Data to POST when doing an update.
382 std::string update_list_data_
;
384 // When true, protocol manager will not start an update unless
385 // ForceScheduleNextUpdate() is called. This is set for testing purpose.
386 bool disable_auto_update_
;
388 #if defined(OS_ANDROID)
389 // When true, protocol_manager will not check network connection
390 // type when scheduling next update. This is set for testing purpose.
391 bool disable_connection_check_
;
394 // ID for URLFetchers for testing.
397 // Whether the app is in foreground or background.
398 bool app_in_foreground_
;
400 DISALLOW_COPY_AND_ASSIGN(SafeBrowsingProtocolManager
);
403 // Interface of a factory to create ProtocolManager. Useful for tests.
404 class SBProtocolManagerFactory
{
406 SBProtocolManagerFactory() {}
407 virtual ~SBProtocolManagerFactory() {}
408 virtual SafeBrowsingProtocolManager
* CreateProtocolManager(
409 SafeBrowsingProtocolManagerDelegate
* delegate
,
410 net::URLRequestContextGetter
* request_context_getter
,
411 const SafeBrowsingProtocolConfig
& config
) = 0;
413 DISALLOW_COPY_AND_ASSIGN(SBProtocolManagerFactory
);
416 // Delegate interface for the SafeBrowsingProtocolManager.
417 class SafeBrowsingProtocolManagerDelegate
{
419 typedef base::Callback
<void(
420 const std::vector
<SBListChunkRanges
>&, /* List of chunks */
421 bool, /* database_error */
422 bool /* is_extended_reporting */
423 )> GetChunksCallback
;
424 typedef base::Callback
<void(void)> AddChunksCallback
;
426 virtual ~SafeBrowsingProtocolManagerDelegate();
428 // |UpdateStarted()| is called just before the SafeBrowsing update protocol
430 virtual void UpdateStarted() = 0;
432 // |UpdateFinished()| is called just after the SafeBrowsing update protocol
434 virtual void UpdateFinished(bool success
) = 0;
436 // Wipe out the local database. The SafeBrowsing server can request this.
437 virtual void ResetDatabase() = 0;
439 // Retrieve all the local database chunks, and invoke |callback| with the
440 // results. The SafeBrowsingProtocolManagerDelegate must only invoke the
441 // callback if the SafeBrowsingProtocolManager is still alive. Only one call
442 // may be made to GetChunks at a time.
443 virtual void GetChunks(GetChunksCallback callback
) = 0;
445 // Add new chunks to the database. Invokes |callback| when complete, but must
446 // call at a later time.
447 virtual void AddChunks(const std::string
& list
,
448 scoped_ptr
<ScopedVector
<SBChunkData
> > chunks
,
449 AddChunksCallback callback
) = 0;
451 // Delete chunks from the database.
452 virtual void DeleteChunks(
453 scoped_ptr
<std::vector
<SBChunkDelete
> > chunk_deletes
) = 0;
456 #endif // CHROME_BROWSER_SAFE_BROWSING_PROTOCOL_MANAGER_H_