Fix mouse warp with 2x displays
[chromium-blink-merge.git] / net / spdy / hpack_decoder.cc
blob8c59437aafad0e971610374e68219c350bce337c
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 <utility>
9 #include "base/basictypes.h"
10 #include "base/logging.h"
11 #include "net/spdy/hpack_constants.h"
12 #include "net/spdy/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(),
42 headers_data,
43 headers_data + headers_data_length);
44 return true;
47 bool HpackDecoder::HandleControlFrameHeadersComplete(SpdyStreamId id,
48 size_t* compressed_len) {
49 HpackInputStream input_stream(max_string_literal_size_,
50 headers_block_buffer_);
51 regular_header_seen_ = false;
52 if (compressed_len) {
53 *compressed_len = headers_block_buffer_.size();
55 while (input_stream.HasMoreData()) {
56 if (!DecodeNextOpcode(&input_stream)) {
57 headers_block_buffer_.clear();
58 return false;
61 headers_block_buffer_.clear();
63 // Emit the Cookie header, if any crumbles were encountered.
64 if (!cookie_value_.empty()) {
65 decoded_block_[kCookieKey] = cookie_value_;
66 cookie_value_.clear();
68 return true;
71 bool HpackDecoder::HandleHeaderRepresentation(StringPiece name,
72 StringPiece value) {
73 typedef std::pair<SpdyHeaderBlock::iterator, bool> InsertResult;
75 // Fail if pseudo-header follows regular header.
76 if (name.size() > 0) {
77 if (name[0] == kPseudoHeaderPrefix) {
78 if (regular_header_seen_) return false;
79 } else {
80 regular_header_seen_ = true;
84 if (name == kCookieKey) {
85 if (cookie_value_.empty()) {
86 cookie_value_.assign(value.data(), value.size());
87 } else {
88 cookie_value_ += "; ";
89 cookie_value_.insert(cookie_value_.end(), value.begin(), value.end());
91 } else {
92 InsertResult result = decoded_block_.insert(
93 std::make_pair(name.as_string(), value.as_string()));
94 if (!result.second) {
95 result.first->second.push_back('\0');
96 result.first->second.insert(result.first->second.end(),
97 value.begin(),
98 value.end());
101 return true;
104 bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) {
105 // Implements 7.1: Indexed Header Field Representation.
106 if (input_stream->MatchPrefixAndConsume(kIndexedOpcode)) {
107 return DecodeNextIndexedHeader(input_stream);
109 // Implements 7.2.1: Literal Header Field with Incremental Indexing.
110 if (input_stream->MatchPrefixAndConsume(kLiteralIncrementalIndexOpcode)) {
111 return DecodeNextLiteralHeader(input_stream, true);
113 // Implements 7.2.2: Literal Header Field without Indexing.
114 if (input_stream->MatchPrefixAndConsume(kLiteralNoIndexOpcode)) {
115 return DecodeNextLiteralHeader(input_stream, false);
117 // Implements 7.2.3: Literal Header Field never Indexed.
118 // TODO(jgraettinger): Preserve the never-indexed bit.
119 if (input_stream->MatchPrefixAndConsume(kLiteralNeverIndexOpcode)) {
120 return DecodeNextLiteralHeader(input_stream, false);
122 // Implements 7.3: Header Table Size Update.
123 if (input_stream->MatchPrefixAndConsume(kHeaderTableSizeUpdateOpcode)) {
124 return DecodeNextHeaderTableSizeUpdate(input_stream);
126 // Unrecognized opcode.
127 return false;
130 bool HpackDecoder::DecodeNextHeaderTableSizeUpdate(
131 HpackInputStream* input_stream) {
132 uint32 size = 0;
133 if (!input_stream->DecodeNextUint32(&size)) {
134 return false;
136 if (size > header_table_.settings_size_bound()) {
137 return false;
139 header_table_.SetMaxSize(size);
140 return true;
143 bool HpackDecoder::DecodeNextIndexedHeader(HpackInputStream* input_stream) {
144 uint32 index = 0;
145 if (!input_stream->DecodeNextUint32(&index))
146 return false;
148 const HpackEntry* entry = header_table_.GetByIndex(index);
149 if (entry == NULL)
150 return false;
152 return HandleHeaderRepresentation(entry->name(), entry->value());
155 bool HpackDecoder::DecodeNextLiteralHeader(HpackInputStream* input_stream,
156 bool should_index) {
157 StringPiece name;
158 if (!DecodeNextName(input_stream, &name))
159 return false;
161 StringPiece value;
162 if (!DecodeNextStringLiteral(input_stream, false, &value))
163 return false;
165 if (!HandleHeaderRepresentation(name, value)) return false;
167 if (!should_index)
168 return true;
170 ignore_result(header_table_.TryAddEntry(name, value));
171 return true;
174 bool HpackDecoder::DecodeNextName(
175 HpackInputStream* input_stream, StringPiece* next_name) {
176 uint32 index_or_zero = 0;
177 if (!input_stream->DecodeNextUint32(&index_or_zero))
178 return false;
180 if (index_or_zero == 0)
181 return DecodeNextStringLiteral(input_stream, true, next_name);
183 const HpackEntry* entry = header_table_.GetByIndex(index_or_zero);
184 if (entry == NULL) {
185 return false;
186 } else if (entry->IsStatic()) {
187 *next_name = entry->name();
188 } else {
189 // |entry| could be evicted as part of this insertion. Preemptively copy.
190 key_buffer_.assign(entry->name());
191 *next_name = key_buffer_;
193 return true;
196 bool HpackDecoder::DecodeNextStringLiteral(HpackInputStream* input_stream,
197 bool is_key,
198 StringPiece* output) {
199 if (input_stream->MatchPrefixAndConsume(kStringLiteralHuffmanEncoded)) {
200 string* buffer = is_key ? &key_buffer_ : &value_buffer_;
201 bool result = input_stream->DecodeNextHuffmanString(huffman_table_, buffer);
202 *output = StringPiece(*buffer);
203 return result;
204 } else if (input_stream->MatchPrefixAndConsume(
205 kStringLiteralIdentityEncoded)) {
206 return input_stream->DecodeNextIdentityString(output);
207 } else {
208 return false;
212 } // namespace net