1 // Copyright 2013 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 #include "chrome/browser/feedback/feedback_uploader.h"
7 #include "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/task_runner_util.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "content/public/browser/browser_context.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "net/base/load_flags.h"
16 #include "net/url_request/url_fetcher.h"
19 using content::BrowserThread
;
24 const char kFeedbackPostUrl
[] =
25 "https://www.google.com/tools/feedback/chrome/__submit";
26 const char kProtBufMimeType
[] = "application/x-protobuf";
28 const int64 kRetryDelayMinutes
= 60;
32 struct FeedbackReport
{
33 FeedbackReport(const base::Time
& upload_at
, scoped_ptr
<std::string
> data
)
34 : upload_at(upload_at
), data(data
.Pass()) {}
36 FeedbackReport(const FeedbackReport
& report
) {
37 upload_at
= report
.upload_at
;
38 data
= report
.data
.Pass();
41 FeedbackReport
& operator=(const FeedbackReport
& report
) {
42 upload_at
= report
.upload_at
;
43 data
= report
.data
.Pass();
47 base::Time upload_at
; // Upload this report at or after this time.
48 mutable scoped_ptr
<std::string
> data
;
51 bool FeedbackUploader::ReportsUploadTimeComparator::operator()(
52 const FeedbackReport
& a
, const FeedbackReport
& b
) const {
53 return a
.upload_at
> b
.upload_at
;
56 FeedbackUploader::FeedbackUploader(content::BrowserContext
* context
)
58 retry_delay_(base::TimeDelta::FromMinutes(kRetryDelayMinutes
)) {
60 dispatch_callback_
= base::Bind(&FeedbackUploader::DispatchReport
,
64 FeedbackUploader::~FeedbackUploader() {
67 void FeedbackUploader::QueueReport(scoped_ptr
<std::string
> data
) {
68 reports_queue_
.push(FeedbackReport(base::Time::Now(), data
.Pass()));
72 void FeedbackUploader::DispatchReport(scoped_ptr
<std::string
> data
) {
74 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kFeedbackServer
))
75 post_url
= GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
76 switches::kFeedbackServer
));
78 post_url
= GURL(kFeedbackPostUrl
);
80 // Save the report data pointer since the report.Pass() in the next statement
81 // will invalidate the scoper.
82 std::string
* data_ptr
= data
.get();
83 net::URLFetcher
* fetcher
= net::URLFetcher::Create(
84 post_url
, net::URLFetcher::POST
,
85 new FeedbackUploaderDelegate(
87 base::Bind(&FeedbackUploader::UpdateUploadTimer
, AsWeakPtr()),
88 base::Bind(&FeedbackUploader::RetryReport
, AsWeakPtr())));
90 fetcher
->SetUploadData(std::string(kProtBufMimeType
), *data_ptr
);
91 fetcher
->SetRequestContext(context_
->GetRequestContext());
92 fetcher
->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES
|
93 net::LOAD_DO_NOT_SEND_COOKIES
);
97 void FeedbackUploader::UpdateUploadTimer() {
98 if (reports_queue_
.empty())
101 const FeedbackReport
& report
= reports_queue_
.top();
102 base::Time now
= base::Time::Now();
103 if (report
.upload_at
<= now
) {
104 scoped_ptr
<std::string
> data
= report
.data
.Pass();
105 reports_queue_
.pop();
106 dispatch_callback_
.Run(data
.Pass());
108 // Stop the old timer and start an updated one.
109 if (upload_timer_
.IsRunning())
110 upload_timer_
.Stop();
112 FROM_HERE
, report
.upload_at
- now
, this,
113 &FeedbackUploader::UpdateUploadTimer
);
117 void FeedbackUploader::RetryReport(scoped_ptr
<std::string
> data
) {
119 FeedbackReport(base::Time::Now() + retry_delay_
, data
.Pass()));
123 void FeedbackUploader::setup_for_test(
124 const ReportDataCallback
& dispatch_callback
,
125 const base::TimeDelta
& retry_delay
) {
126 dispatch_callback_
= dispatch_callback
;
127 retry_delay_
= retry_delay
;
130 } // namespace feedback