Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: chrome/browser/bug_report_util.cc

Issue 9006003: Refactor and fix feedback (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 2011 -> 2012 Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/bug_report_util.h ('k') | chrome/browser/feedback/feedback_data.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/bug_report_util.h"
6
7 #include <sstream>
8 #include <string>
9
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/public/browser/web_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"
35
36 #if defined(OS_CHROMEOS)
37 #include "chrome/browser/chromeos/notifications/system_notification.h"
38 #endif
39
40 using content::WebContents;
41
42 namespace {
43
44 const int kBugReportVersion = 1;
45
46 const char kReportPhishingUrl[] =
47 "http://www.google.com/safebrowsing/report_phish/";
48
49 // URL to post bug reports to.
50 static char const kBugReportPostUrl[] =
51 "https://www.google.com/tools/feedback/chrome/__submit";
52
53 static char const kProtBufMimeType[] = "application/x-protobuf";
54 static char const kPngMimeType[] = "image/png";
55
56 // Tags we use in product specific data
57 static char const kChromeVersionTag[] = "CHROME VERSION";
58 static char const kOsVersionTag[] = "OS VERSION";
59
60 static char const kNotificationId[] = "feedback.chromeos";
61
62 static int const kHttpPostSuccessNoContent = 204;
63 static int const kHttpPostFailNoConnection = -1;
64 static int const kHttpPostFailClientError = 400;
65 static int const kHttpPostFailServerError = 500;
66
67 #if defined(OS_CHROMEOS)
68 static char const kBZip2MimeType[] = "application/x-bzip2";
69 static char const kLogsAttachmentName[] = "system_logs.bz2";
70 // Maximum number of lines in system info log chunk to be still included
71 // in product specific data.
72 const size_t kMaxLineCount = 40;
73 // Maximum number of bytes in system info log chunk to be still included
74 // in product specific data.
75 const size_t kMaxSystemLogLength = 4 * 1024;
76 #endif
77
78 const int64 kInitialRetryDelay = 900000; // 15 minutes
79 const int64 kRetryDelayIncreaseFactor = 2;
80 const int64 kRetryDelayLimit = 14400000; // 4 hours
81
82
83 } // namespace
84
85
86 // Simple content::URLFetcherDelegate to clean up URLFetcher on completion.
87 class BugReportUtil::PostCleanup : public content::URLFetcherDelegate {
88 public:
89 PostCleanup(Profile* profile, std::string* post_body,
90 int64 previous_delay) : profile_(profile),
91 post_body_(post_body),
92 previous_delay_(previous_delay) { }
93 // Overridden from content::URLFetcherDelegate.
94 virtual void OnURLFetchComplete(const content::URLFetcher* source);
95
96 protected:
97 virtual ~PostCleanup() {}
98
99 private:
100 Profile* profile_;
101 std::string* post_body_;
102 int64 previous_delay_;
103
104 DISALLOW_COPY_AND_ASSIGN(PostCleanup);
105 };
106
107 // Don't use the data parameter, instead use the pointer we pass into every
108 // post cleanup object - that pointer will be deleted and deleted only on a
109 // successful post to the feedback server.
110 void BugReportUtil::PostCleanup::OnURLFetchComplete(
111 const content::URLFetcher* source) {
112 std::stringstream error_stream;
113 int response_code = source->GetResponseCode();
114 if (response_code == kHttpPostSuccessNoContent) {
115 // We've sent our report, delete the report data
116 delete post_body_;
117
118 error_stream << "Success";
119 } else {
120 // Uh oh, feedback failed, send it off to retry
121 if (previous_delay_) {
122 if (previous_delay_ < kRetryDelayLimit)
123 previous_delay_ *= kRetryDelayIncreaseFactor;
124 } else {
125 previous_delay_ = kInitialRetryDelay;
126 }
127 BugReportUtil::DispatchFeedback(profile_, post_body_, previous_delay_);
128
129 // Process the error for debug output
130 if (response_code == kHttpPostFailNoConnection) {
131 error_stream << "No connection to server.";
132 } else if ((response_code > kHttpPostFailClientError) &&
133 (response_code < kHttpPostFailServerError)) {
134 error_stream << "Client error: HTTP response code " << response_code;
135 } else if (response_code > kHttpPostFailServerError) {
136 error_stream << "Server error: HTTP response code " << response_code;
137 } else {
138 error_stream << "Unknown error: HTTP response code " << response_code;
139 }
140 }
141
142 LOG(WARNING) << "FEEDBACK: Submission to feedback server (" <<
143 source->GetURL() << ") status: " << error_stream.str();
144
145 // Delete the URLFetcher.
146 delete source;
147 // And then delete ourselves.
148 delete this;
149 }
150
151 // static
152 void BugReportUtil::SetOSVersion(std::string* os_version) {
153 #if defined(OS_WIN)
154 base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
155 base::win::OSInfo::VersionNumber version_number = os_info->version_number();
156 *os_version = base::StringPrintf("%d.%d.%d",
157 version_number.major,
158 version_number.minor,
159 version_number.build);
160 int service_pack = os_info->service_pack().major;
161 if (service_pack > 0)
162 os_version->append(base::StringPrintf("Service Pack %d", service_pack));
163 #elif defined(OS_MACOSX)
164 *os_version = base::SysInfo::OperatingSystemVersion();
165 #else
166 *os_version = "unknown";
167 #endif
168 }
169
170 // static
171 void BugReportUtil::DispatchFeedback(Profile* profile,
172 std::string* post_body,
173 int64 delay) {
174 DCHECK(post_body);
175
176 MessageLoop::current()->PostDelayedTask(FROM_HERE, base::Bind(
177 &BugReportUtil::SendFeedback, profile, post_body, delay), delay);
178 }
179
180 // static
181 void BugReportUtil::SendFeedback(Profile* profile,
182 std::string* post_body,
183 int64 previous_delay) {
184 DCHECK(post_body);
185
186 GURL post_url;
187 if (CommandLine::ForCurrentProcess()->
188 HasSwitch(switches::kFeedbackServer))
189 post_url = GURL(CommandLine::ForCurrentProcess()->
190 GetSwitchValueASCII(switches::kFeedbackServer));
191 else
192 post_url = GURL(kBugReportPostUrl);
193
194 content::URLFetcher* fetcher = content::URLFetcher::Create(
195 post_url, content::URLFetcher::POST,
196 new BugReportUtil::PostCleanup(profile, post_body, previous_delay));
197 fetcher->SetRequestContext(profile->GetRequestContext());
198
199 fetcher->SetUploadData(std::string(kProtBufMimeType), *post_body);
200 fetcher->Start();
201 }
202
203
204 // static
205 void BugReportUtil::AddFeedbackData(
206 userfeedback::ExternalExtensionSubmit* feedback_data,
207 const std::string& key, const std::string& value) {
208 // Don't bother with empty keys or values
209 if (key=="" || value == "") return;
210 // Create log_value object and add it to the web_data object
211 userfeedback::ProductSpecificData log_value;
212 log_value.set_key(key);
213 log_value.set_value(value);
214 userfeedback::WebData* web_data = feedback_data->mutable_web_data();
215 *(web_data->add_product_specific_data()) = log_value;
216 }
217
218 #if defined(OS_CHROMEOS)
219 bool BugReportUtil::ValidFeedbackSize(const std::string& content) {
220 if (content.length() > kMaxSystemLogLength)
221 return false;
222 size_t line_count = 0;
223 const char* text = content.c_str();
224 for (size_t i = 0; i < content.length(); i++) {
225 if (*(text + i) == '\n') {
226 line_count++;
227 if (line_count > kMaxLineCount)
228 return false;
229 }
230 }
231 return true;
232 }
233 #endif
234
235 // static
236 void BugReportUtil::SendReport(
237 Profile* profile
238 , int problem_type
239 , const std::string& page_url_text
240 , const std::string& description
241 , ScreenshotDataPtr image_data_ptr
242 , int png_width
243 , int png_height
244 #if defined(OS_CHROMEOS)
245 , const std::string& user_email_text
246 , const char* zipped_logs_data
247 , int zipped_logs_length
248 , const chromeos::system::LogDictionaryType* const sys_info
249 #endif
250 ) {
251 // Create google feedback protocol buffer objects
252 userfeedback::ExternalExtensionSubmit feedback_data;
253 // type id set to 0, unused field but needs to be initialized to 0
254 feedback_data.set_type_id(0);
255
256 userfeedback::CommonData* common_data = feedback_data.mutable_common_data();
257 userfeedback::WebData* web_data = feedback_data.mutable_web_data();
258
259 // Set GAIA id to 0. We're not using gaia id's for recording
260 // use feedback - we're using the e-mail field, allows users to
261 // submit feedback from incognito mode and specify any mail id
262 // they wish
263 common_data->set_gaia_id(0);
264
265 #if defined(OS_CHROMEOS)
266 // Add the user e-mail to the feedback object
267 common_data->set_user_email(user_email_text);
268 #endif
269
270 // Add the description to the feedback object
271 common_data->set_description(description);
272
273 // Add the language
274 std::string chrome_locale = g_browser_process->GetApplicationLocale();
275 common_data->set_source_description_language(chrome_locale);
276
277 // Set the url
278 web_data->set_url(page_url_text);
279
280 // Add the Chrome version
281 chrome::VersionInfo version_info;
282 if (version_info.is_valid()) {
283 std::string chrome_version = version_info.Name() + " - " +
284 version_info.Version() +
285 " (" + version_info.LastChange() + ")";
286 AddFeedbackData(&feedback_data, std::string(kChromeVersionTag),
287 chrome_version);
288 }
289
290 // Add OS version (eg, for WinXP SP2: "5.1.2600 Service Pack 2").
291 std::string os_version = "";
292 SetOSVersion(&os_version);
293 AddFeedbackData(&feedback_data, std::string(kOsVersionTag), os_version);
294
295 // Include the page image if we have one.
296 if (image_data_ptr.get() && image_data_ptr->size()) {
297 userfeedback::PostedScreenshot screenshot;
298 screenshot.set_mime_type(kPngMimeType);
299 // Set the dimensions of the screenshot
300 userfeedback::Dimensions dimensions;
301 dimensions.set_width(static_cast<float>(png_width));
302 dimensions.set_height(static_cast<float>(png_height));
303 *(screenshot.mutable_dimensions()) = dimensions;
304
305 int image_data_size = image_data_ptr->size();
306 char* image_data = reinterpret_cast<char*>(&(image_data_ptr->front()));
307 screenshot.set_binary_content(std::string(image_data, image_data_size));
308
309 // Set the screenshot object in feedback
310 *(feedback_data.mutable_screenshot()) = screenshot;
311 }
312
313 #if defined(OS_CHROMEOS)
314 if (sys_info) {
315 // Add the product specific data
316 for (chromeos::system::LogDictionaryType::const_iterator i =
317 sys_info->begin(); i != sys_info->end(); ++i) {
318 if (!CommandLine::ForCurrentProcess()->HasSwitch(
319 switches::kCompressSystemFeedback) || ValidFeedbackSize(i->second)) {
320 AddFeedbackData(&feedback_data, i->first, i->second);
321 }
322 }
323
324 // If we have zipped logs, add them here
325 if (zipped_logs_data && CommandLine::ForCurrentProcess()->HasSwitch(
326 switches::kCompressSystemFeedback)) {
327 userfeedback::ProductSpecificBinaryData attachment;
328 attachment.set_mime_type(kBZip2MimeType);
329 attachment.set_name(kLogsAttachmentName);
330 attachment.set_data(std::string(zipped_logs_data, zipped_logs_length));
331 *(feedback_data.add_product_specific_binary_data()) = attachment;
332 }
333 }
334 #endif
335
336 // Set our Chrome specific data
337 userfeedback::ChromeData chrome_data;
338 #if defined(OS_CHROMEOS)
339 chrome_data.set_chrome_platform(
340 userfeedback::ChromeData_ChromePlatform_CHROME_OS);
341 userfeedback::ChromeOsData chrome_os_data;
342 chrome_os_data.set_category(
343 (userfeedback::ChromeOsData_ChromeOsCategory) problem_type);
344 *(chrome_data.mutable_chrome_os_data()) = chrome_os_data;
345 #else
346 chrome_data.set_chrome_platform(
347 userfeedback::ChromeData_ChromePlatform_CHROME_BROWSER);
348 userfeedback::ChromeBrowserData chrome_browser_data;
349 chrome_browser_data.set_category(
350 (userfeedback::ChromeBrowserData_ChromeBrowserCategory) problem_type);
351 *(chrome_data.mutable_chrome_browser_data()) = chrome_browser_data;
352 #endif
353
354 *(feedback_data.mutable_chrome_data()) = chrome_data;
355
356 // Serialize our report to a string pointer we can pass around
357 std::string* post_body = new std::string;
358 feedback_data.SerializeToString(post_body);
359
360 // We have the body of our POST, so send it off to the server with 0 delay
361 DispatchFeedback(profile, post_body, 0);
362 }
363
364 #if defined(ENABLE_SAFE_BROWSING)
365 // static
366 void BugReportUtil::ReportPhishing(WebContents* current_tab,
367 const std::string& phishing_url) {
368 current_tab->GetController().LoadURL(
369 safe_browsing_util::GeneratePhishingReportUrl(
370 kReportPhishingUrl, phishing_url,
371 false /* not client-side detection */),
372 content::Referrer(),
373 content::PAGE_TRANSITION_LINK,
374 std::string());
375 }
376 #endif
377
378 static std::vector<unsigned char>* screenshot_png = NULL;
379 static gfx::Rect* screenshot_size = NULL;
380
381 // static
382 std::vector<unsigned char>* BugReportUtil::GetScreenshotPng() {
383 if (screenshot_png == NULL)
384 screenshot_png = new std::vector<unsigned char>;
385 return screenshot_png;
386 }
387
388 // static
389 void BugReportUtil::ClearScreenshotPng() {
390 if (screenshot_png)
391 screenshot_png->clear();
392 }
393
394 // static
395 gfx::Rect& BugReportUtil::GetScreenshotSize() {
396 if (screenshot_size == NULL)
397 screenshot_size = new gfx::Rect();
398 return *screenshot_size;
399 }
400
401 // static
402 void BugReportUtil::SetScreenshotSize(const gfx::Rect& rect) {
403 gfx::Rect& screen_size = GetScreenshotSize();
404 screen_size = rect;
405 }
OLDNEW
« no previous file with comments | « chrome/browser/bug_report_util.h ('k') | chrome/browser/feedback/feedback_data.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698