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