Return backed up TemplateURL on default search change
[chromium-blink-merge.git] / chrome / browser / bug_report_util.cc
blob72284a055a1c300752136c6fd364e65ebe127ac9
1 // Copyright (c) 2011 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/bug_report_util.h"
7 #include <sstream>
8 #include <string>
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/file_util.h"
13 #include "base/file_version_info.h"
14 #include "base/memory/singleton.h"
15 #include "base/string_util.h"
16 #include "base/stringprintf.h"
17 #include "base/utf_string_conversions.h"
18 #include "base/win/windows_version.h"
19 #include "chrome/browser/browser_process_impl.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
22 #include "chrome/browser/ui/browser_list.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/chrome_version_info.h"
25 #include "content/browser/tab_contents/tab_contents.h"
26 #include "content/public/common/url_fetcher.h"
27 #include "content/public/common/url_fetcher_delegate.h"
28 #include "googleurl/src/gurl.h"
29 #include "grit/generated_resources.h"
30 #include "grit/locale_settings.h"
31 #include "grit/theme_resources.h"
32 #include "net/url_request/url_request_status.h"
33 #include "ui/base/l10n/l10n_util.h"
34 #include "unicode/locid.h"
36 #if defined(OS_CHROMEOS)
37 #include "chrome/browser/chromeos/notifications/system_notification.h"
38 #endif
40 namespace {
42 const int kBugReportVersion = 1;
44 const char kReportPhishingUrl[] =
45 "http://www.google.com/safebrowsing/report_phish/";
47 // URL to post bug reports to.
48 static char const kBugReportPostUrl[] =
49 "https://www.google.com/tools/feedback/chrome/__submit";
51 static char const kProtBufMimeType[] = "application/x-protobuf";
52 static char const kPngMimeType[] = "image/png";
54 // Tags we use in product specific data
55 static char const kChromeVersionTag[] = "CHROME VERSION";
56 static char const kOsVersionTag[] = "OS VERSION";
58 static char const kNotificationId[] = "feedback.chromeos";
60 static int const kHttpPostSuccessNoContent = 204;
61 static int const kHttpPostFailNoConnection = -1;
62 static int const kHttpPostFailClientError = 400;
63 static int const kHttpPostFailServerError = 500;
65 #if defined(OS_CHROMEOS)
66 static char const kBZip2MimeType[] = "application/x-bzip2";
67 static char const kLogsAttachmentName[] = "system_logs.bz2";
68 // Maximum number of lines in system info log chunk to be still included
69 // in product specific data.
70 const size_t kMaxLineCount = 40;
71 // Maximum number of bytes in system info log chunk to be still included
72 // in product specific data.
73 const size_t kMaxSystemLogLength = 4 * 1024;
74 #endif
76 const int64 kInitialRetryDelay = 900000; // 15 minutes
77 const int64 kRetryDelayIncreaseFactor = 2;
78 const int64 kRetryDelayLimit = 14400000; // 4 hours
81 } // namespace
84 // Simple content::URLFetcherDelegate to clean up URLFetcher on completion.
85 class BugReportUtil::PostCleanup : public content::URLFetcherDelegate {
86 public:
87 PostCleanup(Profile* profile, std::string* post_body,
88 int64 previous_delay) : profile_(profile),
89 post_body_(post_body),
90 previous_delay_(previous_delay) { }
91 // Overridden from content::URLFetcherDelegate.
92 virtual void OnURLFetchComplete(const content::URLFetcher* source);
94 protected:
95 virtual ~PostCleanup() {}
97 private:
98 Profile* profile_;
99 std::string* post_body_;
100 int64 previous_delay_;
102 DISALLOW_COPY_AND_ASSIGN(PostCleanup);
105 // Don't use the data parameter, instead use the pointer we pass into every
106 // post cleanup object - that pointer will be deleted and deleted only on a
107 // successful post to the feedback server.
108 void BugReportUtil::PostCleanup::OnURLFetchComplete(
109 const content::URLFetcher* source) {
110 std::stringstream error_stream;
111 int response_code = source->GetResponseCode();
112 if (response_code == kHttpPostSuccessNoContent) {
113 // We've sent our report, delete the report data
114 delete post_body_;
116 error_stream << "Success";
117 } else {
118 // Uh oh, feedback failed, send it off to retry
119 if (previous_delay_) {
120 if (previous_delay_ < kRetryDelayLimit)
121 previous_delay_ *= kRetryDelayIncreaseFactor;
122 } else {
123 previous_delay_ = kInitialRetryDelay;
125 BugReportUtil::DispatchFeedback(profile_, post_body_, previous_delay_);
127 // Process the error for debug output
128 if (response_code == kHttpPostFailNoConnection) {
129 error_stream << "No connection to server.";
130 } else if ((response_code > kHttpPostFailClientError) &&
131 (response_code < kHttpPostFailServerError)) {
132 error_stream << "Client error: HTTP response code " << response_code;
133 } else if (response_code > kHttpPostFailServerError) {
134 error_stream << "Server error: HTTP response code " << response_code;
135 } else {
136 error_stream << "Unknown error: HTTP response code " << response_code;
140 LOG(WARNING) << "FEEDBACK: Submission to feedback server (" <<
141 source->GetURL() << ") status: " << error_stream.str();
143 // Delete the URLFetcher.
144 delete source;
145 // And then delete ourselves.
146 delete this;
149 // static
150 void BugReportUtil::SetOSVersion(std::string* os_version) {
151 #if defined(OS_WIN)
152 base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
153 base::win::OSInfo::VersionNumber version_number = os_info->version_number();
154 *os_version = base::StringPrintf("%d.%d.%d",
155 version_number.major,
156 version_number.minor,
157 version_number.build);
158 int service_pack = os_info->service_pack().major;
159 if (service_pack > 0)
160 os_version->append(base::StringPrintf("Service Pack %d", service_pack));
161 #elif defined(OS_MACOSX)
162 *os_version = base::SysInfo::OperatingSystemVersion();
163 #else
164 *os_version = "unknown";
165 #endif
168 // static
169 void BugReportUtil::DispatchFeedback(Profile* profile,
170 std::string* post_body,
171 int64 delay) {
172 DCHECK(post_body);
174 MessageLoop::current()->PostDelayedTask(FROM_HERE, base::Bind(
175 &BugReportUtil::SendFeedback, profile, post_body, delay), delay);
178 // static
179 void BugReportUtil::SendFeedback(Profile* profile,
180 std::string* post_body,
181 int64 previous_delay) {
182 DCHECK(post_body);
184 GURL post_url;
185 if (CommandLine::ForCurrentProcess()->
186 HasSwitch(switches::kFeedbackServer))
187 post_url = GURL(CommandLine::ForCurrentProcess()->
188 GetSwitchValueASCII(switches::kFeedbackServer));
189 else
190 post_url = GURL(kBugReportPostUrl);
192 content::URLFetcher* fetcher = content::URLFetcher::Create(
193 post_url, content::URLFetcher::POST,
194 new BugReportUtil::PostCleanup(profile, post_body, previous_delay));
195 fetcher->SetRequestContext(profile->GetRequestContext());
197 fetcher->SetUploadData(std::string(kProtBufMimeType), *post_body);
198 fetcher->Start();
202 // static
203 void BugReportUtil::AddFeedbackData(
204 userfeedback::ExternalExtensionSubmit* feedback_data,
205 const std::string& key, const std::string& value) {
206 // Don't bother with empty keys or values
207 if (key=="" || value == "") return;
208 // Create log_value object and add it to the web_data object
209 userfeedback::ProductSpecificData log_value;
210 log_value.set_key(key);
211 log_value.set_value(value);
212 userfeedback::WebData* web_data = feedback_data->mutable_web_data();
213 *(web_data->add_product_specific_data()) = log_value;
216 #if defined(OS_CHROMEOS)
217 bool BugReportUtil::ValidFeedbackSize(const std::string& content) {
218 if (content.length() > kMaxSystemLogLength)
219 return false;
220 size_t line_count = 0;
221 const char* text = content.c_str();
222 for (size_t i = 0; i < content.length(); i++) {
223 if (*(text + i) == '\n') {
224 line_count++;
225 if (line_count > kMaxLineCount)
226 return false;
229 return true;
231 #endif
233 // static
234 void BugReportUtil::SendReport(
235 Profile* profile
236 , int problem_type
237 , const std::string& page_url_text
238 , const std::string& description
239 , ScreenshotDataPtr image_data_ptr
240 , int png_width
241 , int png_height
242 #if defined(OS_CHROMEOS)
243 , const std::string& user_email_text
244 , const char* zipped_logs_data
245 , int zipped_logs_length
246 , const chromeos::system::LogDictionaryType* const sys_info
247 #endif
249 // Create google feedback protocol buffer objects
250 userfeedback::ExternalExtensionSubmit feedback_data;
251 // type id set to 0, unused field but needs to be initialized to 0
252 feedback_data.set_type_id(0);
254 userfeedback::CommonData* common_data = feedback_data.mutable_common_data();
255 userfeedback::WebData* web_data = feedback_data.mutable_web_data();
257 // Set GAIA id to 0. We're not using gaia id's for recording
258 // use feedback - we're using the e-mail field, allows users to
259 // submit feedback from incognito mode and specify any mail id
260 // they wish
261 common_data->set_gaia_id(0);
263 #if defined(OS_CHROMEOS)
264 // Add the user e-mail to the feedback object
265 common_data->set_user_email(user_email_text);
266 #endif
268 // Add the description to the feedback object
269 common_data->set_description(description);
271 // Add the language
272 std::string chrome_locale = g_browser_process->GetApplicationLocale();
273 common_data->set_source_description_language(chrome_locale);
275 // Set the url
276 web_data->set_url(page_url_text);
278 // Add the Chrome version
279 chrome::VersionInfo version_info;
280 if (version_info.is_valid()) {
281 std::string chrome_version = version_info.Name() + " - " +
282 version_info.Version() +
283 " (" + version_info.LastChange() + ")";
284 AddFeedbackData(&feedback_data, std::string(kChromeVersionTag),
285 chrome_version);
288 // Add OS version (eg, for WinXP SP2: "5.1.2600 Service Pack 2").
289 std::string os_version = "";
290 SetOSVersion(&os_version);
291 AddFeedbackData(&feedback_data, std::string(kOsVersionTag), os_version);
293 // Include the page image if we have one.
294 if (image_data_ptr.get() && image_data_ptr->size()) {
295 userfeedback::PostedScreenshot screenshot;
296 screenshot.set_mime_type(kPngMimeType);
297 // Set the dimensions of the screenshot
298 userfeedback::Dimensions dimensions;
299 dimensions.set_width(static_cast<float>(png_width));
300 dimensions.set_height(static_cast<float>(png_height));
301 *(screenshot.mutable_dimensions()) = dimensions;
303 int image_data_size = image_data_ptr->size();
304 char* image_data = reinterpret_cast<char*>(&(image_data_ptr->front()));
305 screenshot.set_binary_content(std::string(image_data, image_data_size));
307 // Set the screenshot object in feedback
308 *(feedback_data.mutable_screenshot()) = screenshot;
311 #if defined(OS_CHROMEOS)
312 if (sys_info) {
313 // Add the product specific data
314 for (chromeos::system::LogDictionaryType::const_iterator i =
315 sys_info->begin(); i != sys_info->end(); ++i) {
316 if (!CommandLine::ForCurrentProcess()->HasSwitch(
317 switches::kCompressSystemFeedback) || ValidFeedbackSize(i->second)) {
318 AddFeedbackData(&feedback_data, i->first, i->second);
322 // If we have zipped logs, add them here
323 if (zipped_logs_data && CommandLine::ForCurrentProcess()->HasSwitch(
324 switches::kCompressSystemFeedback)) {
325 userfeedback::ProductSpecificBinaryData attachment;
326 attachment.set_mime_type(kBZip2MimeType);
327 attachment.set_name(kLogsAttachmentName);
328 attachment.set_data(std::string(zipped_logs_data, zipped_logs_length));
329 *(feedback_data.add_product_specific_binary_data()) = attachment;
332 #endif
334 // Set our Chrome specific data
335 userfeedback::ChromeData chrome_data;
336 #if defined(OS_CHROMEOS)
337 chrome_data.set_chrome_platform(
338 userfeedback::ChromeData_ChromePlatform_CHROME_OS);
339 userfeedback::ChromeOsData chrome_os_data;
340 chrome_os_data.set_category(
341 (userfeedback::ChromeOsData_ChromeOsCategory) problem_type);
342 *(chrome_data.mutable_chrome_os_data()) = chrome_os_data;
343 #else
344 chrome_data.set_chrome_platform(
345 userfeedback::ChromeData_ChromePlatform_CHROME_BROWSER);
346 userfeedback::ChromeBrowserData chrome_browser_data;
347 chrome_browser_data.set_category(
348 (userfeedback::ChromeBrowserData_ChromeBrowserCategory) problem_type);
349 *(chrome_data.mutable_chrome_browser_data()) = chrome_browser_data;
350 #endif
352 *(feedback_data.mutable_chrome_data()) = chrome_data;
354 // Serialize our report to a string pointer we can pass around
355 std::string* post_body = new std::string;
356 feedback_data.SerializeToString(post_body);
358 // We have the body of our POST, so send it off to the server with 0 delay
359 DispatchFeedback(profile, post_body, 0);
362 #if defined(ENABLE_SAFE_BROWSING)
363 // static
364 void BugReportUtil::ReportPhishing(TabContents* currentTab,
365 const std::string& phishing_url) {
366 currentTab->GetController().LoadURL(
367 safe_browsing_util::GeneratePhishingReportUrl(
368 kReportPhishingUrl, phishing_url,
369 false /* not client-side detection */),
370 content::Referrer(),
371 content::PAGE_TRANSITION_LINK,
372 std::string());
374 #endif
376 static std::vector<unsigned char>* screenshot_png = NULL;
377 static gfx::Rect* screenshot_size = NULL;
379 // static
380 std::vector<unsigned char>* BugReportUtil::GetScreenshotPng() {
381 if (screenshot_png == NULL)
382 screenshot_png = new std::vector<unsigned char>;
383 return screenshot_png;
386 // static
387 void BugReportUtil::ClearScreenshotPng() {
388 if (screenshot_png)
389 screenshot_png->clear();
392 // static
393 gfx::Rect& BugReportUtil::GetScreenshotSize() {
394 if (screenshot_size == NULL)
395 screenshot_size = new gfx::Rect();
396 return *screenshot_size;
399 // static
400 void BugReportUtil::SetScreenshotSize(const gfx::Rect& rect) {
401 gfx::Rect& screen_size = GetScreenshotSize();
402 screen_size = rect;