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