Roll WebRTC 9745:9761, Libjingle 9742:9761
[chromium-blink-merge.git] / net / spdy / hpack / hpack_decoder.cc
blob88b453aa0ae551f690064ac0e039f98badd61d75
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.
5 #include "net/spdy/hpack/hpack_decoder.h"
7 #include <utility>
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "net/spdy/hpack/hpack_constants.h"
12 #include "net/spdy/hpack/hpack_output_stream.h"
14 namespace net {
16 using base::StringPiece;
17 using std::string;
19 namespace {
21 const char kCookieKey[] = "cookie";
23 } // namespace
25 HpackDecoder::HpackDecoder(const HpackHuffmanTable& table)
26 : max_string_literal_size_(kDefaultMaxStringLiteralSize),
27 regular_header_seen_(false),
28 huffman_table_(table) {}
30 HpackDecoder::~HpackDecoder() {}
32 bool HpackDecoder::HandleControlFrameHeadersData(SpdyStreamId id,
33 const char* headers_data,
34 size_t headers_data_length) {
35 decoded_block_.clear();
37 size_t new_size = headers_block_buffer_.size() + headers_data_length;
38 if (new_size > kMaxDecodeBufferSize) {
39 return false;
41 headers_block_buffer_.insert(headers_block_buffer_.end(), headers_data,
42 headers_data + headers_data_length);
43 return true;
46 bool HpackDecoder::HandleControlFrameHeadersComplete(SpdyStreamId id,
47 size_t* compressed_len) {
48 HpackInputStream input_stream(max_string_literal_size_,
49 headers_block_buffer_);
50 regular_header_seen_ = false;
51 if (compressed_len) {
52 *compressed_len = headers_block_buffer_.size();
54 while (input_stream.HasMoreData()) {
55 if (!DecodeNextOpcode(&input_stream)) {
56 headers_block_buffer_.clear();
57 return false;
60 headers_block_buffer_.clear();
62 return true;
65 bool HpackDecoder::HandleHeaderRepresentation(StringPiece name,
66 StringPiece value) {
67 // Fail if pseudo-header follows regular header.
68 if (name.size() > 0) {
69 if (name[0] == kPseudoHeaderPrefix) {
70 if (regular_header_seen_) {
71 return false;
73 } else {
74 regular_header_seen_ = true;
78 if (name == kCookieKey) {
79 // Create new cookie header, or append to existing.
80 auto it = decoded_block_.find(kCookieKey);
81 if (it == decoded_block_.end()) {
82 decoded_block_[kCookieKey].assign(value.data(), value.size());
83 } else {
84 decoded_block_[kCookieKey].append("; ");
85 value.AppendToString(&decoded_block_[kCookieKey]);
87 } else {
88 auto result = decoded_block_.insert(
89 std::make_pair(name.as_string(), value.as_string()));
90 if (!result.second) {
91 // Key |name| already exists, append new value.
92 result.first->second.push_back('\0');
93 result.first->second.insert(result.first->second.end(), value.begin(),
94 value.end());
97 return true;
100 bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) {
101 // Implements 7.1: Indexed Header Field Representation.
102 if (input_stream->MatchPrefixAndConsume(kIndexedOpcode)) {
103 return DecodeNextIndexedHeader(input_stream);
105 // Implements 7.2.1: Literal Header Field with Incremental Indexing.
106 if (input_stream->MatchPrefixAndConsume(kLiteralIncrementalIndexOpcode)) {
107 return DecodeNextLiteralHeader(input_stream, true);
109 // Implements 7.2.2: Literal Header Field without Indexing.
110 if (input_stream->MatchPrefixAndConsume(kLiteralNoIndexOpcode)) {
111 return DecodeNextLiteralHeader(input_stream, false);
113 // Implements 7.2.3: Literal Header Field never Indexed.
114 // TODO(jgraettinger): Preserve the never-indexed bit.
115 if (input_stream->MatchPrefixAndConsume(kLiteralNeverIndexOpcode)) {
116 return DecodeNextLiteralHeader(input_stream, false);
118 // Implements 7.3: Header Table Size Update.
119 if (input_stream->MatchPrefixAndConsume(kHeaderTableSizeUpdateOpcode)) {
120 return DecodeNextHeaderTableSizeUpdate(input_stream);
122 // Unrecognized opcode.
123 return false;
126 bool HpackDecoder::DecodeNextHeaderTableSizeUpdate(
127 HpackInputStream* input_stream) {
128 uint32 size = 0;
129 if (!input_stream->DecodeNextUint32(&size)) {
130 return false;
132 if (size > header_table_.settings_size_bound()) {
133 return false;
135 header_table_.SetMaxSize(size);
136 return true;
139 bool HpackDecoder::DecodeNextIndexedHeader(HpackInputStream* input_stream) {
140 uint32 index = 0;
141 if (!input_stream->DecodeNextUint32(&index)) {
142 return false;
145 const HpackEntry* entry = header_table_.GetByIndex(index);
146 if (entry == NULL) {
147 return false;
150 return HandleHeaderRepresentation(entry->name(), entry->value());
153 bool HpackDecoder::DecodeNextLiteralHeader(HpackInputStream* input_stream,
154 bool should_index) {
155 StringPiece name;
156 if (!DecodeNextName(input_stream, &name)) {
157 return false;
160 StringPiece value;
161 if (!DecodeNextStringLiteral(input_stream, false, &value)) {
162 return false;
165 if (!HandleHeaderRepresentation(name, value)) {
166 return false;
169 if (!should_index) {
170 return true;
173 ignore_result(header_table_.TryAddEntry(name, value));
174 return true;
177 bool HpackDecoder::DecodeNextName(HpackInputStream* input_stream,
178 StringPiece* next_name) {
179 uint32 index_or_zero = 0;
180 if (!input_stream->DecodeNextUint32(&index_or_zero)) {
181 return false;
184 if (index_or_zero == 0) {
185 return DecodeNextStringLiteral(input_stream, true, next_name);
188 const HpackEntry* entry = header_table_.GetByIndex(index_or_zero);
189 if (entry == NULL) {
190 return false;
192 if (entry->IsStatic()) {
193 *next_name = entry->name();
194 } else {
195 // |entry| could be evicted as part of this insertion. Preemptively copy.
196 key_buffer_.assign(entry->name());
197 *next_name = key_buffer_;
199 return true;
202 bool HpackDecoder::DecodeNextStringLiteral(HpackInputStream* input_stream,
203 bool is_key,
204 StringPiece* output) {
205 if (input_stream->MatchPrefixAndConsume(kStringLiteralHuffmanEncoded)) {
206 string* buffer = is_key ? &key_buffer_ : &value_buffer_;
207 bool result = input_stream->DecodeNextHuffmanString(huffman_table_, buffer);
208 *output = StringPiece(*buffer);
209 return result;
211 if (input_stream->MatchPrefixAndConsume(kStringLiteralIdentityEncoded)) {
212 return input_stream->DecodeNextIdentityString(output);
214 return false;
217 } // namespace net