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_decoder.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/logging.h"
      9 #include "net/spdy/hpack_constants.h"
     10 #include "net/spdy/hpack_output_stream.h"
     11 
     12 namespace net {
     13 
     14 using base::StringPiece;
     15 using std::string;
     16 
     17 namespace {
     18 
     19 const char kCookieKey[] = "cookie";
     20 
     21 }  // namespace
     22 
     23 HpackDecoder::HpackDecoder(const HpackHuffmanTable& table)
     24     : max_string_literal_size_(kDefaultMaxStringLiteralSize),
     25       regular_header_seen_(false),
     26       huffman_table_(table) {}
     27 
     28 HpackDecoder::~HpackDecoder() {}
     29 
     30 bool HpackDecoder::HandleControlFrameHeadersData(SpdyStreamId id,
     31                                                  const char* headers_data,
     32                                                  size_t headers_data_length) {
     33   decoded_block_.clear();
     34 
     35   size_t new_size = headers_block_buffer_.size() + headers_data_length;
     36   if (new_size > kMaxDecodeBufferSize) {
     37     return false;
     38   }
     39   headers_block_buffer_.insert(headers_block_buffer_.end(),
     40                                headers_data,
     41                                headers_data + headers_data_length);
     42   return true;
     43 }
     44 
     45 bool HpackDecoder::HandleControlFrameHeadersComplete(SpdyStreamId id) {
     46   HpackInputStream input_stream(max_string_literal_size_,
     47                                 headers_block_buffer_);
     48   regular_header_seen_ = false;
     49   while (input_stream.HasMoreData()) {
     50     if (!DecodeNextOpcode(&input_stream)) {
     51       headers_block_buffer_.clear();
     52       return false;
     53     }
     54   }
     55   headers_block_buffer_.clear();
     56 
     57   // Emit the Cookie header, if any crumbles were encountered.
     58   if (!cookie_value_.empty()) {
     59     decoded_block_[kCookieKey] = cookie_value_;
     60     cookie_value_.clear();
     61   }
     62   return true;
     63 }
     64 
     65 bool HpackDecoder::HandleHeaderRepresentation(StringPiece name,
     66                                               StringPiece value) {
     67   typedef std::pair<std::map<string, string>::iterator, bool> InsertResult;
     68 
     69   // Fail if pseudo-header follows regular header.
     70   if (name.size() > 0) {
     71     if (name[0] == kPseudoHeaderPrefix) {
     72       if (regular_header_seen_) return false;
     73     } else {
     74       regular_header_seen_ = true;
     75     }
     76   }
     77 
     78   if (name == kCookieKey) {
     79     if (cookie_value_.empty()) {
     80       cookie_value_.assign(value.data(), value.size());
     81     } else {
     82       cookie_value_ += "; ";
     83       cookie_value_.insert(cookie_value_.end(), value.begin(), value.end());
     84     }
     85   } else {
     86     InsertResult result = decoded_block_.insert(
     87         std::make_pair(name.as_string(), value.as_string()));
     88     if (!result.second) {
     89       result.first->second.push_back('\0');
     90       result.first->second.insert(result.first->second.end(),
     91                                   value.begin(),
     92                                   value.end());
     93     }
     94   }
     95   return true;
     96 }
     97 
     98 bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) {
     99   // Implements 7.1: Indexed Header Field Representation.
    100   if (input_stream->MatchPrefixAndConsume(kIndexedOpcode)) {
    101     return DecodeNextIndexedHeader(input_stream);
    102   }
    103   // Implements 7.2.1: Literal Header Field with Incremental Indexing.
    104   if (input_stream->MatchPrefixAndConsume(kLiteralIncrementalIndexOpcode)) {
    105     return DecodeNextLiteralHeader(input_stream, true);
    106   }
    107   // Implements 7.2.2: Literal Header Field without Indexing.
    108   if (input_stream->MatchPrefixAndConsume(kLiteralNoIndexOpcode)) {
    109     return DecodeNextLiteralHeader(input_stream, false);
    110   }
    111   // Implements 7.2.3: Literal Header Field never Indexed.
    112   // TODO(jgraettinger): Preserve the never-indexed bit.
    113   if (input_stream->MatchPrefixAndConsume(kLiteralNeverIndexOpcode)) {
    114     return DecodeNextLiteralHeader(input_stream, false);
    115   }
    116   // Implements 7.3: Header Table Size Update.
    117   if (input_stream->MatchPrefixAndConsume(kHeaderTableSizeUpdateOpcode)) {
    118     return DecodeNextHeaderTableSizeUpdate(input_stream);
    119   }
    120   // Unrecognized opcode.
    121   return false;
    122 }
    123 
    124 bool HpackDecoder::DecodeNextHeaderTableSizeUpdate(
    125     HpackInputStream* input_stream) {
    126   uint32 size = 0;
    127   if (!input_stream->DecodeNextUint32(&size)) {
    128     return false;
    129   }
    130   if (size > header_table_.settings_size_bound()) {
    131     return false;
    132   }
    133   header_table_.SetMaxSize(size);
    134   return true;
    135 }
    136 
    137 bool HpackDecoder::DecodeNextIndexedHeader(HpackInputStream* input_stream) {
    138   uint32 index = 0;
    139   if (!input_stream->DecodeNextUint32(&index))
    140     return false;
    141 
    142   const HpackEntry* entry = header_table_.GetByIndex(index);
    143   if (entry == NULL)
    144     return false;
    145 
    146   return HandleHeaderRepresentation(entry->name(), entry->value());
    147 }
    148 
    149 bool HpackDecoder::DecodeNextLiteralHeader(HpackInputStream* input_stream,
    150                                            bool should_index) {
    151   StringPiece name;
    152   if (!DecodeNextName(input_stream, &name))
    153     return false;
    154 
    155   StringPiece value;
    156   if (!DecodeNextStringLiteral(input_stream, false, &value))
    157     return false;
    158 
    159   if (!HandleHeaderRepresentation(name, value)) return false;
    160 
    161   if (!should_index)
    162     return true;
    163 
    164   ignore_result(header_table_.TryAddEntry(name, value));
    165   return true;
    166 }
    167 
    168 bool HpackDecoder::DecodeNextName(
    169     HpackInputStream* input_stream, StringPiece* next_name) {
    170   uint32 index_or_zero = 0;
    171   if (!input_stream->DecodeNextUint32(&index_or_zero))
    172     return false;
    173 
    174   if (index_or_zero == 0)
    175     return DecodeNextStringLiteral(input_stream, true, next_name);
    176 
    177   const HpackEntry* entry = header_table_.GetByIndex(index_or_zero);
    178   if (entry == NULL) {
    179     return false;
    180   } else if (entry->IsStatic()) {
    181     *next_name = entry->name();
    182   } else {
    183     // |entry| could be evicted as part of this insertion. Preemptively copy.
    184     key_buffer_.assign(entry->name());
    185     *next_name = key_buffer_;
    186   }
    187   return true;
    188 }
    189 
    190 bool HpackDecoder::DecodeNextStringLiteral(HpackInputStream* input_stream,
    191                                            bool is_key,
    192                                            StringPiece* output) {
    193   if (input_stream->MatchPrefixAndConsume(kStringLiteralHuffmanEncoded)) {
    194     string* buffer = is_key ? &key_buffer_ : &value_buffer_;
    195     bool result = input_stream->DecodeNextHuffmanString(huffman_table_, buffer);
    196     *output = StringPiece(*buffer);
    197     return result;
    198   } else if (input_stream->MatchPrefixAndConsume(
    199       kStringLiteralIdentityEncoded)) {
    200     return input_stream->DecodeNextIdentityString(output);
    201   } else {
    202     return false;
    203   }
    204 }
    205 
    206 }  // namespace net
    207