|  | // Copyright 2014 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_FEEDBACK_FEEDBACK_UPLOADER_H_ | 
|  | #define COMPONENTS_FEEDBACK_FEEDBACK_UPLOADER_H_ | 
|  |  | 
|  | #include <list> | 
|  | #include <queue> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/ref_counted.h" | 
|  | #include "base/memory/weak_ptr.h" | 
|  | #include "base/single_thread_task_runner.h" | 
|  | #include "base/time/time.h" | 
|  | #include "base/timer/timer.h" | 
|  | #include "components/keyed_service/core/keyed_service.h" | 
|  | #include "url/gurl.h" | 
|  |  | 
|  | namespace content { | 
|  | class BrowserContext; | 
|  | }  // namespace content | 
|  |  | 
|  | namespace network { | 
|  | struct ResourceRequest; | 
|  | class SimpleURLLoader; | 
|  | class SharedURLLoaderFactory; | 
|  | }  // namespace network | 
|  |  | 
|  | namespace feedback { | 
|  |  | 
|  | class FeedbackReport; | 
|  |  | 
|  | // FeedbackUploader is used to add a feedback report to the queue of reports | 
|  | // being uploaded. In case uploading a report fails, it is written to disk and | 
|  | // tried again when it's turn comes up next in the queue. | 
|  | class FeedbackUploader : public KeyedService, | 
|  | public base::SupportsWeakPtr<FeedbackUploader> { | 
|  | public: | 
|  | FeedbackUploader( | 
|  | scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, | 
|  | content::BrowserContext* context, | 
|  | scoped_refptr<base::SingleThreadTaskRunner> task_runner); | 
|  | ~FeedbackUploader() override; | 
|  |  | 
|  | static void SetMinimumRetryDelayForTesting(base::TimeDelta delay); | 
|  |  | 
|  | // Queues a report for uploading. | 
|  | void QueueReport(std::unique_ptr<std::string> data); | 
|  |  | 
|  | bool QueueEmpty() const { return reports_queue_.empty(); } | 
|  |  | 
|  | content::BrowserContext* context() { return context_; } | 
|  |  | 
|  | const base::FilePath& feedback_reports_path() const { | 
|  | return feedback_reports_path_; | 
|  | } | 
|  |  | 
|  | scoped_refptr<base::SingleThreadTaskRunner> task_runner() const { | 
|  | return task_runner_; | 
|  | } | 
|  |  | 
|  | base::TimeDelta retry_delay() const { return retry_delay_; } | 
|  |  | 
|  | protected: | 
|  | // Virtual to give implementers a chance to do work before the report is | 
|  | // disptached. Implementers can then call | 
|  | // FeedbackUploader::StartSendingReport() when ready so that the report is | 
|  | // dispatched. | 
|  | virtual void StartDispatchingReport(); | 
|  |  | 
|  | // Invoked when a feedback report upload succeeds. It will reset the | 
|  | // |retry_delay_| to its minimum value and schedules the next report upload if | 
|  | // any. | 
|  | void OnReportUploadSuccess(); | 
|  |  | 
|  | // Invoked when |report_being_dispatched_| fails to upload. If |should_retry| | 
|  | // is true, it will double the |retry_delay_| and reenqueue | 
|  | // |report_being_dispatched_| with the new delay. All subsequent retries will | 
|  | // keep increasing the delay until a successful upload is encountered. | 
|  | void OnReportUploadFailure(bool should_retry); | 
|  |  | 
|  | const scoped_refptr<FeedbackReport>& report_being_dispatched() const { | 
|  | return report_being_dispatched_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | friend class FeedbackUploaderTest; | 
|  |  | 
|  | // This is a std::list so that iterators remain valid during modifications. | 
|  | using UrlLoaderList = std::list<std::unique_ptr<network::SimpleURLLoader>>; | 
|  |  | 
|  | struct ReportsUploadTimeComparator { | 
|  | bool operator()(const scoped_refptr<FeedbackReport>& a, | 
|  | const scoped_refptr<FeedbackReport>& b) const; | 
|  | }; | 
|  |  | 
|  | // Called from DispatchReport() to give implementers a chance to add extra | 
|  | // headers to the upload request before it's sent. | 
|  | virtual void AppendExtraHeadersToUploadRequest( | 
|  | network::ResourceRequest* resource_request); | 
|  |  | 
|  | // Uploads the |report_being_dispatched_| to be uploaded. It must | 
|  | // call either OnReportUploadSuccess() or OnReportUploadFailure() so that | 
|  | // dispatching reports can progress. | 
|  | void DispatchReport(); | 
|  |  | 
|  | void OnDispatchComplete(UrlLoaderList::iterator it, | 
|  | std::unique_ptr<std::string> response_body); | 
|  |  | 
|  | // Update our timer for uploading the next report. | 
|  | void UpdateUploadTimer(); | 
|  |  | 
|  | void QueueReportWithDelay(std::unique_ptr<std::string> data, | 
|  | base::TimeDelta delay); | 
|  |  | 
|  | // URLLoaderFactory used for network requests. | 
|  | scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; | 
|  |  | 
|  | // Browser context this uploader was created for. | 
|  | content::BrowserContext* context_; | 
|  |  | 
|  | const base::FilePath feedback_reports_path_; | 
|  |  | 
|  | // Timer to upload the next report at. | 
|  | base::OneShotTimer upload_timer_; | 
|  |  | 
|  | // See comment of |FeedbackUploaderFactory::task_runner_|. | 
|  | scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 
|  |  | 
|  | scoped_refptr<FeedbackReport> report_being_dispatched_; | 
|  |  | 
|  | const GURL feedback_post_url_; | 
|  |  | 
|  | // Priority queue of reports prioritized by the time the report is supposed | 
|  | // to be uploaded at. | 
|  | std::priority_queue<scoped_refptr<FeedbackReport>, | 
|  | std::vector<scoped_refptr<FeedbackReport>>, | 
|  | ReportsUploadTimeComparator> | 
|  | reports_queue_; | 
|  |  | 
|  | base::TimeDelta retry_delay_; | 
|  |  | 
|  | // True when a report is currently being dispatched. Only a single report | 
|  | // at-a-time should be dispatched. | 
|  | bool is_dispatching_; | 
|  |  | 
|  | UrlLoaderList uploads_in_progress_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(FeedbackUploader); | 
|  | }; | 
|  |  | 
|  | }  // namespace feedback | 
|  |  | 
|  | #endif  // COMPONENTS_FEEDBACK_FEEDBACK_UPLOADER_H_ |