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