OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/spdy/hpack/hpack_input_stream.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/logging.h" | |
10 #include "net/spdy/hpack/hpack_huffman_decoder.h" | |
11 #include "net/spdy/spdy_bug_tracker.h" | |
12 | |
13 namespace net { | |
14 | |
15 HpackInputStream::HpackInputStream(SpdyStringPiece buffer) | |
16 : buffer_(buffer), | |
17 bit_offset_(0), | |
18 parsed_bytes_(0), | |
19 parsed_bytes_current_(0), | |
20 need_more_data_(false) {} | |
21 | |
22 HpackInputStream::~HpackInputStream() {} | |
23 | |
24 bool HpackInputStream::HasMoreData() const { | |
25 return !buffer_.empty(); | |
26 } | |
27 | |
28 bool HpackInputStream::MatchPrefixAndConsume(HpackPrefix prefix) { | |
29 if (buffer_.empty()) { | |
30 need_more_data_ = true; | |
31 return false; | |
32 } | |
33 | |
34 DCHECK_GT(prefix.bit_size, 0u); | |
35 DCHECK_LE(prefix.bit_size, 8u); | |
36 | |
37 uint32_t peeked = 0; | |
38 size_t peeked_count = 0; | |
39 | |
40 if (!PeekBits(&peeked_count, &peeked)) { | |
41 return false; | |
42 } | |
43 | |
44 if ((peeked >> (32 - prefix.bit_size)) == prefix.bits) { | |
45 ConsumeBits(prefix.bit_size); | |
46 return true; | |
47 } | |
48 return false; | |
49 } | |
50 | |
51 bool HpackInputStream::PeekNextOctet(uint8_t* next_octet) { | |
52 if (buffer_.empty()) { | |
53 need_more_data_ = true; | |
54 return false; | |
55 } | |
56 if ((bit_offset_ > 0)) { | |
57 DVLOG(1) << "HpackInputStream::PeekNextOctet bit_offset_=" << bit_offset_; | |
58 return false; | |
59 } | |
60 | |
61 *next_octet = buffer_[0]; | |
62 return true; | |
63 } | |
64 | |
65 bool HpackInputStream::DecodeNextOctet(uint8_t* next_octet) { | |
66 if (!PeekNextOctet(next_octet)) { | |
67 return false; | |
68 } | |
69 | |
70 buffer_.remove_prefix(1); | |
71 parsed_bytes_current_ += 1; | |
72 return true; | |
73 } | |
74 | |
75 bool HpackInputStream::DecodeNextUint32(uint32_t* I) { | |
76 size_t N = 8 - bit_offset_; | |
77 DCHECK_GT(N, 0u); | |
78 DCHECK_LE(N, 8u); | |
79 | |
80 bit_offset_ = 0; | |
81 | |
82 *I = 0; | |
83 | |
84 uint8_t next_marker = (1 << N) - 1; | |
85 uint8_t next_octet = 0; | |
86 if (!DecodeNextOctet(&next_octet)) { | |
87 if (!need_more_data_) { | |
88 DVLOG(1) << "HpackInputStream::DecodeNextUint32 initial octet error"; | |
89 } | |
90 return false; | |
91 } | |
92 *I = next_octet & next_marker; | |
93 | |
94 bool has_more = (*I == next_marker); | |
95 size_t shift = 0; | |
96 while (has_more && (shift < 32)) { | |
97 uint8_t next_octet = 0; | |
98 if (!DecodeNextOctet(&next_octet)) { | |
99 if (!need_more_data_) { | |
100 DVLOG(1) << "HpackInputStream::DecodeNextUint32 shift=" << shift; | |
101 } | |
102 return false; | |
103 } | |
104 has_more = (next_octet & 0x80) != 0; | |
105 next_octet &= 0x7f; | |
106 uint32_t addend = next_octet << shift; | |
107 // Check for overflow. | |
108 if ((addend >> shift) != next_octet) { | |
109 DVLOG(1) << "HpackInputStream::DecodeNextUint32 overflow"; | |
110 return false; | |
111 } | |
112 *I += addend; | |
113 shift += 7; | |
114 } | |
115 | |
116 return !has_more; | |
117 } | |
118 | |
119 bool HpackInputStream::DecodeNextIdentityString(SpdyStringPiece* str) { | |
120 uint32_t size = 0; | |
121 if (!DecodeNextUint32(&size)) { | |
122 return false; | |
123 } | |
124 | |
125 if (size > buffer_.size()) { | |
126 need_more_data_ = true; | |
127 return false; | |
128 } | |
129 | |
130 *str = SpdyStringPiece(buffer_.data(), size); | |
131 buffer_.remove_prefix(size); | |
132 parsed_bytes_current_ += size; | |
133 return true; | |
134 } | |
135 | |
136 bool HpackInputStream::DecodeNextHuffmanString(SpdyString* str) { | |
137 uint32_t encoded_size = 0; | |
138 if (!DecodeNextUint32(&encoded_size)) { | |
139 if (!need_more_data_) { | |
140 DVLOG(1) << "HpackInputStream::DecodeNextHuffmanString " | |
141 << "unable to decode size"; | |
142 } | |
143 return false; | |
144 } | |
145 | |
146 if (encoded_size > buffer_.size()) { | |
147 need_more_data_ = true; | |
148 DVLOG(1) << "HpackInputStream::DecodeNextHuffmanString " << encoded_size | |
149 << " > " << buffer_.size(); | |
150 return false; | |
151 } | |
152 | |
153 HpackInputStream bounded_reader(buffer_.substr(0, encoded_size)); | |
154 buffer_.remove_prefix(encoded_size); | |
155 parsed_bytes_current_ += encoded_size; | |
156 | |
157 return HpackHuffmanDecoder::DecodeString(&bounded_reader, str); | |
158 } | |
159 | |
160 bool HpackInputStream::PeekBits(size_t* peeked_count, uint32_t* out) const { | |
161 size_t byte_offset = (bit_offset_ + *peeked_count) / 8; | |
162 size_t bit_offset = (bit_offset_ + *peeked_count) % 8; | |
163 | |
164 if (*peeked_count >= 32 || byte_offset >= buffer_.size()) { | |
165 return false; | |
166 } | |
167 // We'll read the minimum of the current byte remainder, | |
168 // and the remaining unfilled bits of |out|. | |
169 size_t bits_to_read = std::min(32 - *peeked_count, 8 - bit_offset); | |
170 | |
171 uint32_t new_bits = static_cast<uint32_t>(buffer_[byte_offset]); | |
172 // Shift byte remainder to most-signifcant bits of |new_bits|. | |
173 // This drops the leading |bit_offset| bits of the byte. | |
174 new_bits = new_bits << (24 + bit_offset); | |
175 // Shift bits to the most-significant open bits of |out|. | |
176 new_bits = new_bits >> *peeked_count; | |
177 | |
178 CHECK_EQ(*out & new_bits, 0u); | |
179 *out |= new_bits; | |
180 | |
181 *peeked_count += bits_to_read; | |
182 return true; | |
183 } | |
184 | |
185 std::pair<size_t, uint32_t> HpackInputStream::InitializePeekBits() { | |
186 size_t peeked_count = 0; | |
187 uint32_t bits = 0; | |
188 if (bit_offset_ == 0) { | |
189 switch (buffer_.size()) { | |
190 default: | |
191 DCHECK_LE(4u, buffer_.size()); | |
192 bits = static_cast<uint32_t>(static_cast<unsigned char>(buffer_[3])); | |
193 peeked_count += 8; | |
194 /* FALLTHROUGH */ | |
195 case 3: | |
196 bits |= (static_cast<uint32_t>(static_cast<unsigned char>(buffer_[2])) | |
197 << 8); | |
198 peeked_count += 8; | |
199 /* FALLTHROUGH */ | |
200 case 2: | |
201 bits |= (static_cast<uint32_t>(static_cast<unsigned char>(buffer_[1])) | |
202 << 16); | |
203 peeked_count += 8; | |
204 /* FALLTHROUGH */ | |
205 case 1: | |
206 bits |= (static_cast<uint32_t>(static_cast<unsigned char>(buffer_[0])) | |
207 << 24); | |
208 peeked_count += 8; | |
209 break; | |
210 case 0: | |
211 break; | |
212 } | |
213 } else { | |
214 SPDY_BUG << "InitializePeekBits called with non-zero bit_offset_: " | |
215 << bit_offset_; | |
216 } | |
217 return std::make_pair(peeked_count, bits); | |
218 } | |
219 | |
220 void HpackInputStream::ConsumeBits(size_t bit_count) { | |
221 size_t byte_count = (bit_offset_ + bit_count) / 8; | |
222 bit_offset_ = (bit_offset_ + bit_count) % 8; | |
223 CHECK_GE(buffer_.size(), byte_count); | |
224 if (bit_offset_ != 0) { | |
225 CHECK_GT(buffer_.size(), 0u); | |
226 } | |
227 buffer_.remove_prefix(byte_count); | |
228 parsed_bytes_current_ += byte_count; | |
229 } | |
230 | |
231 void HpackInputStream::ConsumeByteRemainder() { | |
232 if (bit_offset_ != 0) { | |
233 ConsumeBits(8 - bit_offset_); | |
234 } | |
235 } | |
236 | |
237 uint32_t HpackInputStream::ParsedBytes() const { | |
238 return parsed_bytes_; | |
239 } | |
240 | |
241 bool HpackInputStream::NeedMoreData() const { | |
242 return need_more_data_; | |
243 } | |
244 | |
245 void HpackInputStream::MarkCurrentPosition() { | |
246 parsed_bytes_ = parsed_bytes_current_; | |
247 } | |
248 | |
249 } // namespace net | |
OLD | NEW |