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

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: merge conlict 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
« no previous file with comments | « sync/BUILD.gn ('k') | sync/internal_api/http_bridge_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
11 #include "base/strings/string_util.h"
10 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
11 #include "net/base/load_flags.h" 13 #include "net/base/load_flags.h"
12 #include "net/base/net_errors.h" 14 #include "net/base/net_errors.h"
13 #include "net/http/http_cache.h" 15 #include "net/http/http_cache.h"
14 #include "net/http/http_network_layer.h" 16 #include "net/http/http_network_layer.h"
15 #include "net/http/http_request_headers.h" 17 #include "net/http/http_request_headers.h"
16 #include "net/http/http_response_headers.h" 18 #include "net/http/http_response_headers.h"
17 #include "net/url_request/static_http_user_agent_settings.h" 19 #include "net/url_request/static_http_user_agent_settings.h"
18 #include "net/url_request/url_fetcher.h" 20 #include "net/url_request/url_fetcher.h"
19 #include "net/url_request/url_request_context.h" 21 #include "net/url_request/url_request_context.h"
20 #include "net/url_request/url_request_job_factory_impl.h" 22 #include "net/url_request/url_request_job_factory_impl.h"
21 #include "net/url_request/url_request_status.h" 23 #include "net/url_request/url_request_status.h"
22 #include "sync/internal_api/public/base/cancelation_signal.h" 24 #include "sync/internal_api/public/base/cancelation_signal.h"
25 #include "third_party/zlib/zlib.h"
23 26
24 namespace syncer { 27 namespace syncer {
25 28
26 namespace { 29 namespace {
27 30
28 // It's possible for an http request to be silently stalled. We set a time 31 // 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 32 // limit for all http requests, beyond which the request is cancelled and
30 // treated as a transient failure. 33 // treated as a transient failure.
31 const int kMaxHttpRequestTimeSeconds = 60 * 5; // 5 minutes. 34 const int kMaxHttpRequestTimeSeconds = 60 * 5; // 5 minutes.
32 35
33 // Helper method for logging timeouts via UMA. 36 // Helper method for logging timeouts via UMA.
34 void LogTimeout(bool timed_out) { 37 void LogTimeout(bool timed_out) {
35 UMA_HISTOGRAM_BOOLEAN("Sync.URLFetchTimedOut", timed_out); 38 UMA_HISTOGRAM_BOOLEAN("Sync.URLFetchTimedOut", timed_out);
36 } 39 }
37 40
41 bool IsSyncHttpContentCompressionEnabled() {
42 const std::string group_name =
43 base::FieldTrialList::FindFullName("SyncHttpContentCompression");
44 return StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
45 }
46
47 void RecordSyncRequestContentLengthHistograms(int64 compressed_content_length,
48 int64 original_content_length) {
49 UMA_HISTOGRAM_COUNTS("Sync.RequestContentLength.Compressed",
50 compressed_content_length);
51 UMA_HISTOGRAM_COUNTS("Sync.RequestContentLength.Original",
52 original_content_length);
53 }
54
55 void RecordSyncResponseContentLengthHistograms(int64 compressed_content_length,
56 int64 original_content_length) {
57 UMA_HISTOGRAM_COUNTS("Sync.ResponseContentLength.Compressed",
58 compressed_content_length);
59 UMA_HISTOGRAM_COUNTS("Sync.ResponseContentLength.Original",
60 original_content_length);
61 }
62
63 // -----------------------------------------------------------------------------
64 // The rest of the code in the anon namespace is copied from
65 // components/metrics/compression_utils.cc
66 // TODO(gangwu): crbug.com/515695. The following code is copied from
67 // components/metrics/compression_utils.cc. We copied them because if we
68 // reference them, we will get cycle dependency warning. Once the functions
69 // have been moved from //component to //base, we can remove the following
70 // functions.
71 //------------------------------------------------------------------------------
72 // The difference in bytes between a zlib header and a gzip header.
73 const size_t kGzipZlibHeaderDifferenceBytes = 16;
74
75 // Pass an integer greater than the following get a gzip header instead of a
76 // zlib header when calling deflateInit2() and inflateInit2().
77 const int kWindowBitsToGetGzipHeader = 16;
78
79 // This describes the amount of memory zlib uses to compress data. It can go
80 // from 1 to 9, with 8 being the default. For details, see:
81 // http://www.zlib.net/manual.html (search for memLevel).
82 const int kZlibMemoryLevel = 8;
83
84 // This code is taken almost verbatim from third_party/zlib/compress.c. The only
85 // difference is deflateInit2() is called which sets the window bits to be > 16.
86 // That causes a gzip header to be emitted rather than a zlib header.
87 int GzipCompressHelper(Bytef* dest,
88 uLongf* dest_length,
89 const Bytef* source,
90 uLong source_length) {
91 z_stream stream;
92
93 stream.next_in = bit_cast<Bytef*>(source);
94 stream.avail_in = static_cast<uInt>(source_length);
95 stream.next_out = dest;
96 stream.avail_out = static_cast<uInt>(*dest_length);
97 if (static_cast<uLong>(stream.avail_out) != *dest_length)
98 return Z_BUF_ERROR;
99
100 stream.zalloc = static_cast<alloc_func>(0);
101 stream.zfree = static_cast<free_func>(0);
102 stream.opaque = static_cast<voidpf>(0);
103
104 gz_header gzip_header;
105 memset(&gzip_header, 0, sizeof(gzip_header));
106 int err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
107 MAX_WBITS + kWindowBitsToGetGzipHeader,
108 kZlibMemoryLevel, Z_DEFAULT_STRATEGY);
109 if (err != Z_OK)
110 return err;
111
112 err = deflateSetHeader(&stream, &gzip_header);
113 if (err != Z_OK)
114 return err;
115
116 err = deflate(&stream, Z_FINISH);
117 if (err != Z_STREAM_END) {
118 deflateEnd(&stream);
119 return err == Z_OK ? Z_BUF_ERROR : err;
120 }
121 *dest_length = stream.total_out;
122
123 err = deflateEnd(&stream);
124 return err;
125 }
126
127 bool GzipCompress(const std::string& input, std::string* output) {
128 const uLongf input_size = static_cast<uLongf>(input.size());
129 std::vector<Bytef> compressed_data(kGzipZlibHeaderDifferenceBytes +
130 compressBound(input_size));
131
132 uLongf compressed_size = static_cast<uLongf>(compressed_data.size());
133 if (GzipCompressHelper(&compressed_data.front(), &compressed_size,
134 bit_cast<const Bytef*>(input.data()),
135 input_size) != Z_OK) {
136 return false;
137 }
138
139 compressed_data.resize(compressed_size);
140 output->assign(compressed_data.begin(), compressed_data.end());
141 return true;
142 }
143
38 } // namespace 144 } // namespace
39 145
40 HttpBridgeFactory::HttpBridgeFactory( 146 HttpBridgeFactory::HttpBridgeFactory(
41 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter, 147 const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
42 const NetworkTimeUpdateCallback& network_time_update_callback, 148 const NetworkTimeUpdateCallback& network_time_update_callback,
43 CancelationSignal* cancelation_signal) 149 CancelationSignal* cancelation_signal)
44 : request_context_getter_(request_context_getter), 150 : request_context_getter_(request_context_getter),
45 network_time_update_callback_(network_time_update_callback), 151 network_time_update_callback_(network_time_update_callback),
46 cancelation_signal_(cancelation_signal) { 152 cancelation_signal_(cancelation_signal) {
47 // Registration should never fail. This should happen on the UI thread during 153 // Registration should never fail. This should happen on the UI thread during
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 302
197 // Start the timer on the network thread (the same thread progress is made 303 // Start the timer on the network thread (the same thread progress is made
198 // on, and on which the url fetcher lives). 304 // on, and on which the url fetcher lives).
199 DCHECK(!fetch_state_.http_request_timeout_timer.get()); 305 DCHECK(!fetch_state_.http_request_timeout_timer.get());
200 fetch_state_.http_request_timeout_timer.reset(new base::Timer(false, false)); 306 fetch_state_.http_request_timeout_timer.reset(new base::Timer(false, false));
201 fetch_state_.http_request_timeout_timer->Start( 307 fetch_state_.http_request_timeout_timer->Start(
202 FROM_HERE, base::TimeDelta::FromSeconds(kMaxHttpRequestTimeSeconds), 308 FROM_HERE, base::TimeDelta::FromSeconds(kMaxHttpRequestTimeSeconds),
203 base::Bind(&HttpBridge::OnURLFetchTimedOut, this)); 309 base::Bind(&HttpBridge::OnURLFetchTimedOut, this));
204 310
205 DCHECK(request_context_getter_.get()); 311 DCHECK(request_context_getter_.get());
312 fetch_state_.start_time = base::Time::Now();
206 fetch_state_.url_poster = 313 fetch_state_.url_poster =
207 net::URLFetcher::Create(url_for_request_, net::URLFetcher::POST, this) 314 net::URLFetcher::Create(url_for_request_, net::URLFetcher::POST, this)
208 .release(); 315 .release();
209 fetch_state_.url_poster->SetRequestContext(request_context_getter_.get()); 316 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_); 317 fetch_state_.url_poster->SetExtraRequestHeaders(extra_headers_);
318
319 int64 compressed_content_size = 0;
320 if (IsSyncHttpContentCompressionEnabled()) {
321 std::string compressed_request_content;
322 GzipCompress(request_content_, &compressed_request_content);
323 compressed_content_size = compressed_request_content.size();
324 fetch_state_.url_poster->SetUploadData(content_type_,
325 compressed_request_content);
326 fetch_state_.url_poster->AddExtraRequestHeader("Content-Encoding: gzip");
327 } else {
328 fetch_state_.url_poster->SetUploadData(content_type_, request_content_);
329 fetch_state_.url_poster->AddExtraRequestHeader(base::StringPrintf(
330 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding, "deflate"));
331 }
332
333 RecordSyncRequestContentLengthHistograms(compressed_content_size,
334 request_content_.size());
335
212 fetch_state_.url_poster->AddExtraRequestHeader(base::StringPrintf( 336 fetch_state_.url_poster->AddExtraRequestHeader(base::StringPrintf(
213 "%s: %s", net::HttpRequestHeaders::kUserAgent, user_agent_.c_str())); 337 "%s: %s", net::HttpRequestHeaders::kUserAgent, user_agent_.c_str()));
214 fetch_state_.url_poster->SetLoadFlags(net::LOAD_BYPASS_CACHE | 338 fetch_state_.url_poster->SetLoadFlags(net::LOAD_BYPASS_CACHE |
215 net::LOAD_DISABLE_CACHE | 339 net::LOAD_DISABLE_CACHE |
216 net::LOAD_DO_NOT_SAVE_COOKIES | 340 net::LOAD_DO_NOT_SAVE_COOKIES |
217 net::LOAD_DO_NOT_SEND_COOKIES); 341 net::LOAD_DO_NOT_SEND_COOKIES);
218 fetch_state_.start_time = base::Time::Now();
219 342
220 fetch_state_.url_poster->Start(); 343 fetch_state_.url_poster->Start();
221 } 344 }
222 345
223 int HttpBridge::GetResponseContentLength() const { 346 int HttpBridge::GetResponseContentLength() const {
224 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_); 347 DCHECK_EQ(base::MessageLoop::current(), created_on_loop_);
225 base::AutoLock lock(fetch_state_lock_); 348 base::AutoLock lock(fetch_state_lock_);
226 DCHECK(fetch_state_.request_completed); 349 DCHECK(fetch_state_.request_completed);
227 return fetch_state_.response_content.size(); 350 return fetch_state_.response_content.size();
228 } 351 }
(...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. 431 // Use a real (non-debug) log to facilitate troubleshooting in the wild.
309 VLOG(2) << "HttpBridge::OnURLFetchComplete for: " 432 VLOG(2) << "HttpBridge::OnURLFetchComplete for: "
310 << fetch_state_.url_poster->GetURL().spec(); 433 << fetch_state_.url_poster->GetURL().spec();
311 VLOG(1) << "HttpBridge received response code: " 434 VLOG(1) << "HttpBridge received response code: "
312 << fetch_state_.http_response_code; 435 << fetch_state_.http_response_code;
313 436
314 source->GetResponseAsString(&fetch_state_.response_content); 437 source->GetResponseAsString(&fetch_state_.response_content);
315 fetch_state_.response_headers = source->GetResponseHeaders(); 438 fetch_state_.response_headers = source->GetResponseHeaders();
316 UpdateNetworkTime(); 439 UpdateNetworkTime();
317 440
441 int64 compressed_content_length = fetch_state_.response_content.size();
442 int64 original_content_length = compressed_content_length;
443 if (fetch_state_.response_headers &&
444 fetch_state_.response_headers->HasHeaderValue("content-encoding",
445 "gzip")) {
446 compressed_content_length =
447 fetch_state_.response_headers->GetContentLength();
448 }
449 RecordSyncResponseContentLengthHistograms(compressed_content_length,
450 original_content_length);
451
318 // End of the line for url_poster_. It lives only on the IO loop. 452 // 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 453 // 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. 454 // URLFetcher, so it seems most natural / "polite" to let the stack unwind.
321 base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster); 455 base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster);
322 fetch_state_.url_poster = NULL; 456 fetch_state_.url_poster = NULL;
323 457
324 // Wake the blocked syncer thread in MakeSynchronousPost. 458 // Wake the blocked syncer thread in MakeSynchronousPost.
325 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted! 459 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted!
326 http_post_completed_.Signal(); 460 http_post_completed_.Signal();
327 } 461 }
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 int64 sane_time_ms = 0; 526 int64 sane_time_ms = 0;
393 if (base::StringToInt64(sane_time_str, &sane_time_ms)) { 527 if (base::StringToInt64(sane_time_str, &sane_time_ms)) {
394 network_time_update_callback_.Run( 528 network_time_update_callback_.Run(
395 base::Time::FromJsTime(sane_time_ms), 529 base::Time::FromJsTime(sane_time_ms),
396 base::TimeDelta::FromMilliseconds(1), 530 base::TimeDelta::FromMilliseconds(1),
397 fetch_state_.end_time - fetch_state_.start_time); 531 fetch_state_.end_time - fetch_state_.start_time);
398 } 532 }
399 } 533 }
400 534
401 } // namespace syncer 535 } // namespace syncer
OLDNEW
« no previous file with comments | « sync/BUILD.gn ('k') | sync/internal_api/http_bridge_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698