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

Unified Diff: net/filter/sdch_source_stream.cc

Issue 2368433002: Add net::SdchSourceStream and net::SdchPolicyDelegate (Closed)
Patch Set: Rebased to fix compile error Created 4 years, 2 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/sdch_source_stream.cc
diff --git a/net/filter/sdch_source_stream.cc b/net/filter/sdch_source_stream.cc
new file mode 100644
index 0000000000000000000000000000000000000000..500e21eb9775ad7dd9d72a9125baba1799028482
--- /dev/null
+++ b/net/filter/sdch_source_stream.cc
@@ -0,0 +1,183 @@
+// 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/sdch_source_stream.h"
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "net/base/io_buffer.h"
+#include "sdch/open-vcdiff/src/google/vcdecoder.h"
+
+namespace net {
+
+namespace {
+
+const size_t kServerIdLength = 9;
+const char kSDCH[] = "SDCH";
+
+// Flushes as many bytes as possible from |buffered_output_ to |output_buffer|.
+// Return the number of bytes flushed.
+int FlushBufferedOutput(char* output_buffer,
+ int output_buffer_size,
+ const std::string& buffered_output) {
+ size_t to_flush = std::min(base::checked_cast<size_t>(output_buffer_size),
+ buffered_output.length());
+ memcpy(output_buffer, buffered_output.data(), to_flush);
+ return to_flush;
+}
+
+} // namespace
+
+SdchSourceStream::SdchSourceStream(std::unique_ptr<SourceStream> previous,
+ Delegate* delegate)
+ : FilterSourceStream(SourceStream::TYPE_SDCH, std::move(previous)),
+ delegate_(delegate),
+ input_state_(STATE_LOAD_DICTIONARY) {
+ CHECK(delegate);
+}
+
+SdchSourceStream::~SdchSourceStream() {}
+
+std::string SdchSourceStream::GetTypeAsString() const {
+ return kSDCH;
+}
+
+int SdchSourceStream::FilterData(IOBuffer* output_buffer,
+ int output_buffer_size,
+ IOBuffer* input_buffer,
+ int input_buffer_size,
+ int* consumed_bytes,
+ bool /*upstream_end_reached*/) {
+ DCHECK_LE(0, input_buffer_size);
+ int input_data_size = input_buffer_size;
+ char* input_data = input_buffer->data();
+ int bytes_out = 0;
+ while ((input_data_size > 0 || !buffered_output_.empty()) &&
+ output_buffer_size - bytes_out > 0) {
+ switch (input_state_) {
+ case STATE_LOAD_DICTIONARY: {
+ // Copy at most |kServerIdLength| from |input_buffer|.
+ size_t to_copy =
+ std::min(kServerIdLength - dictionary_server_id_.length(),
+ base::checked_cast<size_t>(input_data_size));
+ dictionary_server_id_.append(input_data, to_copy);
+ input_data_size -= to_copy;
+ input_data += to_copy;
+
+ // Not enough bytes for a dictionary ID accumulated yet.
+ if (dictionary_server_id_.length() != kServerIdLength) {
+ DCHECK_EQ(0, input_data_size);
+ *consumed_bytes = input_buffer_size;
+ return 0;
+ }
+ if (!CouldBeDictionaryId(dictionary_server_id_)) {
+ // If |dictionary_server_id_| is bogus, it should appear in output
+ // stream, so append it to |buffered_output_| here.
+ buffered_output_.append(dictionary_server_id_);
+ if (!HandleError(delegate_->OnDictionaryIdError(&buffered_output_))) {
+ return ERR_CONTENT_DECODING_FAILED;
+ }
+ break;
+ }
+ const std::string* dictionary_text = nullptr;
+ // To avoid passing a std::string with a null terminator into
+ // GetDictionary(), server hash here removes the last byte blindly.
+ if (!delegate_->OnGetDictionary(
+ dictionary_server_id_.substr(0, kServerIdLength - 1),
+ &dictionary_text)) {
+ // If GetDictionaryId fails and delegate chooses to pass through,
+ // preserve the dictionary id in the output.
+ buffered_output_.append(dictionary_server_id_);
+ if (!HandleError(
+ delegate_->OnGetDictionaryError(&buffered_output_))) {
+ return ERR_CONTENT_DECODING_FAILED;
+ }
+ break;
+ }
+ decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
+ decoder_->SetAllowVcdTarget(false);
+ decoder_->StartDecoding(dictionary_text->data(),
+ dictionary_text->length());
+ input_state_ = STATE_DECODE;
+ break;
+ }
+ case STATE_DECODE: {
+ int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
+ output_buffer_size - bytes_out,
+ buffered_output_);
+ buffered_output_.erase(0, flushed);
+ bytes_out += flushed;
+ if (!buffered_output_.empty())
+ break;
+ bool ok = decoder_->DecodeChunk(input_data, input_data_size,
+ &buffered_output_);
+ // Calls to DecodeChunk always consume all their input, so this always
+ // drains the entire buffer.
+ input_data += input_data_size;
+ input_data_size = 0;
+ if (!ok) {
+ decoder_.reset();
+ if (!HandleError(delegate_->OnDecodingError(&buffered_output_))) {
+ return ERR_CONTENT_DECODING_FAILED;
+ }
+ }
+ break;
+ }
+ case STATE_OUTPUT_REPLACE: {
+ int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
+ output_buffer_size - bytes_out,
+ buffered_output_);
+ buffered_output_.erase(0, flushed);
+ bytes_out += flushed;
+ break;
+ }
+ case STATE_PASS_THROUGH: {
+ int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
+ output_buffer_size - bytes_out,
+ buffered_output_);
+ buffered_output_.erase(0, flushed);
+ bytes_out += flushed;
Randy Smith (Not in Mondays) 2016/10/07 18:46:26 nit, suggestion (I don't have strong feelings here
xunjieli 2016/10/10 19:31:28 Done.
+ if (!buffered_output_.empty())
+ break;
+ size_t to_copy =
+ std::min(output_buffer_size - bytes_out, input_data_size);
+ memcpy(output_buffer->data() + bytes_out, input_data, to_copy);
+ input_data += to_copy;
+ input_data_size -= to_copy;
+ break;
+ }
+ }
+ }
+ *consumed_bytes = input_buffer_size - input_data_size;
+ return bytes_out;
+}
+
+bool SdchSourceStream::CouldBeDictionaryId(const std::string& id) const {
+ for (size_t i = 0; i < kServerIdLength - 1; i++) {
+ char base64_char = id[i];
+ if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char)
+ return false;
+ }
+ if (id[kServerIdLength - 1] != '\0')
+ return false;
+ return true;
+}
+
+bool SdchSourceStream::HandleError(Delegate::ErrorRecovery error_recover) {
+ switch (error_recover) {
+ case Delegate::NONE:
+ return false;
+ case Delegate::PASS_THROUGH:
+ input_state_ = STATE_PASS_THROUGH;
+ break;
+ case Delegate::REPLACE_OUTPUT:
+ input_state_ = STATE_OUTPUT_REPLACE;
+ break;
+ }
+ return true;
+}
+
+} // namespace net

Powered by Google App Engine
This is Rietveld 408576698