Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/filter/brotli_stream_source.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/bit_cast.h" | |
| 9 #include "base/memory/ptr_util.h" | |
| 10 #include "base/metrics/histogram_macros.h" | |
| 11 | |
| 12 namespace net { | |
| 13 | |
| 14 namespace { | |
| 15 | |
| 16 const char kBrotli[] = "br"; | |
| 17 | |
| 18 } // namespace | |
| 19 | |
| 20 class BrotliStreamSource : public FilterStreamSource { | |
|
mmenke
2016/07/21 18:14:07
This should be in an anonymous namespace.
xunjieli
2016/07/27 20:32:01
Done.
| |
| 21 public: | |
| 22 BrotliStreamSource(std::unique_ptr<StreamSource> previous) | |
|
mmenke
2016/07/21 18:14:07
explicit
xunjieli
2016/07/27 20:32:01
Done.
| |
| 23 : FilterStreamSource(StreamSource::TYPE_BROTLI, std::move(previous)), | |
| 24 decoding_status_(DecodingStatus::DECODING_IN_PROGRESS), | |
| 25 used_memory_(0), | |
| 26 used_memory_maximum_(0), | |
| 27 produced_bytes_(0), | |
| 28 consumed_bytes_(0) { | |
| 29 brotli_state_ = BrotliCreateState(AllocateMemory, FreeMemory, this); | |
| 30 CHECK(brotli_state_); | |
|
mmenke
2016/07/21 18:14:07
include base/logging.h
xunjieli
2016/07/27 20:32:01
Done.
| |
| 31 } | |
| 32 | |
| 33 ~BrotliStreamSource() override { | |
| 34 BrotliDestroyState(brotli_state_); | |
| 35 brotli_state_ = nullptr; | |
| 36 DCHECK(used_memory_ == 0); | |
|
mmenke
2016/07/21 18:14:08
DCHECK_EQ
xunjieli
2016/07/27 20:32:00
Done.
| |
| 37 | |
| 38 UMA_HISTOGRAM_ENUMERATION( | |
| 39 "BrotliFilter.Status", static_cast<int>(decoding_status_), | |
| 40 static_cast<int>(DecodingStatus::DECODING_STATUS_COUNT)); | |
| 41 if (decoding_status_ == DecodingStatus::DECODING_DONE) { | |
| 42 // CompressionPercent is undefined when there is no output produced. | |
| 43 if (produced_bytes_ != 0) { | |
| 44 UMA_HISTOGRAM_PERCENTAGE( | |
| 45 "BrotliFilter.CompressionPercent", | |
| 46 static_cast<int>((consumed_bytes_ * 100) / produced_bytes_)); | |
| 47 } | |
| 48 } | |
| 49 // All code here is for gathering stats, and can be removed when | |
| 50 // BrotliStreamSource is considered stable. | |
| 51 static const int kBuckets = 48; | |
| 52 static const int64_t kMaxKb = 1 << (kBuckets / 3); // 64MiB in KiB | |
|
mmenke
2016/07/21 18:14:07
Think it's preferred not to use static on local co
xunjieli
2016/07/27 20:32:01
Done.
| |
| 53 UMA_HISTOGRAM_CUSTOM_COUNTS("BrotliFilter.UsedMemoryKB", | |
| 54 used_memory_maximum_ / 1024, 1, kMaxKb, | |
| 55 kBuckets); | |
| 56 } | |
| 57 | |
| 58 private: | |
| 59 // Reported in UMA and must be kept in sync with the histograms.xml file. | |
| 60 enum class DecodingStatus : int { | |
| 61 DECODING_IN_PROGRESS = 0, | |
| 62 DECODING_DONE, | |
| 63 DECODING_ERROR, | |
| 64 | |
| 65 DECODING_STATUS_COUNT | |
| 66 // DECODING_STATUS_COUNT must always be the last element in this enum. | |
| 67 }; | |
| 68 | |
| 69 // StreamSource implementation | |
| 70 std::string GetTypeAsString() const override { return kBrotli; } | |
| 71 | |
| 72 int FilterData(IOBuffer* output_buffer, | |
| 73 size_t output_buffer_size, | |
| 74 DrainableIOBuffer* input_buffer) override { | |
| 75 const uint8_t* next_in = bit_cast<uint8_t*>(input_buffer->data()); | |
| 76 size_t available_in = input_buffer->BytesRemaining(); | |
| 77 uint8_t* next_out = bit_cast<uint8_t*>(output_buffer->data()); | |
| 78 size_t available_out = output_buffer_size; | |
| 79 size_t total_out = 0; | |
| 80 BrotliResult result = | |
| 81 BrotliDecompressStream(&available_in, &next_in, &available_out, | |
| 82 &next_out, &total_out, brotli_state_); | |
| 83 | |
| 84 size_t bytes_used = input_buffer->BytesRemaining() - available_in; | |
| 85 size_t bytes_written = output_buffer_size - available_out; | |
| 86 CHECK_GE(bytes_used, 0u); | |
| 87 CHECK_GE(bytes_written, 0u); | |
| 88 produced_bytes_ += bytes_written; | |
| 89 consumed_bytes_ += bytes_used; | |
| 90 | |
| 91 input_buffer->DidConsume(bytes_used); | |
| 92 | |
| 93 switch (result) { | |
| 94 case BROTLI_RESULT_NEEDS_MORE_OUTPUT: | |
| 95 // Fall through. | |
| 96 case BROTLI_RESULT_SUCCESS: | |
| 97 decoding_status_ = DecodingStatus::DECODING_DONE; | |
| 98 return bytes_written; | |
| 99 case BROTLI_RESULT_NEEDS_MORE_INPUT: | |
| 100 decoding_status_ = DecodingStatus::DECODING_IN_PROGRESS; | |
| 101 break; | |
| 102 // If the decompressor threw an error, fail synchronously. | |
| 103 default: | |
| 104 decoding_status_ = DecodingStatus::DECODING_ERROR; | |
| 105 return ERR_CONTENT_DECODING_FAILED; | |
| 106 } | |
| 107 | |
| 108 DCHECK_EQ(BROTLI_RESULT_NEEDS_MORE_INPUT, result); | |
| 109 // Decompress needs more input has consumed all existing input. | |
| 110 DCHECK_EQ(0, input_buffer->BytesRemaining()); | |
| 111 | |
| 112 return bytes_written; | |
| 113 } | |
| 114 | |
| 115 static void* AllocateMemory(void* opaque, size_t size) { | |
| 116 BrotliStreamSource* filter = reinterpret_cast<BrotliStreamSource*>(opaque); | |
| 117 return filter->AllocateMemoryInternal(size); | |
| 118 } | |
| 119 | |
| 120 static void FreeMemory(void* opaque, void* address) { | |
| 121 BrotliStreamSource* filter = reinterpret_cast<BrotliStreamSource*>(opaque); | |
| 122 filter->FreeMemoryInternal(address); | |
| 123 } | |
| 124 | |
| 125 void* AllocateMemoryInternal(size_t size) { | |
| 126 size_t* array = reinterpret_cast<size_t*>(malloc(size + sizeof(size_t))); | |
| 127 if (!array) | |
| 128 return nullptr; | |
| 129 used_memory_ += size; | |
| 130 if (used_memory_maximum_ < used_memory_) | |
| 131 used_memory_maximum_ = used_memory_; | |
| 132 array[0] = size; | |
| 133 return &array[1]; | |
| 134 } | |
| 135 | |
| 136 void FreeMemoryInternal(void* address) { | |
| 137 if (!address) | |
| 138 return; | |
| 139 size_t* array = reinterpret_cast<size_t*>(address); | |
| 140 used_memory_ -= array[-1]; | |
| 141 free(&array[-1]); | |
| 142 } | |
| 143 | |
| 144 BrotliState* brotli_state_; | |
| 145 | |
| 146 DecodingStatus decoding_status_; | |
| 147 | |
| 148 size_t used_memory_; | |
| 149 size_t used_memory_maximum_; | |
| 150 size_t produced_bytes_; | |
| 151 size_t consumed_bytes_; | |
| 152 | |
| 153 DISALLOW_COPY_AND_ASSIGN(BrotliStreamSource); | |
| 154 }; | |
| 155 | |
| 156 std::unique_ptr<FilterStreamSource> CreateBrotliStreamSource( | |
| 157 std::unique_ptr<StreamSource> previous) { | |
| 158 return base::WrapUnique(new BrotliStreamSource(std::move(previous))); | |
| 159 } | |
| 160 | |
| 161 } // namespace net | |
| OLD | NEW |