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

Side by Side 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 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 // Flushes as many bytes as possible from |buffered_output_ to |output_buffer|.
22 // Return the number of bytes flushed.
23 int FlushBufferedOutput(char* output_buffer,
24 int output_buffer_size,
25 const std::string& buffered_output) {
26 size_t to_flush = std::min(base::checked_cast<size_t>(output_buffer_size),
27 buffered_output.length());
28 memcpy(output_buffer, buffered_output.data(), to_flush);
29 return to_flush;
30 }
31
32 } // namespace
33
34 SdchSourceStream::SdchSourceStream(std::unique_ptr<SourceStream> previous,
35 Delegate* delegate)
36 : FilterSourceStream(SourceStream::TYPE_SDCH, std::move(previous)),
37 delegate_(delegate),
38 input_state_(STATE_LOAD_DICTIONARY) {
39 CHECK(delegate);
40 }
41
42 SdchSourceStream::~SdchSourceStream() {}
43
44 std::string SdchSourceStream::GetTypeAsString() const {
45 return kSDCH;
46 }
47
48 int SdchSourceStream::FilterData(IOBuffer* output_buffer,
49 int output_buffer_size,
50 IOBuffer* input_buffer,
51 int input_buffer_size,
52 int* consumed_bytes,
53 bool /*upstream_end_reached*/) {
54 DCHECK_LE(0, input_buffer_size);
55 int input_data_size = input_buffer_size;
56 char* input_data = input_buffer->data();
57 int bytes_out = 0;
58 while ((input_data_size > 0 || !buffered_output_.empty()) &&
59 output_buffer_size - bytes_out > 0) {
60 switch (input_state_) {
61 case STATE_LOAD_DICTIONARY: {
62 // Copy at most |kServerIdLength| from |input_buffer|.
63 size_t to_copy =
64 std::min(kServerIdLength - dictionary_server_id_.length(),
65 base::checked_cast<size_t>(input_data_size));
66 dictionary_server_id_.append(input_data, to_copy);
67 input_data_size -= to_copy;
68 input_data += to_copy;
69
70 // Not enough bytes for a dictionary ID accumulated yet.
71 if (dictionary_server_id_.length() != kServerIdLength) {
72 DCHECK_EQ(0, input_data_size);
73 *consumed_bytes = input_buffer_size;
74 return 0;
75 }
76 if (!CouldBeDictionaryId(dictionary_server_id_)) {
77 // If |dictionary_server_id_| is bogus, it should appear in output
78 // stream, so append it to |buffered_output_| here.
79 buffered_output_.append(dictionary_server_id_);
80 if (!HandleError(delegate_->OnDictionaryIdError(&buffered_output_))) {
81 return ERR_CONTENT_DECODING_FAILED;
82 }
83 break;
84 }
85 const std::string* dictionary_text = nullptr;
86 // To avoid passing a std::string with a null terminator into
87 // GetDictionary(), server hash here removes the last byte blindly.
88 if (!delegate_->OnGetDictionary(
89 dictionary_server_id_.substr(0, kServerIdLength - 1),
90 &dictionary_text)) {
91 // If GetDictionaryId fails and delegate chooses to pass through,
92 // preserve the dictionary id in the output.
93 buffered_output_.append(dictionary_server_id_);
94 if (!HandleError(
95 delegate_->OnGetDictionaryError(&buffered_output_))) {
96 return ERR_CONTENT_DECODING_FAILED;
97 }
98 break;
99 }
100 decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
101 decoder_->SetAllowVcdTarget(false);
102 decoder_->StartDecoding(dictionary_text->data(),
103 dictionary_text->length());
104 input_state_ = STATE_DECODE;
105 break;
106 }
107 case STATE_DECODE: {
108 int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
109 output_buffer_size - bytes_out,
110 buffered_output_);
111 buffered_output_.erase(0, flushed);
112 bytes_out += flushed;
113 if (!buffered_output_.empty())
114 break;
115 bool ok = decoder_->DecodeChunk(input_data, input_data_size,
116 &buffered_output_);
117 // Calls to DecodeChunk always consume all their input, so this always
118 // drains the entire buffer.
119 input_data += input_data_size;
120 input_data_size = 0;
121 if (!ok) {
122 decoder_.reset();
123 if (!HandleError(delegate_->OnDecodingError(&buffered_output_))) {
124 return ERR_CONTENT_DECODING_FAILED;
125 }
126 }
127 break;
128 }
129 case STATE_OUTPUT_REPLACE: {
130 int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
131 output_buffer_size - bytes_out,
132 buffered_output_);
133 buffered_output_.erase(0, flushed);
134 bytes_out += flushed;
135 break;
136 }
137 case STATE_PASS_THROUGH: {
138 int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
139 output_buffer_size - bytes_out,
140 buffered_output_);
141 buffered_output_.erase(0, flushed);
142 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.
143 if (!buffered_output_.empty())
144 break;
145 size_t to_copy =
146 std::min(output_buffer_size - bytes_out, input_data_size);
147 memcpy(output_buffer->data() + bytes_out, input_data, to_copy);
148 input_data += to_copy;
149 input_data_size -= to_copy;
150 break;
151 }
152 }
153 }
154 *consumed_bytes = input_buffer_size - input_data_size;
155 return bytes_out;
156 }
157
158 bool SdchSourceStream::CouldBeDictionaryId(const std::string& id) const {
159 for (size_t i = 0; i < kServerIdLength - 1; i++) {
160 char base64_char = id[i];
161 if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char)
162 return false;
163 }
164 if (id[kServerIdLength - 1] != '\0')
165 return false;
166 return true;
167 }
168
169 bool SdchSourceStream::HandleError(Delegate::ErrorRecovery error_recover) {
170 switch (error_recover) {
171 case Delegate::NONE:
172 return false;
173 case Delegate::PASS_THROUGH:
174 input_state_ = STATE_PASS_THROUGH;
175 break;
176 case Delegate::REPLACE_OUTPUT:
177 input_state_ = STATE_OUTPUT_REPLACE;
178 break;
179 }
180 return true;
181 }
182
183 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698