• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors
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/filter_source_stream.h"
6 
7 #include <utility>
8 
9 #include "base/check_op.h"
10 #include "base/containers/fixed_flat_map.h"
11 #include "base/functional/bind.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/notreached.h"
14 #include "base/numerics/safe_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "components/miracle_parameter/common/public/miracle_parameter.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/net_errors.h"
19 
20 namespace net {
21 
22 namespace {
23 
24 constexpr char kDeflate[] = "deflate";
25 constexpr char kGZip[] = "gzip";
26 constexpr char kXGZip[] = "x-gzip";
27 constexpr char kBrotli[] = "br";
28 constexpr char kZstd[] = "zstd";
29 
30 BASE_FEATURE(kBufferSizeForFilterSourceStreamFeature,
31              "BufferSizeForFilterSourceStreamFeature",
32              base::FEATURE_ENABLED_BY_DEFAULT);
33 
34 MIRACLE_PARAMETER_FOR_INT(GetBufferSizeForFilterSourceStream,
35                           kBufferSizeForFilterSourceStreamFeature,
36                           "BufferSizeForFilterSourceStream",
37                           32 * 1024)
38 
39 }  // namespace
40 
FilterSourceStream(SourceType type,std::unique_ptr<SourceStream> upstream)41 FilterSourceStream::FilterSourceStream(SourceType type,
42                                        std::unique_ptr<SourceStream> upstream)
43     : SourceStream(type), upstream_(std::move(upstream)) {
44   DCHECK(upstream_);
45 }
46 
47 FilterSourceStream::~FilterSourceStream() = default;
48 
Read(IOBuffer * read_buffer,int read_buffer_size,CompletionOnceCallback callback)49 int FilterSourceStream::Read(IOBuffer* read_buffer,
50                              int read_buffer_size,
51                              CompletionOnceCallback callback) {
52   DCHECK_EQ(STATE_NONE, next_state_);
53   DCHECK(read_buffer);
54   DCHECK_LT(0, read_buffer_size);
55 
56   // Allocate a BlockBuffer during first Read().
57   if (!input_buffer_) {
58     input_buffer_ = base::MakeRefCounted<IOBufferWithSize>(
59         GetBufferSizeForFilterSourceStream());
60     // This is first Read(), start with reading data from |upstream_|.
61     next_state_ = STATE_READ_DATA;
62   } else {
63     // Otherwise start with filtering data, which will tell us whether this
64     // stream needs input data.
65     next_state_ = STATE_FILTER_DATA;
66   }
67 
68   output_buffer_ = read_buffer;
69   output_buffer_size_ = base::checked_cast<size_t>(read_buffer_size);
70   int rv = DoLoop(OK);
71 
72   if (rv == ERR_IO_PENDING)
73     callback_ = std::move(callback);
74   return rv;
75 }
76 
Description() const77 std::string FilterSourceStream::Description() const {
78   std::string next_type_string = upstream_->Description();
79   if (next_type_string.empty())
80     return GetTypeAsString();
81   return next_type_string + "," + GetTypeAsString();
82 }
83 
MayHaveMoreBytes() const84 bool FilterSourceStream::MayHaveMoreBytes() const {
85   return !upstream_end_reached_;
86 }
87 
ParseEncodingType(const std::string & encoding)88 FilterSourceStream::SourceType FilterSourceStream::ParseEncodingType(
89     const std::string& encoding) {
90   std::string lower_encoding = base::ToLowerASCII(encoding);
91   static constexpr auto kEncodingMap =
92       base::MakeFixedFlatMap<base::StringPiece, SourceType>({
93           {"", TYPE_NONE},
94           {kBrotli, TYPE_BROTLI},
95           {kDeflate, TYPE_DEFLATE},
96           {kGZip, TYPE_GZIP},
97           {kXGZip, TYPE_GZIP},
98           {kZstd, TYPE_ZSTD},
99       });
100   auto* encoding_type = kEncodingMap.find(lower_encoding);
101   if (encoding_type == kEncodingMap.end()) {
102     return TYPE_UNKNOWN;
103   }
104   return encoding_type->second;
105 }
106 
DoLoop(int result)107 int FilterSourceStream::DoLoop(int result) {
108   DCHECK_NE(STATE_NONE, next_state_);
109 
110   int rv = result;
111   do {
112     State state = next_state_;
113     next_state_ = STATE_NONE;
114     switch (state) {
115       case STATE_READ_DATA:
116         rv = DoReadData();
117         break;
118       case STATE_READ_DATA_COMPLETE:
119         rv = DoReadDataComplete(rv);
120         break;
121       case STATE_FILTER_DATA:
122         DCHECK_LE(0, rv);
123         rv = DoFilterData();
124         break;
125       default:
126         NOTREACHED() << "bad state: " << state;
127         rv = ERR_UNEXPECTED;
128         break;
129     }
130   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
131   return rv;
132 }
133 
DoReadData()134 int FilterSourceStream::DoReadData() {
135   // Read more data means subclasses have consumed all input or this is the
136   // first read in which case the |drainable_input_buffer_| is not initialized.
137   DCHECK(drainable_input_buffer_ == nullptr ||
138          0 == drainable_input_buffer_->BytesRemaining());
139 
140   next_state_ = STATE_READ_DATA_COMPLETE;
141   // Use base::Unretained here is safe because |this| owns |upstream_|.
142   int rv =
143       upstream_->Read(input_buffer_.get(), GetBufferSizeForFilterSourceStream(),
144                       base::BindOnce(&FilterSourceStream::OnIOComplete,
145                                      base::Unretained(this)));
146 
147   return rv;
148 }
149 
DoReadDataComplete(int result)150 int FilterSourceStream::DoReadDataComplete(int result) {
151   DCHECK_NE(ERR_IO_PENDING, result);
152 
153   if (result >= OK) {
154     drainable_input_buffer_ =
155         base::MakeRefCounted<DrainableIOBuffer>(input_buffer_, result);
156     next_state_ = STATE_FILTER_DATA;
157   }
158   if (result <= OK)
159     upstream_end_reached_ = true;
160   return result;
161 }
162 
DoFilterData()163 int FilterSourceStream::DoFilterData() {
164   DCHECK(output_buffer_);
165   DCHECK(drainable_input_buffer_);
166 
167   size_t consumed_bytes = 0;
168   base::expected<size_t, Error> bytes_output = FilterData(
169       output_buffer_.get(), output_buffer_size_, drainable_input_buffer_.get(),
170       drainable_input_buffer_->BytesRemaining(), &consumed_bytes,
171       upstream_end_reached_);
172 
173   const auto bytes_remaining =
174       base::checked_cast<size_t>(drainable_input_buffer_->BytesRemaining());
175   if (bytes_output.has_value() && bytes_output.value() == 0) {
176     DCHECK_EQ(consumed_bytes, bytes_remaining);
177   } else {
178     DCHECK_LE(consumed_bytes, bytes_remaining);
179   }
180   // FilterData() is not allowed to return ERR_IO_PENDING.
181   if (!bytes_output.has_value())
182     DCHECK_NE(ERR_IO_PENDING, bytes_output.error());
183 
184   if (consumed_bytes > 0)
185     drainable_input_buffer_->DidConsume(consumed_bytes);
186 
187   // Received data or encountered an error.
188   if (!bytes_output.has_value()) {
189     CHECK_LT(bytes_output.error(), 0);
190     return bytes_output.error();
191   }
192   if (bytes_output.value() != 0)
193     return base::checked_cast<int>(bytes_output.value());
194 
195   // If no data is returned, continue reading if |this| needs more input.
196   if (NeedMoreData()) {
197     DCHECK_EQ(0, drainable_input_buffer_->BytesRemaining());
198     next_state_ = STATE_READ_DATA;
199   }
200   return 0;
201 }
202 
OnIOComplete(int result)203 void FilterSourceStream::OnIOComplete(int result) {
204   DCHECK_EQ(STATE_READ_DATA_COMPLETE, next_state_);
205 
206   int rv = DoLoop(result);
207   if (rv == ERR_IO_PENDING)
208     return;
209 
210   output_buffer_ = nullptr;
211   output_buffer_size_ = 0;
212 
213   std::move(callback_).Run(rv);
214 }
215 
NeedMoreData() const216 bool FilterSourceStream::NeedMoreData() const {
217   return !upstream_end_reached_;
218 }
219 
220 }  // namespace net
221