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

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

Issue 2368433002: Add net::SdchSourceStream and net::SdchPolicyDelegate (Closed)
Patch Set: Make SdchPolicyDelegate owned by SdchSourceStream 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
23 // Flushes as many bytes as possible from |buffered_output_ to |output_buffer|.
24 // Return the number of bytes flushed.
25 int FlushBufferedOutput(char* output_buffer,
26 int output_buffer_size,
27 const std::string& buffered_output) {
28 size_t to_flush = std::min(base::checked_cast<size_t>(output_buffer_size),
29 buffered_output.length());
30 memcpy(output_buffer, buffered_output.data(), to_flush);
31 return to_flush;
32 }
33
34 } // namespace
35
36 SdchSourceStream::SdchSourceStream(std::unique_ptr<SourceStream> previous,
37 std::unique_ptr<Delegate> delegate,
38 SourceStream::SourceType type)
39 : FilterSourceStream(SourceStream::TYPE_SDCH, std::move(previous)),
40 delegate_(std::move(delegate)),
41 possible_pass_through_(type == SourceStream::TYPE_SDCH_POSSIBLE),
42 input_state_(STATE_LOAD_DICTIONARY) {
43 DCHECK(SourceStream::TYPE_SDCH == type ||
44 SourceStream::TYPE_SDCH_POSSIBLE == type);
45 }
46
47 SdchSourceStream::~SdchSourceStream() {
48 delegate_->OnStreamDestroyed(input_state_, buffered_output_, decoder_.get());
49 }
50
51 std::string SdchSourceStream::GetTypeAsString() const {
52 return kSDCH;
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(
88 possible_pass_through_, &buffered_output_)))
89 return ERR_CONTENT_DECODING_FAILED;
90 break;
91 }
92 const std::string* dictionary_text = nullptr;
93 // To avoid passing a std::string with a null terminator into
94 // GetDictionary(), server hash here removes the last byte blindly.
95 if (!delegate_->OnGetDictionary(
96 dictionary_server_id_.substr(0, kServerIdLength - 1),
97 &dictionary_text)) {
98 // If GetDictionaryId fails and delegate chooses to pass through,
99 // preserve the dictionary id in the output.
100 buffered_output_.append(dictionary_server_id_);
101 if (!HandleError(delegate_->OnGetDictionaryError(
102 possible_pass_through_, &buffered_output_))) {
103 return ERR_CONTENT_DECODING_FAILED;
104 }
105 break;
106 }
107 decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
108 decoder_->SetAllowVcdTarget(false);
109 decoder_->StartDecoding(dictionary_text->data(),
110 dictionary_text->length());
111 input_state_ = STATE_DECODE;
112 break;
113 }
114 case STATE_DECODE: {
115 int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
116 output_buffer_size - bytes_out,
117 buffered_output_);
118 buffered_output_.erase(0, flushed);
119 bytes_out += flushed;
120 if (!buffered_output_.empty())
121 break;
122 bool ok = decoder_->DecodeChunk(input_data, input_data_size,
123 &buffered_output_);
124 // Calls to DecodeChunk always consume all their input, so this always
125 // drains the entire buffer.
126 input_data += input_data_size;
127 input_data_size = 0;
128 if (!ok) {
129 decoder_.reset();
130 if (!HandleError(delegate_->OnDecodingError(&buffered_output_)))
131 return ERR_CONTENT_DECODING_FAILED;
132 }
133 break;
134 }
135 case STATE_OUTPUT_REPLACE: {
136 int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
137 output_buffer_size - bytes_out,
138 buffered_output_);
139 buffered_output_.erase(0, flushed);
140 bytes_out += flushed;
141 break;
142 }
143 case STATE_PASS_THROUGH: {
144 if (buffered_output_.empty())
145 break;
146 int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
147 output_buffer_size - bytes_out,
148 buffered_output_);
149 buffered_output_.erase(0, flushed);
150 bytes_out += flushed;
151 if (!buffered_output_.empty())
152 break;
153 size_t to_copy =
154 std::min(output_buffer_size - bytes_out, input_data_size);
155 memcpy(output_buffer->data() + bytes_out, input_data, to_copy);
156 input_data += to_copy;
157 input_data_size -= to_copy;
158 break;
159 }
160 }
161 }
162 *consumed_bytes = input_buffer_size - input_data_size;
163 return bytes_out;
164 }
165
166 bool SdchSourceStream::CouldBeDictionaryId(const std::string& id) const {
167 for (size_t i = 0; i < kServerIdLength - 1; i++) {
168 char base64_char = id[i];
169 if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char)
170 return false;
171 }
172 if (id[kServerIdLength - 1] != '\0')
173 return false;
174 return true;
175 }
176
177 bool SdchSourceStream::HandleError(Delegate::ErrorRecovery error_recover) {
178 switch (error_recover) {
179 case Delegate::NONE:
180 return false;
181 case Delegate::PASS_THROUGH:
182 input_state_ = STATE_PASS_THROUGH;
183 break;
184 case Delegate::REPLACE_OUTPUT:
185 input_state_ = STATE_OUTPUT_REPLACE;
186 break;
187 }
188 return true;
189 }
190
191 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698