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_input_stream.h" 6 7 #include <algorithm> 8 9 #include "base/basictypes.h" 10 #include "base/logging.h" 11 12 namespace net { 13 14 using base::StringPiece; 15 using std::string; 16 17 HpackInputStream::HpackInputStream(uint32 max_string_literal_size, 18 StringPiece buffer) 19 : max_string_literal_size_(max_string_literal_size), 20 buffer_(buffer), 21 bit_offset_(0) {} 22 23 HpackInputStream::~HpackInputStream() {} 24 25 bool HpackInputStream::HasMoreData() const { 26 return !buffer_.empty(); 27 } 28 29 bool HpackInputStream::MatchPrefixAndConsume(HpackPrefix prefix) { 30 DCHECK_GT(prefix.bit_size, 0u); 31 DCHECK_LE(prefix.bit_size, 8u); 32 33 uint32 peeked = 0; 34 size_t peeked_count = 0; 35 36 if (!PeekBits(&peeked_count, &peeked)) 37 return false; 38 39 if ((peeked >> (32 - prefix.bit_size)) == prefix.bits) { 40 ConsumeBits(prefix.bit_size); 41 return true; 42 } 43 return false; 44 } 45 46 bool HpackInputStream::PeekNextOctet(uint8* next_octet) { 47 if ((bit_offset_ > 0) || buffer_.empty()) 48 return false; 49 50 *next_octet = buffer_[0]; 51 return true; 52 } 53 54 bool HpackInputStream::DecodeNextOctet(uint8* next_octet) { 55 if (!PeekNextOctet(next_octet)) 56 return false; 57 58 buffer_.remove_prefix(1); 59 return true; 60 } 61 62 bool HpackInputStream::DecodeNextUint32(uint32* I) { 63 size_t N = 8 - bit_offset_; 64 DCHECK_GT(N, 0u); 65 DCHECK_LE(N, 8u); 66 67 bit_offset_ = 0; 68 69 *I = 0; 70 71 uint8 next_marker = (1 << N) - 1; 72 uint8 next_octet = 0; 73 if (!DecodeNextOctet(&next_octet)) 74 return false; 75 *I = next_octet & next_marker; 76 77 bool has_more = (*I == next_marker); 78 size_t shift = 0; 79 while (has_more && (shift < 32)) { 80 uint8 next_octet = 0; 81 if (!DecodeNextOctet(&next_octet)) 82 return false; 83 has_more = (next_octet & 0x80) != 0; 84 next_octet &= 0x7f; 85 uint32 addend = next_octet << shift; 86 // Check for overflow. 87 if ((addend >> shift) != next_octet) { 88 return false; 89 } 90 *I += addend; 91 shift += 7; 92 } 93 94 return !has_more; 95 } 96 97 bool HpackInputStream::DecodeNextIdentityString(StringPiece* str) { 98 uint32 size = 0; 99 if (!DecodeNextUint32(&size)) 100 return false; 101 102 if (size > max_string_literal_size_) 103 return false; 104 105 if (size > buffer_.size()) 106 return false; 107 108 *str = StringPiece(buffer_.data(), size); 109 buffer_.remove_prefix(size); 110 return true; 111 } 112 113 bool HpackInputStream::DecodeNextHuffmanString(const HpackHuffmanTable& table, 114 string* str) { 115 uint32 encoded_size = 0; 116 if (!DecodeNextUint32(&encoded_size)) 117 return false; 118 119 if (encoded_size > buffer_.size()) 120 return false; 121 122 HpackInputStream bounded_reader( 123 max_string_literal_size_, 124 StringPiece(buffer_.data(), encoded_size)); 125 buffer_.remove_prefix(encoded_size); 126 127 // HpackHuffmanTable will not decode beyond |max_string_literal_size_|. 128 return table.DecodeString(&bounded_reader, max_string_literal_size_, str); 129 } 130 131 bool HpackInputStream::PeekBits(size_t* peeked_count, uint32* out) { 132 size_t byte_offset = (bit_offset_ + *peeked_count) / 8; 133 size_t bit_offset = (bit_offset_ + *peeked_count) % 8; 134 135 if (*peeked_count >= 32 || byte_offset >= buffer_.size()) { 136 return false; 137 } 138 // We'll read the minimum of the current byte remainder, 139 // and the remaining unfilled bits of |out|. 140 size_t bits_to_read = std::min(32 - *peeked_count, 8 - bit_offset); 141 142 uint32 new_bits = static_cast<uint32>(buffer_[byte_offset]); 143 // Shift byte remainder to most-signifcant bits of |new_bits|. 144 // This drops the leading |bit_offset| bits of the byte. 145 new_bits = new_bits << (24 + bit_offset); 146 // Shift bits to the most-significant open bits of |out|. 147 new_bits = new_bits >> *peeked_count; 148 149 CHECK_EQ(*out & new_bits, 0u); 150 *out |= new_bits; 151 152 *peeked_count += bits_to_read; 153 return true; 154 } 155 156 void HpackInputStream::ConsumeBits(size_t bit_count) { 157 size_t byte_count = (bit_offset_ + bit_count) / 8; 158 bit_offset_ = (bit_offset_ + bit_count) % 8; 159 CHECK_GE(buffer_.size(), byte_count); 160 if (bit_offset_ != 0) { 161 CHECK_GT(buffer_.size(), 0u); 162 } 163 buffer_.remove_prefix(byte_count); 164 } 165 166 void HpackInputStream::ConsumeByteRemainder() { 167 if (bit_offset_ != 0) { 168 ConsumeBits(8 - bit_offset_); 169 } 170 } 171 172 } // namespace net 173