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

Side by Side Diff: sync/internal_api/http_bridge.cc

Issue 1246523003: [Sync] Finch Experiment : Enable compression between sync client and server (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix compile warning Created 5 years, 4 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
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sync/internal_api/public/http_bridge.h" 5 #include "sync/internal_api/public/http_bridge.h"
6 6
7 #include "base/message_loop/message_loop.h" 7 #include "base/message_loop/message_loop.h"
8 #include "base/metrics/field_trial.h"
8 #include "base/metrics/histogram_macros.h" 9 #include "base/metrics/histogram_macros.h"
9 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/stringprintf.h" 11 #include "base/strings/stringprintf.h"
11 #include "net/base/load_flags.h" 12 #include "net/base/load_flags.h"
12 #include "net/base/net_errors.h" 13 #include "net/base/net_errors.h"
13 #include "net/http/http_cache.h" 14 #include "net/http/http_cache.h"
14 #include "net/http/http_network_layer.h" 15 #include "net/http/http_network_layer.h"
15 #include "net/http/http_request_headers.h" 16 #include "net/http/http_request_headers.h"
16 #include "net/http/http_response_headers.h" 17 #include "net/http/http_response_headers.h"
17 #include "net/url_request/static_http_user_agent_settings.h" 18 #include "net/url_request/static_http_user_agent_settings.h"
(...skipping 10 matching lines...) Expand all
28 // It's possible for an http request to be silently stalled. We set a time 29 // It's possible for an http request to be silently stalled. We set a time
29 // limit for all http requests, beyond which the request is cancelled and 30 // limit for all http requests, beyond which the request is cancelled and
30 // treated as a transient failure. 31 // treated as a transient failure.
31 const int kMaxHttpRequestTimeSeconds = 60 * 5; // 5 minutes. 32 const int kMaxHttpRequestTimeSeconds = 60 * 5; // 5 minutes.
32 33
33 // Helper method for logging timeouts via UMA. 34 // Helper method for logging timeouts via UMA.
34 void LogTimeout(bool timed_out) { 35 void LogTimeout(bool timed_out) {
35 UMA_HISTOGRAM_BOOLEAN("Sync.URLFetchTimedOut", timed_out); 36 UMA_HISTOGRAM_BOOLEAN("Sync.URLFetchTimedOut", timed_out);
36 } 37 }
37 38
39 bool IsSyncHttpContentCompressionEnabled() {
40 const std::string group_name =
41 base::FieldTrialList::FindFullName("SyncHttpContentCompression");
42 return group_name == "Enabled";
43 }
44
45 // The difference in bytes between a zlib header and a gzip header.
Nicolas Zea 2015/07/30 19:59:44 Add a comment that explains that makes it clear wh
Gang Wu 2015/07/31 00:39:45 Done.
46 const size_t kGzipZlibHeaderDifferenceBytes = 16;
47
48 // Pass an integer greater than the following get a gzip header instead of a
49 // zlib header when calling deflateInit2() and inflateInit2().
50 const int kWindowBitsToGetGzipHeader = 16;
51
52 // This describes the amount of memory zlib uses to compress data. It can go
53 // from 1 to 9, with 8 being the default. For details, see:
54 // http://www.zlib.net/manual.html (search for memLevel).
55 const int kZlibMemoryLevel = 8;
56
57 // This code is taken almost verbatim from third_party/zlib/compress.c. The only
58 // difference is deflateInit2() is called which sets the window bits to be > 16.
59 // That causes a gzip header to be emitted rather than a zlib header.
60 int GzipCompressHelper(Bytef* dest,
61 uLongf* dest_length,
62 const Bytef* source,
63 uLong source_length) {
64 z_stream stream;
65
66 stream.next_in = bit_cast<Bytef*>(source);
67 stream.avail_in = static_cast<uInt>(source_length);
68 stream.next_out = dest;
69 stream.avail_out = static_cast<uInt>(*dest_length);
70 if (static_cast<uLong>(stream.avail_out) != *dest_length)
71 return Z_BUF_ERROR;
72
73 stream.zalloc = static_cast<alloc_func>(0);
74 stream.zfree = static_cast<free_func>(0);
75 stream.opaque = static_cast<voidpf>(0);
76
77 gz_header gzip_header;
78 memset(&gzip_header, 0, sizeof(gzip_header));
79 int err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
80 MAX_WBITS + kWindowBitsToGetGzipHeader,
81 kZlibMemoryLevel, Z_DEFAULT_STRATEGY);
82 if (err != Z_OK)
83 return err;
84
85 err = deflateSetHeader(&stream, &gzip_header);
86 if (err != Z_OK)
87 return err;
88
89 err = deflate(&stream, Z_FINISH);
90 if (err != Z_STREAM_END) {
91 deflateEnd(&stream);
92 return err == Z_OK ? Z_BUF_ERROR : err;
93 }
94 *dest_length = stream.total_out;
95
96 err = deflateEnd(&stream);
97 return err;
98 }
99
100 // This code is taken almost verbatim from third_party/zlib/uncompr.c. The only
101 // difference is inflateInit2() is called which sets the window bits to be > 16.
102 // That causes a gzip header to be parsed rather than a zlib header.
103 int GzipUncompressHelper(Bytef* dest,
104 uLongf* dest_length,
105 const Bytef* source,
106 uLong source_length) {
107 z_stream stream;
108
109 stream.next_in = bit_cast<Bytef*>(source);
110 stream.avail_in = static_cast<uInt>(source_length);
111 if (static_cast<uLong>(stream.avail_in) != source_length)
112 return Z_BUF_ERROR;
113
114 stream.next_out = dest;
115 stream.avail_out = static_cast<uInt>(*dest_length);
116 if (static_cast<uLong>(stream.avail_out) != *dest_length)
117 return Z_BUF_ERROR;
118
119 stream.zalloc = static_cast<alloc_func>(0);
120 stream.zfree = static_cast<free_func>(0);
121
122 int err = inflateInit2(&stream, MAX_WBITS + kWindowBitsToGetGzipHeader);
123 if (err != Z_OK)
124 return err;
125
126 err = inflate(&stream, Z_FINISH);
127 if (err != Z_STREAM_END) {
128 inflateEnd(&stream);
129 if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
130 return Z_DATA_ERROR;
131 return err;
132 }
133 *dest_length = stream.total_out;
134
135 err = inflateEnd(&stream);
136 return err;
137 }
138
139 // Returns the uncompressed size from GZIP-compressed |compressed_data|.
140 uint32 GetUncompressedSize(const std::string& compressed_data) {
141 // The uncompressed size is stored in the last 4 bytes of |input| in LE.
142 uint32 size;
143 if (compressed_data.length() < sizeof(size))
144 return 0;
145 memcpy(&size, &compressed_data[compressed_data.length() - sizeof(size)],
146 sizeof(size));
147 return base::ByteSwapToLE32(size);
148 }
149
150 void RecordSyncRequestContentLengthHistograms(int64 compressed_content_length,
151 int64 original_content_length) {
152 UMA_HISTOGRAM_COUNTS("Sync.RequestContentLengthCompressed",
153 compressed_content_length);
154 UMA_HISTOGRAM_COUNTS("Sync.RequestContentLengthOriginal",
155 original_content_length);
156 }
157
158 void RecordSyncResponseContentLengthHistograms(int64 compressed_content_length,
159 int64 original_content_length) {
160 UMA_HISTOGRAM_COUNTS("Sync.ResponseContentLengthCompressed",
161 compressed_content_length);
162 UMA_HISTOGRAM_COUNTS("Sync.ResponseContentLengthOriginal",
163 original_content_length);
164 }
165
38 } // namespace 166 } // namespace
39 167
168 bool GzipCompress(const std::string& input, std::string* output) {
169 const uLongf input_size = static_cast<uLongf>(input.size());
170 std::vector<Bytef> compressed_data(kGzipZlibHeaderDifferenceBytes +
171 compressBound(input_size));
172
173 uLongf compressed_size = static_cast<uLongf>(compressed_data.size());
174 if (GzipCompressHelper(&compressed_data.front(), &compressed_size,
175 bit_cast<const Bytef*>(input.data()),
176 input_size) != Z_OK) {
177 return false;
178 }
179
180 compressed_data.resize(compressed_size);
181 output->assign(compressed_data.begin(), compressed_data.end());
182 DCHECK_EQ(input_size, GetUncompressedSize(*output));
183 return true;
184 }
185
186 bool GzipUncompress(const std::string& input, std::string* output) {
187 std::string uncompressed_output;
188 uLongf uncompressed_size = static_cast<uLongf>(GetUncompressedSize(input));
189 uncompressed_output.resize(uncompressed_size);
190 if (GzipUncompressHelper(bit_cast<Bytef*>(uncompressed_output.data()),
191 &uncompressed_size,
192 bit_cast<const Bytef*>(input.data()),
193 static_cast<uLongf>(input.length())) == Z_OK) {
194 output->swap(uncompressed_output);
195 return true;
196 }
197 return false;
198 }
199
40 HttpBridgeFactory::HttpBridgeFactory( 200 HttpBridgeFactory::HttpBridgeFactory(
41 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, 201 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
42 const NetworkTimeUpdateCallback& network_time_update_callback, 202 const NetworkTimeUpdateCallback& network_time_update_callback,
43 CancelationSignal* cancelation_signal) 203 CancelationSignal* cancelation_signal)
44 : request_context_getter_(request_context_getter), 204 : request_context_getter_(request_context_getter),
45 network_time_update_callback_(network_time_update_callback), 205 network_time_update_callback_(network_time_update_callback),
46 cancelation_signal_(cancelation_signal) { 206 cancelation_signal_(cancelation_signal) {
47 // Registration should never fail. This should happen on the UI thread during 207 // Registration should never fail. This should happen on the UI thread during
48 // init. It would be impossible for a shutdown to have been requested at this 208 // init. It would be impossible for a shutdown to have been requested at this
49 // point. 209 // point.
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 356
197 // Start the timer on the network thread (the same thread progress is made 357 // Start the timer on the network thread (the same thread progress is made
198 // on, and on which the url fetcher lives). 358 // on, and on which the url fetcher lives).
199 DCHECK(!fetch_state_.http_request_timeout_timer.get()); 359 DCHECK(!fetch_state_.http_request_timeout_timer.get());
200 fetch_state_.http_request_timeout_timer.reset(new base::Timer(false, false)); 360 fetch_state_.http_request_timeout_timer.reset(new base::Timer(false, false));
201 fetch_state_.http_request_timeout_timer->Start( 361 fetch_state_.http_request_timeout_timer->Start(
202 FROM_HERE, base::TimeDelta::FromSeconds(kMaxHttpRequestTimeSeconds), 362 FROM_HERE, base::TimeDelta::FromSeconds(kMaxHttpRequestTimeSeconds),
203 base::Bind(&HttpBridge::OnURLFetchTimedOut, this)); 363 base::Bind(&HttpBridge::OnURLFetchTimedOut, this));
204 364
205 DCHECK(request_context_getter_.get()); 365 DCHECK(request_context_getter_.get());
366 fetch_state_.start_time = base::Time::Now();
206 fetch_state_.url_poster = 367 fetch_state_.url_poster =
207 net::URLFetcher::Create(url_for_request_, net::URLFetcher::POST, this) 368 net::URLFetcher::Create(url_for_request_, net::URLFetcher::POST, this)
208 .release(); 369 .release();
209 fetch_state_.url_poster->SetRequestContext(request_context_getter_.get()); 370 fetch_state_.url_poster->SetRequestContext(request_context_getter_.get());
210 fetch_state_.url_poster->SetUploadData(content_type_, request_content_);
211 fetch_state_.url_poster->SetExtraRequestHeaders(extra_headers_); 371 fetch_state_.url_poster->SetExtraRequestHeaders(extra_headers_);
372
373 int compressed_content_size = 0;
Nicolas Zea 2015/07/30 19:59:44 You're using an int here, but the RequestXXXMethod
Gang Wu 2015/07/31 00:39:45 int64, since GetContentLength() return int64 it mi
374 if (IsSyncHttpContentCompressionEnabled()) {
375 std::string compressed_request_content;
376 GzipCompress(request_content_, &compressed_request_content);
377 compressed_content_size = compressed_request_content.size();
378 fetch_state_.url_poster->SetUploadData(content_type_,
379 compressed_request_content);
380 fetch_state_.url_poster->AddExtraRequestHeader("Content-Encoding: gzip");
381 } else {
382 fetch_state_.url_poster->SetUploadData(content_type_, request_content_);
383 fetch_state_.url_poster->AddExtraRequestHeader("Accept-Encoding: deflate");
384 }
385
386 RecordSyncRequestContentLengthHistograms(compressed_content_size,
387 request_content_.size());
388
212 fetch_state_.url_poster->AddExtraRequestHeader(base::StringPrintf( 389 fetch_state_.url_poster->AddExtraRequestHeader(base::StringPrintf(
213 "%s: %s", net::HttpRequestHeaders::kUserAgent, user_agent_.c_str())); 390 "%s: %s", net::HttpRequestHeaders::kUserAgent, user_agent_.c_str()));
214 fetch_state_.url_poster->SetLoadFlags(net::LOAD_BYPASS_CACHE | 391 fetch_state_.url_poster->SetLoadFlags(net::LOAD_BYPASS_CACHE |
215 net::LOAD_DISABLE_CACHE | 392 net::LOAD_DISABLE_CACHE |
216 net::LOAD_DO_NOT_SAVE_COOKIES | 393 net::LOAD_DO_NOT_SAVE_COOKIES |
217 net::LOAD_DO_NOT_SEND_COOKIES); 394 net::LOAD_DO_NOT_SEND_COOKIES);
218 fetch_state_.start_time = base::Time::Now();
219 395
220 fetch_state_.url_poster->Start(); 396 fetch_state_.url_poster->Start();
221 } 397 }
222 398
223 int HttpBridge::GetResponseContentLength() const { 399 int HttpBridge::GetResponseContentLength() const {
224 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 400 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_);
225 base::AutoLock lock(fetch_state_lock_); 401 base::AutoLock lock(fetch_state_lock_);
226 DCHECK(fetch_state_.request_completed); 402 DCHECK(fetch_state_.request_completed);
227 return fetch_state_.response_content.size(); 403 return fetch_state_.response_content.size();
228 } 404 }
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 // Use a real (non-debug) log to facilitate troubleshooting in the wild. 484 // Use a real (non-debug) log to facilitate troubleshooting in the wild.
309 VLOG(2) << "HttpBridge::OnURLFetchComplete for: " 485 VLOG(2) << "HttpBridge::OnURLFetchComplete for: "
310 << fetch_state_.url_poster->GetURL().spec(); 486 << fetch_state_.url_poster->GetURL().spec();
311 VLOG(1) << "HttpBridge received response code: " 487 VLOG(1) << "HttpBridge received response code: "
312 << fetch_state_.http_response_code; 488 << fetch_state_.http_response_code;
313 489
314 source->GetResponseAsString(&fetch_state_.response_content); 490 source->GetResponseAsString(&fetch_state_.response_content);
315 fetch_state_.response_headers = source->GetResponseHeaders(); 491 fetch_state_.response_headers = source->GetResponseHeaders();
316 UpdateNetworkTime(); 492 UpdateNetworkTime();
317 493
494 int64 compressed_content_length = fetch_state_.response_content.size();
Nicolas Zea 2015/07/30 19:59:44 Same comment above about type consistency/correctn
Gang Wu 2015/07/31 00:39:45 Done.
495 int64 original_content_length = compressed_content_length;
496 if (fetch_state_.response_headers &&
497 fetch_state_.response_headers->HasHeaderValue("content-encoding",
498 "gzip")) {
499 compressed_content_length =
500 fetch_state_.response_headers->GetContentLength();
501 }
502 RecordSyncResponseContentLengthHistograms(compressed_content_length,
503 original_content_length);
504
318 // End of the line for url_poster_. It lives only on the IO loop. 505 // End of the line for url_poster_. It lives only on the IO loop.
319 // We defer deletion because we're inside a callback from a component of the 506 // We defer deletion because we're inside a callback from a component of the
320 // URLFetcher, so it seems most natural / "polite" to let the stack unwind. 507 // URLFetcher, so it seems most natural / "polite" to let the stack unwind.
321 base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster); 508 base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster);
322 fetch_state_.url_poster = NULL; 509 fetch_state_.url_poster = NULL;
323 510
324 // Wake the blocked syncer thread in MakeSynchronousPost. 511 // Wake the blocked syncer thread in MakeSynchronousPost.
325 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted! 512 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted!
326 http_post_completed_.Signal(); 513 http_post_completed_.Signal();
327 } 514 }
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 int64 sane_time_ms = 0; 579 int64 sane_time_ms = 0;
393 if (base::StringToInt64(sane_time_str, &sane_time_ms)) { 580 if (base::StringToInt64(sane_time_str, &sane_time_ms)) {
394 network_time_update_callback_.Run( 581 network_time_update_callback_.Run(
395 base::Time::FromJsTime(sane_time_ms), 582 base::Time::FromJsTime(sane_time_ms),
396 base::TimeDelta::FromMilliseconds(1), 583 base::TimeDelta::FromMilliseconds(1),
397 fetch_state_.end_time - fetch_state_.start_time); 584 fetch_state_.end_time - fetch_state_.start_time);
398 } 585 }
399 } 586 }
400 587
401 } // namespace syncer 588 } // namespace syncer
OLDNEW
« no previous file with comments | « no previous file | sync/internal_api/http_bridge_unittest.cc » ('j') | sync/internal_api/http_bridge_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698