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

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

Powered by Google App Engine
This is Rietveld 408576698