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 #include "base/logging.h" | |
8 #include "base/memory/partial_circular_buffer.h" | |
9 #include "base/shared_memory.h" | |
10 #include "base/stringprintf.h" | |
11 #include "content/public/browser/browser_thread.h" | |
12 #include "net/base/mime_util.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 // TODO(grunell): Temporary. Send product and version info with the UploadLog | |
23 // call or in ctor. Not necessary if this file is moved to chrome/ (TBD). | |
24 #include "chrome/common/chrome_version_info.h" | |
25 | |
26 namespace components { | |
27 | |
28 namespace { | |
29 | |
30 const int kLogCountLimit = 5; | |
31 const uint32 kIntermediateCompressionBufferBytes = 256 * 1024; // 256 KB | |
32 | |
33 const char kUploadURL[] = "https://clients2.google.com/cr/report"; | |
34 const char kUploadContentType[] = "multipart/form-data"; | |
35 const char kMultipartBoundary[] = | |
36 "----**--yradnuoBgoLtrapitluMklaTelgooG--**----"; | |
37 | |
38 } // namespace | |
39 | |
40 WebRtcLogUploader::WebRtcLogUploader() | |
41 : log_count_(0) { | |
42 } | |
43 | |
44 WebRtcLogUploader::~WebRtcLogUploader() { | |
45 } | |
46 | |
47 void WebRtcLogUploader::OnURLFetchComplete( | |
48 const net::URLFetcher* source) { | |
49 } | |
50 | |
51 void WebRtcLogUploader::OnURLFetchUploadProgress( | |
52 const net::URLFetcher* source, int64 current, int64 total) { | |
53 } | |
54 | |
55 bool WebRtcLogUploader::ApplyForStartLogging() { | |
56 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
57 if (log_count_ < kLogCountLimit) { | |
58 ++log_count_; | |
59 return true; | |
60 } | |
61 return false; | |
62 } | |
63 | |
64 void WebRtcLogUploader::UploadLog(net::URLRequestContextGetter* request_context, | |
65 scoped_ptr<base::SharedMemory> shared_memory, | |
66 uint32 length, | |
67 const std::string& app_session_id, | |
68 const std::string& app_url) { | |
69 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
70 DCHECK(shared_memory); | |
71 DCHECK(shared_memory->memory()); | |
72 | |
73 std::string post_data; | |
74 SetupMultipart(&post_data, reinterpret_cast<uint8*>(shared_memory->memory()), | |
75 length, app_session_id, app_url); | |
76 | |
77 std::string content_type = kUploadContentType; | |
78 content_type.append("; boundary="); | |
79 content_type.append(kMultipartBoundary); | |
80 | |
81 net::URLFetcher* url_fetcher = | |
82 net::URLFetcher::Create(GURL(kUploadURL), net::URLFetcher::POST, this); | |
83 url_fetcher->SetRequestContext(request_context); | |
84 url_fetcher->SetUploadData(content_type, post_data); | |
85 url_fetcher->Start(); | |
86 | |
87 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | |
88 base::Bind(&WebRtcLogUploader::DecreaseLogCount, base::Unretained(this))); | |
89 } | |
90 | |
91 void WebRtcLogUploader::SetupMultipart(std::string* post_data, | |
92 uint8* log_buffer, | |
93 uint32 log_buffer_length, | |
94 const std::string& app_session_id, | |
95 const std::string& app_url) { | |
96 #if defined(OS_WIN) | |
Jói
2013/05/24 21:14:06
This logic for determining the product name for Cr
Henrik Grunell
2013/05/27 13:00:32
Yes, I've checked this with cpu@ and there isn't.
| |
97 const char product[] = "Chrome"; | |
98 #elif defined(OS_MACOSX) | |
99 const char product[] = "Chrome_Mac"; | |
100 #elif defined(OS_LINUX) | |
101 #if !defined(ADDRESS_SANITIZER) | |
102 const char product[] = "Chrome_Linux"; | |
103 #else | |
104 const char product[] = "Chrome_Linux_ASan"; | |
105 #endif | |
106 #elif defined(OS_ANDROID) | |
107 const char product[] = "Chrome_Android"; | |
108 #elif defined(OS_CHROMEOS) | |
109 const char product[] = "Chrome_ChromeOS"; | |
110 #else | |
111 // This file should not be compiled for other platforms. | |
112 COMPILE_ASSERT(false); | |
113 #endif | |
114 net::AddMultipartValueForUpload("prod", product, kMultipartBoundary, | |
115 "", post_data); | |
116 chrome::VersionInfo version_info; | |
117 net::AddMultipartValueForUpload("ver", version_info.Version(), | |
118 kMultipartBoundary, "", post_data); | |
119 net::AddMultipartValueForUpload("guid", "0", kMultipartBoundary, | |
120 "", post_data); | |
121 net::AddMultipartValueForUpload("type", "webrtc_log", kMultipartBoundary, | |
122 "", post_data); | |
123 net::AddMultipartValueForUpload("app_session_id", app_session_id, | |
124 kMultipartBoundary, "", post_data); | |
125 net::AddMultipartValueForUpload("url", app_url, kMultipartBoundary, | |
126 "", post_data); | |
127 AddLogData(post_data, log_buffer, log_buffer_length); | |
128 net::AddMultipartFinalDelimiterForUpload(kMultipartBoundary, post_data); | |
129 } | |
130 | |
131 void WebRtcLogUploader::AddLogData(std::string* post_data, | |
132 uint8* log_buffer, | |
133 uint32 log_buffer_length) { | |
134 post_data->append("--"); | |
135 post_data->append(kMultipartBoundary); | |
136 post_data->append("\r\n"); | |
137 post_data->append("Content-Disposition: form-data; name=\"log\""); | |
138 post_data->append("; filename=\"log.gz\"\r\n"); | |
139 post_data->append("Content-Type: application/gzip\r\n\r\n"); | |
140 | |
141 CompressLog(post_data, log_buffer, log_buffer_length); | |
142 | |
143 post_data->append("\r\n"); | |
144 } | |
145 | |
146 void WebRtcLogUploader::CompressLog(std::string* post_data, | |
147 uint8* input, | |
148 uint32 input_size) { | |
149 base::PartialCircularBuffer read_pcb(input, input_size); | |
150 | |
151 z_stream stream = {0}; | |
152 int result = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, | |
153 // windowBits = 15 is default, 16 is added to | |
154 // produce a gzip header + trailer. | |
155 15 + 16, | |
156 8, // memLevel = 8 is default. | |
157 Z_DEFAULT_STRATEGY); | |
158 DCHECK_EQ(Z_OK, result); | |
159 | |
160 scoped_ptr<uint8[]> intermediate_buffer( | |
Jói
2013/05/24 21:14:06
As far as I can tell, this can be stack-allocated
Henrik Grunell
2013/05/27 13:00:32
OK, done.
| |
161 new uint8[kIntermediateCompressionBufferBytes]); | |
162 memset(intermediate_buffer.get(), 0, kIntermediateCompressionBufferBytes); | |
163 | |
164 IncreaseMultipartBufferSize(post_data, &stream); | |
Jói
2013/05/24 21:14:06
A better name might indicate that this sets stream
Henrik Grunell
2013/05/27 13:00:32
Agree. I thing the suggested name is fine. Done.
| |
165 uint32 read = 0; | |
166 | |
167 do { | |
168 if (stream.avail_in == 0) { | |
169 read = read_pcb.Read(&intermediate_buffer.get()[0], | |
170 kIntermediateCompressionBufferBytes); | |
171 stream.next_in = &intermediate_buffer.get()[0]; | |
172 stream.avail_in = read; | |
173 if (read != kIntermediateCompressionBufferBytes) | |
174 break; | |
175 } | |
176 result = deflate(&stream, Z_SYNC_FLUSH); | |
177 DCHECK_EQ(Z_OK, result); | |
178 if (stream.avail_out == 0) | |
179 IncreaseMultipartBufferSize(post_data, &stream); | |
180 } while (true); | |
181 | |
182 // Ensure we have enough room in the output buffer. Easier to always just do a | |
183 // resize than looping around and resize if needed. | |
184 if (stream.avail_out < kIntermediateCompressionBufferBytes) | |
185 IncreaseMultipartBufferSize(post_data, &stream); | |
186 | |
187 result = deflate(&stream, Z_FINISH); | |
Jói
2013/05/24 21:14:06
Will this be OK if (stream.avail_in == 0)? Seems l
Henrik Grunell
2013/05/27 13:00:32
Yes, this is OK. If there's no more input it will
| |
188 DCHECK_EQ(Z_STREAM_END, result); | |
189 result = deflateEnd(&stream); | |
190 DCHECK_EQ(Z_OK, result); | |
191 | |
192 post_data->resize(post_data->size() - stream.avail_out); | |
193 } | |
194 | |
195 void WebRtcLogUploader::IncreaseMultipartBufferSize(std::string* post_data, | |
196 z_stream* stream) { | |
197 size_t old_size = post_data->size() - stream->avail_out; | |
198 post_data->resize(old_size + kIntermediateCompressionBufferBytes); | |
199 stream->next_out = reinterpret_cast<uint8*>(&(*post_data)[old_size]); | |
200 stream->avail_out = kIntermediateCompressionBufferBytes; | |
201 } | |
202 | |
203 void WebRtcLogUploader::DecreaseLogCount() { | |
204 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
205 --log_count_; | |
206 } | |
207 | |
208 } // namespace components | |
OLD | NEW |