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

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

Issue 2368433002: Add net::SdchSourceStream and net::SdchPolicyDelegate (Closed)
Patch Set: tidy up tests 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 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/sdch_source_stream.h"
6
7 #include "base/auto_reset.h"
8 #include "base/bind.h"
9 #include "base/logging.h"
10 #include "base/numerics/safe_conversions.h"
11 #include "net/base/io_buffer.h"
12 #include "sdch/open-vcdiff/src/google/vcdecoder.h"
13
14 namespace net {
15
16 namespace {
17
18 const size_t kServerIdLength = 9;
19 const char kSDCH[] = "SDCH";
20
21 } // namespace
22
23 SdchSourceStream::SdchSourceStream(std::unique_ptr<SourceStream> previous,
24 Delegate* delegate)
25 : FilterSourceStream(SourceStream::TYPE_SDCH, std::move(previous)),
26 delegate_(delegate),
27 output_replaced_(false),
28 passthrough_(false),
29 input_state_(STATE_LOAD_DICTIONARY) {
30 CHECK(delegate);
31 }
32
33 SdchSourceStream::~SdchSourceStream() {}
34
35 void SdchSourceStream::StopDecoding() {
36 DCHECK(in_delegate_handler_);
37 passthrough_ = true;
Randy Smith (Not in Mondays) 2016/09/27 20:09:13 For reasons we've sorta explored in the gzip CL, I
xunjieli 2016/09/30 15:32:17 Done. The pass-through case is a bit tricky. If th
38 }
39
40 void SdchSourceStream::ReplaceOutput(const char* data, size_t size) {
41 DCHECK(in_delegate_handler_);
42 output_replaced_ = true;
43 buffered_output_.assign(data, size);
44 }
45
46 std::string SdchSourceStream::GetTypeAsString() const {
47 return kSDCH;
48 }
49
50 int SdchSourceStream::FilterData(IOBuffer* output_buffer,
51 int output_buffer_size,
52 IOBuffer* input_buffer,
53 int input_buffer_size,
54 int* consumed_bytes,
55 bool /*upstream_end_reached*/) {
56 DCHECK_LE(0, input_buffer_size);
57 size_t input_data_size = input_buffer_size;
58 char* input_data = input_buffer->data();
59 int bytes_out = 0;
60 while (true) {
61 InputState state = input_state_;
Randy Smith (Not in Mondays) 2016/09/27 20:09:13 Why the separate variable? It seems like it's onl
xunjieli 2016/09/30 15:32:18 Done.
62 switch (state) {
Randy Smith (Not in Mondays) 2016/09/27 20:09:13 nit, suggestion: Order these states (here and in t
xunjieli 2016/09/30 15:32:18 Done.
63 case STATE_LOAD_DICTIONARY: {
64 // Copy at most |kServerIdLength| from |input_buffer|.
65 size_t to_copy = std::min(kServerIdLength - dictionary_id_.length(),
66 input_data_size);
67 dictionary_id_.append(input_data, to_copy);
68 input_data_size -= to_copy;
69 input_data += to_copy;
70
71 // Not enough bytes for a dictionary ID accumulated yet.
72 if (dictionary_id_.length() != kServerIdLength) {
73 *consumed_bytes = input_buffer_size - input_data_size;
74 return 0;
75 }
76 // To avoid passing a std::string with a null terminator into
77 // GetDictionary(), |server_hash| here removes the last byte blindly,
78 // and this method only calls GetDictionary() with it if
79 // CouldBeDictionaryId() returns true.
80 std::string server_hash = dictionary_id_.substr(0, kServerIdLength - 1);
Randy Smith (Not in Mondays) 2016/09/27 20:09:13 nit, suggestion: server_hash only appears to be us
xunjieli 2016/09/30 15:32:18 Done.
81 const std::string* dictionary_text = nullptr;
82 if (!CouldBeDictionaryId(dictionary_id_) ||
83 !delegate_->OnGetDictionary(server_hash, &dictionary_text)) {
84 input_data_size = 0;
85 buffered_output_.append(dictionary_id_);
86 bool handled = AskDelegateToHandleDictionaryError();
87 if (!handled)
88 return ERR_CONTENT_DECODING_FAILED;
89 input_state_ = STATE_HANDLE_ERROR;
90 break;
91 }
92 decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
93 decoder_->SetAllowVcdTarget(false);
94 decoder_->StartDecoding(dictionary_text->data(),
95 dictionary_text->length());
96 input_state_ = STATE_DECODE;
97 break;
98 }
99 case STATE_FLUSH_INTERNAL_BUFFER: {
100 size_t to_copy =
101 std::min(base::checked_cast<size_t>(output_buffer_size - bytes_out),
102 buffered_output_.length());
103 memcpy(output_buffer->data() + bytes_out, buffered_output_.data(),
104 to_copy);
105 buffered_output_.erase(0, to_copy);
106 bytes_out += to_copy;
107 if (!buffered_output_.empty()) {
108 *consumed_bytes = input_buffer_size - input_data_size;
109 return bytes_out;
110 }
111 input_state_ = STATE_DECODE;
Randy Smith (Not in Mondays) 2016/09/27 20:09:13 Sorry, I'm really confused. Under what circumstan
xunjieli 2016/09/30 15:32:17 Done.FLUSH_INTERNAL_BUFFER is not an error state.
112 break;
113 }
114 case STATE_PASS_THROUGH: {
115 DCHECK(buffered_output_.empty());
116 size_t to_copy =
117 std::min(base::checked_cast<size_t>(output_buffer_size - bytes_out),
118 input_data_size);
119 memcpy(output_buffer->data() + bytes_out, input_data, to_copy);
120 input_data += to_copy;
121 input_data_size -= to_copy;
122 *consumed_bytes = input_buffer_size - input_data_size;
123 return bytes_out;
124 }
125 case STATE_HANDLE_ERROR: {
126 DCHECK(passthrough_ || output_replaced_);
127 DCHECK(!(passthrough_ && output_replaced_));
128 if (passthrough_) {
129 input_state_ = STATE_PASS_THROUGH;
130 }
131 if (output_replaced_) {
132 input_state_ = STATE_FLUSH_INTERNAL_BUFFER;
133 }
134 break;
135 }
136 case STATE_DECODE: {
137 DCHECK(buffered_output_.empty());
138 if (input_data_size == 0) {
139 *consumed_bytes = input_buffer_size - input_data_size;
140 return bytes_out;
141 }
Randy Smith (Not in Mondays) 2016/09/27 20:09:13 nit: It "feels" like this test is generic, not spe
xunjieli 2016/09/30 15:32:18 Done.
142 bool ok = decoder_->DecodeChunk(input_data, input_data_size,
143 &buffered_output_);
144 // Calls to DecodeChunk always consume all their input, so this always
145 // drains the entire buffer.
146 input_data += input_data_size;
147 input_data_size = 0;
148 if (!ok) {
149 decoder_.reset();
150 bool handled = AskDelegateToHandleDecodingError();
151 if (!handled)
152 return ERR_CONTENT_DECODING_FAILED;
153 input_state_ = STATE_HANDLE_ERROR;
154 break;
155 }
156 input_state_ = STATE_FLUSH_INTERNAL_BUFFER;
157 break;
158 }
159 }
160 }
161 NOTREACHED();
162 return ERR_UNEXPECTED;
163 }
164
165 bool SdchSourceStream::CouldBeDictionaryId(const std::string& id) const {
166 for (size_t i = 0; i < kServerIdLength - 1; i++) {
167 char base64_char = id[i];
168 if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char)
169 return false;
170 }
171 if (id[kServerIdLength - 1] != '\0')
172 return false;
173 return true;
174 }
175
176 bool SdchSourceStream::AskDelegateToHandleDictionaryError() {
177 base::AutoReset<bool> resetter(&in_delegate_handler_, true);
178 return delegate_->OnDictionaryError(this);
179 }
180
181 bool SdchSourceStream::AskDelegateToHandleDecodingError() {
182 base::AutoReset<bool> resetter(&in_delegate_handler_, true);
183 return delegate_->OnDecodingError(this);
184 }
185
186 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698