OLD | NEW |
---|---|
(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 | |
OLD | NEW |