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

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 file added by mistake. 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 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "base/memory/partial_circular_buffer.h"
10 #include "base/shared_memory.h"
11 #include "base/stringprintf.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "net/base/network_delegate.h"
14 #include "net/proxy/proxy_config.h"
15 #include "net/proxy/proxy_config_service.h"
16 #include "net/url_request/url_fetcher.h"
17 #include "net/url_request/url_request_context.h"
18 #include "net/url_request/url_request_context_builder.h"
19 #include "net/url_request/url_request_context_getter.h"
20 #include "third_party/zlib/zlib.h"
21
22 namespace components {
23
24 namespace {
25
26 const int kLogCountLimit = 5;
27 const uint32 kIntermediateCompressionBufferBytes = 256 * 1024; // 256 KB
28
29 const char kUploadURL[] = "https://clients2.google.com/cr/report";
30 const char kUploadContentType[] = "multipart/form-data";
31 const char kMultipartBoundary[] =
32 "----**--yradnuoBgoLtrapitluMklaTelgooG--**----";
33
34 // Config getter that always returns direct settings.
35 class ProxyConfigServiceDirect : public net::ProxyConfigService {
36 public:
37 // ProxyConfigService implementation.
38 virtual void AddObserver(Observer* observer) OVERRIDE {}
39 virtual void RemoveObserver(Observer* observer) OVERRIDE {}
40 virtual ConfigAvailability GetLatestProxyConfig(
41 net::ProxyConfig* config) OVERRIDE {
42 *config = net::ProxyConfig::CreateDirect();
43 return CONFIG_VALID;
44 }
45 };
46
47 } // namespace
48
49 class WebRtcLogURLRequestContextGetter : public net::URLRequestContextGetter {
50 public:
51 WebRtcLogURLRequestContextGetter() {}
52
53 // net::URLRequestContextGetter implementation.
54 virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
55 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
56
57 if (!url_request_context_) {
58 net::URLRequestContextBuilder builder;
59 #if defined(OS_LINUX) || defined(OS_ANDROID)
60 builder.set_proxy_config_service(new ProxyConfigServiceDirect());
61 #endif
62 url_request_context_.reset(builder.Build());
63 CHECK(url_request_context_.get());
64 }
65
66 return url_request_context_.get();
67 }
68
69 virtual scoped_refptr<base::SingleThreadTaskRunner>
70 GetNetworkTaskRunner() const OVERRIDE {
71 return content::BrowserThread::GetMessageLoopProxyForThread(
72 content::BrowserThread::IO);
73 }
74
75 private:
76 virtual ~WebRtcLogURLRequestContextGetter() {}
77
78 // NULL if not yet initialized. Otherwise, it is the URLRequestContext
79 // instance that was lazily created by GetURLRequestContext().
80 // Access only from the IO thread.
81 scoped_ptr<net::URLRequestContext> url_request_context_;
82
83 DISALLOW_COPY_AND_ASSIGN(WebRtcLogURLRequestContextGetter);
84 };
85
86
87 WebRtcLogUploader::WebRtcLogUploader()
88 : log_count_(0) {
89 }
90
91 WebRtcLogUploader::~WebRtcLogUploader() {
92 }
93
94 void WebRtcLogUploader::OnURLFetchComplete(
95 const net::URLFetcher* source) {
96 }
97
98 void WebRtcLogUploader::OnURLFetchUploadProgress(
99 const net::URLFetcher* source, int64 current, int64 total) {
100 }
101
102 bool WebRtcLogUploader::ApplyForStartLogging() {
103 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
104 if (log_count_ < kLogCountLimit) {
105 ++log_count_;
106 return true;
107 }
108 return false;
109 }
110
111 void WebRtcLogUploader::UploadLog(scoped_ptr<base::SharedMemory> shared_memory,
112 uint32 length) {
113 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
114 DCHECK(shared_memory);
115 DCHECK(shared_memory->memory());
116
117 base::FilePath upload_file_path;
118 if (file_util::CreateTemporaryFile(&upload_file_path)) {
119 SetupMultipartFile(reinterpret_cast<uint8*>(shared_memory->memory()),
120 length, upload_file_path);
121
122 if (!request_context_getter_)
123 request_context_getter_ = new WebRtcLogURLRequestContextGetter();
124
125 std::string content_type = kUploadContentType;
126 content_type.append("; boundary=");
127 content_type.append(kMultipartBoundary);
128
129 net::URLFetcher* url_fetcher =
130 net::URLFetcher::Create(GURL(kUploadURL), net::URLFetcher::POST, this);
131 url_fetcher->SetRequestContext(request_context_getter_);
132 url_fetcher->SetUploadFilePath(
133 content_type, upload_file_path, 0, kuint64max,
134 content::BrowserThread::GetMessageLoopProxyForThread(
135 content::BrowserThread::FILE));
136 url_fetcher->Start();
137 } else {
138 DLOG(ERROR) << "WebRtcLogUploader could not create temporary file: "
139 << upload_file_path.value();
140 }
141
142 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
143 base::Bind(&WebRtcLogUploader::DecreaseLogCount, base::Unretained(this)));
144 }
145
146 void WebRtcLogUploader::SetupMultipartFile(
147 uint8* log_buffer, uint32 log_buffer_length,
148 const base::FilePath& upload_file_path) {
149 int flags = base::PLATFORM_FILE_CREATE_ALWAYS |
150 base::PLATFORM_FILE_WRITE;
151 bool created = false;
152 base::PlatformFileError error = base::PLATFORM_FILE_OK;
153 base::PlatformFile multipart_file =
154 CreatePlatformFile(upload_file_path, flags, &created, &error);
155 DCHECK(created);
156 DCHECK_EQ(error, base::PLATFORM_FILE_OK);
157
158 // TODO(grunell): Correct product name.
159 AddPairString(multipart_file, "prod", "Chrome");
160 // TODO(grunell): Correct version.
161 AddPairString(multipart_file, "ver", "0.0.1.1-dev-test");
162 AddPairString(multipart_file, "guid", "0");
163 AddPairString(multipart_file, "type", "log");
164
165 AddUrlChunks();
166
167 AddLogData(multipart_file, log_buffer, log_buffer_length);
168
169 std::string str = "--";
170 str.append(kMultipartBoundary);
171 str.append("--\r\n");
172 base::WritePlatformFileAtCurrentPos(multipart_file, str.c_str(), str.size());
173
174 DCHECK(base::ClosePlatformFile(multipart_file));
175 }
176
177 void WebRtcLogUploader::AddPairString(base::PlatformFile multipart_file,
178 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(base::PlatformFile multipart_file,
190 uint8* log_buffer,
191 uint32 log_buffer_length) {
192 std::string str = "--";
193 str.append(kMultipartBoundary);
194 str.append("\r\n");
195 str.append("Content-Disposition: form-data; name=\"log\"");
196 str.append("; filename=\"log.gz\"\r\n");
197 str.append("Content-Type: application/gzip\r\n\r\n");
198 base::WritePlatformFileAtCurrentPos(multipart_file, str.c_str(), 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 base::PartialCircularBuffer read_pcb(input, input_size);
232
233 z_stream stream = {0};
234 int result = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
235 // windowBits = 15 is default, 16 is added to
236 // produce a gzip header + trailer.
237 15 + 16,
238 8, // memLevel = 8 is default.
239 Z_DEFAULT_STRATEGY);
240 DCHECK_EQ(Z_OK, result);
241
242 scoped_ptr<uint8[]> intermediate_buffer(
243 new uint8[kIntermediateCompressionBufferBytes]);
244 scoped_ptr<uint8[]> compressed(
245 new uint8[kIntermediateCompressionBufferBytes]);
246 memset(intermediate_buffer.get(), 0, kIntermediateCompressionBufferBytes);
247 memset(compressed.get(), 0, kIntermediateCompressionBufferBytes);
248
249 char* compressed_char_ptr = reinterpret_cast<char*>(&compressed.get()[0]);
250 uint32 read = 0;
251
252 do {
253 read = read_pcb.Read(intermediate_buffer.get(),
254 kIntermediateCompressionBufferBytes);
255 stream.next_in = &intermediate_buffer.get()[0];
256 stream.avail_in = read;
257 stream.next_out = &compressed.get()[0];
258 stream.avail_out = kIntermediateCompressionBufferBytes;
259 if (read != kIntermediateCompressionBufferBytes)
260 break;
261
262 result = deflate(&stream, Z_SYNC_FLUSH);
263 DCHECK_EQ(Z_OK, result);
264 DCHECK_LE(stream.avail_out, kIntermediateCompressionBufferBytes);
265 base::WritePlatformFileAtCurrentPos(
266 output_file, compressed_char_ptr,
267 kIntermediateCompressionBufferBytes - stream.avail_out);
268 } while (true);
269
270 result = deflate(&stream, Z_FINISH);
271 DCHECK(result == Z_STREAM_END);
272 DCHECK_LE(stream.avail_out, kIntermediateCompressionBufferBytes);
273 base::WritePlatformFileAtCurrentPos(
274 output_file, compressed_char_ptr,
275 kIntermediateCompressionBufferBytes - stream.avail_out);
276
277 result = deflateEnd(&stream);
278 DCHECK_EQ(Z_OK, result);
279 }
280
281 void WebRtcLogUploader::DecreaseLogCount() {
282 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
283 --log_count_;
284 }
285
286 } // namespace components
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698