Give names to all utility processes.
[chromium-blink-merge.git] / chrome / browser / tracing / crash_service_uploader.cc
blobed408d516ea063eea85c3001874817569da37d22
1 // Copyright 2014 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/tracing/crash_service_uploader.h"
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/format_macros.h"
11 #include "base/memory/shared_memory.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/time/time.h"
17 #include "chrome/common/chrome_version_info.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/common/content_switches.h"
20 #include "net/base/mime_util.h"
21 #include "net/base/network_delegate.h"
22 #include "net/proxy/proxy_config.h"
23 #include "net/proxy/proxy_config_service.h"
24 #include "net/url_request/url_fetcher.h"
25 #include "net/url_request/url_request_context.h"
26 #include "net/url_request/url_request_context_builder.h"
27 #include "net/url_request/url_request_context_getter.h"
28 #include "third_party/zlib/zlib.h"
29 #include "url/gurl.h"
31 using std::string;
33 namespace {
34 const char kUploadURL[] = "https://clients2.google.com/cr/staging_report";
35 const char kUploadContentType[] = "multipart/form-data";
36 const char kMultipartBoundary[] =
37 "----**--yradnuoBgoLtrapitluMklaTelgooG--**----";
38 const int kHttpResponseOk = 200;
40 } // namespace
42 TraceCrashServiceUploader::TraceCrashServiceUploader(
43 net::URLRequestContextGetter* request_context)
44 : request_context_(request_context) {
45 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
48 TraceCrashServiceUploader::~TraceCrashServiceUploader() {
49 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
52 void TraceCrashServiceUploader::OnURLFetchComplete(
53 const net::URLFetcher* source) {
54 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
55 DCHECK_EQ(source, url_fetcher_.get());
56 int response_code = source->GetResponseCode();
57 string feedback;
58 bool success = (response_code == kHttpResponseOk);
59 if (success) {
60 source->GetResponseAsString(&feedback);
61 } else {
62 feedback =
63 "Uploading failed, response code: " + base::IntToString(response_code);
66 content::BrowserThread::PostTask(
67 content::BrowserThread::UI, FROM_HERE,
68 base::Bind(done_callback_, success, feedback));
69 url_fetcher_.reset();
72 void TraceCrashServiceUploader::OnURLFetchUploadProgress(
73 const net::URLFetcher* source,
74 int64 current,
75 int64 total) {
76 DCHECK(url_fetcher_.get());
78 LOG(WARNING) << "Upload progress: " << current << " of " << total;
79 content::BrowserThread::PostTask(
80 content::BrowserThread::UI, FROM_HERE,
81 base::Bind(progress_callback_, current, total));
84 void TraceCrashServiceUploader::DoUpload(
85 const std::string& file_contents,
86 const UploadProgressCallback& progress_callback,
87 const UploadDoneCallback& done_callback) {
88 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
89 content::BrowserThread::PostTask(
90 content::BrowserThread::FILE, FROM_HERE,
91 base::Bind(&TraceCrashServiceUploader::DoUploadOnFileThread,
92 base::Unretained(this), file_contents, progress_callback,
93 done_callback));
96 void TraceCrashServiceUploader::DoUploadOnFileThread(
97 const std::string& file_contents,
98 const UploadProgressCallback& progress_callback,
99 const UploadDoneCallback& done_callback) {
100 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
101 DCHECK(!url_fetcher_.get());
103 progress_callback_ = progress_callback;
104 done_callback_ = done_callback;
106 const base::CommandLine& command_line =
107 *base::CommandLine::ForCurrentProcess();
108 std::string upload_url = kUploadURL;
109 if (command_line.HasSwitch(switches::kTraceUploadURL)) {
110 upload_url = command_line.GetSwitchValueASCII(switches::kTraceUploadURL);
112 if (!GURL(upload_url).is_valid())
113 upload_url.clear();
115 if (upload_url.empty()) {
116 OnUploadError("Upload URL empty or invalid");
117 return;
120 #if defined(OS_WIN)
121 const char product[] = "Chrome";
122 #elif defined(OS_MACOSX)
123 const char product[] = "Chrome_Mac";
124 #elif defined(OS_LINUX)
125 const char product[] = "Chrome_Linux";
126 #elif defined(OS_ANDROID)
127 const char product[] = "Chrome_Android";
128 #elif defined(OS_CHROMEOS)
129 const char product[] = "Chrome_ChromeOS";
130 #else
131 #error Platform not supported.
132 #endif
134 // VersionInfo::ProductNameAndVersionForUserAgent() returns a string like
135 // "Chrome/aa.bb.cc.dd", split out the part before the "/".
136 chrome::VersionInfo version_info;
137 std::vector<std::string> product_components;
138 base::SplitString(version_info.ProductNameAndVersionForUserAgent(), '/',
139 &product_components);
140 DCHECK_EQ(2U, product_components.size());
141 std::string version;
142 if (product_components.size() == 2U) {
143 version = product_components[1];
144 } else {
145 version = "unknown";
148 if (url_fetcher_.get()) {
149 OnUploadError("Already uploading.");
150 return;
153 scoped_ptr<char[]> compressed_contents(new char[kMaxUploadBytes]);
154 int compressed_bytes;
155 if (!Compress(file_contents, kMaxUploadBytes, compressed_contents.get(),
156 &compressed_bytes)) {
157 OnUploadError("Compressing file failed.");
158 return;
161 std::string post_data;
162 SetupMultipart(product, version, "trace.json.gz",
163 std::string(compressed_contents.get(), compressed_bytes),
164 &post_data);
166 content::BrowserThread::PostTask(
167 content::BrowserThread::UI, FROM_HERE,
168 base::Bind(&TraceCrashServiceUploader::CreateAndStartURLFetcher,
169 base::Unretained(this), upload_url, post_data));
172 void TraceCrashServiceUploader::OnUploadError(std::string error_message) {
173 LOG(ERROR) << error_message;
174 content::BrowserThread::PostTask(
175 content::BrowserThread::UI, FROM_HERE,
176 base::Bind(done_callback_, false, error_message));
179 void TraceCrashServiceUploader::SetupMultipart(
180 const std::string& product,
181 const std::string& version,
182 const std::string& trace_filename,
183 const std::string& trace_contents,
184 std::string* post_data) {
185 net::AddMultipartValueForUpload("prod", product, kMultipartBoundary, "",
186 post_data);
187 net::AddMultipartValueForUpload("ver", version + "-trace", kMultipartBoundary,
188 "", post_data);
189 net::AddMultipartValueForUpload("guid", "0", kMultipartBoundary, "",
190 post_data);
191 net::AddMultipartValueForUpload("type", "trace", kMultipartBoundary, "",
192 post_data);
193 // No minidump means no need for crash to process the report.
194 net::AddMultipartValueForUpload("should_process", "false", kMultipartBoundary,
195 "", post_data);
197 AddTraceFile(trace_filename, trace_contents, post_data);
199 net::AddMultipartFinalDelimiterForUpload(kMultipartBoundary, post_data);
202 void TraceCrashServiceUploader::AddTraceFile(const std::string& trace_filename,
203 const std::string& trace_contents,
204 std::string* post_data) {
205 post_data->append("--");
206 post_data->append(kMultipartBoundary);
207 post_data->append("\r\n");
208 post_data->append("Content-Disposition: form-data; name=\"trace\"");
209 post_data->append("; filename=\"");
210 post_data->append(trace_filename);
211 post_data->append("\"\r\n");
212 post_data->append("Content-Type: application/gzip\r\n\r\n");
213 post_data->append(trace_contents);
214 post_data->append("\r\n");
217 bool TraceCrashServiceUploader::Compress(std::string input,
218 int max_compressed_bytes,
219 char* compressed,
220 int* compressed_bytes) {
221 DCHECK(compressed);
222 DCHECK(compressed_bytes);
223 z_stream stream = {0};
224 int result = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
225 // 16 is added to produce a gzip header + trailer.
226 MAX_WBITS + 16,
227 8, // memLevel = 8 is default.
228 Z_DEFAULT_STRATEGY);
229 DCHECK_EQ(Z_OK, result);
230 stream.next_in = reinterpret_cast<uint8*>(&input[0]);
231 stream.avail_in = input.size();
232 stream.next_out = reinterpret_cast<uint8*>(compressed);
233 stream.avail_out = max_compressed_bytes;
234 // Do a one-shot compression. This will return Z_STREAM_END only if |output|
235 // is large enough to hold all compressed data.
236 result = deflate(&stream, Z_FINISH);
237 bool success = (result == Z_STREAM_END);
238 result = deflateEnd(&stream);
239 DCHECK(result == Z_OK || result == Z_DATA_ERROR);
241 if (success)
242 *compressed_bytes = max_compressed_bytes - stream.avail_out;
244 LOG(WARNING) << "input size: " << input.size()
245 << ", output size: " << *compressed_bytes;
246 return success;
249 void TraceCrashServiceUploader::CreateAndStartURLFetcher(
250 const std::string& upload_url,
251 const std::string& post_data) {
252 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
253 DCHECK(!url_fetcher_.get());
255 std::string content_type = kUploadContentType;
256 content_type.append("; boundary=");
257 content_type.append(kMultipartBoundary);
259 url_fetcher_.reset(
260 net::URLFetcher::Create(GURL(upload_url), net::URLFetcher::POST, this));
261 url_fetcher_->SetRequestContext(request_context_);
262 url_fetcher_->SetUploadData(content_type, post_data);
263 url_fetcher_->Start();