diff options
author | rkc@chromium.org <rkc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-19 22:46:03 +0000 |
---|---|---|
committer | rkc@chromium.org <rkc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-19 22:46:03 +0000 |
commit | 4abf1a4814b4639ca3e21bdcc89c876dec380072 (patch) | |
tree | 061a53638b944628482ec9a6ebbebc01840e9b6d /chrome/browser/feedback | |
parent | 4799e5b86eef5fe9281baec4def22e5092dc2b0d (diff) | |
download | chromium_src-4abf1a4814b4639ca3e21bdcc89c876dec380072.zip chromium_src-4abf1a4814b4639ca3e21bdcc89c876dec380072.tar.gz chromium_src-4abf1a4814b4639ca3e21bdcc89c876dec380072.tar.bz2 |
Add feedback uploader to upload reports in a sequenced manner with retries.
This is the first part of the CL that will enable re-sending feedback reports that were sent when the user was offline, across sessions.
R=jcivelli@chromium.org, zork@chromium.org
BUG=249853
Review URL: https://codereview.chromium.org/116863002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@241962 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/feedback')
-rw-r--r-- | chrome/browser/feedback/feedback_uploader.cc | 130 | ||||
-rw-r--r-- | chrome/browser/feedback/feedback_uploader.h | 76 | ||||
-rw-r--r-- | chrome/browser/feedback/feedback_uploader_delegate.cc | 65 | ||||
-rw-r--r-- | chrome/browser/feedback/feedback_uploader_delegate.h | 42 | ||||
-rw-r--r-- | chrome/browser/feedback/feedback_uploader_factory.cc | 37 | ||||
-rw-r--r-- | chrome/browser/feedback/feedback_uploader_factory.h | 45 | ||||
-rw-r--r-- | chrome/browser/feedback/feedback_uploader_unittest.cc | 131 | ||||
-rw-r--r-- | chrome/browser/feedback/feedback_util.cc | 132 |
8 files changed, 533 insertions, 125 deletions
diff --git a/chrome/browser/feedback/feedback_uploader.cc b/chrome/browser/feedback/feedback_uploader.cc new file mode 100644 index 0000000..2cfbc03 --- /dev/null +++ b/chrome/browser/feedback/feedback_uploader.cc @@ -0,0 +1,130 @@ +// Copyright 2013 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. + +#include "chrome/browser/feedback/feedback_uploader.h" + +#include "base/callback.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/task_runner_util.h" +#include "base/threading/sequenced_worker_pool.h" +#include "chrome/common/chrome_switches.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "net/base/load_flags.h" +#include "net/url_request/url_fetcher.h" +#include "url/gurl.h" + +using content::BrowserThread; + +namespace feedback { +namespace { + +const char kFeedbackPostUrl[] = + "https://www.google.com/tools/feedback/chrome/__submit"; +const char kProtBufMimeType[] = "application/x-protobuf"; + +const base::TimeDelta kRetryDelay = base::TimeDelta::FromMinutes(60); + +} // namespace + +struct FeedbackReport { + FeedbackReport(const base::Time& upload_at, scoped_ptr<std::string> data) + : upload_at(upload_at), data(data.Pass()) {} + + FeedbackReport(const FeedbackReport& report) { + upload_at = report.upload_at; + data = report.data.Pass(); + } + + FeedbackReport& operator=(const FeedbackReport& report) { + upload_at = report.upload_at; + data = report.data.Pass(); + return *this; + } + + base::Time upload_at; // Upload this report at or after this time. + mutable scoped_ptr<std::string> data; +}; + +bool FeedbackUploader::ReportsUploadTimeComparator::operator()( + const FeedbackReport& a, const FeedbackReport& b) const { + return a.upload_at > b.upload_at; +} + +FeedbackUploader::FeedbackUploader(content::BrowserContext* context) + : context_(context), + retry_delay_(kRetryDelay) { + CHECK(context_); + dispatch_callback_ = base::Bind(&FeedbackUploader::DispatchReport, + AsWeakPtr()); +} + +FeedbackUploader::~FeedbackUploader() { +} + +void FeedbackUploader::QueueReport(scoped_ptr<std::string> data) { + reports_queue_.push(FeedbackReport(base::Time::Now(), data.Pass())); + UpdateUploadTimer(); +} + +void FeedbackUploader::DispatchReport(scoped_ptr<std::string> data) { + GURL post_url; + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kFeedbackServer)) + post_url = GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kFeedbackServer)); + else + post_url = GURL(kFeedbackPostUrl); + + // Save the report data pointer since the report.Pass() in the next statement + // will invalidate the scoper. + std::string* data_ptr = data.get(); + net::URLFetcher* fetcher = net::URLFetcher::Create( + post_url, net::URLFetcher::POST, + new FeedbackUploaderDelegate( + data.Pass(), + base::Bind(&FeedbackUploader::UpdateUploadTimer, AsWeakPtr()), + base::Bind(&FeedbackUploader::RetryReport, AsWeakPtr()))); + + fetcher->SetUploadData(std::string(kProtBufMimeType), *data_ptr); + fetcher->SetRequestContext(context_->GetRequestContext()); + fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | + net::LOAD_DO_NOT_SEND_COOKIES); + fetcher->Start(); +} + +void FeedbackUploader::UpdateUploadTimer() { + if (reports_queue_.empty()) + return; + + const FeedbackReport& report = reports_queue_.top(); + base::Time now = base::Time::Now(); + if (report.upload_at <= now) { + scoped_ptr<std::string> data = report.data.Pass(); + reports_queue_.pop(); + dispatch_callback_.Run(data.Pass()); + } else { + // Stop the old timer and start an updated one. + if (upload_timer_.IsRunning()) + upload_timer_.Stop(); + upload_timer_.Start( + FROM_HERE, report.upload_at - now, this, + &FeedbackUploader::UpdateUploadTimer); + } +} + +void FeedbackUploader::RetryReport(scoped_ptr<std::string> data) { + reports_queue_.push( + FeedbackReport(base::Time::Now() + retry_delay_, data.Pass())); + UpdateUploadTimer(); +} + +void FeedbackUploader::setup_for_test( + const ReportDataCallback& dispatch_callback, + const base::TimeDelta& retry_delay) { + dispatch_callback_ = dispatch_callback; + retry_delay_ = retry_delay; +} + +} // namespace feedback diff --git a/chrome/browser/feedback/feedback_uploader.h b/chrome/browser/feedback/feedback_uploader.h new file mode 100644 index 0000000..5c31047 --- /dev/null +++ b/chrome/browser/feedback/feedback_uploader.h @@ -0,0 +1,76 @@ +// Copyright 2013 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 CHROME_BROWSER_FEEDBACK_FEEDBACK_UPLOADER_H_ +#define CHROME_BROWSER_FEEDBACK_FEEDBACK_UPLOADER_H_ + +#include <queue> +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "base/timer/timer.h" +#include "chrome/browser/feedback/feedback_uploader_delegate.h" +#include "components/browser_context_keyed_service/browser_context_keyed_service.h" + +namespace content { +class BrowserContext; +} + +namespace feedback { + +struct 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 BrowserContextKeyedService, + public base::SupportsWeakPtr<FeedbackUploader> { + public: + explicit FeedbackUploader(content::BrowserContext* context); + virtual ~FeedbackUploader(); + + void QueueReport(scoped_ptr<std::string> data); + + private: + friend class FeedbackUploaderTest; + struct ReportsUploadTimeComparator { + bool operator()(const FeedbackReport& a, const FeedbackReport& b) const; + }; + + // Dispatches the report to be uploaded. + void DispatchReport(scoped_ptr<std::string> data); + + // Update our timer for uploading the next report. + void UpdateUploadTimer(); + + // Requeue this report with a delay. + void RetryReport(scoped_ptr<std::string> data); + + void setup_for_test(const ReportDataCallback& dispatch_callback, + const base::TimeDelta& retry_delay); + + // Browser context this uploader was created for. + content::BrowserContext* context_; + // Timer to upload the next report at. + base::OneShotTimer<FeedbackUploader> upload_timer_; + // Priority queue of reports prioritized by the time the report is supposed + // to be uploaded at. + std::priority_queue<FeedbackReport, + std::vector<FeedbackReport>, + ReportsUploadTimeComparator> reports_queue_; + + std::vector<FeedbackReport> loaded_reports_; + + ReportDataCallback dispatch_callback_; + base::TimeDelta retry_delay_; + + DISALLOW_COPY_AND_ASSIGN(FeedbackUploader); +}; + +} // namespace feedback + +#endif // CHROME_BROWSER_FEEDBACK_FEEDBACK_UPLOADER_H_ diff --git a/chrome/browser/feedback/feedback_uploader_delegate.cc b/chrome/browser/feedback/feedback_uploader_delegate.cc new file mode 100644 index 0000000..993d590 --- /dev/null +++ b/chrome/browser/feedback/feedback_uploader_delegate.cc @@ -0,0 +1,65 @@ +// Copyright 2013 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. + +#include "chrome/browser/feedback/feedback_uploader_delegate.h" + +#include <sstream> + +#include "base/logging.h" +#include "net/url_request/url_fetcher.h" +#include "url/gurl.h" + +namespace feedback { +namespace { + +const int kHttpPostSuccessNoContent = 204; +const int kHttpPostFailNoConnection = -1; +const int kHttpPostFailClientError = 400; +const int kHttpPostFailServerError = 500; + +} // namespace + +FeedbackUploaderDelegate::FeedbackUploaderDelegate( + scoped_ptr<std::string> post_body, + const base::Closure& success_callback, + const ReportDataCallback& error_callback) + : post_body_(post_body.Pass()), + success_callback_(success_callback), + error_callback_(error_callback) { +} + +FeedbackUploaderDelegate::~FeedbackUploaderDelegate() {} + +void FeedbackUploaderDelegate::OnURLFetchComplete( + const net::URLFetcher* source) { + scoped_ptr<const net::URLFetcher> source_scoper(source); + + std::stringstream error_stream; + int response_code = source->GetResponseCode(); + if (response_code == kHttpPostSuccessNoContent) { + error_stream << "Success"; + success_callback_.Run(); + } else { + // Process the error for debug output + if (response_code == kHttpPostFailNoConnection) { + error_stream << "No connection to server."; + } else if ((response_code > kHttpPostFailClientError) && + (response_code < kHttpPostFailServerError)) { + error_stream << "Client error: HTTP response code " << response_code; + } else if (response_code > kHttpPostFailServerError) { + error_stream << "Server error: HTTP response code " << response_code; + } else { + error_stream << "Unknown error: HTTP response code " << response_code; + } + error_callback_.Run(post_body_.Pass()); + } + + LOG(WARNING) << "FEEDBACK: Submission to feedback server (" + << source->GetURL() << ") status: " << error_stream.str(); + + // This instance won't be used for anything else, delete us. + delete this; +} + +} // namespace feedback diff --git a/chrome/browser/feedback/feedback_uploader_delegate.h b/chrome/browser/feedback/feedback_uploader_delegate.h new file mode 100644 index 0000000..5da18dd --- /dev/null +++ b/chrome/browser/feedback/feedback_uploader_delegate.h @@ -0,0 +1,42 @@ +// Copyright 2013 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 CHROME_BROWSER_FEEDBACK_FEEDBACK_UPLOADER_DELEGATE_H_ +#define CHROME_BROWSER_FEEDBACK_FEEDBACK_UPLOADER_DELEGATE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "net/url_request/url_fetcher_delegate.h" + +namespace feedback { + +typedef base::Callback<void(scoped_ptr<std::string>)> ReportDataCallback; + +// FeedbackUploaderDelegate is a simple http uploader for a feedback report. On +// succes or failure, it deletes itself, but on failure it also notifies the +// error callback specified when constructing the class instance. +class FeedbackUploaderDelegate : public net::URLFetcherDelegate { + public: + FeedbackUploaderDelegate(scoped_ptr<std::string> post_body, + const base::Closure& success_callback, + const ReportDataCallback& error_callback); + virtual ~FeedbackUploaderDelegate(); + + private: + // Overridden from net::URLFetcherDelegate. + virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; + + scoped_ptr<std::string> post_body_; + base::Closure success_callback_; + ReportDataCallback error_callback_; + + DISALLOW_COPY_AND_ASSIGN(FeedbackUploaderDelegate); +}; + +} // namespace feedback + +#endif // CHROME_BROWSER_FEEDBACK_FEEDBACK_UPLOADER_DELEGATE_H_ diff --git a/chrome/browser/feedback/feedback_uploader_factory.cc b/chrome/browser/feedback/feedback_uploader_factory.cc new file mode 100644 index 0000000..02dbc35 --- /dev/null +++ b/chrome/browser/feedback/feedback_uploader_factory.cc @@ -0,0 +1,37 @@ +// Copyright 2013 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. + +#include "chrome/browser/feedback/feedback_uploader_factory.h" + +#include "base/memory/singleton.h" +#include "chrome/browser/feedback/feedback_uploader.h" +#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" + +namespace feedback { + +// static +FeedbackUploaderFactory* FeedbackUploaderFactory::GetInstance() { + return Singleton<FeedbackUploaderFactory>::get(); +} + +// static +FeedbackUploader* FeedbackUploaderFactory::GetForBrowserContext( + content::BrowserContext* context) { + return static_cast<FeedbackUploader*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +FeedbackUploaderFactory::FeedbackUploaderFactory() + : BrowserContextKeyedServiceFactory( + "feedback::FeedbackUploader", + BrowserContextDependencyManager::GetInstance()) {} + +FeedbackUploaderFactory::~FeedbackUploaderFactory() {} + +BrowserContextKeyedService* FeedbackUploaderFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new FeedbackUploader(context); +} + +} // namespace feedback diff --git a/chrome/browser/feedback/feedback_uploader_factory.h b/chrome/browser/feedback/feedback_uploader_factory.h new file mode 100644 index 0000000..ce80a5b --- /dev/null +++ b/chrome/browser/feedback/feedback_uploader_factory.h @@ -0,0 +1,45 @@ +// Copyright 2013 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 CHROME_BROWSER_FEEDBACK_FEEDBACK_UPLOADER_FACTORY_H_ +#define CHROME_BROWSER_FEEDBACK_FEEDBACK_UPLOADER_FACTORY_H_ + +#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h" + +template<typename T> struct DefaultSingletonTraits; + +namespace content { +class BrowserContext; +} + +namespace feedback { + +class FeedbackUploader; + +// Singleton that owns the FeedbackUploaders and associates them with profiles; +class FeedbackUploaderFactory : public BrowserContextKeyedServiceFactory { + public: + // Returns singleton instance of FeedbackUploaderFactory. + static FeedbackUploaderFactory* GetInstance(); + + // Returns the Feedback Uploader associated with |context|. + static FeedbackUploader* GetForBrowserContext( + content::BrowserContext* context); + + private: + friend struct DefaultSingletonTraits<FeedbackUploaderFactory>; + + FeedbackUploaderFactory(); + virtual ~FeedbackUploaderFactory(); + + // BrowserContextKeyedServiceFactory overrides: + virtual BrowserContextKeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const OVERRIDE; + + DISALLOW_COPY_AND_ASSIGN(FeedbackUploaderFactory); +}; + +} // namespace feedback + +#endif // CHROME_BROWSER_FEEDBACK_FEEDBACK_UPLOADER_FACTORY_H_ diff --git a/chrome/browser/feedback/feedback_uploader_unittest.cc b/chrome/browser/feedback/feedback_uploader_unittest.cc new file mode 100644 index 0000000..8ba73e2 --- /dev/null +++ b/chrome/browser/feedback/feedback_uploader_unittest.cc @@ -0,0 +1,131 @@ +// Copyright (c) 2012 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. + +#include "chrome/browser/feedback/feedback_uploader.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "chrome/browser/feedback/feedback_uploader_factory.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/test_browser_thread.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +const char kReportOne[] = "one"; +const char kReportTwo[] = "two"; +const char kReportThree[] = "three"; +const char kReportFour[] = "four"; +const char kReportFive[] = "five"; + +const base::TimeDelta kRetryDelayForTest = + base::TimeDelta::FromMilliseconds(100); + +BrowserContextKeyedService* CreateFeedbackUploaderService( + content::BrowserContext* context) { + return new feedback::FeedbackUploader(Profile::FromBrowserContext(context)); +} + +} // namespace + +namespace feedback { + +class FeedbackUploaderTest : public testing::Test { + protected: + FeedbackUploaderTest() + : ui_thread_(content::BrowserThread::UI, &message_loop_), + profile_(new TestingProfile()), + expected_reports_(0) { + FeedbackUploaderFactory::GetInstance()->SetTestingFactory( + profile_.get(), &CreateFeedbackUploaderService); + + uploader_ = FeedbackUploaderFactory::GetForBrowserContext(profile_.get()); + uploader_->setup_for_test( + base::Bind(&FeedbackUploaderTest::MockDispatchReport, + base::Unretained(this)), + kRetryDelayForTest); + } + + virtual ~FeedbackUploaderTest() { + FeedbackUploaderFactory::GetInstance()->SetTestingFactory( + profile_.get(), NULL); + } + + void QueueReport(const std::string& data) { + uploader_->QueueReport(make_scoped_ptr(new std::string(data))); + } + + void ReportFailure(const std::string& data) { + uploader_->RetryReport(make_scoped_ptr(new std::string(data))); + } + + void MockDispatchReport(scoped_ptr<std::string> report_data) { + dispatched_reports_.push_back(*report_data.get()); + + // Dispatch will always update the timer, whether successful or not, + // simulate the same behavior. + uploader_->UpdateUploadTimer(); + + if (dispatched_reports_.size() >= expected_reports_) { + if (run_loop_.get()) + run_loop_->Quit(); + } + } + + void RunMessageLoop() { + run_loop_.reset(new base::RunLoop()); + run_loop_->Run(); + } + + base::MessageLoop message_loop_; + scoped_ptr<base::RunLoop> run_loop_; + content::TestBrowserThread ui_thread_; + scoped_ptr<TestingProfile> profile_; + + FeedbackUploader* uploader_; + + std::vector<std::string> dispatched_reports_; + size_t expected_reports_; +}; + +TEST_F(FeedbackUploaderTest, QueueMultiple) { + dispatched_reports_.clear(); + QueueReport(kReportOne); + QueueReport(kReportTwo); + QueueReport(kReportThree); + QueueReport(kReportFour); + + EXPECT_EQ(dispatched_reports_.size(), 4u); + EXPECT_EQ(dispatched_reports_[0], kReportOne); + EXPECT_EQ(dispatched_reports_[1], kReportTwo); + EXPECT_EQ(dispatched_reports_[2], kReportThree); + EXPECT_EQ(dispatched_reports_[3], kReportFour); +} + +TEST_F(FeedbackUploaderTest, QueueMultipleWithFailures) { + dispatched_reports_.clear(); + QueueReport(kReportOne); + QueueReport(kReportTwo); + QueueReport(kReportThree); + QueueReport(kReportFour); + + ReportFailure(kReportThree); + ReportFailure(kReportTwo); + QueueReport(kReportFive); + + expected_reports_ = 7; + RunMessageLoop(); + + EXPECT_EQ(dispatched_reports_.size(), 7u); + EXPECT_EQ(dispatched_reports_[0], kReportOne); + EXPECT_EQ(dispatched_reports_[1], kReportTwo); + EXPECT_EQ(dispatched_reports_[2], kReportThree); + EXPECT_EQ(dispatched_reports_[3], kReportFour); + EXPECT_EQ(dispatched_reports_[4], kReportFive); + EXPECT_EQ(dispatched_reports_[5], kReportThree); + EXPECT_EQ(dispatched_reports_[6], kReportTwo); +} + +} // namespace feedback diff --git a/chrome/browser/feedback/feedback_util.cc b/chrome/browser/feedback/feedback_util.cc index b6926db..94e3c53 100644 --- a/chrome/browser/feedback/feedback_util.cc +++ b/chrome/browser/feedback/feedback_util.cc @@ -21,6 +21,8 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h" #include "chrome/browser/feedback/feedback_data.h" +#include "chrome/browser/feedback/feedback_uploader.h" +#include "chrome/browser/feedback/feedback_uploader_factory.h" #include "chrome/browser/metrics/variations/variations_http_header_provider.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" @@ -51,8 +53,6 @@ namespace { -void DispatchFeedback(Profile* profile, std::string* post_body, int64 delay); - GURL GetTargetTabUrl(int session_id, int index) { Browser* browser = chrome::FindBrowserWithID(session_id); // Sanity checks. @@ -69,22 +69,7 @@ GURL GetTargetTabUrl(int session_id, int index) { return GURL(); } -// URL to post bug reports to. -const char kFeedbackPostUrl[] = - "https://www.google.com/tools/feedback/chrome/__submit"; - -const char kProtBufMimeType[] = "application/x-protobuf"; const char kPngMimeType[] = "image/png"; - -const int kHttpPostSuccessNoContent = 204; -const int kHttpPostFailNoConnection = -1; -const int kHttpPostFailClientError = 400; -const int kHttpPostFailServerError = 500; - -const int64 kInitialRetryDelay = 900000; // 15 minutes -const int64 kRetryDelayIncreaseFactor = 2; -const int64 kRetryDelayLimit = 14400000; // 4 hours - const char kArbitraryMimeType[] = "application/octet-stream"; const char kHistogramsAttachmentName[] = "histograms.zip"; const char kLogsAttachmentName[] = "system_logs.zip"; @@ -95,111 +80,6 @@ const int kChromeOSProductId = 208; const int kChromeBrowserProductId = 237; #endif -// Simple net::URLFetcherDelegate to clean up URLFetcher on completion. -class PostCleanup : public net::URLFetcherDelegate { - public: - PostCleanup(Profile* profile, - std::string* post_body, - int64 previous_delay) : profile_(profile), - post_body_(post_body), - previous_delay_(previous_delay) { } - // Overridden from net::URLFetcherDelegate. - virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; - - protected: - virtual ~PostCleanup() {} - - private: - Profile* profile_; - std::string* post_body_; - int64 previous_delay_; - - DISALLOW_COPY_AND_ASSIGN(PostCleanup); -}; - -// Don't use the data parameter, instead use the pointer we pass into every -// post cleanup object - that pointer will be deleted and deleted only on a -// successful post to the feedback server. -void PostCleanup::OnURLFetchComplete( - const net::URLFetcher* source) { - std::stringstream error_stream; - int response_code = source->GetResponseCode(); - if (response_code == kHttpPostSuccessNoContent) { - // We've sent our report, delete the report data - delete post_body_; - - error_stream << "Success"; - } else { - // Uh oh, feedback failed, send it off to retry - if (previous_delay_) { - if (previous_delay_ < kRetryDelayLimit) - previous_delay_ *= kRetryDelayIncreaseFactor; - } else { - previous_delay_ = kInitialRetryDelay; - } - DispatchFeedback(profile_, post_body_, previous_delay_); - - // Process the error for debug output - if (response_code == kHttpPostFailNoConnection) { - error_stream << "No connection to server."; - } else if ((response_code > kHttpPostFailClientError) && - (response_code < kHttpPostFailServerError)) { - error_stream << "Client error: HTTP response code " << response_code; - } else if (response_code > kHttpPostFailServerError) { - error_stream << "Server error: HTTP response code " << response_code; - } else { - error_stream << "Unknown error: HTTP response code " << response_code; - } - } - - LOG(WARNING) << "FEEDBACK: Submission to feedback server (" << - source->GetURL() << ") status: " << error_stream.str(); - - // Delete the URLFetcher. - delete source; - // And then delete ourselves. - delete this; -} - -void SendFeedback(Profile* profile, - std::string* post_body, - int64 previous_delay) { - DCHECK(post_body); - - GURL post_url; - if (CommandLine::ForCurrentProcess()-> - HasSwitch(switches::kFeedbackServer)) - post_url = GURL(CommandLine::ForCurrentProcess()-> - GetSwitchValueASCII(switches::kFeedbackServer)); - else - post_url = GURL(kFeedbackPostUrl); - - net::URLFetcher* fetcher = net::URLFetcher::Create( - post_url, net::URLFetcher::POST, - new PostCleanup(profile, post_body, previous_delay)); - fetcher->SetRequestContext(profile->GetRequestContext()); - fetcher->SetLoadFlags( - net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES); - - net::HttpRequestHeaders headers; - chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( - fetcher->GetOriginalURL(), profile->IsOffTheRecord(), false, &headers); - fetcher->SetExtraRequestHeaders(headers.ToString()); - - fetcher->SetUploadData(std::string(kProtBufMimeType), *post_body); - fetcher->Start(); -} - -void DispatchFeedback(Profile* profile, std::string* post_body, int64 delay) { - DCHECK(post_body); - - base::MessageLoop::current()->PostDelayedTask( - FROM_HERE, - base::Bind(&SendFeedback, profile, post_body, delay), - base::TimeDelta::FromMilliseconds(delay)); -} - - void AddFeedbackData(userfeedback::ExtensionSubmit* feedback_data, const std::string& key, const std::string& value) { // Don't bother with empty keys or values @@ -359,10 +239,12 @@ void SendReport(scoped_refptr<FeedbackData> data) { // This pointer will eventually get deleted by the PostCleanup class, after // we've either managed to successfully upload the report or died trying. - std::string* post_body = new std::string; - feedback_data.SerializeToString(post_body); + scoped_ptr<std::string> post_body(new std::string); + feedback_data.SerializeToString(post_body.get()); - DispatchFeedback(data->profile(), post_body, 0); + feedback::FeedbackUploader *uploader = + feedback::FeedbackUploaderFactory::GetForBrowserContext(data->profile()); + uploader->QueueReport(post_body.Pass()); } bool ZipString(const base::FilePath& filename, |