OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/spdy/hpack_decoder.h" | 5 #include "net/spdy/hpack_decoder.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "net/spdy/hpack_constants.h" | 10 #include "net/spdy/hpack_constants.h" |
11 #include "net/spdy/hpack_output_stream.h" | 11 #include "net/spdy/hpack_output_stream.h" |
12 | 12 |
13 namespace net { | 13 namespace net { |
14 | 14 |
15 using base::StringPiece; | 15 using base::StringPiece; |
16 using std::string; | 16 using std::string; |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 const uint8 kNoState = 0; | 20 const uint8 kNoState = 0; |
21 // Set on entries added to the reference set during this decoding. | 21 // Set on entries added to the reference set during this decoding. |
22 const uint8 kReferencedThisEncoding = 1; | 22 const uint8 kReferencedThisEncoding = 1; |
23 | 23 |
24 } // namespace | 24 } // namespace |
25 | 25 |
26 HpackDecoder::HpackDecoder(const HpackHuffmanTable& table) | 26 HpackDecoder::HpackDecoder(const HpackHuffmanTable& table) |
27 : max_string_literal_size_(kDefaultMaxStringLiteralSize), | 27 : max_string_literal_size_(kDefaultMaxStringLiteralSize), |
28 huffman_table_(table) {} | 28 huffman_table_(table) { |
| 29 } |
29 | 30 |
30 HpackDecoder::~HpackDecoder() {} | 31 HpackDecoder::~HpackDecoder() { |
| 32 } |
31 | 33 |
32 bool HpackDecoder::HandleControlFrameHeadersData(SpdyStreamId id, | 34 bool HpackDecoder::HandleControlFrameHeadersData(SpdyStreamId id, |
33 const char* headers_data, | 35 const char* headers_data, |
34 size_t headers_data_length) { | 36 size_t headers_data_length) { |
35 decoded_block_.clear(); | 37 decoded_block_.clear(); |
36 | 38 |
37 size_t new_size = headers_block_buffer_.size() + headers_data_length; | 39 size_t new_size = headers_block_buffer_.size() + headers_data_length; |
38 if (new_size > kMaxDecodeBufferSize) { | 40 if (new_size > kMaxDecodeBufferSize) { |
39 return false; | 41 return false; |
40 } | 42 } |
(...skipping 10 matching lines...) Expand all Loading... |
51 if (!DecodeNextOpcode(&input_stream)) | 53 if (!DecodeNextOpcode(&input_stream)) |
52 return false; | 54 return false; |
53 } | 55 } |
54 headers_block_buffer_.clear(); | 56 headers_block_buffer_.clear(); |
55 | 57 |
56 // Emit everything in the reference set that hasn't already been emitted. | 58 // Emit everything in the reference set that hasn't already been emitted. |
57 // Also clear entry state for the next decoded headers block. | 59 // Also clear entry state for the next decoded headers block. |
58 // TODO(jgraettinger): We may need to revisit the order in which headers | 60 // TODO(jgraettinger): We may need to revisit the order in which headers |
59 // are emitted (b/14051713). | 61 // are emitted (b/14051713). |
60 for (HpackEntry::OrderedSet::const_iterator it = | 62 for (HpackEntry::OrderedSet::const_iterator it = |
61 header_table_.reference_set().begin(); | 63 header_table_.reference_set().begin(); |
62 it != header_table_.reference_set().end(); ++it) { | 64 it != header_table_.reference_set().end(); |
| 65 ++it) { |
63 HpackEntry* entry = *it; | 66 HpackEntry* entry = *it; |
64 | 67 |
65 if (entry->state() == kNoState) { | 68 if (entry->state() == kNoState) { |
66 HandleHeaderRepresentation(entry->name(), entry->value()); | 69 HandleHeaderRepresentation(entry->name(), entry->value()); |
67 } else { | 70 } else { |
68 entry->set_state(kNoState); | 71 entry->set_state(kNoState); |
69 } | 72 } |
70 } | 73 } |
71 // Emit the Cookie header, if any crumbles were encountered. | 74 // Emit the Cookie header, if any crumbles were encountered. |
72 if (!cookie_name_.empty()) { | 75 if (!cookie_name_.empty()) { |
(...skipping 16 matching lines...) Expand all Loading... |
89 cookie_value_.assign(value.data(), value.size()); | 92 cookie_value_.assign(value.data(), value.size()); |
90 } else { | 93 } else { |
91 cookie_value_ += "; "; | 94 cookie_value_ += "; "; |
92 cookie_value_.insert(cookie_value_.end(), value.begin(), value.end()); | 95 cookie_value_.insert(cookie_value_.end(), value.begin(), value.end()); |
93 } | 96 } |
94 } else { | 97 } else { |
95 InsertResult result = decoded_block_.insert( | 98 InsertResult result = decoded_block_.insert( |
96 std::make_pair(name.as_string(), value.as_string())); | 99 std::make_pair(name.as_string(), value.as_string())); |
97 if (!result.second) { | 100 if (!result.second) { |
98 result.first->second.push_back('\0'); | 101 result.first->second.push_back('\0'); |
99 result.first->second.insert(result.first->second.end(), | 102 result.first->second.insert( |
100 value.begin(), | 103 result.first->second.end(), value.begin(), value.end()); |
101 value.end()); | |
102 } | 104 } |
103 } | 105 } |
104 } | 106 } |
105 | 107 |
106 bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) { | 108 bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) { |
107 // Implements 4.4: Encoding context update. Context updates are a special-case | 109 // Implements 4.4: Encoding context update. Context updates are a special-case |
108 // of indexed header, and must be tested prior to |kIndexedOpcode| below. | 110 // of indexed header, and must be tested prior to |kIndexedOpcode| below. |
109 if (input_stream->MatchPrefixAndConsume(kEncodingContextOpcode)) { | 111 if (input_stream->MatchPrefixAndConsume(kEncodingContextOpcode)) { |
110 return DecodeNextContextUpdate(input_stream); | 112 return DecodeNextContextUpdate(input_stream); |
111 } | 113 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 // If index == 0, |kEncodingContextOpcode| would have matched. | 155 // If index == 0, |kEncodingContextOpcode| would have matched. |
154 CHECK_NE(index, 0u); | 156 CHECK_NE(index, 0u); |
155 | 157 |
156 HpackEntry* entry = header_table_.GetByIndex(index); | 158 HpackEntry* entry = header_table_.GetByIndex(index); |
157 if (entry == NULL) | 159 if (entry == NULL) |
158 return false; | 160 return false; |
159 | 161 |
160 if (entry->IsStatic()) { | 162 if (entry->IsStatic()) { |
161 HandleHeaderRepresentation(entry->name(), entry->value()); | 163 HandleHeaderRepresentation(entry->name(), entry->value()); |
162 | 164 |
163 HpackEntry* new_entry = header_table_.TryAddEntry( | 165 HpackEntry* new_entry = |
164 entry->name(), entry->value()); | 166 header_table_.TryAddEntry(entry->name(), entry->value()); |
165 if (new_entry) { | 167 if (new_entry) { |
166 header_table_.Toggle(new_entry); | 168 header_table_.Toggle(new_entry); |
167 new_entry->set_state(kReferencedThisEncoding); | 169 new_entry->set_state(kReferencedThisEncoding); |
168 } | 170 } |
169 } else { | 171 } else { |
170 entry->set_state(kNoState); | 172 entry->set_state(kNoState); |
171 if (header_table_.Toggle(entry)) { | 173 if (header_table_.Toggle(entry)) { |
172 HandleHeaderRepresentation(entry->name(), entry->value()); | 174 HandleHeaderRepresentation(entry->name(), entry->value()); |
173 entry->set_state(kReferencedThisEncoding); | 175 entry->set_state(kReferencedThisEncoding); |
174 } | 176 } |
(...skipping 17 matching lines...) Expand all Loading... |
192 return true; | 194 return true; |
193 | 195 |
194 HpackEntry* new_entry = header_table_.TryAddEntry(name, value); | 196 HpackEntry* new_entry = header_table_.TryAddEntry(name, value); |
195 if (new_entry) { | 197 if (new_entry) { |
196 header_table_.Toggle(new_entry); | 198 header_table_.Toggle(new_entry); |
197 new_entry->set_state(kReferencedThisEncoding); | 199 new_entry->set_state(kReferencedThisEncoding); |
198 } | 200 } |
199 return true; | 201 return true; |
200 } | 202 } |
201 | 203 |
202 bool HpackDecoder::DecodeNextName( | 204 bool HpackDecoder::DecodeNextName(HpackInputStream* input_stream, |
203 HpackInputStream* input_stream, StringPiece* next_name) { | 205 StringPiece* next_name) { |
204 uint32 index_or_zero = 0; | 206 uint32 index_or_zero = 0; |
205 if (!input_stream->DecodeNextUint32(&index_or_zero)) | 207 if (!input_stream->DecodeNextUint32(&index_or_zero)) |
206 return false; | 208 return false; |
207 | 209 |
208 if (index_or_zero == 0) | 210 if (index_or_zero == 0) |
209 return DecodeNextStringLiteral(input_stream, true, next_name); | 211 return DecodeNextStringLiteral(input_stream, true, next_name); |
210 | 212 |
211 const HpackEntry* entry = header_table_.GetByIndex(index_or_zero); | 213 const HpackEntry* entry = header_table_.GetByIndex(index_or_zero); |
212 if (entry == NULL) { | 214 if (entry == NULL) { |
213 return false; | 215 return false; |
214 } else if (entry->IsStatic()) { | 216 } else if (entry->IsStatic()) { |
215 *next_name = entry->name(); | 217 *next_name = entry->name(); |
216 } else { | 218 } else { |
217 // |entry| could be evicted as part of this insertion. Preemptively copy. | 219 // |entry| could be evicted as part of this insertion. Preemptively copy. |
218 key_buffer_.assign(entry->name()); | 220 key_buffer_.assign(entry->name()); |
219 *next_name = key_buffer_; | 221 *next_name = key_buffer_; |
220 } | 222 } |
221 return true; | 223 return true; |
222 } | 224 } |
223 | 225 |
224 bool HpackDecoder::DecodeNextStringLiteral(HpackInputStream* input_stream, | 226 bool HpackDecoder::DecodeNextStringLiteral(HpackInputStream* input_stream, |
225 bool is_key, | 227 bool is_key, |
226 StringPiece* output) { | 228 StringPiece* output) { |
227 if (input_stream->MatchPrefixAndConsume(kStringLiteralHuffmanEncoded)) { | 229 if (input_stream->MatchPrefixAndConsume(kStringLiteralHuffmanEncoded)) { |
228 string* buffer = is_key ? &key_buffer_ : &value_buffer_; | 230 string* buffer = is_key ? &key_buffer_ : &value_buffer_; |
229 bool result = input_stream->DecodeNextHuffmanString(huffman_table_, buffer); | 231 bool result = input_stream->DecodeNextHuffmanString(huffman_table_, buffer); |
230 *output = StringPiece(*buffer); | 232 *output = StringPiece(*buffer); |
231 return result; | 233 return result; |
232 } else if (input_stream->MatchPrefixAndConsume( | 234 } else if (input_stream->MatchPrefixAndConsume( |
233 kStringLiteralIdentityEncoded)) { | 235 kStringLiteralIdentityEncoded)) { |
234 return input_stream->DecodeNextIdentityString(output); | 236 return input_stream->DecodeNextIdentityString(output); |
235 } else { | 237 } else { |
236 return false; | 238 return false; |
237 } | 239 } |
238 } | 240 } |
239 | 241 |
240 } // namespace net | 242 } // namespace net |
OLD | NEW |