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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sync/BUILD.gn ('k') | sync/internal_api/http_bridge_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sync/internal_api/http_bridge.cc
diff --git a/sync/internal_api/http_bridge.cc b/sync/internal_api/http_bridge.cc
index c64822d5836d2e729d6f7bca00069e5eebbd7c80..e5729f2dcf26f66552ee1fc02262a4d7dcc6258b 100644
--- a/sync/internal_api/http_bridge.cc
+++ b/sync/internal_api/http_bridge.cc
@@ -5,8 +5,10 @@
#include "sync/internal_api/public/http_bridge.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -20,6 +22,7 @@
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_status.h"
#include "sync/internal_api/public/base/cancelation_signal.h"
+#include "third_party/zlib/zlib.h"
namespace syncer {
@@ -35,6 +38,109 @@ void LogTimeout(bool timed_out) {
UMA_HISTOGRAM_BOOLEAN("Sync.URLFetchTimedOut", timed_out);
}
+bool IsSyncHttpContentCompressionEnabled() {
+ const std::string group_name =
+ base::FieldTrialList::FindFullName("SyncHttpContentCompression");
+ return StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
+}
+
+void RecordSyncRequestContentLengthHistograms(int64 compressed_content_length,
+ int64 original_content_length) {
+ UMA_HISTOGRAM_COUNTS("Sync.RequestContentLength.Compressed",
+ compressed_content_length);
+ UMA_HISTOGRAM_COUNTS("Sync.RequestContentLength.Original",
+ original_content_length);
+}
+
+void RecordSyncResponseContentLengthHistograms(int64 compressed_content_length,
+ int64 original_content_length) {
+ UMA_HISTOGRAM_COUNTS("Sync.ResponseContentLength.Compressed",
+ compressed_content_length);
+ UMA_HISTOGRAM_COUNTS("Sync.ResponseContentLength.Original",
+ original_content_length);
+}
+
+// -----------------------------------------------------------------------------
+// The rest of the code in the anon namespace is copied from
+// components/metrics/compression_utils.cc
+// TODO(gangwu): crbug.com/515695. The following code is copied from
+// components/metrics/compression_utils.cc. We copied them because if we
+// reference them, we will get cycle dependency warning. Once the functions
+// have been moved from //component to //base, we can remove the following
+// functions.
+//------------------------------------------------------------------------------
+// The difference in bytes between a zlib header and a gzip header.
+const size_t kGzipZlibHeaderDifferenceBytes = 16;
+
+// Pass an integer greater than the following get a gzip header instead of a
+// zlib header when calling deflateInit2() and inflateInit2().
+const int kWindowBitsToGetGzipHeader = 16;
+
+// This describes the amount of memory zlib uses to compress data. It can go
+// from 1 to 9, with 8 being the default. For details, see:
+// http://www.zlib.net/manual.html (search for memLevel).
+const int kZlibMemoryLevel = 8;
+
+// This code is taken almost verbatim from third_party/zlib/compress.c. The only
+// difference is deflateInit2() is called which sets the window bits to be > 16.
+// That causes a gzip header to be emitted rather than a zlib header.
+int GzipCompressHelper(Bytef* dest,
+ uLongf* dest_length,
+ const Bytef* source,
+ uLong source_length) {
+ z_stream stream;
+
+ stream.next_in = bit_cast<Bytef*>(source);
+ stream.avail_in = static_cast<uInt>(source_length);
+ stream.next_out = dest;
+ stream.avail_out = static_cast<uInt>(*dest_length);
+ if (static_cast<uLong>(stream.avail_out) != *dest_length)
+ return Z_BUF_ERROR;
+
+ stream.zalloc = static_cast<alloc_func>(0);
+ stream.zfree = static_cast<free_func>(0);
+ stream.opaque = static_cast<voidpf>(0);
+
+ gz_header gzip_header;
+ memset(&gzip_header, 0, sizeof(gzip_header));
+ int err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+ MAX_WBITS + kWindowBitsToGetGzipHeader,
+ kZlibMemoryLevel, Z_DEFAULT_STRATEGY);
+ if (err != Z_OK)
+ return err;
+
+ err = deflateSetHeader(&stream, &gzip_header);
+ if (err != Z_OK)
+ return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *dest_length = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+bool GzipCompress(const std::string& input, std::string* output) {
+ const uLongf input_size = static_cast<uLongf>(input.size());
+ std::vector<Bytef> compressed_data(kGzipZlibHeaderDifferenceBytes +
+ compressBound(input_size));
+
+ uLongf compressed_size = static_cast<uLongf>(compressed_data.size());
+ if (GzipCompressHelper(&compressed_data.front(), &compressed_size,
+ bit_cast<const Bytef*>(input.data()),
+ input_size) != Z_OK) {
+ return false;
+ }
+
+ compressed_data.resize(compressed_size);
+ output->assign(compressed_data.begin(), compressed_data.end());
+ return true;
+}
+
} // namespace
HttpBridgeFactory::HttpBridgeFactory(
@@ -203,19 +309,36 @@ void HttpBridge::MakeAsynchronousPost() {
base::Bind(&HttpBridge::OnURLFetchTimedOut, this));
DCHECK(request_context_getter_.get());
+ fetch_state_.start_time = base::Time::Now();
fetch_state_.url_poster =
net::URLFetcher::Create(url_for_request_, net::URLFetcher::POST, this)
.release();
fetch_state_.url_poster->SetRequestContext(request_context_getter_.get());
- fetch_state_.url_poster->SetUploadData(content_type_, request_content_);
fetch_state_.url_poster->SetExtraRequestHeaders(extra_headers_);
+
+ int64 compressed_content_size = 0;
+ if (IsSyncHttpContentCompressionEnabled()) {
+ std::string compressed_request_content;
+ GzipCompress(request_content_, &compressed_request_content);
+ compressed_content_size = compressed_request_content.size();
+ fetch_state_.url_poster->SetUploadData(content_type_,
+ compressed_request_content);
+ fetch_state_.url_poster->AddExtraRequestHeader("Content-Encoding: gzip");
+ } else {
+ fetch_state_.url_poster->SetUploadData(content_type_, request_content_);
+ fetch_state_.url_poster->AddExtraRequestHeader(base::StringPrintf(
+ "%s: %s", net::HttpRequestHeaders::kAcceptEncoding, "deflate"));
+ }
+
+ RecordSyncRequestContentLengthHistograms(compressed_content_size,
+ request_content_.size());
+
fetch_state_.url_poster->AddExtraRequestHeader(base::StringPrintf(
"%s: %s", net::HttpRequestHeaders::kUserAgent, user_agent_.c_str()));
fetch_state_.url_poster->SetLoadFlags(net::LOAD_BYPASS_CACHE |
net::LOAD_DISABLE_CACHE |
net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DO_NOT_SEND_COOKIES);
- fetch_state_.start_time = base::Time::Now();
fetch_state_.url_poster->Start();
}
@@ -315,6 +438,17 @@ void HttpBridge::OnURLFetchComplete(const net::URLFetcher* source) {
fetch_state_.response_headers = source->GetResponseHeaders();
UpdateNetworkTime();
+ int64 compressed_content_length = fetch_state_.response_content.size();
+ int64 original_content_length = compressed_content_length;
+ if (fetch_state_.response_headers &&
+ fetch_state_.response_headers->HasHeaderValue("content-encoding",
+ "gzip")) {
+ compressed_content_length =
+ fetch_state_.response_headers->GetContentLength();
+ }
+ RecordSyncResponseContentLengthHistograms(compressed_content_length,
+ original_content_length);
+
// End of the line for url_poster_. It lives only on the IO loop.
// We defer deletion because we're inside a callback from a component of the
// URLFetcher, so it seems most natural / "polite" to let the stack unwind.
« 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