OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "net/filter/brotli_source_stream.h" | 5 #include "net/filter/brotli_source_stream.h" |
6 | 6 |
| 7 #include <brotli/decode.h> |
| 8 |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/bit_cast.h" | 10 #include "base/bit_cast.h" |
9 #include "base/logging.h" | 11 #include "base/logging.h" |
10 #include "base/macros.h" | 12 #include "base/macros.h" |
11 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
12 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
13 #include "net/base/io_buffer.h" | 15 #include "net/base/io_buffer.h" |
14 #include "third_party/brotli/dec/decode.h" | |
15 | 16 |
16 namespace net { | 17 namespace net { |
17 | 18 |
18 namespace { | 19 namespace { |
19 | 20 |
20 const char kBrotli[] = "BROTLI"; | 21 const char kBrotli[] = "BROTLI"; |
21 const uint8_t kGzipHeader[] = {0x1f, 0x8b, 0x08}; | 22 const uint8_t kGzipHeader[] = {0x1f, 0x8b, 0x08}; |
22 | 23 |
23 // BrotliSourceStream applies Brotli content decoding to a data stream. | 24 // BrotliSourceStream applies Brotli content decoding to a data stream. |
24 // Brotli format specification: http://www.ietf.org/id/draft-alakuijala-brotli. | 25 // Brotli format specification: http://www.ietf.org/id/draft-alakuijala-brotli. |
25 class BrotliSourceStream : public FilterSourceStream { | 26 class BrotliSourceStream : public FilterSourceStream { |
26 public: | 27 public: |
27 explicit BrotliSourceStream(std::unique_ptr<SourceStream> upstream) | 28 explicit BrotliSourceStream(std::unique_ptr<SourceStream> upstream) |
28 : FilterSourceStream(SourceStream::TYPE_BROTLI, std::move(upstream)), | 29 : FilterSourceStream(SourceStream::TYPE_BROTLI, std::move(upstream)), |
29 decoding_status_(DecodingStatus::DECODING_IN_PROGRESS), | 30 decoding_status_(DecodingStatus::DECODING_IN_PROGRESS), |
30 used_memory_(0), | 31 used_memory_(0), |
31 used_memory_maximum_(0), | 32 used_memory_maximum_(0), |
32 consumed_bytes_(0), | 33 consumed_bytes_(0), |
33 produced_bytes_(0), | 34 produced_bytes_(0), |
34 gzip_header_detected_(true) { | 35 gzip_header_detected_(true) { |
35 brotli_state_ = BrotliCreateState(AllocateMemory, FreeMemory, this); | 36 brotli_state_ = |
| 37 BrotliDecoderCreateInstance(AllocateMemory, FreeMemory, this); |
36 CHECK(brotli_state_); | 38 CHECK(brotli_state_); |
37 } | 39 } |
38 | 40 |
39 ~BrotliSourceStream() override { | 41 ~BrotliSourceStream() override { |
40 BrotliErrorCode error_code = BrotliGetErrorCode(brotli_state_); | 42 BrotliDecoderErrorCode error_code = |
41 BrotliDestroyState(brotli_state_); | 43 BrotliDecoderGetErrorCode(brotli_state_); |
| 44 BrotliDecoderDestroyInstance(brotli_state_); |
42 brotli_state_ = nullptr; | 45 brotli_state_ = nullptr; |
43 DCHECK_EQ(0u, used_memory_); | 46 DCHECK_EQ(0u, used_memory_); |
44 | 47 |
45 // Don't report that gzip header was detected in case of lack of input. | 48 // Don't report that gzip header was detected in case of lack of input. |
46 gzip_header_detected_ &= (consumed_bytes_ >= sizeof(kGzipHeader)); | 49 gzip_header_detected_ &= (consumed_bytes_ >= sizeof(kGzipHeader)); |
47 | 50 |
48 UMA_HISTOGRAM_ENUMERATION( | 51 UMA_HISTOGRAM_ENUMERATION( |
49 "BrotliFilter.Status", static_cast<int>(decoding_status_), | 52 "BrotliFilter.Status", static_cast<int>(decoding_status_), |
50 static_cast<int>(DecodingStatus::DECODING_STATUS_COUNT)); | 53 static_cast<int>(DecodingStatus::DECODING_STATUS_COUNT)); |
51 UMA_HISTOGRAM_BOOLEAN("BrotliFilter.GzipHeaderDetected", | 54 UMA_HISTOGRAM_BOOLEAN("BrotliFilter.GzipHeaderDetected", |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 return OK; | 101 return OK; |
99 } | 102 } |
100 | 103 |
101 if (decoding_status_ != DecodingStatus::DECODING_IN_PROGRESS) | 104 if (decoding_status_ != DecodingStatus::DECODING_IN_PROGRESS) |
102 return ERR_CONTENT_DECODING_FAILED; | 105 return ERR_CONTENT_DECODING_FAILED; |
103 | 106 |
104 const uint8_t* next_in = bit_cast<uint8_t*>(input_buffer->data()); | 107 const uint8_t* next_in = bit_cast<uint8_t*>(input_buffer->data()); |
105 size_t available_in = input_buffer_size; | 108 size_t available_in = input_buffer_size; |
106 uint8_t* next_out = bit_cast<uint8_t*>(output_buffer->data()); | 109 uint8_t* next_out = bit_cast<uint8_t*>(output_buffer->data()); |
107 size_t available_out = output_buffer_size; | 110 size_t available_out = output_buffer_size; |
108 size_t total_out = 0; | |
109 // Check if start of the input stream looks like gzip stream. | 111 // Check if start of the input stream looks like gzip stream. |
110 for (size_t i = consumed_bytes_; i < sizeof(kGzipHeader); ++i) { | 112 for (size_t i = consumed_bytes_; i < sizeof(kGzipHeader); ++i) { |
111 if (!gzip_header_detected_) | 113 if (!gzip_header_detected_) |
112 break; | 114 break; |
113 size_t j = i - consumed_bytes_; | 115 size_t j = i - consumed_bytes_; |
114 if (j < available_in && kGzipHeader[i] != next_in[j]) | 116 if (j < available_in && kGzipHeader[i] != next_in[j]) |
115 gzip_header_detected_ = false; | 117 gzip_header_detected_ = false; |
116 } | 118 } |
117 | 119 |
118 BrotliResult result = | 120 BrotliDecoderResult result = |
119 BrotliDecompressStream(&available_in, &next_in, &available_out, | 121 BrotliDecoderDecompressStream(brotli_state_, &available_in, &next_in, |
120 &next_out, &total_out, brotli_state_); | 122 &available_out, &next_out, nullptr); |
121 | 123 |
122 size_t bytes_used = input_buffer_size - available_in; | 124 size_t bytes_used = input_buffer_size - available_in; |
123 size_t bytes_written = output_buffer_size - available_out; | 125 size_t bytes_written = output_buffer_size - available_out; |
124 CHECK_GE(bytes_used, 0u); | 126 CHECK_GE(bytes_used, 0u); |
125 CHECK_GE(bytes_written, 0u); | 127 CHECK_GE(bytes_written, 0u); |
126 produced_bytes_ += bytes_written; | 128 produced_bytes_ += bytes_written; |
127 consumed_bytes_ += bytes_used; | 129 consumed_bytes_ += bytes_used; |
128 | 130 |
129 *consumed_bytes = bytes_used; | 131 *consumed_bytes = bytes_used; |
130 | 132 |
131 switch (result) { | 133 switch (result) { |
132 case BROTLI_RESULT_NEEDS_MORE_OUTPUT: | 134 case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: |
133 return bytes_written; | 135 return bytes_written; |
134 case BROTLI_RESULT_SUCCESS: | 136 case BROTLI_DECODER_RESULT_SUCCESS: |
135 decoding_status_ = DecodingStatus::DECODING_DONE; | 137 decoding_status_ = DecodingStatus::DECODING_DONE; |
136 // Consume remaining bytes to avoid DCHECK in FilterSourceStream. | 138 // Consume remaining bytes to avoid DCHECK in FilterSourceStream. |
137 // See crbug.com/659311. | 139 // See crbug.com/659311. |
138 *consumed_bytes = input_buffer_size; | 140 *consumed_bytes = input_buffer_size; |
139 return bytes_written; | 141 return bytes_written; |
140 case BROTLI_RESULT_NEEDS_MORE_INPUT: | 142 case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: |
141 // Decompress needs more input has consumed all existing input. | 143 // Decompress needs more input has consumed all existing input. |
142 DCHECK_EQ(*consumed_bytes, input_buffer_size); | 144 DCHECK_EQ(*consumed_bytes, input_buffer_size); |
143 decoding_status_ = DecodingStatus::DECODING_IN_PROGRESS; | 145 decoding_status_ = DecodingStatus::DECODING_IN_PROGRESS; |
144 return bytes_written; | 146 return bytes_written; |
145 // If the decompressor threw an error, fail synchronously. | 147 // If the decompressor threw an error, fail synchronously. |
146 default: | 148 default: |
147 decoding_status_ = DecodingStatus::DECODING_ERROR; | 149 decoding_status_ = DecodingStatus::DECODING_ERROR; |
148 return ERR_CONTENT_DECODING_FAILED; | 150 return ERR_CONTENT_DECODING_FAILED; |
149 } | 151 } |
150 } | 152 } |
(...skipping 20 matching lines...) Expand all Loading... |
171 } | 173 } |
172 | 174 |
173 void FreeMemoryInternal(void* address) { | 175 void FreeMemoryInternal(void* address) { |
174 if (!address) | 176 if (!address) |
175 return; | 177 return; |
176 size_t* array = reinterpret_cast<size_t*>(address); | 178 size_t* array = reinterpret_cast<size_t*>(address); |
177 used_memory_ -= array[-1]; | 179 used_memory_ -= array[-1]; |
178 free(&array[-1]); | 180 free(&array[-1]); |
179 } | 181 } |
180 | 182 |
181 BrotliState* brotli_state_; | 183 BrotliDecoderState* brotli_state_; |
182 | 184 |
183 DecodingStatus decoding_status_; | 185 DecodingStatus decoding_status_; |
184 | 186 |
185 size_t used_memory_; | 187 size_t used_memory_; |
186 size_t used_memory_maximum_; | 188 size_t used_memory_maximum_; |
187 size_t consumed_bytes_; | 189 size_t consumed_bytes_; |
188 size_t produced_bytes_; | 190 size_t produced_bytes_; |
189 | 191 |
190 bool gzip_header_detected_; | 192 bool gzip_header_detected_; |
191 | 193 |
192 DISALLOW_COPY_AND_ASSIGN(BrotliSourceStream); | 194 DISALLOW_COPY_AND_ASSIGN(BrotliSourceStream); |
193 }; | 195 }; |
194 | 196 |
195 } // namespace | 197 } // namespace |
196 | 198 |
197 std::unique_ptr<FilterSourceStream> CreateBrotliSourceStream( | 199 std::unique_ptr<FilterSourceStream> CreateBrotliSourceStream( |
198 std::unique_ptr<SourceStream> previous) { | 200 std::unique_ptr<SourceStream> previous) { |
199 return base::WrapUnique(new BrotliSourceStream(std::move(previous))); | 201 return base::WrapUnique(new BrotliSourceStream(std::move(previous))); |
200 } | 202 } |
201 | 203 |
202 } // namespace net | 204 } // namespace net |
OLD | NEW |