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