| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/feedback/feedback_util.h" | 5 #include "chrome/browser/feedback/feedback_util.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
| 14 #include "base/file_version_info.h" | 14 #include "base/file_version_info.h" |
| 15 #include "base/memory/singleton.h" | 15 #include "base/memory/singleton.h" |
| 16 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
| 17 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 19 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
| 20 #include "base/win/windows_version.h" | 20 #include "base/win/windows_version.h" |
| 21 #include "chrome/browser/browser_process.h" | 21 #include "chrome/browser/browser_process.h" |
| 22 #include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h" | 22 #include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h" |
| 23 #include "chrome/browser/feedback/feedback_data.h" | 23 #include "chrome/browser/feedback/feedback_data.h" |
| 24 #include "chrome/browser/feedback/feedback_uploader.h" |
| 25 #include "chrome/browser/feedback/feedback_uploader_factory.h" |
| 24 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" | 26 #include "chrome/browser/metrics/variations/variations_http_header_provider.h" |
| 25 #include "chrome/browser/profiles/profile.h" | 27 #include "chrome/browser/profiles/profile.h" |
| 26 #include "chrome/browser/profiles/profile_manager.h" | 28 #include "chrome/browser/profiles/profile_manager.h" |
| 27 #include "chrome/browser/safe_browsing/safe_browsing_util.h" | 29 #include "chrome/browser/safe_browsing/safe_browsing_util.h" |
| 28 #include "chrome/browser/ui/browser_finder.h" | 30 #include "chrome/browser/ui/browser_finder.h" |
| 29 #include "chrome/browser/ui/browser_list.h" | 31 #include "chrome/browser/ui/browser_list.h" |
| 30 #include "chrome/browser/ui/browser_window.h" | 32 #include "chrome/browser/ui/browser_window.h" |
| 31 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 33 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 32 #include "chrome/common/chrome_switches.h" | 34 #include "chrome/common/chrome_switches.h" |
| 33 #include "chrome/common/chrome_version_info.h" | 35 #include "chrome/common/chrome_version_info.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 44 #include "net/url_request/url_fetcher.h" | 46 #include "net/url_request/url_fetcher.h" |
| 45 #include "net/url_request/url_fetcher_delegate.h" | 47 #include "net/url_request/url_fetcher_delegate.h" |
| 46 #include "net/url_request/url_request_status.h" | 48 #include "net/url_request/url_request_status.h" |
| 47 #include "third_party/icu/source/common/unicode/locid.h" | 49 #include "third_party/icu/source/common/unicode/locid.h" |
| 48 #include "third_party/zlib/google/zip.h" | 50 #include "third_party/zlib/google/zip.h" |
| 49 #include "ui/base/l10n/l10n_util.h" | 51 #include "ui/base/l10n/l10n_util.h" |
| 50 #include "url/gurl.h" | 52 #include "url/gurl.h" |
| 51 | 53 |
| 52 namespace { | 54 namespace { |
| 53 | 55 |
| 54 void DispatchFeedback(Profile* profile, std::string* post_body, int64 delay); | |
| 55 | |
| 56 GURL GetTargetTabUrl(int session_id, int index) { | 56 GURL GetTargetTabUrl(int session_id, int index) { |
| 57 Browser* browser = chrome::FindBrowserWithID(session_id); | 57 Browser* browser = chrome::FindBrowserWithID(session_id); |
| 58 // Sanity checks. | 58 // Sanity checks. |
| 59 if (!browser || index >= browser->tab_strip_model()->count()) | 59 if (!browser || index >= browser->tab_strip_model()->count()) |
| 60 return GURL(); | 60 return GURL(); |
| 61 | 61 |
| 62 if (index >= 0) { | 62 if (index >= 0) { |
| 63 content::WebContents* target_tab = | 63 content::WebContents* target_tab = |
| 64 browser->tab_strip_model()->GetWebContentsAt(index); | 64 browser->tab_strip_model()->GetWebContentsAt(index); |
| 65 if (target_tab) | 65 if (target_tab) |
| 66 return target_tab->GetURL(); | 66 return target_tab->GetURL(); |
| 67 } | 67 } |
| 68 | 68 |
| 69 return GURL(); | 69 return GURL(); |
| 70 } | 70 } |
| 71 | 71 |
| 72 // URL to post bug reports to. | |
| 73 const char kFeedbackPostUrl[] = | |
| 74 "https://www.google.com/tools/feedback/chrome/__submit"; | |
| 75 | |
| 76 const char kProtBufMimeType[] = "application/x-protobuf"; | |
| 77 const char kPngMimeType[] = "image/png"; | 72 const char kPngMimeType[] = "image/png"; |
| 78 | |
| 79 const int kHttpPostSuccessNoContent = 204; | |
| 80 const int kHttpPostFailNoConnection = -1; | |
| 81 const int kHttpPostFailClientError = 400; | |
| 82 const int kHttpPostFailServerError = 500; | |
| 83 | |
| 84 const int64 kInitialRetryDelay = 900000; // 15 minutes | |
| 85 const int64 kRetryDelayIncreaseFactor = 2; | |
| 86 const int64 kRetryDelayLimit = 14400000; // 4 hours | |
| 87 | |
| 88 const char kArbitraryMimeType[] = "application/octet-stream"; | 73 const char kArbitraryMimeType[] = "application/octet-stream"; |
| 89 const char kHistogramsAttachmentName[] = "histograms.zip"; | 74 const char kHistogramsAttachmentName[] = "histograms.zip"; |
| 90 const char kLogsAttachmentName[] = "system_logs.zip"; | 75 const char kLogsAttachmentName[] = "system_logs.zip"; |
| 91 | 76 |
| 92 #if defined(OS_CHROMEOS) | 77 #if defined(OS_CHROMEOS) |
| 93 const int kChromeOSProductId = 208; | 78 const int kChromeOSProductId = 208; |
| 94 #else | 79 #else |
| 95 const int kChromeBrowserProductId = 237; | 80 const int kChromeBrowserProductId = 237; |
| 96 #endif | 81 #endif |
| 97 | 82 |
| 98 // Simple net::URLFetcherDelegate to clean up URLFetcher on completion. | |
| 99 class PostCleanup : public net::URLFetcherDelegate { | |
| 100 public: | |
| 101 PostCleanup(Profile* profile, | |
| 102 std::string* post_body, | |
| 103 int64 previous_delay) : profile_(profile), | |
| 104 post_body_(post_body), | |
| 105 previous_delay_(previous_delay) { } | |
| 106 // Overridden from net::URLFetcherDelegate. | |
| 107 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; | |
| 108 | |
| 109 protected: | |
| 110 virtual ~PostCleanup() {} | |
| 111 | |
| 112 private: | |
| 113 Profile* profile_; | |
| 114 std::string* post_body_; | |
| 115 int64 previous_delay_; | |
| 116 | |
| 117 DISALLOW_COPY_AND_ASSIGN(PostCleanup); | |
| 118 }; | |
| 119 | |
| 120 // Don't use the data parameter, instead use the pointer we pass into every | |
| 121 // post cleanup object - that pointer will be deleted and deleted only on a | |
| 122 // successful post to the feedback server. | |
| 123 void PostCleanup::OnURLFetchComplete( | |
| 124 const net::URLFetcher* source) { | |
| 125 std::stringstream error_stream; | |
| 126 int response_code = source->GetResponseCode(); | |
| 127 if (response_code == kHttpPostSuccessNoContent) { | |
| 128 // We've sent our report, delete the report data | |
| 129 delete post_body_; | |
| 130 | |
| 131 error_stream << "Success"; | |
| 132 } else { | |
| 133 // Uh oh, feedback failed, send it off to retry | |
| 134 if (previous_delay_) { | |
| 135 if (previous_delay_ < kRetryDelayLimit) | |
| 136 previous_delay_ *= kRetryDelayIncreaseFactor; | |
| 137 } else { | |
| 138 previous_delay_ = kInitialRetryDelay; | |
| 139 } | |
| 140 DispatchFeedback(profile_, post_body_, previous_delay_); | |
| 141 | |
| 142 // Process the error for debug output | |
| 143 if (response_code == kHttpPostFailNoConnection) { | |
| 144 error_stream << "No connection to server."; | |
| 145 } else if ((response_code > kHttpPostFailClientError) && | |
| 146 (response_code < kHttpPostFailServerError)) { | |
| 147 error_stream << "Client error: HTTP response code " << response_code; | |
| 148 } else if (response_code > kHttpPostFailServerError) { | |
| 149 error_stream << "Server error: HTTP response code " << response_code; | |
| 150 } else { | |
| 151 error_stream << "Unknown error: HTTP response code " << response_code; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 LOG(WARNING) << "FEEDBACK: Submission to feedback server (" << | |
| 156 source->GetURL() << ") status: " << error_stream.str(); | |
| 157 | |
| 158 // Delete the URLFetcher. | |
| 159 delete source; | |
| 160 // And then delete ourselves. | |
| 161 delete this; | |
| 162 } | |
| 163 | |
| 164 void SendFeedback(Profile* profile, | |
| 165 std::string* post_body, | |
| 166 int64 previous_delay) { | |
| 167 DCHECK(post_body); | |
| 168 | |
| 169 GURL post_url; | |
| 170 if (CommandLine::ForCurrentProcess()-> | |
| 171 HasSwitch(switches::kFeedbackServer)) | |
| 172 post_url = GURL(CommandLine::ForCurrentProcess()-> | |
| 173 GetSwitchValueASCII(switches::kFeedbackServer)); | |
| 174 else | |
| 175 post_url = GURL(kFeedbackPostUrl); | |
| 176 | |
| 177 net::URLFetcher* fetcher = net::URLFetcher::Create( | |
| 178 post_url, net::URLFetcher::POST, | |
| 179 new PostCleanup(profile, post_body, previous_delay)); | |
| 180 fetcher->SetRequestContext(profile->GetRequestContext()); | |
| 181 fetcher->SetLoadFlags( | |
| 182 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES); | |
| 183 | |
| 184 net::HttpRequestHeaders headers; | |
| 185 chrome_variations::VariationsHttpHeaderProvider::GetInstance()->AppendHeaders( | |
| 186 fetcher->GetOriginalURL(), profile->IsOffTheRecord(), false, &headers); | |
| 187 fetcher->SetExtraRequestHeaders(headers.ToString()); | |
| 188 | |
| 189 fetcher->SetUploadData(std::string(kProtBufMimeType), *post_body); | |
| 190 fetcher->Start(); | |
| 191 } | |
| 192 | |
| 193 void DispatchFeedback(Profile* profile, std::string* post_body, int64 delay) { | |
| 194 DCHECK(post_body); | |
| 195 | |
| 196 base::MessageLoop::current()->PostDelayedTask( | |
| 197 FROM_HERE, | |
| 198 base::Bind(&SendFeedback, profile, post_body, delay), | |
| 199 base::TimeDelta::FromMilliseconds(delay)); | |
| 200 } | |
| 201 | |
| 202 | |
| 203 void AddFeedbackData(userfeedback::ExtensionSubmit* feedback_data, | 83 void AddFeedbackData(userfeedback::ExtensionSubmit* feedback_data, |
| 204 const std::string& key, const std::string& value) { | 84 const std::string& key, const std::string& value) { |
| 205 // Don't bother with empty keys or values | 85 // Don't bother with empty keys or values |
| 206 if (key == "" || value == "") return; | 86 if (key == "" || value == "") return; |
| 207 // Create log_value object and add it to the web_data object | 87 // Create log_value object and add it to the web_data object |
| 208 userfeedback::ProductSpecificData log_value; | 88 userfeedback::ProductSpecificData log_value; |
| 209 log_value.set_key(key); | 89 log_value.set_key(key); |
| 210 log_value.set_value(value); | 90 log_value.set_value(value); |
| 211 userfeedback::WebData* web_data = feedback_data->mutable_web_data(); | 91 userfeedback::WebData* web_data = feedback_data->mutable_web_data(); |
| 212 *(web_data->add_product_specific_data()) = log_value; | 92 *(web_data->add_product_specific_data()) = log_value; |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 chrome_browser_data.set_category( | 232 chrome_browser_data.set_category( |
| 353 userfeedback::ChromeBrowserData_ChromeBrowserCategory_OTHER); | 233 userfeedback::ChromeBrowserData_ChromeBrowserCategory_OTHER); |
| 354 *(chrome_data.mutable_chrome_browser_data()) = chrome_browser_data; | 234 *(chrome_data.mutable_chrome_browser_data()) = chrome_browser_data; |
| 355 feedback_data.set_product_id(kChromeBrowserProductId); | 235 feedback_data.set_product_id(kChromeBrowserProductId); |
| 356 #endif | 236 #endif |
| 357 | 237 |
| 358 *(feedback_data.mutable_chrome_data()) = chrome_data; | 238 *(feedback_data.mutable_chrome_data()) = chrome_data; |
| 359 | 239 |
| 360 // This pointer will eventually get deleted by the PostCleanup class, after | 240 // This pointer will eventually get deleted by the PostCleanup class, after |
| 361 // we've either managed to successfully upload the report or died trying. | 241 // we've either managed to successfully upload the report or died trying. |
| 362 std::string* post_body = new std::string; | 242 scoped_ptr<std::string> post_body(new std::string); |
| 363 feedback_data.SerializeToString(post_body); | 243 feedback_data.SerializeToString(post_body.get()); |
| 364 | 244 |
| 365 DispatchFeedback(data->profile(), post_body, 0); | 245 feedback::FeedbackUploader *uploader = |
| 246 feedback::FeedbackUploaderFactory::GetForBrowserContext(data->profile()); |
| 247 uploader->QueueReport(post_body.Pass()); |
| 366 } | 248 } |
| 367 | 249 |
| 368 bool ZipString(const base::FilePath& filename, | 250 bool ZipString(const base::FilePath& filename, |
| 369 const std::string& data, std::string* compressed_logs) { | 251 const std::string& data, std::string* compressed_logs) { |
| 370 base::FilePath temp_path; | 252 base::FilePath temp_path; |
| 371 base::FilePath zip_file; | 253 base::FilePath zip_file; |
| 372 | 254 |
| 373 // Create a temporary directory, put the logs into a file in it. Create | 255 // Create a temporary directory, put the logs into a file in it. Create |
| 374 // another temporary file to receive the zip file in. | 256 // another temporary file to receive the zip file in. |
| 375 if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &temp_path)) | 257 if (!base::CreateNewTempDirectory(base::FilePath::StringType(), &temp_path)) |
| 376 return false; | 258 return false; |
| 377 if (file_util::WriteFile(temp_path.Append(filename), | 259 if (file_util::WriteFile(temp_path.Append(filename), |
| 378 data.c_str(), data.size()) == -1) | 260 data.c_str(), data.size()) == -1) |
| 379 return false; | 261 return false; |
| 380 | 262 |
| 381 bool succeed = base::CreateTemporaryFile(&zip_file) && | 263 bool succeed = base::CreateTemporaryFile(&zip_file) && |
| 382 zip::Zip(temp_path, zip_file, false) && | 264 zip::Zip(temp_path, zip_file, false) && |
| 383 base::ReadFileToString(zip_file, compressed_logs); | 265 base::ReadFileToString(zip_file, compressed_logs); |
| 384 | 266 |
| 385 base::DeleteFile(temp_path, true); | 267 base::DeleteFile(temp_path, true); |
| 386 base::DeleteFile(zip_file, false); | 268 base::DeleteFile(zip_file, false); |
| 387 | 269 |
| 388 return succeed; | 270 return succeed; |
| 389 } | 271 } |
| 390 | 272 |
| 391 } // namespace feedback_util | 273 } // namespace feedback_util |
| OLD | NEW |