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

Side by Side Diff: net/filter/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: Refactor common logic Created 4 years, 9 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/stream_source.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/strings/string_util.h"
10 #include "net/filter/block_buffer.h"
11 #include "net/filter/brotli_stream_source.h"
12 #include "net/filter/gzip_stream_source.h"
13 #include "net/filter/sdch_stream_source.h"
14
15 namespace net {
16
17 namespace {
18
19 const char kDeflate[] = "deflate";
20 const char kGZip[] = "gzip";
21 const char kSdch[] = "sdch";
22 const char kXGZip[] = "x-gzip";
23 const char kBrotli[] = "br";
24
25 std::vector<StreamSource::SourceType> SourceTypeNamesToTypes(
26 const std::vector<std::string>& types) {
27 std::vector<StreamSource::SourceType> result;
28 for (const auto& type : types) {
29 if (base::LowerCaseEqualsASCII(type, kBrotli)) {
30 result.push_back(StreamSource::SOURCE_BROTLI);
31 } else if (base::LowerCaseEqualsASCII(type, kDeflate)) {
32 result.push_back(StreamSource::SOURCE_DEFLATE);
33 } else if (base::LowerCaseEqualsASCII(type, kGZip) ||
34 base::LowerCaseEqualsASCII(type, kXGZip)) {
35 result.push_back(StreamSource::SOURCE_GZIP);
36 } else if (base::LowerCaseEqualsASCII(type, kSdch)) {
37 result.push_back(StreamSource::SOURCE_SDCH);
38 }
39 }
mmenke 2016/03/04 21:15:57 If we see an unrecognized scheme, we should just g
Randy Smith (Not in Mondays) 2016/03/09 23:03:56 Define "give up"? The current behavior (which I d
mmenke 2016/03/09 23:11:50 That's what I meant by "give up". :)
xunjieli 2016/04/20 19:16:10 Acknowledged.
40 return result;
41 }
42
43 std::string SourceTypeAsString(StreamSource::SourceType type) {
44 switch (type) {
45 case StreamSource::SOURCE_BROTLI:
mmenke 2016/03/04 21:15:57 We presumably won't change these often, but I sugg
xunjieli 2016/04/20 19:16:09 Done.
46 return "SOURCE_TYPE_BROTLI";
47 case StreamSource::SOURCE_DEFLATE:
48 return "SOURCE_TYPE_DEFLATE";
49 case StreamSource::SOURCE_GZIP:
50 return "SOURCE_TYPE_GZIP";
51 case StreamSource::SOURCE_SDCH:
52 return "SOURCE_TYPE_SDCH";
53 case StreamSource::SOURCE_GZIP_FALLBACK:
54 return "SOURCE_TYPE_GZIP_FALLBACK";
55 case StreamSource::SOURCE_INVALID:
56 return "SOURCE_TYPE_INVALID";
57 case StreamSource::SOURCE_NONE:
58 return "SOURCE_TYPE_NONE";
59 }
mmenke 2016/03/04 21:15:56 NOTREACHED()?
xunjieli 2016/04/20 19:16:09 Done.
60 return "";
61 }
62
63 scoped_ptr<StreamSource> BuildSource(scoped_ptr<StreamSource> current,
mmenke 2016/03/04 21:15:57 Randy may have an opinion here, but I think it's a
Randy Smith (Not in Mondays) 2016/03/09 23:03:56 This matches the (IMO bad for the reasons you arti
xunjieli 2016/04/20 19:16:10 Done. I moved them to a util file.
64 StreamSource::SourceType type,
65 SdchStreamSourceDelegate* delegate) {
66 if (type == StreamSource::SOURCE_BROTLI) {
67 scoped_ptr<BrotliStreamSource> next(
68 new BrotliStreamSource(std::move(current)));
69 current = std::move(next);
mmenke 2016/03/04 21:15:57 overwriting current with next seems weird. Sugges
xunjieli 2016/04/20 19:16:10 Done.
70 } else if (type == StreamSource::SOURCE_SDCH) {
71 scoped_ptr<SdchStreamSource> next(
72 new SdchStreamSource(std::move(current), delegate));
73 if (next->Init())
74 current = std::move(next);
mmenke 2016/03/04 21:15:57 On failure, just return NULL? I'd also like to se
xunjieli 2016/04/20 19:16:09 Partially DONE. How do we make SDCH's init() fail?
75 } else if (type == StreamSource::SOURCE_GZIP ||
76 type == StreamSource::SOURCE_DEFLATE ||
77 type == StreamSource::SOURCE_GZIP_FALLBACK) {
78 scoped_ptr<GzipStreamSource> next(new GzipStreamSource(std::move(current)));
79 GzipStreamSource::GzipStreamSourceMode mode =
80 type == StreamSource::SOURCE_DEFLATE
81 ? GzipStreamSource::GZIP_STREAM_SOURCE_DEFLATE
82 : GzipStreamSource::GZIP_STREAM_SOURCE_GZIP;
83 bool fallback = type == StreamSource::SOURCE_GZIP_FALLBACK;
84 if (next->Init(mode, fallback))
85 current = std::move(next);
mmenke 2016/03/04 21:15:56 On failure, just return NULL?
xunjieli 2016/04/20 19:16:09 Done.
86 }
87 return current;
88 }
89
90 } // namespace
91
92 StreamSource::StreamSource(SourceType type, scoped_ptr<StreamSource> previous)
93 : type_(type), previous_(std::move(previous)) {
94 // Initializes |buffer_| if only the stream source needs to read input data
95 // from |previous_|.
96 if (previous_)
97 buffer_.reset(new BlockBuffer());
Randy Smith (Not in Mondays) 2016/03/09 23:03:56 Could get rid of this magic here by allocating it
xunjieli 2016/04/20 19:16:10 Done.
98 }
99
100 StreamSource::~StreamSource() {}
101
102 Error StreamSource::Read(IOBuffer* dest_buffer,
103 size_t buffer_size,
104 size_t* bytes_read,
105 const OnReadCompleteCallback& callback) {
106 *bytes_read = 0;
107
108 Error error = OK;
109 while (error == OK) {
110 size_t single_bytes_read = 0;
111 error = ReadInternal(dest_buffer, buffer_size, &single_bytes_read);
112 *bytes_read += single_bytes_read;
113
114 // ReadInternal() returns synchronously or an error occurred, return right
115 // here.
116 if ((error == OK && single_bytes_read > 0) ||
117 (error != OK && error != ERR_IO_PENDING))
Randy Smith (Not in Mondays) 2016/03/09 23:03:56 Is ReadInternal *allowed* to return ERR_IO_PENDING
xunjieli 2016/04/20 19:16:09 Done.
118 return error;
119
120 // Needs more input, it has consumed all existing input.
121 DCHECK(!buffer_ || !buffer_->HasMoreBytes());
122
123 if (!previous_)
124 break;
mmenke 2016/03/04 21:15:57 This previous_ magic (And the magic in the constru
Randy Smith (Not in Mondays) 2016/03/09 23:03:56 Based on my current understanding, I'd prefer the
xunjieli 2016/04/20 19:16:09 Done.
xunjieli 2016/04/20 19:16:09 Done.
125
126 // Dispatch a read to refill the input buffer.
127 size_t previous_bytes_read = 0;
128 error = previous_->Read(
129 buffer_->buffer(), buffer_->size(), &previous_bytes_read,
130 base::Bind(&StreamSource::OnReadComplete, base::Unretained(this),
Randy Smith (Not in Mondays) 2016/03/09 23:03:56 nit, knee-jerk response: Use of Unretained should
xunjieli 2016/04/20 19:16:10 Done.
131 base::Unretained(dest_buffer), buffer_size));
132
133 // OK with 0 bytes read means EOF. Since the buffer is already empty, and
134 // Decompress already failed to return any more data, this source is also
Randy Smith (Not in Mondays) 2016/03/09 23:03:56 nit: I think you mean ReadInternal, not Decompress
xunjieli 2016/04/20 19:16:10 Done.
135 // at EOF. Just return that synchronously.
136 if (error == OK && previous_bytes_read == 0)
137 return OK;
138
139 // If the underlying read completed synchronously, mark the buffer as
140 // refilled and try again.
141 if (error == OK)
142 buffer_->WasRefilled(previous_bytes_read);
143 }
144
145 DCHECK(!buffer_ || !buffer_->HasMoreBytes());
146
147 if (error == ERR_IO_PENDING) {
148 callback_ = callback;
149 pending_read_buffer_ = dest_buffer;
mmenke 2016/03/04 21:15:57 Hrm...seems a little weird to set these when this
Randy Smith (Not in Mondays) 2016/03/09 23:03:56 No, I think I agree. I'd vote for making the call
xunjieli 2016/04/20 19:16:10 Done.
xunjieli 2016/04/20 19:16:10 Done.
150 }
151 return error;
152 }
153
154 void StreamSource::OnReadComplete(IOBuffer* dest_buffer,
155 size_t dest_buffer_size,
156 Error error,
157 size_t bytes_read) {
158 DCHECK(!buffer_ || !buffer_->HasMoreBytes());
159 DCHECK_EQ(dest_buffer, pending_read_buffer_.get());
160 DCHECK(!callback_.is_null());
161
162 // Take a ref for the lifetime of this function.
163 scoped_refptr<IOBuffer> dest_ref(dest_buffer);
164 pending_read_buffer_ = nullptr;
165
166 // If the underlying read failed, fail this read directly.
167 if (error != OK) {
168 base::ResetAndReturn(&callback_).Run(error, bytes_read);
169 return;
170 }
171
172 if (bytes_read == 0) {
173 // EOF. Since the buffer is empty, there is no more data to decompress (any
174 // internally buffered data would have been drained already before calling
175 // the previous stream's Read). Return EOF to our caller.
176 if (!callback_.is_null()) {
mmenke 2016/03/04 21:15:56 Why check this here, but not in the "error != OK"
xunjieli 2016/04/20 19:16:10 Done.
177 base::ResetAndReturn(&callback_).Run(error, bytes_read);
178 }
179 return;
180 }
181
182 // Mark the buffer as refilled and try decompressing.
183 buffer_->WasRefilled(bytes_read);
184
185 // Recurse. Read runs the callback if completes synchronously,
Randy Smith (Not in Mondays) 2016/03/09 23:03:56 I think this comment is wrong? The code is callin
xunjieli 2016/04/20 19:16:10 Done.
186 // Otherwise, Read will have posted an asynchronous read that
187 // will later re-invoke OnReadComplete to run the callback.
188 error = Read(dest_buffer, dest_buffer_size, &bytes_read, callback_);
189 if (error != ERR_IO_PENDING)
190 base::ResetAndReturn(&callback_).Run(error, bytes_read);
191 }
192
193 scoped_ptr<StreamSource> StreamSource::BuildSourceChain(
194 scoped_ptr<StreamSource> current,
195 const std::vector<std::string>& type_names,
196 SdchStreamSourceDelegate* sdch_delegate) {
mmenke 2016/03/04 21:15:56 Suggest just passing in the headers, and walking t
xunjieli 2016/04/20 19:16:10 Done.
197 std::vector<SourceType> types = SourceTypeNamesToTypes(type_names);
198
199 // SDCH-specific hack: if the first filter is SDCH, add a gzip filter in front
200 // of it in fallback mode.
201 if (!types.empty() && types.at(0) == SOURCE_SDCH)
202 types.insert(types.begin(), SOURCE_GZIP_FALLBACK);
203
204 for (const auto& type : types) {
205 current = BuildSource(std::move(current), type, sdch_delegate);
206 if (current == nullptr)
207 return nullptr;
208 }
209
210 return current;
211 }
212
213 std::string StreamSource::OrderedStreamSourceList() const {
214 if (previous_) {
215 return SourceTypeAsString(type_) + "," +
216 previous_->OrderedStreamSourceList();
217 } else {
218 return SourceTypeAsString(type_);
219 }
220 }
221
222 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698