// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_SAFE_BROWSING_DB_V4_GET_HASH_PROTOCOL_MANAGER_H_ #define COMPONENTS_SAFE_BROWSING_DB_V4_GET_HASH_PROTOCOL_MANAGER_H_ // A class that implements Chrome's interface with the SafeBrowsing V4 protocol. // // The V4GetHashProtocolManager handles formatting and making requests of, and // handling responses from, Google's SafeBrowsing servers. The purpose of this // class is to get full hash matches from the SB server for the given set of // hash prefixes. #include #include #include "base/containers/hash_tables.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/threading/non_thread_safe.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "components/safe_browsing_db/safebrowsing.pb.h" #include "components/safe_browsing_db/util.h" #include "net/url_request/url_fetcher_delegate.h" #include "net/url_request/url_request_status.h" #include "url/gurl.h" namespace net { class URLFetcher; class URLRequestContextGetter; } // namespace net namespace safe_browsing { // Config passed to the constructor of a V4GetHashProtocolManager. struct V4GetHashProtocolConfig { std::string client_name; std::string version; std::string key_param; }; class V4GetHashProtocolManagerFactory; class V4GetHashProtocolManager : public net::URLFetcherDelegate, public base::NonThreadSafe { public: // FullHashCallback is invoked when GetFullHashes completes. // Parameters: // - The vector of full hash results. If empty, indicates that there // were no matches, and that the resource is safe. // - The negative cache duration of the result. typedef base::Callback&, const base::TimeDelta&)> FullHashCallback; ~V4GetHashProtocolManager() override; // Makes the passed |factory| the factory used to instantiate // a V4GetHashProtocolManager. Useful for tests. static void RegisterFactory(V4GetHashProtocolManagerFactory* factory) { factory_ = factory; } // Create an instance of the safe browsing v4 protocol manager. static V4GetHashProtocolManager* Create( net::URLRequestContextGetter* request_context_getter, const V4GetHashProtocolConfig& config); // net::URLFetcherDelegate interface. void OnURLFetchComplete(const net::URLFetcher* source) override; // Retrieve the full hash for a set of prefixes, and invoke the callback // argument when the results are retrieved. The callback may be invoked // synchronously. virtual void GetFullHashes(const std::vector& prefixes, const std::vector& platforms, ThreatType threat_type, FullHashCallback callback); // Retrieve the full hash and API metadata for a set of prefixes, and invoke // the callback argument when the results are retrieved. The callback may be // invoked synchronously. virtual void GetFullHashesWithApis(const std::vector& prefixes, FullHashCallback callback); // Enumerate failures for histogramming purposes. DO NOT CHANGE THE // ORDERING OF THESE VALUES. enum ResultType { // 200 response code means that the server recognized the hash // prefix. GET_HASH_STATUS_200 = 0, // Subset of successful responses where the response body wasn't parsable. GET_HASH_PARSE_ERROR = 1, // Gethash request failed (network error). GET_HASH_NETWORK_ERROR = 2, // Gethash request returned HTTP result code other than 200. GET_HASH_HTTP_ERROR = 3, // Gethash attempted during error backoff, no request sent. GET_HASH_BACKOFF_ERROR = 4, // Gethash attempted before min wait duration elapsed, no request sent. GET_HASH_MIN_WAIT_DURATION_ERROR = 5, // Memory space for histograms is determined by the max. ALWAYS // ADD NEW VALUES BEFORE THIS ONE. GET_HASH_RESULT_MAX = 6 }; // Record a GetHash result. static void RecordGetHashResult(ResultType result_type); // Record HTTP response code when there's no error in fetching an HTTP // request, and the error code, when there is. // |metric_name| is the name of the UMA metric to record the response code or // error code against, |status| represents the status of the HTTP request, and // |response code| represents the HTTP response code received from the server. static void RecordHttpResponseOrErrorCode(const char* metric_name, const net::URLRequestStatus& status, int response_code); protected: // Constructs a V4GetHashProtocolManager that issues // network requests using |request_context_getter|. V4GetHashProtocolManager(net::URLRequestContextGetter* request_context_getter, const V4GetHashProtocolConfig& config); private: FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashUrl); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashRequest); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponse); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponseWrongThreatEntryType); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponseSocialEngineeringThreatType); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponseNonPermissionMetadata); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestParseHashResponseInconsistentThreatTypes); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashBackOffTimes); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashErrorHandlingOK); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashErrorHandlingNetwork); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingV4GetHashProtocolManagerTest, TestGetHashErrorHandlingResponseCode); friend class V4GetHashProtocolManagerFactoryImpl; // Generates GetHashWithApis Pver4 request URL for retrieving full hashes. // |request_base64| is the serialized FindFullHashesRequest protocol buffer // encoded in base 64. GURL GetHashUrl(const std::string& request_base64) const; // Fills a FindFullHashesRequest protocol buffer for a request. // Returns the serialized and base 64 encoded request as a string. std::string GetHashRequest(const std::vector& prefixes, const std::vector& platforms, ThreatType threat_type); // Composes a URL using |prefix|, |method| (e.g.: encodedFullHashes). // |request_base64|, |client_id|, |version| and |key_param|. |prefix| // should contain the entire url prefix including scheme, host and path. static std::string ComposePver4Url(const std::string& prefix, const std::string& method, const std::string& request_base64, const std::string& client_id, const std::string& version, const std::string& key_param); // Parses a FindFullHashesResponse protocol buffer and fills the results in // |full_hashes| and |negative_cache_duration|. |data| is a serialized // FindFullHashes protocol buffer. |negative_cache_duration| is the duration // to cache the response for entities that did not match the threat list. // Returns true if parsing is successful, false otherwise. bool ParseHashResponse(const std::string& data_base64, std::vector* full_hashes, base::TimeDelta* negative_cache_duration); // Worker function for calculating the GetHash backoff times. // |multiplier| is doubled for each consecutive error after the // first, and |error_count| is incremented with each call. static base::TimeDelta GetNextBackOffInterval(size_t* error_count, size_t* multiplier); // Resets the gethash error counter and multiplier. void ResetGetHashErrors(); // Updates internal state for each GetHash response error, assuming that // the current time is |now|. void HandleGetHashError(const base::Time& now); private: // Map of GetHash requests to parameters which created it. typedef base::hash_map HashRequests; // The factory that controls the creation of V4GetHashProtocolManager. // This is used by tests. static V4GetHashProtocolManagerFactory* factory_; // Current active request (in case we need to cancel) for updates or chunks // from the SafeBrowsing service. We can only have one of these outstanding // at any given time unlike GetHash requests, which are tracked separately. scoped_ptr request_; // The number of HTTP response errors since the the last successful HTTP // response, used for request backoff timing. size_t gethash_error_count_; // Multiplier for the backoff error after the second. size_t gethash_back_off_mult_; HashRequests hash_requests_; // For v4, the next gethash time is set to the backoff time is the last // response was an error, or the minimum wait time if the last response was // successful. base::Time next_gethash_time_; // Current product version sent in each request. std::string version_; // The safe browsing client name sent in each request. std::string client_name_; // The Google API key. std::string key_param_; // The context we use to issue network requests. scoped_refptr request_context_getter_; // ID for URLFetchers for testing. int url_fetcher_id_; DISALLOW_COPY_AND_ASSIGN(V4GetHashProtocolManager); }; // Interface of a factory to create V4GetHashProtocolManager. Useful for tests. class V4GetHashProtocolManagerFactory { public: V4GetHashProtocolManagerFactory() {} virtual ~V4GetHashProtocolManagerFactory() {} virtual V4GetHashProtocolManager* CreateProtocolManager( net::URLRequestContextGetter* request_context_getter, const V4GetHashProtocolConfig& config) = 0; private: DISALLOW_COPY_AND_ASSIGN(V4GetHashProtocolManagerFactory); }; } // namespace safe_browsing #endif // COMPONENTS_SAFE_BROWSING_DB_V4_GET_HASH_PROTOCOL_MANAGER_H_