Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(589)

Side by Side Diff: components/webrtc_log_uploader/webrtc_log_uploader.cc

Issue 14329020: Implementing uploading of a WebRTC diagnostic log. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed two files Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
Jói 2013/05/08 14:14:22 nit: no (c)
Henrik Grunell 2013/05/08 16:05:05 Removed. Though my conclusion from the bug and the
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 "components/webrtc_log_uploader/webrtc_log_uploader.h"
6
7 #if defined(USE_SYSTEM_LIBBZ2)
8 #include <bzlib.h>
9 #else
10 #include "third_party/bzip2/bzlib.h"
11 #endif
12
13 #include "base/logging.h"
14 #include "base/partial_circular_buffer.h"
15 #include "base/shared_memory.h"
16 #include "base/stringprintf.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "net/base/network_delegate.h"
19 #include "net/proxy/proxy_config.h"
20 #include "net/proxy/proxy_config_service.h"
21 #include "net/url_request/url_fetcher.h"
22 #include "net/url_request/url_request_context.h"
23 #include "net/url_request/url_request_context_builder.h"
24 #include "net/url_request/url_request_context_getter.h"
25
26 namespace components {
27
28 namespace {
29
30 const uint32 kIntermediateCompressionBufferSize = 256 * 1024; // 256 KB
31
32 const char kTempUploadFile[] = "/tmp/chromium-webrtc-log-upload";
Jói 2013/05/08 14:14:22 This isn't going to work on all platforms. I thin
Henrik Grunell 2013/05/08 16:05:05 Done.
33 const char kUploadURL[] = "https://clients2.google.com/cr/report";
Jói 2013/05/08 14:14:22 Is this a new API? It should probably require an A
Henrik Grunell 2013/05/08 16:05:05 This is the ordinary crash server. See chrome/app/
34 const char kUploadContentType[] = "multipart/form-data";
35 const char kMultipartBoundary[] =
36 "----**--yradnuoBgoLtrapitluMklaTelgooG--**----";
37
38 // Config getter that always returns direct settings.
39 class ProxyConfigServiceDirect : public net::ProxyConfigService {
40 public:
41 // ProxyConfigService implementation.
42 virtual void AddObserver(Observer* observer) OVERRIDE {}
43 virtual void RemoveObserver(Observer* observer) OVERRIDE {}
44 virtual ConfigAvailability GetLatestProxyConfig(
45 net::ProxyConfig* config) OVERRIDE {
46 *config = net::ProxyConfig::CreateDirect();
47 return CONFIG_VALID;
48 }
49 };
50
51 } // namespace
52
53 class WebRtcLogURLRequestContextGetter : public net::URLRequestContextGetter {
54 public:
55 WebRtcLogURLRequestContextGetter() {}
56
57 // net::URLRequestContextGetter implementation.
58 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
59 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
60
61 if (!url_request_context_) {
62 net::URLRequestContextBuilder builder;
63 #if defined(OS_LINUX) || defined(OS_ANDROID)
64 builder.set_proxy_config_service(new ProxyConfigServiceDirect());
65 #endif
66 url_request_context_.reset(builder.Build());
67 }
68 CHECK(url_request_context_.get());
69
70 return url_request_context_.get();
71 }
72
73 virtual scoped_refptr<base::SingleThreadTaskRunner>
74 GetNetworkTaskRunner() const OVERRIDE {
75 return content::BrowserThread::GetMessageLoopProxyForThread(
76 content::BrowserThread::IO);
77 }
78
79 private:
80 virtual ~WebRtcLogURLRequestContextGetter() {}
81
82 // NULL if not yet initialized. Otherwise, it is the URLRequestContext
83 // instance that was lazily created by GetURLRequestContext().
84 // Access only from the IO thread.
85 scoped_ptr<net::URLRequestContext> url_request_context_;
86
87 DISALLOW_COPY_AND_ASSIGN(WebRtcLogURLRequestContextGetter);
88 };
89
90
91 WebRtcLogUploader::WebRtcLogUploader()
92 : multipart_file_(base::kInvalidPlatformFileValue) {
93 }
94
95 WebRtcLogUploader::~WebRtcLogUploader() {
96 }
97
98 void WebRtcLogUploader::OnURLFetchComplete(
99 const net::URLFetcher* source) {
100 std::vector<net::URLFetcher*>::iterator it;
101 for (it = url_fetchers_.begin(); it != url_fetchers_.end(); ++it) {
102 if (*it == source) {
103 url_fetchers_.erase(it);
104 break;
105 }
106 }
107 delete source;
108 }
109
110 void WebRtcLogUploader::OnURLFetchUploadProgress(
111 const net::URLFetcher* source, int64 current, int64 total) {
112 }
113
114 void WebRtcLogUploader::UploadLog(base::SharedMemory* shared_memory,
115 uint32 length) {
116 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
117 DCHECK(shared_memory);
118 DCHECK(shared_memory->memory());
119
120 // We have taken ownership of |shared_memory|, make sure it's deleted when
121 // we're done.
122 // TODO(grunell): Remove when passing a scoped_ptr instead.
123 scoped_ptr<base::SharedMemory> scoped_shared_memory(shared_memory);
124
125 SetupMultipartFile(reinterpret_cast<uint8*>(scoped_shared_memory->memory()),
126 length);
127
128 if (!request_context_getter_)
129 request_context_getter_ = new WebRtcLogURLRequestContextGetter();
130
131 std::string content_type = kUploadContentType;
132 content_type.append("; boundary=");
133 content_type.append(kMultipartBoundary);
134
135 net::URLFetcher* url_fetcher =
136 net::URLFetcher::Create(GURL(kUploadURL), net::URLFetcher::POST, this);
137 url_fetcher->SetRequestContext(request_context_getter_);
138 url_fetcher->SetUploadFilePath(
139 content_type, base::FilePath(kTempUploadFile), 0, kuint64max,
140 content::BrowserThread::GetMessageLoopProxyForThread(
141 content::BrowserThread::FILE));
142 url_fetcher->Start();
143 url_fetchers_.push_back(url_fetcher);
144 }
145
146 void WebRtcLogUploader::SetupMultipartFile(uint8* log_buffer,
Jói 2013/05/08 14:14:22 Is it possible to reuse existing code to create a
Henrik Grunell 2013/05/08 16:05:05 Yeah, couldn't really find anything reusable when
147 uint32 log_buffer_length) {
148 int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
149 base::PLATFORM_FILE_WRITE;
150 bool created = false;
151 base::PlatformFileError error = base::PLATFORM_FILE_OK;
152 // TODO(grunell): Handle several logs. (Different random file names etc.)
153 multipart_file_ =
154 CreatePlatformFile(base::FilePath(kTempUploadFile), flags,
155 &created, &error);
156 DCHECK(created);
157 DCHECK(error == base::PLATFORM_FILE_OK);
158
159 // TODO(grunell): Correct product name.
160 AddPairString("prod", "Chrome");
161 // TODO(grunell): Correct version.
162 AddPairString("ver", "0.0.1.1-dev-test");
163 AddPairString("guid", "0");
164 AddPairString("type", "log");
165
166 AddUrlChunks();
167
168 AddLogData(log_buffer, log_buffer_length);
169
170 std::stringstream ss;
171 ss << "--" << kMultipartBoundary << "--" << "\r\n";
172 base::WritePlatformFileAtCurrentPos(
173 multipart_file_, ss.str().data(), ss.str().size());
174
175 DCHECK(base::ClosePlatformFile(multipart_file_));
176 }
177
178 void WebRtcLogUploader::AddPairString(const std::string& key,
179 const std::string& value) {
180 std::string str;
181 AddMultipartValueForUpload(key, value, kMultipartBoundary, "", &str);
182 base::WritePlatformFileAtCurrentPos(multipart_file_, str.c_str(), str.size());
183 }
184
185 void WebRtcLogUploader::AddUrlChunks() {
186 // TODO(grunell): Implement.
187 }
188
189 void WebRtcLogUploader::AddLogData(uint8* log_buffer,
190 uint32 log_buffer_length) {
191 std::stringstream ss;
192 ss << "--" << kMultipartBoundary << "\r\n";
193 ss << "Content-Disposition: form-data; name=\"log\"";
194 ss << "; filename=\"log.bz2\"" << "\r\n";
195 ss << "Content-Type: application/x-bzip" << "\r\n";
196 ss << "\r\n";
197 base::WritePlatformFileAtCurrentPos(
198 multipart_file_, ss.str().data(), ss.str().size());
199
200 CompressLog(log_buffer, log_buffer_length, multipart_file_);
201
202 std::string end_str = "\r\n";
203 base::WritePlatformFileAtCurrentPos(
204 multipart_file_, end_str.c_str(), end_str.size());
205 }
206
207 // TODO(grunell): This is copied from cloud_print_helpers.cc. Break out to its
208 // own file.
209 void WebRtcLogUploader::AddMultipartValueForUpload(
210 const std::string& value_name, const std::string& value,
211 const std::string& mime_boundary, const std::string& content_type,
212 std::string* post_data) {
213 DCHECK(post_data);
214 // First line is the boundary
215 post_data->append("--" + mime_boundary + "\r\n");
216 // Next line is the Content-disposition
217 post_data->append(base::StringPrintf("Content-Disposition: form-data; "
218 "name=\"%s\"\r\n", value_name.c_str()));
219 if (!content_type.empty()) {
220 // If Content-type is specified, the next line is that
221 post_data->append(base::StringPrintf("Content-Type: %s\r\n",
222 content_type.c_str()));
223 }
224 // Leave an empty line and append the value.
225 post_data->append(base::StringPrintf("\r\n%s\r\n", value.c_str()));
226 }
227
228 void WebRtcLogUploader::CompressLog(uint8* input,
229 uint32 input_size,
230 base::PlatformFile output_file) {
231 // TODO(grunell): Remove debugging code.
232 const bool debug_print = false;
233
234 if (debug_print) LOG(ERROR) << "*** DUMPING LOG BUFFER BEGIN ***";
235
236 base::PartialCircularBuffer read_pcb(input, input_size);
237
238 bz_stream stream = {0};
239 int result = BZ2_bzCompressInit(&stream, 3, 0, 0);
240 DCHECK(result == BZ_OK);
241
242 scoped_ptr<uint8[]> intermediate_buffer(
243 new uint8[kIntermediateCompressionBufferSize]);
244 scoped_ptr<uint8[]> compressed(
245 new uint8[kIntermediateCompressionBufferSize]);
246 memset(intermediate_buffer.get(), 0, kIntermediateCompressionBufferSize);
247 memset(compressed.get(), 0, kIntermediateCompressionBufferSize);
248 uint32 read = read_pcb.Read(intermediate_buffer.get(),
Jói 2013/05/08 14:14:22 This and the stream.next_in, stream.avail_in setup
Henrik Grunell 2013/05/08 16:05:05 In case the intermediate buffer isn't filled, that
Jói 2013/05/08 17:00:31 I see. I think a do-while loop with a break will
Henrik Grunell 2013/05/15 20:17:53 Done.
249 kIntermediateCompressionBufferSize);
250
251 if (debug_print) {
252 std::string tmp(
253 reinterpret_cast<char*>(&intermediate_buffer.get()[0]), read);
254 LOG(ERROR) << "Data (" << read << "):" << '\n' << tmp;
255 }
256
257 stream.next_in = reinterpret_cast<char*>(&intermediate_buffer.get()[0]);
258 stream.avail_in = read;
259 char* compressed_char_ptr = reinterpret_cast<char*>(&compressed.get()[0]);
260
261 // Keeps track of written output.
262 unsigned int last_total_out = stream.total_out_lo32;
263
264 while (read == kIntermediateCompressionBufferSize) {
265 stream.next_out = compressed_char_ptr;
266 stream.avail_out = kIntermediateCompressionBufferSize;
267 result = BZ2_bzCompress(&stream, BZ_RUN);
268 if (debug_print) {
269 LOG(ERROR) << "RESULT = " << result << ", read = " << read;
270 LOG(ERROR) << "avail_in = " << stream.avail_in
271 << ", total_in_lo32 = " << stream.total_in_lo32;
272 LOG(ERROR) << "avail_out = " << stream.avail_out
273 << ", total_out_lo32 = " << stream.total_out_lo32;
274 }
275 DCHECK(result == BZ_RUN_OK);
276 base::WritePlatformFileAtCurrentPos(output_file, compressed_char_ptr,
277 stream.total_out_lo32 - last_total_out);
278 last_total_out = stream.total_out_lo32;
279 read = read_pcb.Read(intermediate_buffer.get(),
280 kIntermediateCompressionBufferSize);
281 stream.next_in = reinterpret_cast<char*>(&intermediate_buffer.get()[0]);
282 stream.avail_in = read;
283
284 if (debug_print) {
285 std::string tmp(
286 reinterpret_cast<char*>(&intermediate_buffer.get()[0]), read);
287 LOG(ERROR) << "Data (" << read << "):" << '\n' << tmp;
288 }
289 }
290
291 do {
292 stream.next_out = compressed_char_ptr;
293 stream.avail_out = kIntermediateCompressionBufferSize;
294 result = BZ2_bzCompress(&stream, BZ_FINISH);
295 if (debug_print) {
296 LOG(ERROR) << "RESULT = " << result << ", read = " << read;
297 LOG(ERROR) << "avail_in = " << stream.avail_in
298 << ", total_in_lo32 = " << stream.total_in_lo32;
299 LOG(ERROR) << "avail_out = " << stream.avail_out
300 << ", total_out_lo32 = " << stream.total_out_lo32;
301 }
302 base::WritePlatformFileAtCurrentPos(output_file, compressed_char_ptr,
303 stream.total_out_lo32 - last_total_out);
304 last_total_out = stream.total_out_lo32;
305 } while (result == BZ_FINISH_OK);
306 DCHECK(result == BZ_STREAM_END);
307
308 result = BZ2_bzCompressEnd(&stream);
309 DCHECK(result == BZ_OK);
310
311 if (debug_print) LOG(ERROR) << "*** DUMPING LOG BUFFER END ***";
312 }
313
314 } // namespace components
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698