Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / net / spdy / hpack_decoder.cc
blob162b33e9240dc94746578ca4f5a423531bcb43b2
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_decoder.h"
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"
12 namespace net {
14 using base::StringPiece;
15 using std::string;
17 namespace {
19 const char kCookieKey[] = "cookie";
21 } // namespace
23 HpackDecoder::HpackDecoder(const HpackHuffmanTable& table)
24 : max_string_literal_size_(kDefaultMaxStringLiteralSize),
25 huffman_table_(table) {}
27 HpackDecoder::~HpackDecoder() {}
29 bool HpackDecoder::HandleControlFrameHeadersData(SpdyStreamId id,
30 const char* headers_data,
31 size_t headers_data_length) {
32 decoded_block_.clear();
34 size_t new_size = headers_block_buffer_.size() + headers_data_length;
35 if (new_size > kMaxDecodeBufferSize) {
36 return false;
38 headers_block_buffer_.insert(headers_block_buffer_.end(),
39 headers_data,
40 headers_data + headers_data_length);
41 return true;
44 bool HpackDecoder::HandleControlFrameHeadersComplete(SpdyStreamId id) {
45 HpackInputStream input_stream(max_string_literal_size_,
46 headers_block_buffer_);
47 while (input_stream.HasMoreData()) {
48 if (!DecodeNextOpcode(&input_stream)) {
49 headers_block_buffer_.clear();
50 return false;
53 headers_block_buffer_.clear();
55 // Emit the Cookie header, if any crumbles were encountered.
56 if (!cookie_value_.empty()) {
57 decoded_block_[kCookieKey] = cookie_value_;
58 cookie_value_.clear();
60 return true;
63 void HpackDecoder::HandleHeaderRepresentation(StringPiece name,
64 StringPiece value) {
65 typedef std::pair<std::map<string, string>::iterator, bool> InsertResult;
67 if (name == kCookieKey) {
68 if (cookie_value_.empty()) {
69 cookie_value_.assign(value.data(), value.size());
70 } else {
71 cookie_value_ += "; ";
72 cookie_value_.insert(cookie_value_.end(), value.begin(), value.end());
74 } else {
75 InsertResult result = decoded_block_.insert(
76 std::make_pair(name.as_string(), value.as_string()));
77 if (!result.second) {
78 result.first->second.push_back('\0');
79 result.first->second.insert(result.first->second.end(),
80 value.begin(),
81 value.end());
86 bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) {
87 // Implements 7.1: Indexed Header Field Representation.
88 if (input_stream->MatchPrefixAndConsume(kIndexedOpcode)) {
89 return DecodeNextIndexedHeader(input_stream);
91 // Implements 7.2.1: Literal Header Field with Incremental Indexing.
92 if (input_stream->MatchPrefixAndConsume(kLiteralIncrementalIndexOpcode)) {
93 return DecodeNextLiteralHeader(input_stream, true);
95 // Implements 7.2.2: Literal Header Field without Indexing.
96 if (input_stream->MatchPrefixAndConsume(kLiteralNoIndexOpcode)) {
97 return DecodeNextLiteralHeader(input_stream, false);
99 // Implements 7.2.3: Literal Header Field never Indexed.
100 // TODO(jgraettinger): Preserve the never-indexed bit.
101 if (input_stream->MatchPrefixAndConsume(kLiteralNeverIndexOpcode)) {
102 return DecodeNextLiteralHeader(input_stream, false);
104 // Implements 7.3: Header Table Size Update.
105 if (input_stream->MatchPrefixAndConsume(kHeaderTableSizeUpdateOpcode)) {
106 return DecodeNextHeaderTableSizeUpdate(input_stream);
108 // Unrecognized opcode.
109 return false;
112 bool HpackDecoder::DecodeNextHeaderTableSizeUpdate(
113 HpackInputStream* input_stream) {
114 uint32 size = 0;
115 if (!input_stream->DecodeNextUint32(&size)) {
116 return false;
118 if (size > header_table_.settings_size_bound()) {
119 return false;
121 header_table_.SetMaxSize(size);
122 return true;
125 bool HpackDecoder::DecodeNextIndexedHeader(HpackInputStream* input_stream) {
126 uint32 index = 0;
127 if (!input_stream->DecodeNextUint32(&index))
128 return false;
130 HpackEntry* entry = header_table_.GetByIndex(index);
131 if (entry == NULL)
132 return false;
134 HandleHeaderRepresentation(entry->name(), entry->value());
135 return true;
138 bool HpackDecoder::DecodeNextLiteralHeader(HpackInputStream* input_stream,
139 bool should_index) {
140 StringPiece name;
141 if (!DecodeNextName(input_stream, &name))
142 return false;
144 StringPiece value;
145 if (!DecodeNextStringLiteral(input_stream, false, &value))
146 return false;
148 HandleHeaderRepresentation(name, value);
150 if (!should_index)
151 return true;
153 ignore_result(header_table_.TryAddEntry(name, value));
154 return true;
157 bool HpackDecoder::DecodeNextName(
158 HpackInputStream* input_stream, StringPiece* next_name) {
159 uint32 index_or_zero = 0;
160 if (!input_stream->DecodeNextUint32(&index_or_zero))
161 return false;
163 if (index_or_zero == 0)
164 return DecodeNextStringLiteral(input_stream, true, next_name);
166 const HpackEntry* entry = header_table_.GetByIndex(index_or_zero);
167 if (entry == NULL) {
168 return false;
169 } else if (entry->IsStatic()) {
170 *next_name = entry->name();
171 } else {
172 // |entry| could be evicted as part of this insertion. Preemptively copy.
173 key_buffer_.assign(entry->name());
174 *next_name = key_buffer_;
176 return true;
179 bool HpackDecoder::DecodeNextStringLiteral(HpackInputStream* input_stream,
180 bool is_key,
181 StringPiece* output) {
182 if (input_stream->MatchPrefixAndConsume(kStringLiteralHuffmanEncoded)) {
183 string* buffer = is_key ? &key_buffer_ : &value_buffer_;
184 bool result = input_stream->DecodeNextHuffmanString(huffman_table_, buffer);
185 *output = StringPiece(*buffer);
186 return result;
187 } else if (input_stream->MatchPrefixAndConsume(
188 kStringLiteralIdentityEncoded)) {
189 return input_stream->DecodeNextIdentityString(output);
190 } else {
191 return false;
195 } // namespace net