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

Side by Side Diff: net/filter/brotli_filter.cc

Issue 2478703004: Remove net::Filter code (Closed)
Patch Set: Address Matt's comment Created 4 years, 1 month 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 | « net/filter/brotli_filter.h ('k') | net/filter/brotli_filter_disabled.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/filter/brotli_filter.h"
6
7 #include "base/bit_cast.h"
8 #include "base/macros.h"
9 #include "base/metrics/histogram_macros.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "base/numerics/safe_math.h"
12 #include "third_party/brotli/dec/decode.h"
13
14 namespace net {
15
16 namespace {
17 const uint8_t kGzipHeader[] = {0x1f, 0x8b, 0x08};
18 }
19
20 // BrotliFilter applies Brotli content decoding to a data stream.
21 // Brotli format specification: http://www.ietf.org/id/draft-alakuijala-brotli
22 //
23 // BrotliFilter is a subclass of Filter. See the latter's header file filter.h
24 // for sample usage.
25 class BrotliFilter : public Filter {
26 public:
27 BrotliFilter(FilterType type)
28 : Filter(type),
29 decoding_status_(DecodingStatus::DECODING_IN_PROGRESS),
30 used_memory_(0),
31 used_memory_maximum_(0),
32 consumed_bytes_(0),
33 produced_bytes_(0),
34 gzip_header_detected_(true) {
35 brotli_state_ = BrotliCreateState(BrotliFilter::AllocateMemory,
36 BrotliFilter::FreeMemory, this);
37 CHECK(brotli_state_);
38 }
39
40 ~BrotliFilter() override {
41 BrotliErrorCode error_code = BrotliGetErrorCode(brotli_state_);
42 BrotliDestroyState(brotli_state_);
43 brotli_state_ = nullptr;
44 DCHECK(used_memory_ == 0);
45
46 // Don't report that gzip header was detected in case of lack of input.
47 gzip_header_detected_ &= (consumed_bytes_ >= sizeof(kGzipHeader));
48
49 UMA_HISTOGRAM_ENUMERATION(
50 "BrotliFilter.Status", static_cast<int>(decoding_status_),
51 static_cast<int>(DecodingStatus::DECODING_STATUS_COUNT));
52 UMA_HISTOGRAM_BOOLEAN("BrotliFilter.GzipHeaderDetected",
53 gzip_header_detected_);
54 if (decoding_status_ == DecodingStatus::DECODING_DONE) {
55 // CompressionPercent is undefined when there is no output produced.
56 if (produced_bytes_ != 0) {
57 UMA_HISTOGRAM_PERCENTAGE(
58 "BrotliFilter.CompressionPercent",
59 static_cast<int>((consumed_bytes_ * 100) / produced_bytes_));
60 }
61 }
62 if (error_code < 0) {
63 UMA_HISTOGRAM_ENUMERATION("BrotliFilter.ErrorCode",
64 -static_cast<int>(error_code),
65 1 - BROTLI_LAST_ERROR_CODE);
66 }
67
68 // All code here is for gathering stats, and can be removed when
69 // BrotliFilter is considered stable.
70 static const int kBuckets = 48;
71 static const int64_t kMaxKb = 1 << (kBuckets / 3); // 64MiB in KiB
72 UMA_HISTOGRAM_CUSTOM_COUNTS("BrotliFilter.UsedMemoryKB",
73 used_memory_maximum_ / 1024, 1, kMaxKb,
74 kBuckets);
75 }
76
77 // Decodes the pre-filter data and writes the output into the |dest_buffer|
78 // passed in.
79 // The function returns FilterStatus. See filter.h for its description.
80 //
81 // Upon entry, |*dest_len| is the total size (in number of chars) of the
82 // destination buffer. Upon exit, |*dest_len| is the actual number of chars
83 // written into the destination buffer.
84 //
85 // This function will fail if there is no pre-filter data in the
86 // |stream_buffer_|. On the other hand, |*dest_len| can be 0 upon successful
87 // return. For example, decompressor may process some pre-filter data
88 // but not produce output yet.
89 FilterStatus ReadFilteredData(char* dest_buffer, int* dest_len) override {
90 if (!dest_buffer || !dest_len)
91 return Filter::FILTER_ERROR;
92
93 if (decoding_status_ == DecodingStatus::DECODING_DONE) {
94 *dest_len = 0;
95 return Filter::FILTER_DONE;
96 }
97
98 if (decoding_status_ != DecodingStatus::DECODING_IN_PROGRESS)
99 return Filter::FILTER_ERROR;
100
101 size_t output_buffer_size = base::checked_cast<size_t>(*dest_len);
102 size_t input_buffer_size = base::checked_cast<size_t>(stream_data_len_);
103
104 size_t available_in = input_buffer_size;
105 const uint8_t* next_in = bit_cast<uint8_t*>(next_stream_data_);
106 size_t available_out = output_buffer_size;
107 uint8_t* next_out = bit_cast<uint8_t*>(dest_buffer);
108 size_t total_out = 0;
109
110 // Check if start of the input stream looks like gzip stream.
111 for (size_t i = consumed_bytes_; i < sizeof(kGzipHeader); ++i) {
112 if (!gzip_header_detected_)
113 break;
114 size_t j = i - consumed_bytes_;
115 if (j < available_in && kGzipHeader[i] != next_in[j])
116 gzip_header_detected_ = false;
117 }
118
119 BrotliResult result =
120 BrotliDecompressStream(&available_in, &next_in, &available_out,
121 &next_out, &total_out, brotli_state_);
122
123 CHECK(available_in <= input_buffer_size);
124 CHECK(available_out <= output_buffer_size);
125 consumed_bytes_ += input_buffer_size - available_in;
126 produced_bytes_ += output_buffer_size - available_out;
127
128 base::CheckedNumeric<size_t> safe_bytes_written(output_buffer_size);
129 safe_bytes_written -= available_out;
130 int bytes_written =
131 base::checked_cast<int>(safe_bytes_written.ValueOrDie());
132
133 switch (result) {
134 case BROTLI_RESULT_NEEDS_MORE_OUTPUT:
135 // Fall through.
136 case BROTLI_RESULT_SUCCESS:
137 *dest_len = bytes_written;
138 stream_data_len_ = base::checked_cast<int>(available_in);
139 next_stream_data_ = bit_cast<char*>(next_in);
140 if (result == BROTLI_RESULT_SUCCESS) {
141 decoding_status_ = DecodingStatus::DECODING_DONE;
142 return Filter::FILTER_DONE;
143 }
144 return Filter::FILTER_OK;
145
146 case BROTLI_RESULT_NEEDS_MORE_INPUT:
147 *dest_len = bytes_written;
148 stream_data_len_ = 0;
149 next_stream_data_ = nullptr;
150 return Filter::FILTER_NEED_MORE_DATA;
151
152 default:
153 decoding_status_ = DecodingStatus::DECODING_ERROR;
154 return Filter::FILTER_ERROR;
155 }
156 }
157
158 private:
159 static void* AllocateMemory(void* opaque, size_t size) {
160 BrotliFilter* filter = reinterpret_cast<BrotliFilter*>(opaque);
161 return filter->AllocateMemoryInternal(size);
162 }
163
164 static void FreeMemory(void* opaque, void* address) {
165 BrotliFilter* filter = reinterpret_cast<BrotliFilter*>(opaque);
166 filter->FreeMemoryInternal(address);
167 }
168
169 void* AllocateMemoryInternal(size_t size) {
170 size_t* array = reinterpret_cast<size_t*>(malloc(size + sizeof(size_t)));
171 if (!array)
172 return nullptr;
173 used_memory_ += size;
174 if (used_memory_maximum_ < used_memory_)
175 used_memory_maximum_ = used_memory_;
176 array[0] = size;
177 return &array[1];
178 }
179
180 void FreeMemoryInternal(void* address) {
181 if (!address)
182 return;
183 size_t* array = reinterpret_cast<size_t*>(address);
184 used_memory_ -= array[-1];
185 free(&array[-1]);
186 }
187
188 // Reported in UMA and must be kept in sync with the histograms.xml file.
189 enum class DecodingStatus : int {
190 DECODING_IN_PROGRESS = 0,
191 DECODING_DONE,
192 DECODING_ERROR,
193
194 DECODING_STATUS_COUNT
195 // DECODING_STATUS_COUNT must always be the last element in this enum.
196 };
197
198 // Tracks the status of decoding.
199 // This variable is updated only by ReadFilteredData.
200 DecodingStatus decoding_status_;
201
202 BrotliState* brotli_state_;
203
204 size_t used_memory_;
205 size_t used_memory_maximum_;
206 size_t consumed_bytes_;
207 size_t produced_bytes_;
208
209 bool gzip_header_detected_;
210
211 DISALLOW_COPY_AND_ASSIGN(BrotliFilter);
212 };
213
214 Filter* CreateBrotliFilter(Filter::FilterType type_id) {
215 return new BrotliFilter(type_id);
216 }
217
218 } // namespace net
OLDNEW
« no previous file with comments | « net/filter/brotli_filter.h ('k') | net/filter/brotli_filter_disabled.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698