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

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

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

Powered by Google App Engine
This is Rietveld 408576698