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

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

Issue 1662763002: [ON HOLD] Implement pull-based design for content decoding (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address comments Created 4 years, 8 months 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
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698