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

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: Upload again (error last upload). 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 2013 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 "components/webrtc_log_uploader/webrtc_log_uploader.h"
6
7 #if defined(USE_SYSTEM_LIBBZ2)
Jói 2013/05/14 21:30:29 nit: I think conditional includes usually come aft
Henrik Grunell 2013/05/15 20:17:53 I've replaced bzlib with zlib; the former has been
8 #include <bzlib.h>
9 #else
10 #include "third_party/bzip2/bzlib.h"
11 #endif
12
13 #include "base/file_util.h"
14 #include "base/logging.h"
15 #include "base/partial_circular_buffer.h"
16 #include "base/shared_memory.h"
17 #include "base/stringprintf.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "net/base/network_delegate.h"
20 #include "net/proxy/proxy_config.h"
21 #include "net/proxy/proxy_config_service.h"
22 #include "net/url_request/url_fetcher.h"
23 #include "net/url_request/url_request_context.h"
24 #include "net/url_request/url_request_context_builder.h"
25 #include "net/url_request/url_request_context_getter.h"
26
27 namespace components {
28
29 namespace {
30
31 const int kLogCountLimit = 5;
32 const uint32 kIntermediateCompressionBufferSize = 256 * 1024; // 256 KB
Jói 2013/05/14 21:30:29 Suggest renaming to kIntermediateCompressionBuffer
Henrik Grunell 2013/05/15 20:17:53 Done.
33
34 const char kUploadURL[] = "https://clients2.google.com/cr/report";
35 const char kUploadContentType[] = "multipart/form-data";
36 const char kMultipartBoundary[] =
37 "----**--yradnuoBgoLtrapitluMklaTelgooG--**----";
38
39 // Config getter that always returns direct settings.
Jói 2013/05/14 21:30:29 Can you document the motivation for this? I see it
Henrik Grunell 2013/05/15 20:17:53 I'll double check with someone who knows net, back
Henrik Grunell 2013/05/24 13:01:50 I've changed it so that it uses the system context
40 class ProxyConfigServiceDirect : public net::ProxyConfigService {
41 public:
42 // ProxyConfigService implementation.
43 virtual void AddObserver(Observer* observer) OVERRIDE {}
44 virtual void RemoveObserver(Observer* observer) OVERRIDE {}
45 virtual ConfigAvailability GetLatestProxyConfig(
46 net::ProxyConfig* config) OVERRIDE {
47 *config = net::ProxyConfig::CreateDirect();
48 return CONFIG_VALID;
49 }
50 };
51
52 } // namespace
53
54 class WebRtcLogURLRequestContextGetter : public net::URLRequestContextGetter {
55 public:
56 WebRtcLogURLRequestContextGetter() {}
57
58 // net::URLRequestContextGetter implementation.
59 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
60 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
61
62 if (!url_request_context_) {
63 net::URLRequestContextBuilder builder;
64 #if defined(OS_LINUX) || defined(OS_ANDROID)
65 builder.set_proxy_config_service(new ProxyConfigServiceDirect());
66 #endif
67 url_request_context_.reset(builder.Build());
68 CHECK(url_request_context_.get());
69 }
70
71 return url_request_context_.get();
72 }
73
74 virtual scoped_refptr<base::SingleThreadTaskRunner>
75 GetNetworkTaskRunner() const OVERRIDE {
76 return content::BrowserThread::GetMessageLoopProxyForThread(
77 content::BrowserThread::IO);
78 }
79
80 private:
81 virtual ~WebRtcLogURLRequestContextGetter() {}
82
83 // NULL if not yet initialized. Otherwise, it is the URLRequestContext
84 // instance that was lazily created by GetURLRequestContext().
85 // Access only from the IO thread.
86 scoped_ptr<net::URLRequestContext> url_request_context_;
87
88 DISALLOW_COPY_AND_ASSIGN(WebRtcLogURLRequestContextGetter);
89 };
90
91
92 WebRtcLogUploader::WebRtcLogUploader()
93 : log_count_(0) {
94 }
95
96 WebRtcLogUploader::~WebRtcLogUploader() {
97 }
98
99 void WebRtcLogUploader::OnURLFetchComplete(
100 const net::URLFetcher* source) {
101 std::vector<net::URLFetcher*>::iterator it;
102 for (it = url_fetchers_.begin(); it != url_fetchers_.end(); ++it) {
103 if (*it == source) {
104 url_fetchers_.erase(it);
105 break;
106 }
107 }
108 delete source;
Jói 2013/05/14 21:30:29 Why are you deleting the object? I don't think ow
Henrik Grunell 2013/05/15 20:17:53 You're right, I think I got that from a unit test
109 }
110
111 void WebRtcLogUploader::OnURLFetchUploadProgress(
112 const net::URLFetcher* source, int64 current, int64 total) {
113 }
114
115 bool WebRtcLogUploader::ApplyForStartLogging() {
116 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
117 if (log_count_ < kLogCountLimit) {
118 ++log_count_;
119 return true;
120 }
121 return false;
122 }
123
124 void WebRtcLogUploader::UploadLog(scoped_ptr<base::SharedMemory> shared_memory,
125 uint32 length) {
126 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
127 DCHECK(shared_memory);
128 DCHECK(shared_memory->memory());
129
130 base::FilePath upload_file_path;
131 if (file_util::CreateTemporaryFile(&upload_file_path)) {
132 SetupMultipartFile(reinterpret_cast<uint8*>(shared_memory->memory()),
133 length, upload_file_path);
134
135 if (!request_context_getter_)
136 request_context_getter_ = new WebRtcLogURLRequestContextGetter();
137
138 std::string content_type = kUploadContentType;
139 content_type.append("; boundary=");
140 content_type.append(kMultipartBoundary);
141
142 net::URLFetcher* url_fetcher =
143 net::URLFetcher::Create(GURL(kUploadURL), net::URLFetcher::POST, this);
144 url_fetcher->SetRequestContext(request_context_getter_);
145 url_fetcher->SetUploadFilePath(
146 content_type, upload_file_path, 0, kuint64max,
147 content::BrowserThread::GetMessageLoopProxyForThread(
148 content::BrowserThread::FILE));
149 url_fetcher->Start();
150 url_fetchers_.push_back(url_fetcher);
151 } else {
152 DLOG(ERROR) << "Could not create temporary file";
Jói 2013/05/14 21:30:29 Suggest a more informative message, i.e. that it's
Henrik Grunell 2013/05/15 20:17:53 Done.
153 }
154
155 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
156 base::Bind(&WebRtcLogUploader::DecreaseLogCount, base::Unretained(this)));
157 }
158
159 void WebRtcLogUploader::SetupMultipartFile(
160 uint8* log_buffer, uint32 log_buffer_length,
161 const base::FilePath& upload_file_path) {
162 int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
163 base::PLATFORM_FILE_WRITE;
164 bool created = false;
165 base::PlatformFileError error = base::PLATFORM_FILE_OK;
166 base::PlatformFile multipart_file =
167 CreatePlatformFile(upload_file_path, flags, &created, &error);
168 DCHECK(created);
169 DCHECK(error == base::PLATFORM_FILE_OK);
Jói 2013/05/14 21:30:29 DCHECK_EQ
Henrik Grunell 2013/05/15 20:17:53 Done.
170
171 // TODO(grunell): Correct product name.
Jói 2013/05/14 21:30:29 Is this TODO (and the one 2 lines down) for the cu
Henrik Grunell 2013/05/15 20:17:53 I was thinking for the current change, but it can
Henrik Grunell 2013/05/24 13:01:50 It's done now.
172 AddPairString(multipart_file, "prod", "Chrome");
173 // TODO(grunell): Correct version.
174 AddPairString(multipart_file, "ver", "0.0.1.1-dev-test");
175 AddPairString(multipart_file, "guid", "0");
176 AddPairString(multipart_file, "type", "log");
177
178 AddUrlChunks();
179
180 AddLogData(multipart_file, log_buffer, log_buffer_length);
181
182 std::string str = "--";
183 str.append(kMultipartBoundary);
184 str.append("--\r\n");
185 base::WritePlatformFileAtCurrentPos(multipart_file, str.c_str(), str.size());
186
187 DCHECK(base::ClosePlatformFile(multipart_file));
188 }
189
190 void WebRtcLogUploader::AddPairString(base::PlatformFile multipart_file,
191 const std::string& key,
192 const std::string& value) {
193 std::string str;
194 AddMultipartValueForUpload(key, value, kMultipartBoundary, "", &str);
195 base::WritePlatformFileAtCurrentPos(multipart_file, str.c_str(), str.size());
196 }
197
198 void WebRtcLogUploader::AddUrlChunks() {
199 // TODO(grunell): Implement.
Jói 2013/05/14 21:30:29 I'm assuming this is needed for the current change
Henrik Grunell 2013/05/15 20:17:53 Same as reply above. That's my intention but could
Henrik Grunell 2013/05/24 13:01:50 This functions has been removed; not needed.
200 }
201
202 void WebRtcLogUploader::AddLogData(base::PlatformFile multipart_file,
203 uint8* log_buffer,
204 uint32 log_buffer_length) {
205 std::string str = "--";
206 str.append(kMultipartBoundary);
207 str.append("\r\n");
208 str.append("Content-Disposition: form-data; name=\"log\"");
209 str.append("; filename=\"log.bz2\"\r\n");
210 str.append("Content-Type: application/x-bzip\r\n\r\n");
211 base::WritePlatformFileAtCurrentPos(multipart_file, str.c_str(), str.size());
Jói 2013/05/14 21:30:29 I have to wonder, since the log_buffer is in memor
Henrik Grunell 2013/05/15 20:17:53 Very valid point. Here's why I chose a file: after
Henrik Grunell 2013/05/24 13:01:50 Changed to writing to memory instead.
212
213 CompressLog(log_buffer, log_buffer_length, multipart_file);
214
215 std::string end_str = "\r\n";
216 base::WritePlatformFileAtCurrentPos(
217 multipart_file, end_str.c_str(), end_str.size());
218 }
219
220 // TODO(grunell): This is copied from cloud_print_helpers.cc. Break out to its
221 // own file.
222 void WebRtcLogUploader::AddMultipartValueForUpload(
223 const std::string& value_name, const std::string& value,
224 const std::string& mime_boundary, const std::string& content_type,
225 std::string* post_data) {
226 DCHECK(post_data);
227 // First line is the boundary
228 post_data->append("--" + mime_boundary + "\r\n");
229 // Next line is the Content-disposition
230 post_data->append(base::StringPrintf("Content-Disposition: form-data; "
231 "name=\"%s\"\r\n", value_name.c_str()));
232 if (!content_type.empty()) {
233 // If Content-type is specified, the next line is that
234 post_data->append(base::StringPrintf("Content-Type: %s\r\n",
235 content_type.c_str()));
236 }
237 // Leave an empty line and append the value.
238 post_data->append(base::StringPrintf("\r\n%s\r\n", value.c_str()));
239 }
240
241 void WebRtcLogUploader::CompressLog(uint8* input,
242 uint32 input_size,
243 base::PlatformFile output_file) {
244 base::PartialCircularBuffer read_pcb(input, input_size);
245
246 bz_stream stream = {0};
247 int result = BZ2_bzCompressInit(&stream, 3, 0, 0);
248 DCHECK(result == BZ_OK);
249
250 scoped_ptr<uint8[]> intermediate_buffer(
251 new uint8[kIntermediateCompressionBufferSize]);
252 scoped_ptr<uint8[]> compressed(
253 new uint8[kIntermediateCompressionBufferSize]);
254 memset(intermediate_buffer.get(), 0, kIntermediateCompressionBufferSize);
255 memset(compressed.get(), 0, kIntermediateCompressionBufferSize);
256 uint32 read = read_pcb.Read(intermediate_buffer.get(),
257 kIntermediateCompressionBufferSize);
258
259 stream.next_in = reinterpret_cast<char*>(&intermediate_buffer.get()[0]);
260 stream.avail_in = read;
261 char* compressed_char_ptr = reinterpret_cast<char*>(&compressed.get()[0]);
262
263 // Keeps track of written output.
264 unsigned int last_total_out = stream.total_out_lo32;
265
266 while (read == kIntermediateCompressionBufferSize) {
267 stream.next_out = compressed_char_ptr;
268 stream.avail_out = kIntermediateCompressionBufferSize;
269 result = BZ2_bzCompress(&stream, BZ_RUN);
270 DCHECK(result == BZ_RUN_OK);
271 base::WritePlatformFileAtCurrentPos(output_file, compressed_char_ptr,
272 stream.total_out_lo32 - last_total_out);
273 last_total_out = stream.total_out_lo32;
274 read = read_pcb.Read(intermediate_buffer.get(),
275 kIntermediateCompressionBufferSize);
276 stream.next_in = reinterpret_cast<char*>(&intermediate_buffer.get()[0]);
277 stream.avail_in = read;
278 }
279
280 do {
281 stream.next_out = compressed_char_ptr;
282 stream.avail_out = kIntermediateCompressionBufferSize;
283 result = BZ2_bzCompress(&stream, BZ_FINISH);
284 base::WritePlatformFileAtCurrentPos(output_file, compressed_char_ptr,
285 stream.total_out_lo32 - last_total_out);
286 last_total_out = stream.total_out_lo32;
287 } while (result == BZ_FINISH_OK);
288 DCHECK(result == BZ_STREAM_END);
289
290 result = BZ2_bzCompressEnd(&stream);
291 DCHECK(result == BZ_OK);
292 }
293
294 void WebRtcLogUploader::DecreaseLogCount() {
295 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
296 --log_count_;
297 }
298
299 } // namespace components
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698