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

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

Issue 2368433002: Add net::SdchSourceStream and net::SdchPolicyDelegate (Closed)
Patch Set: Fix histograms 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
« no previous file with comments | « net/filter/sdch_source_stream.h ('k') | net/filter/sdch_source_stream_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 bool decoding_not_finished = decoder_ && !decoder_->FinishDecoding();
46 delegate_->OnStreamDestroyed(input_state_, !buffered_output_.empty(),
47 decoding_not_finished);
48 }
49
50 std::string SdchSourceStream::GetTypeAsString() const {
51 if (type() == TYPE_SDCH)
52 return kSdch;
53 DCHECK_EQ(TYPE_SDCH_POSSIBLE, type());
54 return kSdchPossible;
55 }
56
57 int SdchSourceStream::FilterData(IOBuffer* output_buffer,
58 int output_buffer_size,
59 IOBuffer* input_buffer,
60 int input_buffer_size,
61 int* consumed_bytes,
62 bool /*upstream_end_reached*/) {
63 DCHECK_LE(0, input_buffer_size);
64 int input_data_size = input_buffer_size;
65 char* input_data = input_buffer->data();
66 int bytes_out = 0;
67 while ((input_data_size > 0 || !buffered_output_.empty()) &&
68 output_buffer_size - bytes_out > 0) {
69 switch (input_state_) {
70 case STATE_LOAD_DICTIONARY: {
71 // Copy at most |kServerIdLength| from |input_buffer|.
72 size_t to_copy =
73 std::min(kServerIdLength - dictionary_server_id_.length(),
74 base::checked_cast<size_t>(input_data_size));
75 dictionary_server_id_.append(input_data, to_copy);
76 input_data_size -= to_copy;
77 input_data += to_copy;
78
79 // Not enough bytes for a dictionary ID accumulated yet.
80 if (dictionary_server_id_.length() != kServerIdLength) {
81 DCHECK_EQ(0, input_data_size);
82 *consumed_bytes = input_buffer_size;
83 return 0;
84 }
85 if (!CouldBeDictionaryId(dictionary_server_id_)) {
86 // If |dictionary_server_id_| is bogus, it should appear in output
87 // stream, so append it to |buffered_output_| here.
88 buffered_output_.append(dictionary_server_id_);
89 if (!HandleError(delegate_->OnDictionaryIdError(&buffered_output_)))
90 return ERR_CONTENT_DECODING_FAILED;
91 break;
92 }
93 const std::string* dictionary_text = nullptr;
94 // To avoid passing a std::string with a null terminator into
95 // GetDictionary(), server hash here removes the last byte blindly.
96 if (!delegate_->OnGetDictionary(
97 dictionary_server_id_.substr(0, kServerIdLength - 1),
98 &dictionary_text)) {
99 // If GetDictionaryId fails and delegate chooses to pass through,
100 // preserve the dictionary id in the output.
101 buffered_output_.append(dictionary_server_id_);
102 if (!HandleError(
103 delegate_->OnGetDictionaryError(&buffered_output_))) {
104 return ERR_CONTENT_DECODING_FAILED;
105 }
106 break;
107 }
108 decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
109 decoder_->SetAllowVcdTarget(false);
110 decoder_->StartDecoding(dictionary_text->data(),
111 dictionary_text->length());
112 input_state_ = STATE_DECODE;
113 break;
114 }
115 case STATE_DECODE: {
116 int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
117 output_buffer_size - bytes_out,
118 buffered_output_);
119 buffered_output_.erase(0, flushed);
120 bytes_out += flushed;
121 if (!buffered_output_.empty())
122 break;
123 bool ok = decoder_->DecodeChunk(input_data, input_data_size,
124 &buffered_output_);
125 // Calls to DecodeChunk always consume all their input, so this always
126 // drains the entire buffer.
127 input_data += input_data_size;
128 input_data_size = 0;
129 if (!ok) {
130 decoder_.reset();
131 if (!HandleError(delegate_->OnDecodingError(&buffered_output_)))
132 return ERR_CONTENT_DECODING_FAILED;
133 }
134 break;
135 }
136 case STATE_OUTPUT_REPLACE: {
137 int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
138 output_buffer_size - bytes_out,
139 buffered_output_);
140 buffered_output_.erase(0, flushed);
141 bytes_out += flushed;
142 break;
143 }
144 case STATE_PASS_THROUGH: {
145 if (buffered_output_.empty())
146 break;
147 int flushed = FlushBufferedOutput(output_buffer->data() + bytes_out,
148 output_buffer_size - bytes_out,
149 buffered_output_);
150 buffered_output_.erase(0, flushed);
151 bytes_out += flushed;
152 if (!buffered_output_.empty())
153 break;
154 size_t to_copy =
155 std::min(output_buffer_size - bytes_out, input_data_size);
156 memcpy(output_buffer->data() + bytes_out, input_data, to_copy);
157 input_data += to_copy;
158 input_data_size -= to_copy;
159 break;
160 }
161 }
162 }
163 *consumed_bytes = input_buffer_size - input_data_size;
164 return bytes_out;
165 }
166
167 bool SdchSourceStream::CouldBeDictionaryId(const std::string& id) const {
168 for (size_t i = 0; i < kServerIdLength - 1; i++) {
169 char base64_char = id[i];
170 if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char)
171 return false;
172 }
173 if (id[kServerIdLength - 1] != '\0')
174 return false;
175 return true;
176 }
177
178 bool SdchSourceStream::HandleError(Delegate::ErrorRecovery error_recover) {
179 switch (error_recover) {
180 case Delegate::NONE:
181 return false;
182 case Delegate::PASS_THROUGH:
183 input_state_ = STATE_PASS_THROUGH;
184 break;
185 case Delegate::REPLACE_OUTPUT:
186 input_state_ = STATE_OUTPUT_REPLACE;
187 break;
188 }
189 return true;
190 }
191
192 } // namespace net
OLDNEW
« no previous file with comments | « net/filter/sdch_source_stream.h ('k') | net/filter/sdch_source_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698