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

Side by Side Diff: net/spdy/hpack/hpack_input_stream.cc

Issue 1568423002: Implement better HPACK Huffman code decoder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Do not use binary literals. Created 4 years, 11 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/spdy/hpack/hpack_input_stream.h ('k') | net/spdy/hpack/hpack_input_stream_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/spdy/hpack/hpack_input_stream.h" 5 #include "net/spdy/hpack/hpack_input_stream.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "net/spdy/hpack/hpack_huffman_decoder.h"
10 11
11 namespace net { 12 namespace net {
12 13
13 using base::StringPiece; 14 using base::StringPiece;
14 using std::string; 15 using std::string;
15 16
16 HpackInputStream::HpackInputStream(uint32_t max_string_literal_size, 17 HpackInputStream::HpackInputStream(uint32_t max_string_literal_size,
17 StringPiece buffer) 18 StringPiece buffer)
18 : max_string_literal_size_(max_string_literal_size), 19 : max_string_literal_size_(max_string_literal_size),
19 buffer_(buffer), 20 buffer_(buffer),
(...skipping 18 matching lines...) Expand all
38 39
39 if ((peeked >> (32 - prefix.bit_size)) == prefix.bits) { 40 if ((peeked >> (32 - prefix.bit_size)) == prefix.bits) {
40 ConsumeBits(prefix.bit_size); 41 ConsumeBits(prefix.bit_size);
41 return true; 42 return true;
42 } 43 }
43 return false; 44 return false;
44 } 45 }
45 46
46 bool HpackInputStream::PeekNextOctet(uint8_t* next_octet) { 47 bool HpackInputStream::PeekNextOctet(uint8_t* next_octet) {
47 if ((bit_offset_ > 0) || buffer_.empty()) { 48 if ((bit_offset_ > 0) || buffer_.empty()) {
49 DVLOG(1) << "HpackInputStream::PeekNextOctet bit_offset_=" << bit_offset_;
48 return false; 50 return false;
49 } 51 }
50 52
51 *next_octet = buffer_[0]; 53 *next_octet = buffer_[0];
52 return true; 54 return true;
53 } 55 }
54 56
55 bool HpackInputStream::DecodeNextOctet(uint8_t* next_octet) { 57 bool HpackInputStream::DecodeNextOctet(uint8_t* next_octet) {
56 if (!PeekNextOctet(next_octet)) { 58 if (!PeekNextOctet(next_octet)) {
57 return false; 59 return false;
58 } 60 }
59 61
60 buffer_.remove_prefix(1); 62 buffer_.remove_prefix(1);
61 return true; 63 return true;
62 } 64 }
63 65
64 bool HpackInputStream::DecodeNextUint32(uint32_t* I) { 66 bool HpackInputStream::DecodeNextUint32(uint32_t* I) {
65 size_t N = 8 - bit_offset_; 67 size_t N = 8 - bit_offset_;
66 DCHECK_GT(N, 0u); 68 DCHECK_GT(N, 0u);
67 DCHECK_LE(N, 8u); 69 DCHECK_LE(N, 8u);
68 70
69 bit_offset_ = 0; 71 bit_offset_ = 0;
70 72
71 *I = 0; 73 *I = 0;
72 74
73 uint8_t next_marker = (1 << N) - 1; 75 uint8_t next_marker = (1 << N) - 1;
74 uint8_t next_octet = 0; 76 uint8_t next_octet = 0;
75 if (!DecodeNextOctet(&next_octet)) { 77 if (!DecodeNextOctet(&next_octet)) {
78 DVLOG(1) << "HpackInputStream::DecodeNextUint32 initial octet error";
76 return false; 79 return false;
77 } 80 }
78 *I = next_octet & next_marker; 81 *I = next_octet & next_marker;
79 82
80 bool has_more = (*I == next_marker); 83 bool has_more = (*I == next_marker);
81 size_t shift = 0; 84 size_t shift = 0;
82 while (has_more && (shift < 32)) { 85 while (has_more && (shift < 32)) {
83 uint8_t next_octet = 0; 86 uint8_t next_octet = 0;
84 if (!DecodeNextOctet(&next_octet)) { 87 if (!DecodeNextOctet(&next_octet)) {
88 DVLOG(1) << "HpackInputStream::DecodeNextUint32 shift=" << shift;
85 return false; 89 return false;
86 } 90 }
87 has_more = (next_octet & 0x80) != 0; 91 has_more = (next_octet & 0x80) != 0;
88 next_octet &= 0x7f; 92 next_octet &= 0x7f;
89 uint32_t addend = next_octet << shift; 93 uint32_t addend = next_octet << shift;
90 // Check for overflow. 94 // Check for overflow.
91 if ((addend >> shift) != next_octet) { 95 if ((addend >> shift) != next_octet) {
96 DVLOG(1) << "HpackInputStream::DecodeNextUint32 overflow";
92 return false; 97 return false;
93 } 98 }
94 *I += addend; 99 *I += addend;
95 shift += 7; 100 shift += 7;
96 } 101 }
97 102
98 return !has_more; 103 return !has_more;
99 } 104 }
100 105
101 bool HpackInputStream::DecodeNextIdentityString(StringPiece* str) { 106 bool HpackInputStream::DecodeNextIdentityString(StringPiece* str) {
102 uint32_t size = 0; 107 uint32_t size = 0;
103 if (!DecodeNextUint32(&size)) { 108 if (!DecodeNextUint32(&size)) {
104 return false; 109 return false;
105 } 110 }
106 111
107 if (size > max_string_literal_size_) { 112 if (size > max_string_literal_size_) {
108 return false; 113 return false;
109 } 114 }
110 115
111 if (size > buffer_.size()) { 116 if (size > buffer_.size()) {
112 return false; 117 return false;
113 } 118 }
114 119
115 *str = StringPiece(buffer_.data(), size); 120 *str = StringPiece(buffer_.data(), size);
116 buffer_.remove_prefix(size); 121 buffer_.remove_prefix(size);
117 return true; 122 return true;
118 } 123 }
119 124
120 bool HpackInputStream::DecodeNextHuffmanString(const HpackHuffmanTable& table, 125 bool HpackInputStream::DecodeNextHuffmanString(string* str) {
121 string* str) {
122 uint32_t encoded_size = 0; 126 uint32_t encoded_size = 0;
123 if (!DecodeNextUint32(&encoded_size)) { 127 if (!DecodeNextUint32(&encoded_size)) {
128 DVLOG(1) << "HpackInputStream::DecodeNextHuffmanString "
129 << "unable to decode size";
124 return false; 130 return false;
125 } 131 }
126 132
127 if (encoded_size > buffer_.size()) { 133 if (encoded_size > buffer_.size()) {
134 DVLOG(1) << "HpackInputStream::DecodeNextHuffmanString " << encoded_size
135 << " > " << buffer_.size();
128 return false; 136 return false;
129 } 137 }
130 138
131 HpackInputStream bounded_reader(max_string_literal_size_, 139 HpackInputStream bounded_reader(max_string_literal_size_,
132 StringPiece(buffer_.data(), encoded_size)); 140 StringPiece(buffer_.data(), encoded_size));
133 buffer_.remove_prefix(encoded_size); 141 buffer_.remove_prefix(encoded_size);
134 142
135 // HpackHuffmanTable will not decode beyond |max_string_literal_size_|. 143 // DecodeString will not append more than |max_string_literal_size_| chars
136 return table.DecodeString(&bounded_reader, max_string_literal_size_, str); 144 // to |str|.
145 return HpackHuffmanDecoder::DecodeString(&bounded_reader,
146 max_string_literal_size_, str);
137 } 147 }
138 148
139 bool HpackInputStream::PeekBits(size_t* peeked_count, uint32_t* out) const { 149 bool HpackInputStream::PeekBits(size_t* peeked_count, uint32_t* out) const {
140 size_t byte_offset = (bit_offset_ + *peeked_count) / 8; 150 size_t byte_offset = (bit_offset_ + *peeked_count) / 8;
141 size_t bit_offset = (bit_offset_ + *peeked_count) % 8; 151 size_t bit_offset = (bit_offset_ + *peeked_count) % 8;
142 152
143 if (*peeked_count >= 32 || byte_offset >= buffer_.size()) { 153 if (*peeked_count >= 32 || byte_offset >= buffer_.size()) {
144 return false; 154 return false;
145 } 155 }
146 // We'll read the minimum of the current byte remainder, 156 // We'll read the minimum of the current byte remainder,
147 // and the remaining unfilled bits of |out|. 157 // and the remaining unfilled bits of |out|.
148 size_t bits_to_read = std::min(32 - *peeked_count, 8 - bit_offset); 158 size_t bits_to_read = std::min(32 - *peeked_count, 8 - bit_offset);
149 159
150 uint32_t new_bits = static_cast<uint32_t>(buffer_[byte_offset]); 160 uint32_t new_bits = static_cast<uint32_t>(buffer_[byte_offset]);
151 // Shift byte remainder to most-signifcant bits of |new_bits|. 161 // Shift byte remainder to most-signifcant bits of |new_bits|.
152 // This drops the leading |bit_offset| bits of the byte. 162 // This drops the leading |bit_offset| bits of the byte.
153 new_bits = new_bits << (24 + bit_offset); 163 new_bits = new_bits << (24 + bit_offset);
154 // Shift bits to the most-significant open bits of |out|. 164 // Shift bits to the most-significant open bits of |out|.
155 new_bits = new_bits >> *peeked_count; 165 new_bits = new_bits >> *peeked_count;
156 166
157 CHECK_EQ(*out & new_bits, 0u); 167 CHECK_EQ(*out & new_bits, 0u);
158 *out |= new_bits; 168 *out |= new_bits;
159 169
160 *peeked_count += bits_to_read; 170 *peeked_count += bits_to_read;
161 return true; 171 return true;
162 } 172 }
163 173
174 std::pair<size_t, uint32_t> HpackInputStream::InitializePeekBits() {
175 size_t peeked_count = 0;
176 uint32_t bits = 0;
177 if (bit_offset_ == 0) {
178 switch (buffer_.size()) {
179 default:
180 DCHECK_LE(4u, buffer_.size());
181 bits = static_cast<uint32_t>(static_cast<unsigned char>(buffer_[3]));
182 peeked_count += 8;
183 /* FALLTHROUGH */
184 case 3:
185 bits |= (static_cast<uint32_t>(static_cast<unsigned char>(buffer_[2]))
186 << 8);
187 peeked_count += 8;
188 /* FALLTHROUGH */
189 case 2:
190 bits |= (static_cast<uint32_t>(static_cast<unsigned char>(buffer_[1]))
191 << 16);
192 peeked_count += 8;
193 /* FALLTHROUGH */
194 case 1:
195 bits |= (static_cast<uint32_t>(static_cast<unsigned char>(buffer_[0]))
196 << 24);
197 peeked_count += 8;
198 break;
199 case 0:
200 break;
201 }
202 } else {
203 LOG(DFATAL) << "InitializePeekBits called with non-zero bit_offset_: "
204 << bit_offset_;
205 }
206 return std::make_pair(peeked_count, bits);
207 }
208
164 void HpackInputStream::ConsumeBits(size_t bit_count) { 209 void HpackInputStream::ConsumeBits(size_t bit_count) {
165 size_t byte_count = (bit_offset_ + bit_count) / 8; 210 size_t byte_count = (bit_offset_ + bit_count) / 8;
166 bit_offset_ = (bit_offset_ + bit_count) % 8; 211 bit_offset_ = (bit_offset_ + bit_count) % 8;
167 CHECK_GE(buffer_.size(), byte_count); 212 CHECK_GE(buffer_.size(), byte_count);
168 if (bit_offset_ != 0) { 213 if (bit_offset_ != 0) {
169 CHECK_GT(buffer_.size(), 0u); 214 CHECK_GT(buffer_.size(), 0u);
170 } 215 }
171 buffer_.remove_prefix(byte_count); 216 buffer_.remove_prefix(byte_count);
172 } 217 }
173 218
174 void HpackInputStream::ConsumeByteRemainder() { 219 void HpackInputStream::ConsumeByteRemainder() {
175 if (bit_offset_ != 0) { 220 if (bit_offset_ != 0) {
176 ConsumeBits(8 - bit_offset_); 221 ConsumeBits(8 - bit_offset_);
177 } 222 }
178 } 223 }
179 224
180 } // namespace net 225 } // namespace net
OLDNEW
« no previous file with comments | « net/spdy/hpack/hpack_input_stream.h ('k') | net/spdy/hpack/hpack_input_stream_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698