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

Unified 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: Fix a typo Created 4 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: net/filter/filter_source_stream.cc
diff --git a/net/filter/filter_source_stream.cc b/net/filter/filter_source_stream.cc
new file mode 100644
index 0000000000000000000000000000000000000000..82e6d4186084d929c9dcaf18e4a3f0e6a792ee00
--- /dev/null
+++ b/net/filter/filter_source_stream.cc
@@ -0,0 +1,157 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/filter/filter_source_stream.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_util.h"
mmenke 2016/08/18 16:18:41 include net_errors.h
xunjieli 2016/08/19 14:31:39 Done.
+
+namespace net {
+
+namespace {
+
+const size_t kBufferSize = 32 * 1024;
+
+} // namespace
+
+FilterSourceStream::FilterSourceStream(SourceType type,
+ std::unique_ptr<SourceStream> upstream)
+ : SourceStream(type),
+ upstream_(std::move(upstream)),
+ next_state_(STATE_NONE),
+ output_buffer_size_(0),
+ upstream_end_reached_(false) {
+ DCHECK(upstream_);
mmenke 2016/08/18 16:18:41 include logging.h
xunjieli 2016/08/19 14:31:39 Done.
+}
+
+FilterSourceStream::~FilterSourceStream() {}
+
+int FilterSourceStream::Read(IOBuffer* read_buffer,
+ int read_buffer_size,
+ const CompletionCallback& callback) {
+ DCHECK_EQ(STATE_NONE, next_state_);
+ DCHECK(read_buffer);
+ DCHECK_LT(0, read_buffer_size);
+
+ // Allocate a BlockBuffer during first Read().
+ if (!input_buffer_)
+ input_buffer_ = new IOBufferWithSize(kBufferSize);
+
+ if (drainable_input_buffer_ == nullptr) {
mmenke 2016/08/18 16:18:41 This check is the same as checking if !input_buffe
xunjieli 2016/08/19 14:31:39 Done. Good catch!
+ // This is first Read(), start with reading data from |upstream_|.
+ next_state_ = STATE_READ_DATA;
+ } else {
+ // Otherwise start with filtering data, which tells us whether this stream
+ // needs input data.
+ next_state_ = STATE_FILTER_DATA;
+ }
+
+ output_buffer_ = read_buffer;
+ output_buffer_size_ = read_buffer_size;
+ int rv = DoLoop(OK);
+
+ if (rv == ERR_IO_PENDING)
+ callback_ = callback;
+ return rv;
+}
+
+std::string FilterSourceStream::OrderedTypeStringList() const {
+ std::string next_type_string = upstream_->OrderedTypeStringList();
+ if (next_type_string.empty())
+ return GetTypeAsString();
+ return next_type_string + "," + GetTypeAsString();
+}
+
+int FilterSourceStream::DoLoop(int result) {
+ DCHECK_NE(STATE_NONE, next_state_);
+
+ int rv = result;
+ do {
+ State state = next_state_;
+ next_state_ = STATE_NONE;
+ switch (state) {
+ case STATE_READ_DATA:
+ rv = DoReadData();
+ break;
+ case STATE_READ_DATA_COMPLETE:
+ rv = DoReadDataComplete(rv);
+ break;
+ case STATE_FILTER_DATA:
+ DCHECK_LE(0, rv);
+ rv = DoFilterData();
+ break;
+ default:
+ NOTREACHED() << "bad state: " << state;
+ rv = ERR_UNEXPECTED;
+ break;
+ }
+ } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
+ return rv;
+}
+
+int FilterSourceStream::DoReadData() {
+ // Read more data means subclasses have consumed all input or this is the
+ // first read in which case the |drainable_input_buffer_| is not initialized.
+ DCHECK(drainable_input_buffer_ == nullptr ||
+ 0 == drainable_input_buffer_->BytesRemaining());
+
+ // Use base::Unretained here is safe because |this| owns |upstream_|.
+ int rv = upstream_->Read(input_buffer_.get(), kBufferSize,
+ base::Bind(&FilterSourceStream::OnNextReadCompleted,
+ base::Unretained(this)));
+
+ if (rv != ERR_IO_PENDING)
+ next_state_ = STATE_READ_DATA_COMPLETE;
mmenke 2016/08/18 16:18:41 The general way this is done is to unconditionally
xunjieli 2016/08/19 14:31:39 Done.
+ return rv;
+}
+
+int FilterSourceStream::DoReadDataComplete(int result) {
+ DCHECK_NE(ERR_IO_PENDING, result);
+
+ // If EOF is read (result == OK), also pass that to the the filter.
+ if (result >= OK) {
+ drainable_input_buffer_ =
+ new DrainableIOBuffer(input_buffer_.get(), result);
+ next_state_ = STATE_FILTER_DATA;
+ }
+ if (result <= OK)
+ upstream_end_reached_ = true;
+ return result;
+}
+
+void FilterSourceStream::OnNextReadCompleted(int result) {
mmenke 2016/08/18 16:18:42 DCHECK_EQ on next_state_'s value?
xunjieli 2016/08/19 14:31:39 Done.
+ next_state_ = STATE_READ_DATA_COMPLETE;
+ int rv = DoLoop(result);
+ if (rv != ERR_IO_PENDING) {
mmenke 2016/08/18 16:18:42 nit: Early is generally preferred.
xunjieli 2016/08/19 14:31:39 Done.
+ output_buffer_ = nullptr;
+ output_buffer_size_ = 0;
+
+ base::ResetAndReturn(&callback_).Run(rv);
+ }
+}
+
+int FilterSourceStream::DoFilterData() {
+ DCHECK(output_buffer_);
+ DCHECK(drainable_input_buffer_);
+
+ int bytes_output = FilterData(output_buffer_.get(), output_buffer_size_,
+ drainable_input_buffer_.get());
+ if (bytes_output == ERR_CONTENT_DECODING_FAILED) {
+ UMA_HISTOGRAM_ENUMERATION("Net.ContentDecodingFailed.FilterType", type(),
+ TYPE_MAX);
+ }
+ // FilterData() is not allowed to return ERR_IO_PENDING.
+ DCHECK_NE(ERR_IO_PENDING, bytes_output);
+
+ // If data can still be read from |upstream_| and filter did not return any
+ // data, it is likely that the filter needs more input.
+ if (bytes_output == OK && !upstream_end_reached_)
+ next_state_ = STATE_READ_DATA;
+ return bytes_output;
+}
+
+} // namespace net

Powered by Google App Engine
This is Rietveld 408576698