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

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

Issue 2251853002: Add net::SourceStream and net::FilterSourceStream (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address comments Created 4 years, 3 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/filter_source_stream.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
15
16 namespace net {
17
18 namespace {
19
20 const size_t kBufferSize = 32 * 1024;
21
22 } // namespace
23
24 FilterSourceStream::FilterSourceStream(SourceType type,
25 std::unique_ptr<SourceStream> upstream)
26 : SourceStream(type),
27 upstream_(std::move(upstream)),
28 next_state_(STATE_NONE),
29 output_buffer_size_(0),
30 upstream_end_reached_(false) {
31 DCHECK(upstream_);
32 }
33
34 FilterSourceStream::~FilterSourceStream() {}
35
36 int FilterSourceStream::Read(IOBuffer* read_buffer,
37 int read_buffer_size,
38 const CompletionCallback& callback) {
39 DCHECK_EQ(STATE_NONE, next_state_);
40 DCHECK(read_buffer);
41 DCHECK_LT(0, read_buffer_size);
42
43 // Allocate a BlockBuffer during first Read().
44 if (!input_buffer_) {
45 input_buffer_ = new IOBufferWithSize(kBufferSize);
46 // This is first Read(), start with reading data from |upstream_|.
47 next_state_ = STATE_READ_DATA;
48 } else {
49 // Otherwise start with filtering data, which will tell us whether this
50 // stream needs input data.
51 next_state_ = STATE_FILTER_DATA;
52 }
53
54 output_buffer_ = read_buffer;
55 output_buffer_size_ = read_buffer_size;
56 int rv = DoLoop(OK);
57
58 if (rv == ERR_IO_PENDING)
59 callback_ = callback;
60 return rv;
61 }
62
63 std::string FilterSourceStream::Description() const {
64 std::string next_type_string = upstream_->Description();
65 if (next_type_string.empty())
66 return GetTypeAsString();
67 return next_type_string + "," + GetTypeAsString();
68 }
69
70 int FilterSourceStream::DoLoop(int result) {
71 DCHECK_NE(STATE_NONE, next_state_);
72
73 int rv = result;
74 do {
75 State state = next_state_;
76 next_state_ = STATE_NONE;
77 switch (state) {
78 case STATE_READ_DATA:
79 rv = DoReadData();
80 break;
81 case STATE_READ_DATA_COMPLETE:
82 rv = DoReadDataComplete(rv);
83 break;
84 case STATE_FILTER_DATA:
85 DCHECK_LE(0, rv);
86 rv = DoFilterData();
87 break;
88 default:
89 NOTREACHED() << "bad state: " << state;
90 rv = ERR_UNEXPECTED;
91 break;
92 }
93 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
94 return rv;
95 }
96
97 int FilterSourceStream::DoReadData() {
98 // Read more data means subclasses have consumed all input or this is the
99 // first read in which case the |drainable_input_buffer_| is not initialized.
100 DCHECK(drainable_input_buffer_ == nullptr ||
101 0 == drainable_input_buffer_->BytesRemaining());
102
103 next_state_ = STATE_READ_DATA_COMPLETE;
104 // Use base::Unretained here is safe because |this| owns |upstream_|.
105 int rv = upstream_->Read(
106 input_buffer_.get(), kBufferSize,
107 base::Bind(&FilterSourceStream::OnIOComplete, base::Unretained(this)));
108
109 return rv;
110 }
111
112 int FilterSourceStream::DoReadDataComplete(int result) {
113 DCHECK_NE(ERR_IO_PENDING, result);
114
115 if (result >= OK) {
116 drainable_input_buffer_ =
117 new DrainableIOBuffer(input_buffer_.get(), result);
118 next_state_ = STATE_FILTER_DATA;
119 }
120 if (result <= OK)
121 upstream_end_reached_ = true;
122 return result;
123 }
124
125 int FilterSourceStream::DoFilterData() {
126 DCHECK(output_buffer_);
127 DCHECK(drainable_input_buffer_);
128
129 int bytes_output = FilterData(output_buffer_.get(), output_buffer_size_,
130 drainable_input_buffer_.get());
131 if (bytes_output == ERR_CONTENT_DECODING_FAILED) {
132 UMA_HISTOGRAM_ENUMERATION("Net.ContentDecodingFailed.FilterType", type(),
133 TYPE_MAX);
134 }
135 // FilterData() is not allowed to return ERR_IO_PENDING.
136 DCHECK_NE(ERR_IO_PENDING, bytes_output);
137
138 // Received data or encountered an error.
139 if (bytes_output != 0)
140 return bytes_output;
141 // If no data is returned, continue reading if |this| needs more input.
142 if (NeedMoreData()) {
143 DCHECK_EQ(0, drainable_input_buffer_->BytesRemaining());
144 next_state_ = STATE_READ_DATA;
145 }
146 return bytes_output;
147 }
148
149 void FilterSourceStream::OnIOComplete(int result) {
150 DCHECK_EQ(STATE_READ_DATA_COMPLETE, next_state_);
151
152 int rv = DoLoop(result);
153 if (rv == ERR_IO_PENDING)
154 return;
155
156 output_buffer_ = nullptr;
157 output_buffer_size_ = 0;
158
159 base::ResetAndReturn(&callback_).Run(rv);
160 }
161
162 bool FilterSourceStream::NeedMoreData() const {
163 return !upstream_end_reached_;
164 }
165
166 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698