Skip to content

Commit

Permalink
Add brotli content-encoding filter.
Browse files Browse the repository at this point in the history
BUG=472009

Review URL: https://codereview.chromium.org/1431723002

Cr-Commit-Position: refs/heads/master@{#367153}
  • Loading branch information
eustas authored and Commit bot committed Dec 30, 2015
1 parent 552071c commit fbec913
Show file tree
Hide file tree
Showing 23 changed files with 624 additions and 26 deletions.
15 changes: 11 additions & 4 deletions chrome/app/generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -5113,18 +5113,18 @@ Keep your key file in a safe place. You will need it to create new versions of y

<!-- Material Design version of chrome://policy -->
<message name="IDS_FLAGS_ENABLE_MATERIAL_DESIGN_POLICY_PAGE_NAME" desc="Name for the flag to enable the material design policy page.">
Enable Material Design policy page
Enable Material Design policy page
</message>
<message name="IDS_FLAGS_ENABLE_MATERIAL_DESIGN_POLICY_PAGE_DESCRIPTION" desc="Description for the flag to enable the material design policy page.">
If enabled, the chrome://md-policy URL loads the Material Design policy page.
If enabled, the chrome://md-policy URL loads the Material Design policy page.
</message>

<!-- Material Design version of chrome://downloads -->
<message name="IDS_FLAGS_ENABLE_MATERIAL_DESIGN_DOWNLOADS_NAME" desc="Name for the flag to enable the material design downloads page.">
Enable Material Design downloads
Enable Material Design downloads
</message>
<message name="IDS_FLAGS_ENABLE_MATERIAL_DESIGN_DOWNLOADS_DESCRIPTION" desc="Description for the flag to enable the material design downloads page.">
If enabled, the chrome://downloads/ URL loads the Material Design downloads page.
If enabled, the chrome://downloads/ URL loads the Material Design downloads page.
</message>

<!-- Material Design version of chrome://history -->
Expand Down Expand Up @@ -14764,6 +14764,13 @@ Please check your email at <ph name="ACCOUNT_EMAIL">$2<ex>jane.doe@gmail.com</ex
</message>
</if>

<message name="IDS_FLAGS_ENABLE_BROTLI_NAME" desc="Title for the flag to enable Brotli Content-Encoding.">
Brotli Content-Encoding.
</message>
<message name="IDS_FLAGS_ENABLE_BROTLI_DESCRIPTION" desc="Description for the flag to enable Brotli Content-Encoding.">
Enable Brotli Content-Encoding support.
</message>

</messages>
</release>
</grit>
5 changes: 5 additions & 0 deletions chrome/browser/about_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2085,6 +2085,11 @@ const FeatureEntry kFeatureEntries[] = {
IDS_FLAGS_EXPERIMENTAL_FRAMEWORK_DESCRIPTION,
kOsAll,
FEATURE_VALUE_TYPE(features::kExperimentalFramework)},
{"enable-brotli",
IDS_FLAGS_ENABLE_BROTLI_NAME,
IDS_FLAGS_ENABLE_BROTLI_DESCRIPTION,
kOsAll,
FEATURE_VALUE_TYPE(features::kBrotliEncoding)},
#if defined(OS_ANDROID)
{"enable-unified-media-pipeline",
IDS_FLAGS_ENABLE_UNIFIED_MEDIA_PIPELINE_NAME,
Expand Down
5 changes: 5 additions & 0 deletions chrome/browser/io_thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "components/version_info/version_info.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/cookie_store_factory.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/user_agent.h"
#include "net/base/external_estimate_provider.h"
Expand Down Expand Up @@ -844,6 +845,8 @@ void IOThread::Init() {
switches::kEnableUserAlternateProtocolPorts)) {
globals_->enable_user_alternate_protocol_ports = true;
}
globals_->enable_brotli.set(
base::FeatureList::IsEnabled(features::kBrotliEncoding));
// TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466432
// is fixed.
tracked_objects::ScopedTracker tracking_profile13(
Expand Down Expand Up @@ -1138,6 +1141,8 @@ void IOThread::InitializeNetworkSessionParamsFromGlobals(

globals.enable_npn.CopyToIfSet(&params->enable_npn);

globals.enable_brotli.CopyToIfSet(&params->enable_brotli);

globals.enable_quic.CopyToIfSet(&params->enable_quic);
globals.enable_quic_for_proxies.CopyToIfSet(&params->enable_quic_for_proxies);
globals.quic_always_require_handshake_confirmation.CopyToIfSet(
Expand Down
2 changes: 2 additions & 0 deletions chrome/browser/io_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ class IOThread : public content::BrowserThreadDelegate {

Optional<bool> enable_npn;

Optional<bool> enable_brotli;

Optional<bool> enable_quic;
Optional<bool> enable_quic_for_proxies;
Optional<bool> enable_quic_port_selection;
Expand Down
5 changes: 5 additions & 0 deletions content/public/common/content_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ namespace features {

// All features in alphabetical order.

// Enables brotli "Accept-Encoding" advertising and "Content-Encoding" support.
// Brotli format specification: http://www.ietf.org/id/draft-alakuijala-brotli
const base::Feature kBrotliEncoding = {
"brotli-encoding", base::FEATURE_DISABLED_BY_DEFAULT};

// Downloads resumption will be controllable via a flag until it's enabled
// permanently. See https://crbug.com/7648
const base::Feature kDownloadResumption{"DownloadResumption",
Expand Down
1 change: 1 addition & 0 deletions content/public/common/content_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace features {

// All features in alphabetical order. The features should be documented
// alongside the definition of their values in the .cc file.
CONTENT_EXPORT extern const base::Feature kBrotliEncoding;
CONTENT_EXPORT extern const base::Feature kDownloadResumption;
CONTENT_EXPORT extern const base::Feature kExperimentalFramework;

Expand Down
11 changes: 10 additions & 1 deletion net/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -451,11 +451,16 @@ component("net") {
"base/net_string_util_icu.cc",
"base/net_util_icu.cc",
]

# Brotli support.
deps += [ "//third_party/brotli" ]
sources += [ "filter/brotli_filter.cc" ]
}
}

if (is_android) {
# Same as net, but with ICU, file, ftp, and websocket support stripped.
# Same as net, but with brotli encoding, ICU, file, ftp, and websocket
# support stripped.
component("net_small") {
sources = net_shared_sources

Expand Down Expand Up @@ -484,6 +489,9 @@ if (is_android) {
"base/net_string_util_icu_alternatives_android.cc",
"base/net_string_util_icu_alternatives_android.h",
]

# Disable Brotli support.
sources += [ "filter/brotli_filter_disabled.cc" ]
}
}

Expand Down Expand Up @@ -1620,6 +1628,7 @@ test("net_unittests") {
"disk_cache/blockfile/block_files_unittest.cc",

# Need to read input data files.
"filter/brotli_filter_unittest.cc",
"filter/gzip_filter_unittest.cc",
"socket/ssl_server_socket_unittest.cc",
"spdy/fuzzing/hpack_fuzz_util_test.cc",
Expand Down
9 changes: 7 additions & 2 deletions net/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ include_rules = [
"+sdch/open-vcdiff",
"+v8",

# Most of net should not depend on icu, to keep size down when built as a
# library.
# Most of net should not depend on icu, and brotli to keep size down when
# built as a library.
"-base/i18n",
"-third_party/brotli",
"-third_party/icu",
]

Expand Down Expand Up @@ -56,6 +57,10 @@ specific_include_rules = {
"run_all_unittests\.cc": [
"+third_party/mojo/src/mojo/edk",
],

"brotli_filter\.cc": [
"+third_party/brotli",
],
}

skip_child_includes = [
Expand Down
Binary file added net/data/filter_unittests/google.br
Binary file not shown.
113 changes: 113 additions & 0 deletions net/filter/brotli_filter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/filter/brotli_filter.h"

#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
#include "third_party/brotli/dec/decode.h"

namespace net {

// BrotliFilter applies Brotli content decoding to a data stream.
// Brotli format specification: http://www.ietf.org/id/draft-alakuijala-brotli
//
// BrotliFilter is a subclass of Filter. See the latter's header file filter.h
// for sample usage.
class BrotliFilter : public Filter {
public:
BrotliFilter(FilterType type)
: Filter(type), decoding_status_(DECODING_IN_PROGRESS) {
BrotliStateInit(&brotli_state_);
}

~BrotliFilter() override { BrotliStateCleanup(&brotli_state_); }

// Decodes the pre-filter data and writes the output into the |dest_buffer|
// passed in.
// The function returns FilterStatus. See filter.h for its description.
//
// Upon entry, |*dest_len| is the total size (in number of chars) of the
// destination buffer. Upon exit, |*dest_len| is the actual number of chars
// written into the destination buffer.
//
// This function will fail if there is no pre-filter data in the
// |stream_buffer_|. On the other hand, |*dest_len| can be 0 upon successful
// return. For example, decompressor may process some pre-filter data
// but not produce output yet.
FilterStatus ReadFilteredData(char* dest_buffer, int* dest_len) override {
if (!dest_buffer || !dest_len)
return Filter::FILTER_ERROR;

if (decoding_status_ == DECODING_DONE) {
*dest_len = 0;
return Filter::FILTER_DONE;
}

if (decoding_status_ != DECODING_IN_PROGRESS)
return Filter::FILTER_ERROR;

size_t output_buffer_size = base::checked_cast<size_t>(*dest_len);
size_t input_buffer_size = base::checked_cast<size_t>(stream_data_len_);

size_t available_in = input_buffer_size;
const uint8_t* next_in = bit_cast<uint8_t*>(next_stream_data_);
size_t available_out = output_buffer_size;
uint8_t* next_out = bit_cast<uint8_t*>(dest_buffer);
size_t total_out = 0;
BrotliResult result =
BrotliDecompressStream(&available_in, &next_in, &available_out,
&next_out, &total_out, &brotli_state_);

CHECK(available_in <= input_buffer_size);
CHECK(available_out <= output_buffer_size);

base::CheckedNumeric<size_t> safe_bytes_written(output_buffer_size);
safe_bytes_written -= available_out;
int bytes_written =
base::checked_cast<int>(safe_bytes_written.ValueOrDie());

switch (result) {
case BROTLI_RESULT_NEEDS_MORE_OUTPUT:
// Fall through.
case BROTLI_RESULT_SUCCESS:
*dest_len = bytes_written;
stream_data_len_ = base::checked_cast<int>(available_in);
next_stream_data_ = bit_cast<char*>(next_in);
if (result == BROTLI_RESULT_SUCCESS) {
decoding_status_ = DECODING_DONE;
return Filter::FILTER_DONE;
}
return Filter::FILTER_OK;

case BROTLI_RESULT_NEEDS_MORE_INPUT:
*dest_len = bytes_written;
stream_data_len_ = 0;
next_stream_data_ = nullptr;
return Filter::FILTER_NEED_MORE_DATA;

default:
decoding_status_ = DECODING_ERROR;
return Filter::FILTER_ERROR;
}
}

private:
enum DecodingStatus { DECODING_IN_PROGRESS, DECODING_DONE, DECODING_ERROR };

// Tracks the status of decoding.
// This variable is updated only by ReadFilteredData.
DecodingStatus decoding_status_;

BrotliState brotli_state_;

DISALLOW_COPY_AND_ASSIGN(BrotliFilter);
};

Filter* CreateBrotliFilter(Filter::FilterType type_id) {
return new BrotliFilter(type_id);
}

} // namespace net
17 changes: 17 additions & 0 deletions net/filter/brotli_filter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_FILTER_BROTLI_FILTER_H_
#define NET_FILTER_BROTLI_FILTER_H_

#include "net/filter/filter.h"

namespace net {

// Creates instance of filter or returns nullptr if brotli is not supported.
Filter* CreateBrotliFilter(Filter::FilterType type_id);

} // namespace net

#endif // NET_FILTER_BROTLI_FILTER_H__
13 changes: 13 additions & 0 deletions net/filter/brotli_filter_disabled.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/filter/brotli_filter.h"

namespace net {

Filter* CreateBrotliFilter(Filter::FilterType type_id) {
return nullptr;
}

} // namespace net
Loading

0 comments on commit fbec913

Please sign in to comment.