| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/bug_report_util.h" | 5 #include "chrome/browser/bug_report_util.h" |
| 6 | 6 |
| 7 #include "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
| 8 #include "base/file_version_info.h" | 8 #include "base/file_version_info.h" |
| 9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 10 #include "chrome/app/chrome_version_info.h" | 10 #include "chrome/app/chrome_version_info.h" |
| 11 #include "chrome/browser/browser_process_impl.h" | 11 #include "chrome/browser/browser_process_impl.h" |
| 12 #include "chrome/browser/profile.h" | 12 #include "chrome/browser/profile.h" |
| 13 #include "chrome/browser/safe_browsing/safe_browsing_util.h" | 13 #include "chrome/browser/safe_browsing/safe_browsing_util.h" |
| 14 #include "chrome/browser/tab_contents/tab_contents.h" | 14 #include "chrome/browser/tab_contents/tab_contents.h" |
| 15 #include "chrome/common/net/url_fetcher.h" | 15 #include "chrome/common/net/url_fetcher.h" |
| 16 #include "googleurl/src/gurl.h" | 16 #include "googleurl/src/gurl.h" |
| 17 #include "grit/locale_settings.h" | 17 #include "grit/locale_settings.h" |
| 18 #include "unicode/locid.h" | 18 #include "unicode/locid.h" |
| 19 | 19 |
| 20 #include <string> |
| 21 |
| 20 namespace { | 22 namespace { |
| 21 | 23 |
| 22 const int kBugReportVersion = 1; | 24 const int kBugReportVersion = 1; |
| 23 | 25 |
| 24 const char kReportPhishingUrl[] = | 26 const char kReportPhishingUrl[] = |
| 25 "http://www.google.com/safebrowsing/report_phish/"; | 27 "http://www.google.com/safebrowsing/report_phish/"; |
| 26 | 28 |
| 27 // URL to post bug reports to. | 29 // URL to post bug reports to. |
| 28 const char* const kBugReportPostUrl = | 30 const char* const kBugReportPostUrl = |
| 29 "http://web-bug.appspot.com/bugreport"; | 31 "http://feedback2-dev.corp.google.com/tools/feedback/chrome/__submit"; |
| 32 |
| 33 const char* const kProtBufMimeType = "application/x-protobuf"; |
| 34 const char* const kPngMimeType = "image/png"; |
| 35 |
| 36 // Tags we use in product specific data |
| 37 const char* const kPageTitleTag = "PAGE TITLE"; |
| 38 const char* const kProblemTypeTag = "PROBLEM TYPE"; |
| 39 const char* const kChromeVersionTag = "CHROME VERSION"; |
| 40 const char* const kOsVersionTag = "OS VERSION"; |
| 41 |
| 30 | 42 |
| 31 } // namespace | 43 } // namespace |
| 32 | 44 |
| 33 // Simple URLFetcher::Delegate to clean up URLFetcher on completion. | 45 // Simple URLFetcher::Delegate to clean up URLFetcher on completion. |
| 34 class BugReportUtil::PostCleanup : public URLFetcher::Delegate { | 46 class BugReportUtil::PostCleanup : public URLFetcher::Delegate { |
| 35 public: | 47 public: |
| 36 PostCleanup(); | 48 PostCleanup(); |
| 37 | 49 |
| 38 // Overridden from URLFetcher::Delegate. | 50 // Overridden from URLFetcher::Delegate. |
| 39 virtual void OnURLFetchComplete(const URLFetcher* source, | 51 virtual void OnURLFetchComplete(const URLFetcher* source, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 int32 major; | 94 int32 major; |
| 83 int32 minor; | 95 int32 minor; |
| 84 int32 bugFix; | 96 int32 bugFix; |
| 85 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugFix); | 97 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugFix); |
| 86 *os_version = StringPrintf("%d.%d.%d", major, minor, bugFix); | 98 *os_version = StringPrintf("%d.%d.%d", major, minor, bugFix); |
| 87 #else | 99 #else |
| 88 *os_version = "unknown"; | 100 *os_version = "unknown"; |
| 89 #endif | 101 #endif |
| 90 } | 102 } |
| 91 | 103 |
| 92 // Create a MIME boundary marker (27 '-' characters followed by 16 hex digits). | 104 // static |
| 93 void BugReportUtil::CreateMimeBoundary(std::string *out) { | 105 void BugReportUtil::AddFeedbackData( |
| 94 int r1 = rand(); | 106 userfeedback::ExternalExtensionSubmit* feedback_data, |
| 95 int r2 = rand(); | 107 const std::string& key, const std::string& value) { |
| 96 SStringPrintf(out, "---------------------------%08X%08X", r1, r2); | 108 // Create log_value object and add it to the web_data object |
| 109 userfeedback::ProductSpecificData log_value; |
| 110 log_value.set_key(key); |
| 111 log_value.set_value(value); |
| 112 userfeedback::WebData* web_data = feedback_data->mutable_web_data(); |
| 113 *(web_data->add_product_specific_data()) = log_value; |
| 97 } | 114 } |
| 98 | 115 |
| 99 // static | 116 // static |
| 100 void BugReportUtil::SendReport(Profile* profile, | 117 void BugReportUtil::SendReport(Profile* profile, |
| 101 std::string page_title_text, | 118 const std::string& page_title_text, |
| 102 int problem_type, | 119 int problem_type, |
| 103 std::string page_url_text, | 120 const std::string& page_url_text, |
| 104 std::string description, | 121 const std::string& description, |
| 105 const char* png_data, | 122 const char* png_data, |
| 106 int png_data_length) { | 123 int png_data_length, |
| 124 int png_width, |
| 125 int png_height) { |
| 107 GURL post_url(kBugReportPostUrl); | 126 GURL post_url(kBugReportPostUrl); |
| 108 std::string mime_boundary; | |
| 109 CreateMimeBoundary(&mime_boundary); | |
| 110 | 127 |
| 111 // Create a request body and add the mandatory parameters. | 128 // Create google feedback protocol buffer objects |
| 112 std::string post_body; | 129 userfeedback::ExternalExtensionSubmit feedback_data; |
| 130 // type id set to 0, unused field but needs to be initialized to 0 |
| 131 feedback_data.set_type_id(0); |
| 113 | 132 |
| 114 // Add the protocol version: | 133 userfeedback::CommonData* common_data = feedback_data.mutable_common_data(); |
| 115 post_body.append("--" + mime_boundary + "\r\n"); | 134 userfeedback::WebData* web_data = feedback_data.mutable_web_data(); |
| 116 post_body.append("Content-Disposition: form-data; " | 135 |
| 117 "name=\"data_version\"\r\n\r\n"); | 136 // set GAIA id to 0 to indicate no username available |
| 118 post_body.append(StringPrintf("%d\r\n", kBugReportVersion)); | 137 common_data->set_gaia_id(0); |
| 119 | 138 |
| 120 // Add the page title. | 139 // Add the page title. |
| 121 post_body.append("--" + mime_boundary + "\r\n"); | 140 AddFeedbackData(&feedback_data, std::string(kPageTitleTag), |
| 122 post_body.append(page_title_text + "\r\n"); | 141 page_title_text); |
| 123 | 142 |
| 124 // Add the problem type. | 143 AddFeedbackData(&feedback_data, std::string(kProblemTypeTag), |
| 125 post_body.append("--" + mime_boundary + "\r\n"); | 144 StringPrintf("%d\r\n", problem_type)); |
| 126 post_body.append("Content-Disposition: form-data; " | |
| 127 "name=\"problem\"\r\n\r\n"); | |
| 128 post_body.append(StringPrintf("%d\r\n", problem_type)); | |
| 129 | 145 |
| 130 // Add in the URL, if we have one. | 146 // Add the description to the feedback object |
| 131 post_body.append("--" + mime_boundary + "\r\n"); | 147 common_data->set_description(description); |
| 132 post_body.append("Content-Disposition: form-data; " | |
| 133 "name=\"url\"\r\n\r\n"); | |
| 134 | 148 |
| 135 // Convert URL to UTF8. | 149 // Add the language |
| 136 if (page_url_text.empty()) | 150 std::string chrome_locale = g_browser_process->GetApplicationLocale(); |
| 137 post_body.append("n/a\r\n"); | 151 common_data->set_source_descripton_language(chrome_locale); |
| 138 else | |
| 139 post_body.append(page_url_text + "\r\n"); | |
| 140 | 152 |
| 141 // Add Chrome version. | 153 // Set the url |
| 142 post_body.append("--" + mime_boundary + "\r\n"); | 154 web_data->set_url(page_url_text); |
| 143 post_body.append("Content-Disposition: form-data; " | |
| 144 "name=\"chrome_version\"\r\n\r\n"); | |
| 145 | 155 |
| 156 // Add the Chrome version |
| 146 std::string chrome_version; | 157 std::string chrome_version; |
| 147 scoped_ptr<FileVersionInfo> version_info( | 158 scoped_ptr<FileVersionInfo> version_info( |
| 148 chrome_app::GetChromeVersionInfo()); | 159 chrome_app::GetChromeVersionInfo()); |
| 149 if (version_info.get()) { | 160 if (version_info.get()) { |
| 150 chrome_version = WideToUTF8(version_info->product_name()) + " - " + | 161 chrome_version = WideToUTF8(version_info->product_name()) + " - " + |
| 151 WideToUTF8(version_info->file_version()) + | 162 WideToUTF8(version_info->file_version()) + |
| 152 " (" + WideToUTF8(version_info->last_change()) + ")"; | 163 " (" + WideToUTF8(version_info->last_change()) + ")"; |
| 153 } | 164 } |
| 154 | 165 |
| 155 if (chrome_version.empty()) | 166 if (!chrome_version.empty()) |
| 156 post_body.append("n/a\r\n"); | 167 AddFeedbackData(&feedback_data, std::string(kChromeVersionTag), |
| 157 else | 168 chrome_version); |
| 158 post_body.append(chrome_version + "\r\n"); | |
| 159 | 169 |
| 160 // Add OS version (eg, for WinXP SP2: "5.1.2600 Service Pack 2"). | 170 // Add OS version (eg, for WinXP SP2: "5.1.2600 Service Pack 2"). |
| 161 std::string os_version = ""; | 171 std::string os_version = ""; |
| 162 post_body.append("--" + mime_boundary + "\r\n"); | |
| 163 post_body.append("Content-Disposition: form-data; " | |
| 164 "name=\"os_version\"\r\n\r\n"); | |
| 165 SetOSVersion(&os_version); | 172 SetOSVersion(&os_version); |
| 166 post_body.append(os_version + "\r\n"); | 173 AddFeedbackData(&feedback_data, std::string(kOsVersionTag), os_version); |
| 167 | 174 |
| 168 // Add locale. | |
| 169 #if defined(OS_MACOSX) | |
| 170 std::string chrome_locale = g_browser_process->GetApplicationLocale(); | |
| 171 #else | |
| 172 icu::Locale locale = icu::Locale::getDefault(); | |
| 173 const char *lang = locale.getLanguage(); | |
| 174 std::string chrome_locale = (lang)? lang:"en"; | |
| 175 #endif | |
| 176 | |
| 177 post_body.append("--" + mime_boundary + "\r\n"); | |
| 178 post_body.append("Content-Disposition: form-data; " | |
| 179 "name=\"chrome_locale\"\r\n\r\n"); | |
| 180 post_body.append(chrome_locale + "\r\n"); | |
| 181 | |
| 182 // Add a description if we have one. | |
| 183 post_body.append("--" + mime_boundary + "\r\n"); | |
| 184 post_body.append("Content-Disposition: form-data; " | |
| 185 "name=\"description\"\r\n\r\n"); | |
| 186 | |
| 187 if (description.empty()) | |
| 188 post_body.append("n/a\r\n"); | |
| 189 else | |
| 190 post_body.append(description + "\r\n"); | |
| 191 | 175 |
| 192 // Include the page image if we have one. | 176 // Include the page image if we have one. |
| 193 if (png_data != NULL && png_data_length > 0) { | 177 if (png_data) { |
| 194 post_body.append("--" + mime_boundary + "\r\n"); | 178 userfeedback::PostedScreenshot screenshot; |
| 195 post_body.append("Content-Disposition: form-data; name=\"screenshot\"; " | 179 screenshot.set_mime_type(kPngMimeType); |
| 196 "filename=\"screenshot.png\"\r\n"); | 180 |
| 197 post_body.append("Content-Type: application/octet-stream\r\n"); | 181 // Set the dimensions of the screenshot |
| 198 post_body.append(StringPrintf("Content-Length: %d\r\n\r\n", | 182 userfeedback::Dimensions dimensions; |
| 199 png_data_length)); | 183 dimensions.set_width(static_cast<float>(png_width)); |
| 200 post_body.append(png_data, png_data_length); | 184 dimensions.set_height(static_cast<float>(png_height)); |
| 201 post_body.append("\r\n"); | 185 *(screenshot.mutable_dimensions()) = dimensions; |
| 186 screenshot.set_binary_content(std::string(png_data, png_data_length)); |
| 187 |
| 188 // Set the screenshot object in feedback |
| 189 *(feedback_data.mutable_screenshot()) = screenshot; |
| 202 } | 190 } |
| 203 | 191 |
| 204 // TODO(awalker): include the page source if we can get it. | 192 // TODO(awalker): include the page source if we can get it. |
| 205 // if (include_page_source_checkbox_->checked()) { | 193 // if (include_page_source_checkbox_->checked()) { |
| 206 // } | 194 // } |
| 207 | 195 |
| 208 // Terminate the body. | |
| 209 post_body.append("--" + mime_boundary + "--\r\n"); | |
| 210 | |
| 211 // We have the body of our POST, so send it off to the server. | 196 // We have the body of our POST, so send it off to the server. |
| 212 URLFetcher* fetcher = new URLFetcher(post_url, URLFetcher::POST, | 197 URLFetcher* fetcher = new URLFetcher(post_url, URLFetcher::POST, |
| 213 new BugReportUtil::PostCleanup); | 198 new BugReportUtil::PostCleanup); |
| 214 fetcher->set_request_context(profile->GetRequestContext()); | 199 fetcher->set_request_context(profile->GetRequestContext()); |
| 215 std::string mime_type("multipart/form-data; boundary="); | 200 |
| 216 mime_type += mime_boundary; | 201 std::string post_body; |
| 217 fetcher->set_upload_data(mime_type, post_body); | 202 feedback_data.SerializeToString(&post_body); |
| 203 fetcher->set_upload_data(std::string(kProtBufMimeType), post_body); |
| 218 fetcher->Start(); | 204 fetcher->Start(); |
| 219 } | 205 } |
| 220 | 206 |
| 221 // static | 207 // static |
| 222 std::string BugReportUtil::GetMimeType() { | |
| 223 std::string mime_type("multipart/form-data; boundary="); | |
| 224 std::string mime_boundary; | |
| 225 CreateMimeBoundary(&mime_boundary); | |
| 226 mime_type += mime_boundary; | |
| 227 return mime_type; | |
| 228 } | |
| 229 | |
| 230 // static | |
| 231 void BugReportUtil::ReportPhishing(TabContents* currentTab, | 208 void BugReportUtil::ReportPhishing(TabContents* currentTab, |
| 232 const std::string& phishing_url) { | 209 const std::string& phishing_url) { |
| 233 currentTab->controller().LoadURL( | 210 currentTab->controller().LoadURL( |
| 234 safe_browsing_util::GeneratePhishingReportUrl( | 211 safe_browsing_util::GeneratePhishingReportUrl( |
| 235 kReportPhishingUrl, phishing_url), | 212 kReportPhishingUrl, phishing_url), |
| 236 GURL(), | 213 GURL(), |
| 237 PageTransition::LINK); | 214 PageTransition::LINK); |
| 238 } | 215 } |
| 239 | |
| OLD | NEW |