• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
HpackInputStream(uint32 max_string_literal_size,StringPiece buffer)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 
~HpackInputStream()23 HpackInputStream::~HpackInputStream() {}
24 
HasMoreData() const25 bool HpackInputStream::HasMoreData() const {
26   return !buffer_.empty();
27 }
28 
MatchPrefixAndConsume(HpackPrefix prefix)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 
PeekNextOctet(uint8 * next_octet)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 
DecodeNextOctet(uint8 * next_octet)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 
DecodeNextUint32(uint32 * I)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 
DecodeNextIdentityString(StringPiece * str)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 
DecodeNextHuffmanString(const HpackHuffmanTable & table,string * str)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 
PeekBits(size_t * peeked_count,uint32 * out)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 
ConsumeBits(size_t bit_count)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 
ConsumeByteRemainder()166 void HpackInputStream::ConsumeByteRemainder() {
167   if (bit_offset_ != 0) {
168     ConsumeBits(8 - bit_offset_);
169   }
170 }
171 
172 }  // namespace net
173