Home | History | Annotate | Download | only in spdy
      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