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" | |
10 #include "net/spdy/hpack_constants.h" | 9 #include "net/spdy/hpack_constants.h" |
11 #include "net/spdy/hpack_output_stream.h" | 10 #include "net/spdy/hpack_output_stream.h" |
12 | 11 |
13 namespace net { | 12 namespace net { |
14 | 13 |
15 using base::StringPiece; | 14 using base::StringPiece; |
16 using std::string; | 15 using std::string; |
17 | 16 |
18 namespace { | 17 namespace { |
19 | 18 |
20 const uint8 kNoState = 0; | 19 const uint8 kNoState = 0; |
21 // Set on entries added to the reference set during this decoding. | 20 // Set on entries added to the reference set during this decoding. |
22 const uint8 kReferencedThisEncoding = 1; | 21 const uint8 kReferencedThisEncoding = 1; |
23 | 22 |
| 23 const char kCookieKey[] = "cookie"; |
| 24 |
24 } // namespace | 25 } // namespace |
25 | 26 |
26 HpackDecoder::HpackDecoder(const HpackHuffmanTable& table) | 27 HpackDecoder::HpackDecoder(const HpackHuffmanTable& table) |
27 : max_string_literal_size_(kDefaultMaxStringLiteralSize), | 28 : max_string_literal_size_(kDefaultMaxStringLiteralSize), |
28 huffman_table_(table) {} | 29 huffman_table_(table) {} |
29 | 30 |
30 HpackDecoder::~HpackDecoder() {} | 31 HpackDecoder::~HpackDecoder() {} |
31 | 32 |
32 bool HpackDecoder::HandleControlFrameHeadersData(SpdyStreamId id, | 33 bool HpackDecoder::HandleControlFrameHeadersData(SpdyStreamId id, |
33 const char* headers_data, | 34 const char* headers_data, |
(...skipping 28 matching lines...) Expand all Loading... |
62 it != header_table_.reference_set().end(); ++it) { | 63 it != header_table_.reference_set().end(); ++it) { |
63 HpackEntry* entry = *it; | 64 HpackEntry* entry = *it; |
64 | 65 |
65 if (entry->state() == kNoState) { | 66 if (entry->state() == kNoState) { |
66 HandleHeaderRepresentation(entry->name(), entry->value()); | 67 HandleHeaderRepresentation(entry->name(), entry->value()); |
67 } else { | 68 } else { |
68 entry->set_state(kNoState); | 69 entry->set_state(kNoState); |
69 } | 70 } |
70 } | 71 } |
71 // Emit the Cookie header, if any crumbles were encountered. | 72 // Emit the Cookie header, if any crumbles were encountered. |
72 if (!cookie_name_.empty()) { | 73 if (!cookie_value_.empty()) { |
73 decoded_block_[cookie_name_] = cookie_value_; | 74 decoded_block_[kCookieKey] = cookie_value_; |
74 cookie_name_.clear(); | |
75 cookie_value_.clear(); | 75 cookie_value_.clear(); |
76 } | 76 } |
77 return true; | 77 return true; |
78 } | 78 } |
79 | 79 |
80 void HpackDecoder::HandleHeaderRepresentation(StringPiece name, | 80 void HpackDecoder::HandleHeaderRepresentation(StringPiece name, |
81 StringPiece value) { | 81 StringPiece value) { |
82 typedef std::pair<std::map<string, string>::iterator, bool> InsertResult; | 82 typedef std::pair<std::map<string, string>::iterator, bool> InsertResult; |
83 | 83 |
84 // TODO(jgraettinger): HTTP/2 requires strict lowercasing of headers, | 84 if (name == kCookieKey) { |
85 // and the permissiveness here isn't wanted. Back this out in upstream. | 85 if (cookie_value_.empty()) { |
86 if (LowerCaseEqualsASCII(name.begin(), name.end(), "cookie")) { | |
87 if (cookie_name_.empty()) { | |
88 cookie_name_.assign(name.data(), name.size()); | |
89 cookie_value_.assign(value.data(), value.size()); | 86 cookie_value_.assign(value.data(), value.size()); |
90 } else { | 87 } else { |
91 cookie_value_ += "; "; | 88 cookie_value_ += "; "; |
92 cookie_value_.insert(cookie_value_.end(), value.begin(), value.end()); | 89 cookie_value_.insert(cookie_value_.end(), value.begin(), value.end()); |
93 } | 90 } |
94 } else { | 91 } else { |
95 InsertResult result = decoded_block_.insert( | 92 InsertResult result = decoded_block_.insert( |
96 std::make_pair(name.as_string(), value.as_string())); | 93 std::make_pair(name.as_string(), value.as_string())); |
97 if (!result.second) { | 94 if (!result.second) { |
98 result.first->second.push_back('\0'); | 95 result.first->second.push_back('\0'); |
99 result.first->second.insert(result.first->second.end(), | 96 result.first->second.insert(result.first->second.end(), |
100 value.begin(), | 97 value.begin(), |
101 value.end()); | 98 value.end()); |
102 } | 99 } |
103 } | 100 } |
104 } | 101 } |
105 | 102 |
106 bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) { | 103 bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) { |
107 // Implements 4.4: Encoding context update. Context updates are a special-case | |
108 // of indexed header, and must be tested prior to |kIndexedOpcode| below. | |
109 if (input_stream->MatchPrefixAndConsume(kEncodingContextOpcode)) { | |
110 return DecodeNextContextUpdate(input_stream); | |
111 } | |
112 // Implements 4.2: Indexed Header Field Representation. | 104 // Implements 4.2: Indexed Header Field Representation. |
113 if (input_stream->MatchPrefixAndConsume(kIndexedOpcode)) { | 105 if (input_stream->MatchPrefixAndConsume(kIndexedOpcode)) { |
114 return DecodeNextIndexedHeader(input_stream); | 106 return DecodeNextIndexedHeader(input_stream); |
115 } | 107 } |
116 // Implements 4.3.1: Literal Header Field without Indexing. | 108 // Implements 4.3.1: Literal Header Field without Indexing. |
117 if (input_stream->MatchPrefixAndConsume(kLiteralNoIndexOpcode)) { | 109 if (input_stream->MatchPrefixAndConsume(kLiteralNoIndexOpcode)) { |
118 return DecodeNextLiteralHeader(input_stream, false); | 110 return DecodeNextLiteralHeader(input_stream, false); |
119 } | 111 } |
120 // Implements 4.3.2: Literal Header Field with Incremental Indexing. | 112 // Implements 4.3.2: Literal Header Field with Incremental Indexing. |
121 if (input_stream->MatchPrefixAndConsume(kLiteralIncrementalIndexOpcode)) { | 113 if (input_stream->MatchPrefixAndConsume(kLiteralIncrementalIndexOpcode)) { |
122 return DecodeNextLiteralHeader(input_stream, true); | 114 return DecodeNextLiteralHeader(input_stream, true); |
123 } | 115 } |
| 116 // Implements 4.3.3: Literal Header Field never Indexed. |
| 117 // TODO(jgraettinger): Preserve the never-indexed bit. |
| 118 if (input_stream->MatchPrefixAndConsume(kLiteralNeverIndexOpcode)) { |
| 119 return DecodeNextLiteralHeader(input_stream, false); |
| 120 } |
| 121 // Implements 4.4: Encoding context update. |
| 122 if (input_stream->MatchPrefixAndConsume(kEncodingContextOpcode)) { |
| 123 return DecodeNextContextUpdate(input_stream); |
| 124 } |
124 // Unrecognized opcode. | 125 // Unrecognized opcode. |
125 return false; | 126 return false; |
126 } | 127 } |
127 | 128 |
128 bool HpackDecoder::DecodeNextContextUpdate(HpackInputStream* input_stream) { | 129 bool HpackDecoder::DecodeNextContextUpdate(HpackInputStream* input_stream) { |
129 if (input_stream->MatchPrefixAndConsume(kEncodingContextEmptyReferenceSet)) { | 130 if (input_stream->MatchPrefixAndConsume(kEncodingContextEmptyReferenceSet)) { |
130 header_table_.ClearReferenceSet(); | 131 header_table_.ClearReferenceSet(); |
131 return true; | 132 return true; |
132 } | 133 } |
133 if (input_stream->MatchPrefixAndConsume(kEncodingContextNewMaximumSize)) { | 134 if (input_stream->MatchPrefixAndConsume(kEncodingContextNewMaximumSize)) { |
134 uint32 size = 0; | 135 uint32 size = 0; |
135 if (!input_stream->DecodeNextUint32(&size)) { | 136 if (!input_stream->DecodeNextUint32(&size)) { |
136 return false; | 137 return false; |
137 } | 138 } |
138 if (size > header_table_.settings_size_bound()) { | 139 if (size > header_table_.settings_size_bound()) { |
139 return false; | 140 return false; |
140 } | 141 } |
141 header_table_.SetMaxSize(size); | 142 header_table_.SetMaxSize(size); |
142 return true; | 143 return true; |
143 } | 144 } |
144 // Unrecognized encoding context update. | 145 // Unrecognized encoding context update. |
145 return false; | 146 return false; |
146 } | 147 } |
147 | 148 |
148 bool HpackDecoder::DecodeNextIndexedHeader(HpackInputStream* input_stream) { | 149 bool HpackDecoder::DecodeNextIndexedHeader(HpackInputStream* input_stream) { |
149 uint32 index = 0; | 150 uint32 index = 0; |
150 if (!input_stream->DecodeNextUint32(&index)) | 151 if (!input_stream->DecodeNextUint32(&index)) |
151 return false; | 152 return false; |
152 | 153 |
153 // If index == 0, |kEncodingContextOpcode| would have matched. | |
154 CHECK_NE(index, 0u); | |
155 | |
156 HpackEntry* entry = header_table_.GetByIndex(index); | 154 HpackEntry* entry = header_table_.GetByIndex(index); |
157 if (entry == NULL) | 155 if (entry == NULL) |
158 return false; | 156 return false; |
159 | 157 |
160 if (entry->IsStatic()) { | 158 if (entry->IsStatic()) { |
161 HandleHeaderRepresentation(entry->name(), entry->value()); | 159 HandleHeaderRepresentation(entry->name(), entry->value()); |
162 | 160 |
163 HpackEntry* new_entry = header_table_.TryAddEntry( | 161 HpackEntry* new_entry = header_table_.TryAddEntry( |
164 entry->name(), entry->value()); | 162 entry->name(), entry->value()); |
165 if (new_entry) { | 163 if (new_entry) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 return result; | 229 return result; |
232 } else if (input_stream->MatchPrefixAndConsume( | 230 } else if (input_stream->MatchPrefixAndConsume( |
233 kStringLiteralIdentityEncoded)) { | 231 kStringLiteralIdentityEncoded)) { |
234 return input_stream->DecodeNextIdentityString(output); | 232 return input_stream->DecodeNextIdentityString(output); |
235 } else { | 233 } else { |
236 return false; | 234 return false; |
237 } | 235 } |
238 } | 236 } |
239 | 237 |
240 } // namespace net | 238 } // namespace net |
OLD | NEW |