| 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 |