| // Copyright 2016 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef CHROME_BROWSER_SAFE_BROWSING_CERTIFICATE_REPORTING_SERVICE_H_ | 
 | #define CHROME_BROWSER_SAFE_BROWSING_CERTIFICATE_REPORTING_SERVICE_H_ | 
 |  | 
 | #include <map> | 
 | #include <memory> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "base/callback_list.h" | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "base/memory/raw_ref.h" | 
 | #include "base/memory/weak_ptr.h" | 
 | #include "base/threading/thread_checker.h" | 
 | #include "base/time/time.h" | 
 | #include "chrome/browser/ssl/certificate_error_reporter.h" | 
 | #include "components/keyed_service/core/keyed_service.h" | 
 | #include "services/network/public/cpp/shared_url_loader_factory.h" | 
 |  | 
 | class PrefService; | 
 | class Profile; | 
 |  | 
 | namespace base { | 
 | class Clock; | 
 | } | 
 |  | 
 | namespace network { | 
 | class SharedURLLoaderFactory; | 
 | } | 
 |  | 
 | namespace safe_browsing { | 
 | class SafeBrowsingService; | 
 | } | 
 |  | 
 | // This service initiates uploads of invalid certificate reports and retries any | 
 | // failed uploads. Each report is retried until it's older than a certain time | 
 | // to live (TTL). Reports older than this TTL are dropped and no more retried, | 
 | // so that the retry list doesn't grow indefinitely. | 
 | // | 
 | // Lifetime and dependencies: | 
 | // | 
 | // CertificateReportingService uses the URLLoaderFactory from SafeBrowsing | 
 | // service. SafeBrowsingService is created before CertificateReportingService, | 
 | // but is also shut down before any KeyedService is shut down. | 
 | // | 
 | // This class observes SafeBrowsing preference changes to enable/disable | 
 | // reporting. It does this by subscribing to changes in SafeBrowsing and | 
 | // extended reporting preferences. | 
 | class CertificateReportingService : public KeyedService { | 
 |  public: | 
 |   // Events for UMA. Do not rename or remove values, add new values to the end. | 
 |   // Public for testing. | 
 |   enum class ReportOutcome { | 
 |     // A report is submitted. This includes failed and successful uploads as | 
 |     // well as uploads that never return a response. | 
 |     SUBMITTED = 0, | 
 |     // A report submission failed, either because of a net error or a non-HTTP | 
 |     // 200 response from the server. | 
 |     FAILED = 1, | 
 |     // A report submission was successfully sent, receiving an HTTP 200 response | 
 |     // from the server. | 
 |     SUCCESSFUL = 2, | 
 |     // A report was dropped from the reporting queue because it was older | 
 |     // than report TTL, or it was ignored because the queue was full and the | 
 |     // report was older than the oldest report in the queue. Does not include | 
 |     // reports that were cleared because of a SafeBrowsing preference change. | 
 |     DROPPED_OR_IGNORED = 3, | 
 |     EVENT_COUNT = 4 | 
 |   }; | 
 |  | 
 |   // Represents a report to be sent. | 
 |   struct Report { | 
 |     int report_id; | 
 |     base::Time creation_time; | 
 |     std::string serialized_report; | 
 |     bool is_retried; | 
 |     Report(int report_id, | 
 |            base::Time creation_time, | 
 |            const std::string& serialized_report) | 
 |         : report_id(report_id), | 
 |           creation_time(creation_time), | 
 |           serialized_report(serialized_report), | 
 |           is_retried(false) {} | 
 |   }; | 
 |  | 
 |   // This class contains a number of reports, sorted by the first time the | 
 |   // report was to be sent. Oldest reports are at the end of the list. The | 
 |   // number of reports are bounded by |max_size|. The implementation sorts all | 
 |   // items in the list whenever a new item is added. This should be fine for | 
 |   // small values of |max_size| (e.g. fewer than 100 items). In case this is not | 
 |   // sufficient in the future, an array based implementation should be | 
 |   // considered where the array is maintained as a heap. | 
 |   class BoundedReportList { | 
 |    public: | 
 |     explicit BoundedReportList(size_t max_size); | 
 |  | 
 |     BoundedReportList(const BoundedReportList&) = delete; | 
 |     BoundedReportList& operator=(const BoundedReportList&) = delete; | 
 |  | 
 |     ~BoundedReportList(); | 
 |  | 
 |     void Add(const Report& report); | 
 |     void Clear(); | 
 |  | 
 |     const std::vector<Report>& items() const; | 
 |  | 
 |    private: | 
 |     // Maximum number of reports in the list. If the number of reports in the | 
 |     // list is smaller than this number, a new item is immediately added to the | 
 |     // list. Otherwise, the item is compared to the items in the list and only | 
 |     // added when it's newer than the oldest item in the list. | 
 |     const size_t max_size_; | 
 |  | 
 |     std::vector<Report> items_; | 
 |     base::ThreadChecker thread_checker_; | 
 |   }; | 
 |  | 
 |   // Class that handles report uploads and implements the upload retry logic. | 
 |   class Reporter { | 
 |    public: | 
 |     Reporter(std::unique_ptr<CertificateErrorReporter> error_reporter_, | 
 |              std::unique_ptr<BoundedReportList> retry_list, | 
 |              base::Clock* const clock, | 
 |              base::TimeDelta report_ttl, | 
 |              bool retries_enabled); | 
 |  | 
 |     Reporter(const Reporter&) = delete; | 
 |     Reporter& operator=(const Reporter&) = delete; | 
 |  | 
 |     ~Reporter(); | 
 |  | 
 |     // Sends a report. If the send fails, the report will be added to the retry | 
 |     // list. | 
 |     void Send(const std::string& serialized_report); | 
 |  | 
 |     // Sends all pending reports. Skips reports older than the |report_ttl| | 
 |     // provided in the constructor. Failed reports will be added to the retry | 
 |     // list. | 
 |     void SendPending(); | 
 |  | 
 |     // Getter and setters for testing: | 
 |     size_t inflight_report_count_for_testing() const; | 
 |     BoundedReportList* GetQueueForTesting() const; | 
 |     // Sets a closure that is called when there are no more inflight reports. | 
 |     void SetClosureWhenNoInflightReportsForTesting(base::OnceClosure closure); | 
 |  | 
 |    private: | 
 |     void SendInternal(const Report& report); | 
 |     // Called when a report upload fails either because of a net error or a | 
 |     // non-HTTP 200 response code. See | 
 |     // TransportSecurityState::ReportSenderInterface for parameters. | 
 |     void ErrorCallback(int report_id, | 
 |                        int net_error, | 
 |                        int http_response_code); | 
 |     // Called when a report upload is successful. | 
 |     void SuccessCallback(int report_id); | 
 |  | 
 |     std::unique_ptr<CertificateErrorReporter> error_reporter_; | 
 |     std::unique_ptr<BoundedReportList> retry_list_; | 
 |     const raw_ptr<base::Clock> clock_; | 
 |     // Maximum age of a queued report. Reports older than this are discarded in | 
 |     // the next SendPending() call. | 
 |     const base::TimeDelta report_ttl_; | 
 |     const bool retries_enabled_; | 
 |     // Current report id, starting from zero and monotonically incrementing. | 
 |     int current_report_id_; | 
 |  | 
 |     std::map<int, Report> inflight_reports_; | 
 |  | 
 |     base::OnceClosure no_in_flight_reports_; | 
 |  | 
 |     base::WeakPtrFactory<Reporter> weak_factory_{this}; | 
 |   }; | 
 |  | 
 |   // Public for testing. | 
 |   static const char kReportEventHistogram[]; | 
 |  | 
 |   CertificateReportingService( | 
 |       safe_browsing::SafeBrowsingService* safe_browsing_service, | 
 |       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, | 
 |       Profile* profile, | 
 |       uint8_t server_public_key[/* 32 */], | 
 |       uint32_t server_public_key_version, | 
 |       size_t max_queued_report_count, | 
 |       base::TimeDelta max_report_age, | 
 |       base::Clock* clock, | 
 |       const base::RepeatingClosure& reset_callback); | 
 |  | 
 |   CertificateReportingService(const CertificateReportingService&) = delete; | 
 |   CertificateReportingService& operator=(const CertificateReportingService&) = | 
 |       delete; | 
 |  | 
 |   ~CertificateReportingService() override; | 
 |  | 
 |   // KeyedService implementation: | 
 |   void Shutdown() override; | 
 |  | 
 |   // Sends a serialized report. If the report upload fails, the upload is | 
 |   // retried at a future time. | 
 |   void Send(const std::string& serialized_report); | 
 |  | 
 |   // Sends pending reports that are in the retry queue. | 
 |   void SendPending(); | 
 |  | 
 |   // Enables or disables reporting. When disabled, pending report queue is | 
 |   // cleared and incoming reports are ignored. Reporting is enabled by default | 
 |   // once the service is initialized. | 
 |   void SetEnabled(bool enabled); | 
 |  | 
 |   // Getters for testing. | 
 |   Reporter* GetReporterForTesting() const; | 
 |   static GURL GetReportingURLForTesting(); | 
 |  | 
 |  private: | 
 |   // Resets the reporter. Changes in SafeBrowsing or extended reporting enabled | 
 |   // states cause the reporter to be reset. If |enabled| is false, report is set | 
 |   // to null, effectively cancelling all in flight uploads and clearing the | 
 |   // pending reports queue. | 
 |   void Reset(bool enabled); | 
 |  | 
 |   void OnPreferenceChanged(); | 
 |  | 
 |   const raw_ref<const PrefService> pref_service_; | 
 |   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; | 
 |   std::unique_ptr<Reporter> reporter_; | 
 |  | 
 |   // Subscription for state changes. When the callback is notified, it | 
 |   // means SafeBrowsingService is enabled/disabled or one of the preferences | 
 |   // related to it is changed. | 
 |   base::CallbackListSubscription safe_browsing_state_subscription_; | 
 |  | 
 |   // Maximum number of reports to be queued for retry. | 
 |   const size_t max_queued_report_count_; | 
 |  | 
 |   // Maximum age of the reports to be queued for retry, from the time the | 
 |   // certificate error was first encountered by the user. Any report older than | 
 |   // this age is ignored and is not re-uploaded. | 
 |   const base::TimeDelta max_report_age_; | 
 |  | 
 |   const raw_ptr<base::Clock> clock_; | 
 |  | 
 |   // Called when the service is reset. Used for testing. | 
 |   base::RepeatingClosure reset_callback_; | 
 |  | 
 |   // Encryption parameters. | 
 |   raw_ptr<uint8_t> server_public_key_; | 
 |   uint32_t server_public_key_version_; | 
 | }; | 
 |  | 
 | #endif  // CHROME_BROWSER_SAFE_BROWSING_CERTIFICATE_REPORTING_SERVICE_H_ |