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