Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / tracing / trace_uploader.cc
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.
4
5 #include "content/browser/tracing/trace_uploader.h"
6
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/memory/shared_memory.h"
10 #include "base/path_service.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "net/base/mime_util.h"
16 #include "net/base/network_delegate.h"
17 #include "net/proxy/proxy_config.h"
18 #include "net/proxy/proxy_config_service.h"
19 #include "net/url_request/url_fetcher.h"
20 #include "net/url_request/url_request_context.h"
21 #include "net/url_request/url_request_context_builder.h"
22 #include "net/url_request/url_request_context_getter.h"
23 #include "third_party/zlib/zlib.h"
24 #include "url/gurl.h"
25
26 namespace content {
27 namespace {
28 const char kUploadContentType[] = "multipart/form-data";
29 const char kMultipartBoundary[] =
30     "----**--yradnuoBgoLtrapitluMklaTelgooG--**----";
31
32 const int kHttpResponseOk = 200;
33
34 }  // namespace
35
36 TraceUploader::TraceUploader(const std::string& product,
37                              const std::string& version,
38                              const std::string& upload_url,
39                              net::URLRequestContextGetter* request_context)
40     : product_(product),
41       version_(version),
42       upload_url_(upload_url),
43       request_context_(request_context) {
44   DCHECK(!product_.empty());
45   DCHECK(!version_.empty());
46   DCHECK(!upload_url_.empty());
47 }
48
49 TraceUploader::~TraceUploader() {
50   DCHECK_CURRENTLY_ON(BrowserThread::UI);
51 }
52
53 void TraceUploader::OnURLFetchComplete(const net::URLFetcher* source) {
54   DCHECK_CURRENTLY_ON(BrowserThread::UI);
55   DCHECK_EQ(source, url_fetcher_.get());
56   int response_code = source->GetResponseCode();
57   string report_id;
58   string error_message;
59   bool success = (response_code == kHttpResponseOk);
60   if (success) {
61     source->GetResponseAsString(&report_id);
62   } else {
63     error_message = "Uploading failed, response code: " +
64                     base::IntToString(response_code);
65   }
66
67   BrowserThread::PostTask(
68       content::BrowserThread::UI,
69       FROM_HERE,
70       base::Bind(done_callback_, success, report_id, error_message));
71   url_fetcher_.reset();
72 }
73
74 void TraceUploader::OnURLFetchUploadProgress(
75     const net::URLFetcher* source, int64 current, int64 total) {
76   DCHECK(url_fetcher_.get());
77
78   LOG(WARNING) << "Upload progress: " << current << " of " << total;
79   BrowserThread::PostTask(
80       content::BrowserThread::UI,
81       FROM_HERE,
82       base::Bind(progress_callback_, current, total));
83 }
84
85 void TraceUploader::DoUpload(
86     const std::string& file_contents,
87     UploadProgressCallback progress_callback,
88     UploadDoneCallback done_callback) {
89   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
90   DCHECK(!url_fetcher_.get());
91
92   progress_callback_ = progress_callback;
93   done_callback_ = done_callback;
94
95   if (url_fetcher_.get()) {
96     OnUploadError("Already uploading.");
97   }
98
99   scoped_ptr<char[]> compressed_contents(new char[kMaxUploadBytes]);
100   int compressed_bytes;
101   if (!Compress(file_contents, kMaxUploadBytes, compressed_contents.get(),
102                 &compressed_bytes)) {
103     OnUploadError("Compressing file failed.");
104     return;
105   }
106
107   std::string post_data;
108   SetupMultipart("trace.json.gz",
109                  std::string(compressed_contents.get(), compressed_bytes),
110                  &post_data);
111
112   content::BrowserThread::PostTask(
113       content::BrowserThread::UI, FROM_HERE,
114       base::Bind(&TraceUploader::CreateAndStartURLFetcher,
115                  base::Unretained(this),
116                  post_data));
117 }
118
119 void TraceUploader::OnUploadError(std::string error_message) {
120   LOG(ERROR) << error_message;
121   content::BrowserThread::PostTask(
122       content::BrowserThread::UI,
123       FROM_HERE,
124       base::Bind(done_callback_, false, "", error_message));
125 }
126
127 void TraceUploader::SetupMultipart(const std::string& trace_filename,
128                                    const std::string& trace_contents,
129                                    std::string* post_data) {
130   net::AddMultipartValueForUpload("prod", product_, kMultipartBoundary, "",
131                                   post_data);
132   net::AddMultipartValueForUpload("ver", version_ + "-trace",
133                                   kMultipartBoundary, "", post_data);
134   net::AddMultipartValueForUpload("guid", "0", kMultipartBoundary,
135                                   "", post_data);
136   net::AddMultipartValueForUpload("type", "trace", kMultipartBoundary,
137                                   "", post_data);
138   // No minidump means no need for crash to process the report.
139   net::AddMultipartValueForUpload("should_process", "false", kMultipartBoundary,
140                                   "", post_data);
141
142   AddTraceFile(trace_filename, trace_contents, post_data);
143
144   net::AddMultipartFinalDelimiterForUpload(kMultipartBoundary, post_data);
145 }
146
147 void TraceUploader::AddTraceFile(const std::string& trace_filename,
148                                  const std::string& trace_contents,
149                                  std::string* post_data) {
150   post_data->append("--");
151   post_data->append(kMultipartBoundary);
152   post_data->append("\r\n");
153   post_data->append("Content-Disposition: form-data; name=\"trace\"");
154   post_data->append("; filename=\"");
155   post_data->append(trace_filename);
156   post_data->append("\"\r\n");
157   post_data->append("Content-Type: application/gzip\r\n\r\n");
158   post_data->append(trace_contents);
159   post_data->append("\r\n");
160 }
161
162 bool TraceUploader::Compress(std::string input,
163                              int max_compressed_bytes,
164                              char* compressed,
165                              int* compressed_bytes) {
166   DCHECK(compressed);
167   DCHECK(compressed_bytes);
168   z_stream stream = {0};
169   int result = deflateInit2(&stream,
170                             Z_DEFAULT_COMPRESSION,
171                             Z_DEFLATED,
172                             // 16 is added to produce a gzip header + trailer.
173                             MAX_WBITS + 16,
174                             8,  // memLevel = 8 is default.
175                             Z_DEFAULT_STRATEGY);
176   DCHECK_EQ(Z_OK, result);
177   stream.next_in = reinterpret_cast<uint8*>(&input[0]);
178   stream.avail_in = input.size();
179   stream.next_out = reinterpret_cast<uint8*>(compressed);
180   stream.avail_out = max_compressed_bytes;
181   // Do a one-shot compression. This will return Z_STREAM_END only if |output|
182   // is large enough to hold all compressed data.
183   result = deflate(&stream, Z_FINISH);
184   bool success = (result == Z_STREAM_END);
185   result = deflateEnd(&stream);
186   DCHECK(result == Z_OK || result == Z_DATA_ERROR);
187
188   if (success)
189     *compressed_bytes = max_compressed_bytes - stream.avail_out;
190
191   LOG(WARNING) << "input size: " << input.size()
192                << ", output size: " << *compressed_bytes;
193   return success;
194 }
195
196 void TraceUploader::CreateAndStartURLFetcher(const std::string& post_data) {
197   DCHECK_CURRENTLY_ON(BrowserThread::UI);
198   DCHECK(!url_fetcher_.get());
199
200   std::string content_type = kUploadContentType;
201   content_type.append("; boundary=");
202   content_type.append(kMultipartBoundary);
203
204   url_fetcher_.reset(
205       net::URLFetcher::Create(GURL(upload_url_), net::URLFetcher::POST, this));
206   url_fetcher_->SetRequestContext(request_context_);
207   url_fetcher_->SetUploadData(content_type, post_data);
208   url_fetcher_->Start();
209 }
210
211 }  // namespace content