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