| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/hpack_decoder2.h" | 5 #include "net/spdy/hpack/hpack_decoder3.h" |
| 6 | 6 |
| 7 // Tests of HpackDecoder2. | 7 // Tests of HpackDecoder3. |
| 8 |
| 9 #include <stdint.h> |
| 8 | 10 |
| 9 #include <string> | 11 #include <string> |
| 10 #include <tuple> | 12 #include <tuple> |
| 11 #include <utility> | 13 #include <utility> |
| 12 #include <vector> | 14 #include <vector> |
| 13 | 15 |
| 14 #include "base/logging.h" | 16 #include "base/logging.h" |
| 15 #include "base/strings/string_piece.h" | 17 #include "base/strings/string_number_conversions.h" |
| 18 #include "net/http2/hpack/decoder/hpack_decoder_state.h" |
| 19 #include "net/http2/hpack/decoder/hpack_decoder_tables.h" |
| 16 #include "net/http2/hpack/tools/hpack_block_builder.h" | 20 #include "net/http2/hpack/tools/hpack_block_builder.h" |
| 17 #include "net/http2/tools/http2_random.h" | 21 #include "net/http2/tools/http2_random.h" |
| 22 #include "net/spdy/hpack/hpack_constants.h" |
| 18 #include "net/spdy/hpack/hpack_encoder.h" | 23 #include "net/spdy/hpack/hpack_encoder.h" |
| 19 #include "net/spdy/hpack/hpack_entry.h" | |
| 20 #include "net/spdy/hpack/hpack_huffman_table.h" | 24 #include "net/spdy/hpack/hpack_huffman_table.h" |
| 21 #include "net/spdy/hpack/hpack_output_stream.h" | 25 #include "net/spdy/hpack/hpack_output_stream.h" |
| 22 #include "net/spdy/spdy_test_utils.h" | 26 #include "net/spdy/spdy_test_utils.h" |
| 27 #include "testing/gmock/include/gmock/gmock.h" |
| 23 #include "testing/gtest/include/gtest/gtest.h" | 28 #include "testing/gtest/include/gtest/gtest.h" |
| 24 | 29 |
| 25 using base::StringPiece; | 30 using base::StringPiece; |
| 26 using std::string; | 31 using std::string; |
| 32 using ::testing::ElementsAre; |
| 33 using ::testing::Pair; |
| 27 | 34 |
| 28 namespace net { | 35 namespace net { |
| 29 namespace test { | 36 namespace test { |
| 30 | 37 |
| 31 class HpackDecoder2Peer { | 38 class HpackDecoderStatePeer { |
| 32 public: | 39 public: |
| 33 explicit HpackDecoder2Peer(HpackDecoder2* decoder) : decoder_(decoder) {} | 40 static HpackDecoderTables* GetDecoderTables(HpackDecoderState* state) { |
| 41 return &state->decoder_tables_; |
| 42 } |
| 43 }; |
| 44 |
| 45 class Http2HpackDecoderPeer { |
| 46 public: |
| 47 static HpackDecoderState* GetDecoderState(Http2HpackDecoder* decoder) { |
| 48 return &decoder->decoder_state_; |
| 49 } |
| 50 static HpackDecoderTables* GetDecoderTables(Http2HpackDecoder* decoder) { |
| 51 return HpackDecoderStatePeer::GetDecoderTables(GetDecoderState(decoder)); |
| 52 } |
| 53 }; |
| 54 |
| 55 class HpackDecoder3Peer { |
| 56 public: |
| 57 explicit HpackDecoder3Peer(HpackDecoder3* decoder) : decoder_(decoder) {} |
| 34 | 58 |
| 35 void HandleHeaderRepresentation(StringPiece name, StringPiece value) { | 59 void HandleHeaderRepresentation(StringPiece name, StringPiece value) { |
| 36 decoder_->HandleHeaderRepresentation(name, value); | 60 decoder_->listener_adapter_.OnHeader(HpackEntryType::kIndexedLiteralHeader, |
| 61 HpackString(name), HpackString(value)); |
| 37 } | 62 } |
| 38 HpackHeaderTable* header_table() { return &decoder_->header_table_; } | 63 |
| 64 HpackDecoderTables* GetDecoderTables() { |
| 65 return Http2HpackDecoderPeer::GetDecoderTables(&decoder_->hpack_decoder_); |
| 66 } |
| 67 |
| 68 const HpackStringPair* GetTableEntry(uint32_t index) { |
| 69 return GetDecoderTables()->Lookup(index); |
| 70 } |
| 71 |
| 72 size_t current_header_table_size() { |
| 73 return GetDecoderTables()->current_header_table_size(); |
| 74 } |
| 75 |
| 76 size_t header_table_size_limit() { |
| 77 return GetDecoderTables()->header_table_size_limit(); |
| 78 } |
| 79 |
| 80 void set_header_table_size_limit(size_t size) { |
| 81 return GetDecoderTables()->DynamicTableSizeUpdate(size); |
| 82 } |
| 39 | 83 |
| 40 private: | 84 private: |
| 41 HpackDecoder2* decoder_; | 85 HpackDecoder3* decoder_; |
| 42 }; | 86 }; |
| 43 | 87 |
| 44 namespace { | 88 namespace { |
| 45 | 89 |
| 46 using testing::ElementsAre; | |
| 47 using testing::Pair; | |
| 48 | |
| 49 // Is HandleControlFrameHeadersStart to be called, and with what value? | 90 // Is HandleControlFrameHeadersStart to be called, and with what value? |
| 50 enum StartChoice { START_WITH_HANDLER, START_WITHOUT_HANDLER, NO_START }; | 91 enum StartChoice { START_WITH_HANDLER, START_WITHOUT_HANDLER, NO_START }; |
| 51 | 92 |
| 52 class HpackDecoder2Test | 93 class HpackDecoder3Test |
| 53 : public ::testing::TestWithParam<std::tuple<StartChoice, bool>> { | 94 : public ::testing::TestWithParam<std::tuple<StartChoice, bool>> { |
| 54 protected: | 95 protected: |
| 55 HpackDecoder2Test() : decoder_(), decoder_peer_(&decoder_) {} | 96 HpackDecoder3Test() : decoder_(), decoder_peer_(&decoder_) {} |
| 56 | 97 |
| 57 void SetUp() override { | 98 void SetUp() override { |
| 58 std::tie(start_choice_, randomly_split_input_buffer_) = GetParam(); | 99 std::tie(start_choice_, randomly_split_input_buffer_) = GetParam(); |
| 59 } | 100 } |
| 60 | 101 |
| 61 void HandleControlFrameHeadersStart() { | 102 void HandleControlFrameHeadersStart() { |
| 62 switch (start_choice_) { | 103 switch (start_choice_) { |
| 63 case START_WITH_HANDLER: | 104 case START_WITH_HANDLER: |
| 64 decoder_.HandleControlFrameHeadersStart(&handler_); | 105 decoder_.HandleControlFrameHeadersStart(&handler_); |
| 65 break; | 106 break; |
| 66 case START_WITHOUT_HANDLER: | 107 case START_WITHOUT_HANDLER: |
| 67 decoder_.HandleControlFrameHeadersStart(nullptr); | 108 decoder_.HandleControlFrameHeadersStart(nullptr); |
| 68 break; | 109 break; |
| 69 case NO_START: | 110 case NO_START: |
| 70 break; | 111 break; |
| 71 } | 112 } |
| 72 } | 113 } |
| 73 | 114 |
| 74 bool HandleControlFrameHeadersData(StringPiece str) { | 115 bool HandleControlFrameHeadersData(StringPiece str) { |
| 116 VLOG(3) << "HandleControlFrameHeadersData:\n" |
| 117 << base::HexEncode(str.data(), str.size()); |
| 75 return decoder_.HandleControlFrameHeadersData(str.data(), str.size()); | 118 return decoder_.HandleControlFrameHeadersData(str.data(), str.size()); |
| 76 } | 119 } |
| 77 | 120 |
| 78 bool HandleControlFrameHeadersComplete(size_t* size) { | 121 bool HandleControlFrameHeadersComplete(size_t* size) { |
| 79 return decoder_.HandleControlFrameHeadersComplete(size); | 122 return decoder_.HandleControlFrameHeadersComplete(size); |
| 80 } | 123 } |
| 81 | 124 |
| 82 bool DecodeHeaderBlock(StringPiece str) { | 125 bool DecodeHeaderBlock(StringPiece str) { |
| 83 // Don't call this again if HandleControlFrameHeadersData failed previously. | 126 // Don't call this again if HandleControlFrameHeadersData failed previously. |
| 84 EXPECT_FALSE(decode_has_failed_); | 127 EXPECT_FALSE(decode_has_failed_); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 101 decode_has_failed_ = true; | 144 decode_has_failed_ = true; |
| 102 return false; | 145 return false; |
| 103 } | 146 } |
| 104 if (!HandleControlFrameHeadersComplete(nullptr)) { | 147 if (!HandleControlFrameHeadersComplete(nullptr)) { |
| 105 decode_has_failed_ = true; | 148 decode_has_failed_ = true; |
| 106 return false; | 149 return false; |
| 107 } | 150 } |
| 108 return true; | 151 return true; |
| 109 } | 152 } |
| 110 | 153 |
| 154 bool EncodeAndDecodeDynamicTableSizeUpdates(size_t first, size_t second) { |
| 155 HpackBlockBuilder hbb; |
| 156 hbb.AppendDynamicTableSizeUpdate(first); |
| 157 if (second != first) { |
| 158 hbb.AppendDynamicTableSizeUpdate(second); |
| 159 } |
| 160 return DecodeHeaderBlock(hbb.buffer()); |
| 161 } |
| 162 |
| 111 const SpdyHeaderBlock& decoded_block() const { | 163 const SpdyHeaderBlock& decoded_block() const { |
| 112 if (start_choice_ == START_WITH_HANDLER) { | 164 if (start_choice_ == START_WITH_HANDLER) { |
| 113 return handler_.decoded_block(); | 165 return handler_.decoded_block(); |
| 114 } else { | 166 } else { |
| 115 return decoder_.decoded_block(); | 167 return decoder_.decoded_block(); |
| 116 } | 168 } |
| 117 } | 169 } |
| 118 | 170 |
| 119 const SpdyHeaderBlock& DecodeBlockExpectingSuccess(StringPiece str) { | 171 const SpdyHeaderBlock& DecodeBlockExpectingSuccess(StringPiece str) { |
| 120 EXPECT_TRUE(DecodeHeaderBlock(str)); | 172 EXPECT_TRUE(DecodeHeaderBlock(str)); |
| 121 return decoded_block(); | 173 return decoded_block(); |
| 122 } | 174 } |
| 123 | 175 |
| 124 void expectEntry(size_t index, | 176 void expectEntry(size_t index, |
| 125 size_t size, | 177 size_t size, |
| 126 const string& name, | 178 const string& name, |
| 127 const string& value) { | 179 const string& value) { |
| 128 const HpackEntry* entry = decoder_peer_.header_table()->GetByIndex(index); | 180 const HpackStringPair* entry = decoder_peer_.GetTableEntry(index); |
| 129 EXPECT_EQ(name, entry->name()) << "index " << index; | 181 EXPECT_EQ(name, entry->name) << "index " << index; |
| 130 EXPECT_EQ(value, entry->value()); | 182 EXPECT_EQ(value, entry->value); |
| 131 EXPECT_EQ(size, entry->Size()); | 183 EXPECT_EQ(size, entry->size()); |
| 132 EXPECT_EQ(index, decoder_peer_.header_table()->IndexOf(entry)); | |
| 133 } | 184 } |
| 134 | 185 |
| 135 SpdyHeaderBlock MakeHeaderBlock( | 186 SpdyHeaderBlock MakeHeaderBlock( |
| 136 const std::vector<std::pair<string, string>>& headers) { | 187 const std::vector<std::pair<string, string>>& headers) { |
| 137 SpdyHeaderBlock result; | 188 SpdyHeaderBlock result; |
| 138 for (const auto& kv : headers) { | 189 for (const auto& kv : headers) { |
| 139 result.AppendValueOrAddHeader(kv.first, kv.second); | 190 result.AppendValueOrAddHeader(kv.first, kv.second); |
| 140 } | 191 } |
| 141 return result; | 192 return result; |
| 142 } | 193 } |
| 143 | 194 |
| 144 Http2Random random_; | 195 Http2Random random_; |
| 145 HpackDecoder2 decoder_; | 196 HpackHuffmanTable huffman_table_; |
| 146 test::HpackDecoder2Peer decoder_peer_; | 197 HpackDecoder3 decoder_; |
| 198 test::HpackDecoder3Peer decoder_peer_; |
| 147 TestHeadersHandler handler_; | 199 TestHeadersHandler handler_; |
| 148 StartChoice start_choice_; | 200 StartChoice start_choice_; |
| 149 bool randomly_split_input_buffer_; | 201 bool randomly_split_input_buffer_; |
| 150 bool decode_has_failed_ = false; | 202 bool decode_has_failed_ = false; |
| 151 }; | 203 }; |
| 152 | 204 |
| 153 INSTANTIATE_TEST_CASE_P( | 205 INSTANTIATE_TEST_CASE_P( |
| 154 StartChoiceAndRandomlySplitChoice, | 206 StartChoiceAndRandomlySplitChoice, |
| 155 HpackDecoder2Test, | 207 HpackDecoder3Test, |
| 156 ::testing::Combine( | 208 ::testing::Combine( |
| 157 ::testing::Values(START_WITH_HANDLER, START_WITHOUT_HANDLER, NO_START), | 209 ::testing::Values(START_WITH_HANDLER, START_WITHOUT_HANDLER, NO_START), |
| 158 ::testing::Bool())); | 210 ::testing::Bool())); |
| 159 | 211 |
| 160 TEST_P(HpackDecoder2Test, AddHeaderDataWithHandleControlFrameHeadersData) { | 212 TEST_P(HpackDecoder3Test, AddHeaderDataWithHandleControlFrameHeadersData) { |
| 161 // The hpack decode buffer size is limited in size. This test verifies that | 213 // The hpack decode buffer size is limited in size. This test verifies that |
| 162 // adding encoded data under that limit is accepted, and data that exceeds the | 214 // adding encoded data under that limit is accepted, and data that exceeds the |
| 163 // limit is rejected. | 215 // limit is rejected. |
| 164 HandleControlFrameHeadersStart(); | 216 HandleControlFrameHeadersStart(); |
| 165 const size_t kMaxBufferSizeBytes = 50; | 217 const size_t kMaxBufferSizeBytes = 50; |
| 166 const string a_value = string(49, 'x'); | 218 const string a_value = string(49, 'x'); |
| 167 decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes); | 219 decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes); |
| 168 { | 220 HpackBlockBuilder hbb; |
| 169 HpackBlockBuilder hbb; | 221 hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, |
| 170 hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, | 222 false, "a", false, a_value); |
| 171 false, "a", false, a_value); | 223 const string& s = hbb.buffer(); |
| 172 const auto& s = hbb.buffer(); | 224 EXPECT_GT(s.size(), kMaxBufferSizeBytes); |
| 173 EXPECT_TRUE(decoder_.HandleControlFrameHeadersData(s.data(), s.size())); | |
| 174 } | |
| 175 { | |
| 176 HpackBlockBuilder hbb; | |
| 177 hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, | |
| 178 false, "b", false, string(51, 'x')); | |
| 179 const auto& s = hbb.buffer(); | |
| 180 EXPECT_FALSE(decoder_.HandleControlFrameHeadersData(s.data(), s.size())); | |
| 181 } | |
| 182 | 225 |
| 226 // Any one in input buffer must not exceed kMaxBufferSizeBytes. |
| 227 EXPECT_TRUE(HandleControlFrameHeadersData(s.substr(0, s.size() / 2))); |
| 228 EXPECT_TRUE(HandleControlFrameHeadersData(s.substr(s.size() / 2))); |
| 229 |
| 230 EXPECT_FALSE(HandleControlFrameHeadersData(s)); |
| 183 SpdyHeaderBlock expected_block = MakeHeaderBlock({{"a", a_value}}); | 231 SpdyHeaderBlock expected_block = MakeHeaderBlock({{"a", a_value}}); |
| 184 EXPECT_EQ(expected_block, decoded_block()); | 232 EXPECT_EQ(expected_block, decoded_block()); |
| 185 } | 233 } |
| 186 | 234 |
| 187 TEST_P(HpackDecoder2Test, NameTooLong) { | 235 TEST_P(HpackDecoder3Test, NameTooLong) { |
| 188 // Verify that a name longer than the allowed size generates an error. | 236 // Verify that a name longer than the allowed size generates an error. |
| 189 const size_t kMaxBufferSizeBytes = 50; | 237 const size_t kMaxBufferSizeBytes = 50; |
| 190 const string name = string(2 * kMaxBufferSizeBytes, 'x'); | 238 const string name = string(2 * kMaxBufferSizeBytes, 'x'); |
| 191 const string value = "abc"; | 239 const string value = "abc"; |
| 192 | 240 |
| 193 decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes); | 241 decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes); |
| 194 | 242 |
| 195 HpackBlockBuilder hbb; | 243 HpackBlockBuilder hbb; |
| 196 hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, | 244 hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, |
| 197 false, name, false, value); | 245 false, name, false, value); |
| 198 | 246 |
| 199 const size_t fragment_size = (3 * kMaxBufferSizeBytes) / 2; | 247 const size_t fragment_size = (3 * kMaxBufferSizeBytes) / 2; |
| 200 const string fragment = hbb.buffer().substr(0, fragment_size); | 248 const string fragment = hbb.buffer().substr(0, fragment_size); |
| 201 | 249 |
| 202 HandleControlFrameHeadersStart(); | 250 HandleControlFrameHeadersStart(); |
| 203 EXPECT_FALSE(HandleControlFrameHeadersData(fragment)); | 251 EXPECT_FALSE(HandleControlFrameHeadersData(fragment)); |
| 204 } | 252 } |
| 205 | 253 |
| 206 TEST_P(HpackDecoder2Test, HeaderTooLongToBuffer) { | 254 TEST_P(HpackDecoder3Test, HeaderTooLongToBuffer) { |
| 207 // Verify that a header longer than the allowed size generates an error if | 255 // Verify that a header longer than the allowed size generates an error if |
| 208 // it isn't all in one input buffer. | 256 // it isn't all in one input buffer. |
| 209 const string name = "some-key"; | 257 const string name = "some-key"; |
| 210 const string value = "some-value"; | 258 const string value = "some-value"; |
| 211 const size_t kMaxBufferSizeBytes = name.size() + value.size() - 2; | 259 const size_t kMaxBufferSizeBytes = name.size() + value.size() - 2; |
| 212 decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes); | 260 decoder_.set_max_decode_buffer_size_bytes(kMaxBufferSizeBytes); |
| 213 | 261 |
| 214 HpackBlockBuilder hbb; | 262 HpackBlockBuilder hbb; |
| 215 hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, | 263 hbb.AppendLiteralNameAndValue(HpackEntryType::kNeverIndexedLiteralHeader, |
| 216 false, name, false, value); | 264 false, name, false, value); |
| 217 const size_t fragment_size = hbb.size() - 1; | 265 const size_t fragment_size = hbb.size() - 1; |
| 218 const string fragment = hbb.buffer().substr(0, fragment_size); | 266 const string fragment = hbb.buffer().substr(0, fragment_size); |
| 219 | 267 |
| 220 HandleControlFrameHeadersStart(); | 268 HandleControlFrameHeadersStart(); |
| 221 EXPECT_FALSE(HandleControlFrameHeadersData(fragment)); | 269 EXPECT_FALSE(HandleControlFrameHeadersData(fragment)); |
| 222 } | 270 } |
| 223 | 271 |
| 224 // Decode with incomplete data in buffer. | 272 // Decode with incomplete data in buffer. |
| 225 TEST_P(HpackDecoder2Test, DecodeWithIncompleteData) { | 273 TEST_P(HpackDecoder3Test, DecodeWithIncompleteData) { |
| 226 HandleControlFrameHeadersStart(); | 274 HandleControlFrameHeadersStart(); |
| 227 | 275 |
| 228 // No need to wait for more data. | 276 // No need to wait for more data. |
| 229 EXPECT_TRUE(HandleControlFrameHeadersData("\x82\x85\x82")); | 277 EXPECT_TRUE(HandleControlFrameHeadersData("\x82\x85\x82")); |
| 230 std::vector<std::pair<string, string>> expected_headers = { | 278 std::vector<std::pair<string, string>> expected_headers = { |
| 231 {":method", "GET"}, {":path", "/index.html"}, {":method", "GET"}}; | 279 {":method", "GET"}, {":path", "/index.html"}, {":method", "GET"}}; |
| 232 | 280 |
| 233 SpdyHeaderBlock expected_block1 = MakeHeaderBlock(expected_headers); | 281 SpdyHeaderBlock expected_block1 = MakeHeaderBlock(expected_headers); |
| 234 EXPECT_EQ(expected_block1, decoded_block()); | 282 EXPECT_EQ(expected_block1, decoded_block()); |
| 235 | 283 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 249 size_t size = 0; | 297 size_t size = 0; |
| 250 EXPECT_TRUE(HandleControlFrameHeadersComplete(&size)); | 298 EXPECT_TRUE(HandleControlFrameHeadersComplete(&size)); |
| 251 EXPECT_EQ(24u, size); | 299 EXPECT_EQ(24u, size); |
| 252 | 300 |
| 253 expected_headers.push_back({"spam", "gggs"}); | 301 expected_headers.push_back({"spam", "gggs"}); |
| 254 | 302 |
| 255 SpdyHeaderBlock expected_block3 = MakeHeaderBlock(expected_headers); | 303 SpdyHeaderBlock expected_block3 = MakeHeaderBlock(expected_headers); |
| 256 EXPECT_EQ(expected_block3, decoded_block()); | 304 EXPECT_EQ(expected_block3, decoded_block()); |
| 257 } | 305 } |
| 258 | 306 |
| 259 TEST_P(HpackDecoder2Test, HandleHeaderRepresentation) { | 307 TEST_P(HpackDecoder3Test, HandleHeaderRepresentation) { |
| 260 // Make sure the decoder is properly initialized. | 308 // Make sure the decoder is properly initialized. |
| 261 HandleControlFrameHeadersStart(); | 309 HandleControlFrameHeadersStart(); |
| 262 HandleControlFrameHeadersData(""); | 310 HandleControlFrameHeadersData(""); |
| 263 | 311 |
| 264 // All cookie crumbs are joined. | 312 // All cookie crumbs are joined. |
| 265 decoder_peer_.HandleHeaderRepresentation("cookie", " part 1"); | 313 decoder_peer_.HandleHeaderRepresentation("cookie", " part 1"); |
| 266 decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 "); | 314 decoder_peer_.HandleHeaderRepresentation("cookie", "part 2 "); |
| 267 decoder_peer_.HandleHeaderRepresentation("cookie", "part3"); | 315 decoder_peer_.HandleHeaderRepresentation("cookie", "part3"); |
| 268 | 316 |
| 269 // Already-delimited headers are passed through. | 317 // Already-delimited headers are passed through. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 294 EXPECT_THAT(decoded_block(), | 342 EXPECT_THAT(decoded_block(), |
| 295 ElementsAre(Pair("cookie", " part 1; part 2 ; part3; fin!"), | 343 ElementsAre(Pair("cookie", " part 1; part 2 ; part3; fin!"), |
| 296 Pair("passed-through", StringPiece("foo\0baz", 7)), | 344 Pair("passed-through", StringPiece("foo\0baz", 7)), |
| 297 Pair("joined", "not joined"), | 345 Pair("joined", "not joined"), |
| 298 Pair("joineD", StringPiece("value 1\0value 2", 15)), | 346 Pair("joineD", StringPiece("value 1\0value 2", 15)), |
| 299 Pair("empty", ""), | 347 Pair("empty", ""), |
| 300 Pair("empty-joined", StringPiece("\0foo\0\0", 6)))); | 348 Pair("empty-joined", StringPiece("\0foo\0\0", 6)))); |
| 301 } | 349 } |
| 302 | 350 |
| 303 // Decoding indexed static table field should work. | 351 // Decoding indexed static table field should work. |
| 304 TEST_P(HpackDecoder2Test, IndexedHeaderStatic) { | 352 TEST_P(HpackDecoder3Test, IndexedHeaderStatic) { |
| 305 // Reference static table entries #2 and #5. | 353 // Reference static table entries #2 and #5. |
| 306 const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess("\x82\x85"); | 354 const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess("\x82\x85"); |
| 307 SpdyHeaderBlock expected_header_set1; | 355 SpdyHeaderBlock expected_header_set1; |
| 308 expected_header_set1[":method"] = "GET"; | 356 expected_header_set1[":method"] = "GET"; |
| 309 expected_header_set1[":path"] = "/index.html"; | 357 expected_header_set1[":path"] = "/index.html"; |
| 310 EXPECT_EQ(expected_header_set1, header_set1); | 358 EXPECT_EQ(expected_header_set1, header_set1); |
| 311 | 359 |
| 312 // Reference static table entry #2. | 360 // Reference static table entry #2. |
| 313 const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess("\x82"); | 361 const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess("\x82"); |
| 314 SpdyHeaderBlock expected_header_set2; | 362 SpdyHeaderBlock expected_header_set2; |
| 315 expected_header_set2[":method"] = "GET"; | 363 expected_header_set2[":method"] = "GET"; |
| 316 EXPECT_EQ(expected_header_set2, header_set2); | 364 EXPECT_EQ(expected_header_set2, header_set2); |
| 317 } | 365 } |
| 318 | 366 |
| 319 TEST_P(HpackDecoder2Test, IndexedHeaderDynamic) { | 367 TEST_P(HpackDecoder3Test, IndexedHeaderDynamic) { |
| 320 // First header block: add an entry to header table. | 368 // First header block: add an entry to header table. |
| 321 const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess( | 369 const SpdyHeaderBlock& header_set1 = DecodeBlockExpectingSuccess( |
| 322 "\x40\x03" | 370 "\x40\x03" |
| 323 "foo" | 371 "foo" |
| 324 "\x03" | 372 "\x03" |
| 325 "bar"); | 373 "bar"); |
| 326 SpdyHeaderBlock expected_header_set1; | 374 SpdyHeaderBlock expected_header_set1; |
| 327 expected_header_set1["foo"] = "bar"; | 375 expected_header_set1["foo"] = "bar"; |
| 328 EXPECT_EQ(expected_header_set1, header_set1); | 376 EXPECT_EQ(expected_header_set1, header_set1); |
| 329 | 377 |
| 330 // Second header block: add another entry to header table. | 378 // Second header block: add another entry to header table. |
| 331 const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess( | 379 const SpdyHeaderBlock& header_set2 = DecodeBlockExpectingSuccess( |
| 332 "\xbe\x40\x04" | 380 "\xbe\x40\x04" |
| 333 "spam" | 381 "spam" |
| 334 "\x04" | 382 "\x04" |
| 335 "eggs"); | 383 "eggs"); |
| 336 SpdyHeaderBlock expected_header_set2; | 384 SpdyHeaderBlock expected_header_set2; |
| 337 expected_header_set2["foo"] = "bar"; | 385 expected_header_set2["foo"] = "bar"; |
| 338 expected_header_set2["spam"] = "eggs"; | 386 expected_header_set2["spam"] = "eggs"; |
| 339 EXPECT_EQ(expected_header_set2, header_set2); | 387 EXPECT_EQ(expected_header_set2, header_set2); |
| 340 | 388 |
| 341 // Third header block: refer to most recently added entry. | 389 // Third header block: refer to most recently added entry. |
| 342 const SpdyHeaderBlock& header_set3 = DecodeBlockExpectingSuccess("\xbe"); | 390 const SpdyHeaderBlock& header_set3 = DecodeBlockExpectingSuccess("\xbe"); |
| 343 SpdyHeaderBlock expected_header_set3; | 391 SpdyHeaderBlock expected_header_set3; |
| 344 expected_header_set3["spam"] = "eggs"; | 392 expected_header_set3["spam"] = "eggs"; |
| 345 EXPECT_EQ(expected_header_set3, header_set3); | 393 EXPECT_EQ(expected_header_set3, header_set3); |
| 346 } | 394 } |
| 347 | 395 |
| 348 // Test a too-large indexed header. | 396 // Test a too-large indexed header. |
| 349 TEST_P(HpackDecoder2Test, InvalidIndexedHeader) { | 397 TEST_P(HpackDecoder3Test, InvalidIndexedHeader) { |
| 350 // High-bit set, and a prefix of one more than the number of static entries. | 398 // High-bit set, and a prefix of one more than the number of static entries. |
| 351 EXPECT_FALSE(DecodeHeaderBlock("\xbe")); | 399 EXPECT_FALSE(DecodeHeaderBlock("\xbe")); |
| 352 } | 400 } |
| 353 | 401 |
| 354 TEST_P(HpackDecoder2Test, ContextUpdateMaximumSize) { | 402 TEST_P(HpackDecoder3Test, ContextUpdateMaximumSize) { |
| 355 EXPECT_EQ(kDefaultHeaderTableSizeSetting, | 403 EXPECT_EQ(kDefaultHeaderTableSizeSetting, |
| 356 decoder_peer_.header_table()->max_size()); | 404 decoder_peer_.header_table_size_limit()); |
| 357 string input; | 405 string input; |
| 358 { | 406 { |
| 359 // Maximum-size update with size 126. Succeeds. | 407 // Maximum-size update with size 126. Succeeds. |
| 360 HpackOutputStream output_stream; | 408 HpackOutputStream output_stream; |
| 361 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 409 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 362 output_stream.AppendUint32(126); | 410 output_stream.AppendUint32(126); |
| 363 | 411 |
| 364 output_stream.TakeString(&input); | 412 output_stream.TakeString(&input); |
| 365 EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input))); | 413 EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input))); |
| 366 EXPECT_EQ(126u, decoder_peer_.header_table()->max_size()); | 414 EXPECT_EQ(126u, decoder_peer_.header_table_size_limit()); |
| 367 } | 415 } |
| 368 { | 416 { |
| 369 // Maximum-size update with kDefaultHeaderTableSizeSetting. Succeeds. | 417 // Maximum-size update with kDefaultHeaderTableSizeSetting. Succeeds. |
| 370 HpackOutputStream output_stream; | 418 HpackOutputStream output_stream; |
| 371 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 419 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 372 output_stream.AppendUint32(kDefaultHeaderTableSizeSetting); | 420 output_stream.AppendUint32(kDefaultHeaderTableSizeSetting); |
| 373 | 421 |
| 374 output_stream.TakeString(&input); | 422 output_stream.TakeString(&input); |
| 375 EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input))); | 423 EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input))); |
| 376 EXPECT_EQ(kDefaultHeaderTableSizeSetting, | 424 EXPECT_EQ(kDefaultHeaderTableSizeSetting, |
| 377 decoder_peer_.header_table()->max_size()); | 425 decoder_peer_.header_table_size_limit()); |
| 378 } | 426 } |
| 379 { | 427 { |
| 380 // Maximum-size update with kDefaultHeaderTableSizeSetting + 1. Fails. | 428 // Maximum-size update with kDefaultHeaderTableSizeSetting + 1. Fails. |
| 381 HpackOutputStream output_stream; | 429 HpackOutputStream output_stream; |
| 382 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 430 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 383 output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1); | 431 output_stream.AppendUint32(kDefaultHeaderTableSizeSetting + 1); |
| 384 | 432 |
| 385 output_stream.TakeString(&input); | 433 output_stream.TakeString(&input); |
| 386 EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input))); | 434 EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input))); |
| 387 EXPECT_EQ(kDefaultHeaderTableSizeSetting, | 435 EXPECT_EQ(kDefaultHeaderTableSizeSetting, |
| 388 decoder_peer_.header_table()->max_size()); | 436 decoder_peer_.header_table_size_limit()); |
| 389 } | 437 } |
| 390 } | 438 } |
| 391 | 439 |
| 392 // Two HeaderTableSizeUpdates may appear at the beginning of the block | 440 // Two HeaderTableSizeUpdates may appear at the beginning of the block |
| 393 TEST_P(HpackDecoder2Test, TwoTableSizeUpdates) { | 441 TEST_P(HpackDecoder3Test, TwoTableSizeUpdates) { |
| 394 string input; | 442 string input; |
| 395 { | 443 { |
| 396 // Should accept two table size updates, update to second one | 444 // Should accept two table size updates, update to second one |
| 397 HpackOutputStream output_stream; | 445 HpackOutputStream output_stream; |
| 398 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 446 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 399 output_stream.AppendUint32(0); | 447 output_stream.AppendUint32(0); |
| 400 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 448 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 401 output_stream.AppendUint32(122); | 449 output_stream.AppendUint32(122); |
| 402 | 450 |
| 403 output_stream.TakeString(&input); | 451 output_stream.TakeString(&input); |
| 404 EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input))); | 452 EXPECT_TRUE(DecodeHeaderBlock(StringPiece(input))); |
| 405 EXPECT_EQ(122u, decoder_peer_.header_table()->max_size()); | 453 EXPECT_EQ(122u, decoder_peer_.header_table_size_limit()); |
| 406 } | 454 } |
| 407 } | 455 } |
| 408 | 456 |
| 409 // Three HeaderTableSizeUpdates should result in an error | 457 // Three HeaderTableSizeUpdates should result in an error |
| 410 TEST_P(HpackDecoder2Test, ThreeTableSizeUpdatesError) { | 458 TEST_P(HpackDecoder3Test, ThreeTableSizeUpdatesError) { |
| 411 string input; | 459 string input; |
| 412 { | 460 { |
| 413 // Should reject three table size updates, update to second one | 461 // Should reject three table size updates, update to second one |
| 414 HpackOutputStream output_stream; | 462 HpackOutputStream output_stream; |
| 415 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 463 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 416 output_stream.AppendUint32(5); | 464 output_stream.AppendUint32(5); |
| 417 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 465 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 418 output_stream.AppendUint32(10); | 466 output_stream.AppendUint32(10); |
| 419 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 467 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 420 output_stream.AppendUint32(15); | 468 output_stream.AppendUint32(15); |
| 421 | 469 |
| 422 output_stream.TakeString(&input); | 470 output_stream.TakeString(&input); |
| 423 | 471 |
| 424 EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input))); | 472 EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input))); |
| 425 EXPECT_EQ(10u, decoder_peer_.header_table()->max_size()); | 473 EXPECT_EQ(10u, decoder_peer_.header_table_size_limit()); |
| 426 } | 474 } |
| 427 } | 475 } |
| 428 | 476 |
| 429 // HeaderTableSizeUpdates may only appear at the beginning of the block | 477 // HeaderTableSizeUpdates may only appear at the beginning of the block |
| 430 // Any other updates should result in an error | 478 // Any other updates should result in an error |
| 431 TEST_P(HpackDecoder2Test, TableSizeUpdateSecondError) { | 479 TEST_P(HpackDecoder3Test, TableSizeUpdateSecondError) { |
| 432 string input; | 480 string input; |
| 433 { | 481 { |
| 434 // Should reject a table size update appearing after a different entry | 482 // Should reject a table size update appearing after a different entry |
| 435 // The table size should remain as the default | 483 // The table size should remain as the default |
| 436 HpackOutputStream output_stream; | 484 HpackOutputStream output_stream; |
| 437 output_stream.AppendBytes("\x82\x85"); | 485 output_stream.AppendBytes("\x82\x85"); |
| 438 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 486 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 439 output_stream.AppendUint32(123); | 487 output_stream.AppendUint32(123); |
| 440 | 488 |
| 441 output_stream.TakeString(&input); | 489 output_stream.TakeString(&input); |
| 442 | 490 |
| 443 EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input))); | 491 EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input))); |
| 444 EXPECT_EQ(kDefaultHeaderTableSizeSetting, | 492 EXPECT_EQ(kDefaultHeaderTableSizeSetting, |
| 445 decoder_peer_.header_table()->max_size()); | 493 decoder_peer_.header_table_size_limit()); |
| 446 } | 494 } |
| 447 } | 495 } |
| 448 | 496 |
| 449 // HeaderTableSizeUpdates may only appear at the beginning of the block | 497 // HeaderTableSizeUpdates may only appear at the beginning of the block |
| 450 // Any other updates should result in an error | 498 // Any other updates should result in an error |
| 451 TEST_P(HpackDecoder2Test, TableSizeUpdateFirstThirdError) { | 499 TEST_P(HpackDecoder3Test, TableSizeUpdateFirstThirdError) { |
| 452 string input; | 500 string input; |
| 453 { | 501 { |
| 454 // Should reject the second table size update | 502 // Should reject the second table size update |
| 455 // if a different entry appears after the first update | 503 // if a different entry appears after the first update |
| 456 // The table size should update to the first but not the second | 504 // The table size should update to the first but not the second |
| 457 HpackOutputStream output_stream; | 505 HpackOutputStream output_stream; |
| 458 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 506 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 459 output_stream.AppendUint32(60); | 507 output_stream.AppendUint32(60); |
| 460 output_stream.AppendBytes("\x82\x85"); | 508 output_stream.AppendBytes("\x82\x85"); |
| 461 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); | 509 output_stream.AppendPrefix(kHeaderTableSizeUpdateOpcode); |
| 462 output_stream.AppendUint32(125); | 510 output_stream.AppendUint32(125); |
| 463 | 511 |
| 464 output_stream.TakeString(&input); | 512 output_stream.TakeString(&input); |
| 465 | 513 |
| 466 EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input))); | 514 EXPECT_FALSE(DecodeHeaderBlock(StringPiece(input))); |
| 467 EXPECT_EQ(60u, decoder_peer_.header_table()->max_size()); | 515 EXPECT_EQ(60u, decoder_peer_.header_table_size_limit()); |
| 468 } | 516 } |
| 469 } | 517 } |
| 470 | 518 |
| 471 // Decoding two valid encoded literal headers with no indexing should | 519 // Decoding two valid encoded literal headers with no indexing should |
| 472 // work. | 520 // work. |
| 473 TEST_P(HpackDecoder2Test, LiteralHeaderNoIndexing) { | 521 TEST_P(HpackDecoder3Test, LiteralHeaderNoIndexing) { |
| 474 // First header with indexed name, second header with string literal | 522 // First header with indexed name, second header with string literal |
| 475 // name. | 523 // name. |
| 476 const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2"; | 524 const char input[] = "\x04\x0c/sample/path\x00\x06:path2\x0e/sample/path/2"; |
| 477 const SpdyHeaderBlock& header_set = | 525 const SpdyHeaderBlock& header_set = |
| 478 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1)); | 526 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1)); |
| 479 | 527 |
| 480 SpdyHeaderBlock expected_header_set; | 528 SpdyHeaderBlock expected_header_set; |
| 481 expected_header_set[":path"] = "/sample/path"; | 529 expected_header_set[":path"] = "/sample/path"; |
| 482 expected_header_set[":path2"] = "/sample/path/2"; | 530 expected_header_set[":path2"] = "/sample/path/2"; |
| 483 EXPECT_EQ(expected_header_set, header_set); | 531 EXPECT_EQ(expected_header_set, header_set); |
| 484 } | 532 } |
| 485 | 533 |
| 486 // Decoding two valid encoded literal headers with incremental | 534 // Decoding two valid encoded literal headers with incremental |
| 487 // indexing and string literal names should work. | 535 // indexing and string literal names should work. |
| 488 TEST_P(HpackDecoder2Test, LiteralHeaderIncrementalIndexing) { | 536 TEST_P(HpackDecoder3Test, LiteralHeaderIncrementalIndexing) { |
| 489 const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2"; | 537 const char input[] = "\x44\x0c/sample/path\x40\x06:path2\x0e/sample/path/2"; |
| 490 const SpdyHeaderBlock& header_set = | 538 const SpdyHeaderBlock& header_set = |
| 491 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1)); | 539 DecodeBlockExpectingSuccess(StringPiece(input, arraysize(input) - 1)); |
| 492 | 540 |
| 493 SpdyHeaderBlock expected_header_set; | 541 SpdyHeaderBlock expected_header_set; |
| 494 expected_header_set[":path"] = "/sample/path"; | 542 expected_header_set[":path"] = "/sample/path"; |
| 495 expected_header_set[":path2"] = "/sample/path/2"; | 543 expected_header_set[":path2"] = "/sample/path/2"; |
| 496 EXPECT_EQ(expected_header_set, header_set); | 544 EXPECT_EQ(expected_header_set, header_set); |
| 497 } | 545 } |
| 498 | 546 |
| 499 TEST_P(HpackDecoder2Test, LiteralHeaderWithIndexingInvalidNameIndex) { | 547 TEST_P(HpackDecoder3Test, LiteralHeaderWithIndexingInvalidNameIndex) { |
| 500 decoder_.ApplyHeaderTableSizeSetting(0); | 548 decoder_.ApplyHeaderTableSizeSetting(0); |
| 549 EXPECT_TRUE(EncodeAndDecodeDynamicTableSizeUpdates(0, 0)); |
| 501 | 550 |
| 502 // Name is the last static index. Works. | 551 // Name is the last static index. Works. |
| 503 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x7d\x03ooo"))); | 552 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x7d\x03ooo"))); |
| 504 // Name is one beyond the last static index. Fails. | 553 // Name is one beyond the last static index. Fails. |
| 505 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x7e\x03ooo"))); | 554 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x7e\x03ooo"))); |
| 506 } | 555 } |
| 507 | 556 |
| 508 TEST_P(HpackDecoder2Test, LiteralHeaderNoIndexingInvalidNameIndex) { | 557 TEST_P(HpackDecoder3Test, LiteralHeaderNoIndexingInvalidNameIndex) { |
| 509 // Name is the last static index. Works. | 558 // Name is the last static index. Works. |
| 510 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x0f\x2e\x03ooo"))); | 559 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x0f\x2e\x03ooo"))); |
| 511 // Name is one beyond the last static index. Fails. | 560 // Name is one beyond the last static index. Fails. |
| 512 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x0f\x2f\x03ooo"))); | 561 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x0f\x2f\x03ooo"))); |
| 513 } | 562 } |
| 514 | 563 |
| 515 TEST_P(HpackDecoder2Test, LiteralHeaderNeverIndexedInvalidNameIndex) { | 564 TEST_P(HpackDecoder3Test, LiteralHeaderNeverIndexedInvalidNameIndex) { |
| 516 // Name is the last static index. Works. | 565 // Name is the last static index. Works. |
| 517 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x1f\x2e\x03ooo"))); | 566 EXPECT_TRUE(DecodeHeaderBlock(StringPiece("\x1f\x2e\x03ooo"))); |
| 518 // Name is one beyond the last static index. Fails. | 567 // Name is one beyond the last static index. Fails. |
| 519 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x1f\x2f\x03ooo"))); | 568 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\x1f\x2f\x03ooo"))); |
| 520 } | 569 } |
| 521 | 570 |
| 522 TEST_P(HpackDecoder2Test, TruncatedIndex) { | 571 TEST_P(HpackDecoder3Test, TruncatedIndex) { |
| 523 // Indexed Header, varint for index requires multiple bytes, | 572 // Indexed Header, varint for index requires multiple bytes, |
| 524 // but only one provided. | 573 // but only one provided. |
| 525 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xff", 1))); | 574 EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xff", 1))); |
| 526 } | 575 } |
| 527 | 576 |
| 528 TEST_P(HpackDecoder2Test, TruncatedHuffmanLiteral) { | 577 TEST_P(HpackDecoder3Test, TruncatedHuffmanLiteral) { |
| 529 // Literal value, Huffman encoded, but with the last byte missing (i.e. | 578 // Literal value, Huffman encoded, but with the last byte missing (i.e. |
| 530 // drop the final ff shown below). | 579 // drop the final ff shown below). |
| 531 // | 580 // |
| 532 // 41 | == Literal indexed == | 581 // 41 | == Literal indexed == |
| 533 // | Indexed name (idx = 1) | 582 // | Indexed name (idx = 1) |
| 534 // | :authority | 583 // | :authority |
| 535 // 8c | Literal value (len = 12) | 584 // 8c | Literal value (len = 12) |
| 536 // | Huffman encoded: | 585 // | Huffman encoded: |
| 537 // f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k..... | 586 // f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k..... |
| 538 // | Decoded: | 587 // | Decoded: |
| 539 // | www.example.com | 588 // | www.example.com |
| 540 // | -> :authority: www.example.com | 589 // | -> :authority: www.example.com |
| 541 | 590 |
| 542 string first = a2b_hex("418cf1e3c2e5f23a6ba0ab90f4ff"); | 591 string first = a2b_hex("418cf1e3c2e5f23a6ba0ab90f4ff"); |
| 543 EXPECT_TRUE(DecodeHeaderBlock(first)); | 592 EXPECT_TRUE(DecodeHeaderBlock(first)); |
| 544 first = a2b_hex("418cf1e3c2e5f23a6ba0ab90f4"); | 593 first = a2b_hex("418cf1e3c2e5f23a6ba0ab90f4"); |
| 545 EXPECT_FALSE(DecodeHeaderBlock(first)); | 594 EXPECT_FALSE(DecodeHeaderBlock(first)); |
| 546 } | 595 } |
| 547 | 596 |
| 548 TEST_P(HpackDecoder2Test, HuffmanEOSError) { | 597 TEST_P(HpackDecoder3Test, HuffmanEOSError) { |
| 549 // Literal value, Huffman encoded, but with an additional ff byte at the end | 598 // Literal value, Huffman encoded, but with an additional ff byte at the end |
| 550 // of the string, i.e. an EOS that is longer than permitted. | 599 // of the string, i.e. an EOS that is longer than permitted. |
| 551 // | 600 // |
| 552 // 41 | == Literal indexed == | 601 // 41 | == Literal indexed == |
| 553 // | Indexed name (idx = 1) | 602 // | Indexed name (idx = 1) |
| 554 // | :authority | 603 // | :authority |
| 555 // 8d | Literal value (len = 13) | 604 // 8d | Literal value (len = 13) |
| 556 // | Huffman encoded: | 605 // | Huffman encoded: |
| 557 // f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k..... | 606 // f1e3 c2e5 f23a 6ba0 ab90 f4ff | .....:k..... |
| 558 // | Decoded: | 607 // | Decoded: |
| 559 // | www.example.com | 608 // | www.example.com |
| 560 // | -> :authority: www.example.com | 609 // | -> :authority: www.example.com |
| 561 | 610 |
| 562 string first = a2b_hex("418cf1e3c2e5f23a6ba0ab90f4ff"); | 611 string first = a2b_hex("418cf1e3c2e5f23a6ba0ab90f4ff"); |
| 563 EXPECT_TRUE(DecodeHeaderBlock(first)); | 612 EXPECT_TRUE(DecodeHeaderBlock(first)); |
| 564 first = a2b_hex("418df1e3c2e5f23a6ba0ab90f4ffff"); | 613 first = a2b_hex("418df1e3c2e5f23a6ba0ab90f4ffff"); |
| 565 EXPECT_FALSE(DecodeHeaderBlock(first)); | 614 EXPECT_FALSE(DecodeHeaderBlock(first)); |
| 566 } | 615 } |
| 567 | 616 |
| 568 // Round-tripping the header set from E.2.1 should work. | 617 // Round-tripping the header set from RFC 7541 C.3.1 should work. |
| 569 TEST_P(HpackDecoder2Test, BasicE21) { | 618 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.3.1 |
| 619 TEST_P(HpackDecoder3Test, BasicC31) { |
| 570 HpackEncoder encoder(ObtainHpackHuffmanTable()); | 620 HpackEncoder encoder(ObtainHpackHuffmanTable()); |
| 571 | 621 |
| 572 SpdyHeaderBlock expected_header_set; | 622 SpdyHeaderBlock expected_header_set; |
| 573 expected_header_set[":method"] = "GET"; | 623 expected_header_set[":method"] = "GET"; |
| 574 expected_header_set[":scheme"] = "http"; | 624 expected_header_set[":scheme"] = "http"; |
| 575 expected_header_set[":path"] = "/"; | 625 expected_header_set[":path"] = "/"; |
| 576 expected_header_set[":authority"] = "www.example.com"; | 626 expected_header_set[":authority"] = "www.example.com"; |
| 577 | 627 |
| 578 string encoded_header_set; | 628 string encoded_header_set; |
| 579 EXPECT_TRUE( | 629 EXPECT_TRUE( |
| 580 encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set)); | 630 encoder.EncodeHeaderSet(expected_header_set, &encoded_header_set)); |
| 581 | 631 |
| 582 EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set)); | 632 EXPECT_TRUE(DecodeHeaderBlock(encoded_header_set)); |
| 583 EXPECT_EQ(expected_header_set, decoded_block()); | 633 EXPECT_EQ(expected_header_set, decoded_block()); |
| 584 } | 634 } |
| 585 | 635 |
| 586 TEST_P(HpackDecoder2Test, SectionD4RequestHuffmanExamples) { | 636 // RFC 7541, Section C.4: Request Examples with Huffman Coding |
| 637 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.4 |
| 638 TEST_P(HpackDecoder3Test, SectionC4RequestHuffmanExamples) { |
| 587 // TODO(jamessynge): Use net/http2/hpack/tools/hpack_example.h to parse the | 639 // TODO(jamessynge): Use net/http2/hpack/tools/hpack_example.h to parse the |
| 588 // example directly, instead of having it as a comment. | 640 // example directly, instead of having it as a comment. |
| 589 // 82 | == Indexed - Add == | 641 // 82 | == Indexed - Add == |
| 590 // | idx = 2 | 642 // | idx = 2 |
| 591 // | -> :method: GET | 643 // | -> :method: GET |
| 592 // 86 | == Indexed - Add == | 644 // 86 | == Indexed - Add == |
| 593 // | idx = 6 | 645 // | idx = 6 |
| 594 // | -> :scheme: http | 646 // | -> :scheme: http |
| 595 // 84 | == Indexed - Add == | 647 // 84 | == Indexed - Add == |
| 596 // | idx = 4 | 648 // | idx = 4 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 610 EXPECT_THAT(first_header_set, | 662 EXPECT_THAT(first_header_set, |
| 611 ElementsAre( | 663 ElementsAre( |
| 612 // clang-format off | 664 // clang-format off |
| 613 Pair(":method", "GET"), | 665 Pair(":method", "GET"), |
| 614 Pair(":scheme", "http"), | 666 Pair(":scheme", "http"), |
| 615 Pair(":path", "/"), | 667 Pair(":path", "/"), |
| 616 Pair(":authority", "www.example.com"))); | 668 Pair(":authority", "www.example.com"))); |
| 617 // clang-format on | 669 // clang-format on |
| 618 | 670 |
| 619 expectEntry(62, 57, ":authority", "www.example.com"); | 671 expectEntry(62, 57, ":authority", "www.example.com"); |
| 620 EXPECT_EQ(57u, decoder_peer_.header_table()->size()); | 672 EXPECT_EQ(57u, decoder_peer_.current_header_table_size()); |
| 621 | 673 |
| 622 // 82 | == Indexed - Add == | 674 // 82 | == Indexed - Add == |
| 623 // | idx = 2 | 675 // | idx = 2 |
| 624 // | -> :method: GET | 676 // | -> :method: GET |
| 625 // 86 | == Indexed - Add == | 677 // 86 | == Indexed - Add == |
| 626 // | idx = 6 | 678 // | idx = 6 |
| 627 // | -> :scheme: http | 679 // | -> :scheme: http |
| 628 // 84 | == Indexed - Add == | 680 // 84 | == Indexed - Add == |
| 629 // | idx = 4 | 681 // | idx = 4 |
| 630 // | -> :path: / | 682 // | -> :path: / |
| (...skipping 19 matching lines...) Expand all Loading... |
| 650 // clang-format off | 702 // clang-format off |
| 651 Pair(":method", "GET"), | 703 Pair(":method", "GET"), |
| 652 Pair(":scheme", "http"), | 704 Pair(":scheme", "http"), |
| 653 Pair(":path", "/"), | 705 Pair(":path", "/"), |
| 654 Pair(":authority", "www.example.com"), | 706 Pair(":authority", "www.example.com"), |
| 655 Pair("cache-control", "no-cache"))); | 707 Pair("cache-control", "no-cache"))); |
| 656 // clang-format on | 708 // clang-format on |
| 657 | 709 |
| 658 expectEntry(62, 53, "cache-control", "no-cache"); | 710 expectEntry(62, 53, "cache-control", "no-cache"); |
| 659 expectEntry(63, 57, ":authority", "www.example.com"); | 711 expectEntry(63, 57, ":authority", "www.example.com"); |
| 660 EXPECT_EQ(110u, decoder_peer_.header_table()->size()); | 712 EXPECT_EQ(110u, decoder_peer_.current_header_table_size()); |
| 661 | 713 |
| 662 // 82 | == Indexed - Add == | 714 // 82 | == Indexed - Add == |
| 663 // | idx = 2 | 715 // | idx = 2 |
| 664 // | -> :method: GET | 716 // | -> :method: GET |
| 665 // 87 | == Indexed - Add == | 717 // 87 | == Indexed - Add == |
| 666 // | idx = 7 | 718 // | idx = 7 |
| 667 // | -> :scheme: https | 719 // | -> :scheme: https |
| 668 // 85 | == Indexed - Add == | 720 // 85 | == Indexed - Add == |
| 669 // | idx = 5 | 721 // | idx = 5 |
| 670 // | -> :path: /index.html | 722 // | -> :path: /index.html |
| (...skipping 22 matching lines...) Expand all Loading... |
| 693 Pair(":method", "GET"), | 745 Pair(":method", "GET"), |
| 694 Pair(":scheme", "https"), | 746 Pair(":scheme", "https"), |
| 695 Pair(":path", "/index.html"), | 747 Pair(":path", "/index.html"), |
| 696 Pair(":authority", "www.example.com"), | 748 Pair(":authority", "www.example.com"), |
| 697 Pair("custom-key", "custom-value"))); | 749 Pair("custom-key", "custom-value"))); |
| 698 // clang-format on | 750 // clang-format on |
| 699 | 751 |
| 700 expectEntry(62, 54, "custom-key", "custom-value"); | 752 expectEntry(62, 54, "custom-key", "custom-value"); |
| 701 expectEntry(63, 53, "cache-control", "no-cache"); | 753 expectEntry(63, 53, "cache-control", "no-cache"); |
| 702 expectEntry(64, 57, ":authority", "www.example.com"); | 754 expectEntry(64, 57, ":authority", "www.example.com"); |
| 703 EXPECT_EQ(164u, decoder_peer_.header_table()->size()); | 755 EXPECT_EQ(164u, decoder_peer_.current_header_table_size()); |
| 704 } | 756 } |
| 705 | 757 |
| 706 TEST_P(HpackDecoder2Test, SectionD6ResponseHuffmanExamples) { | 758 // RFC 7541, Section C.6: Response Examples with Huffman Coding |
| 707 decoder_.ApplyHeaderTableSizeSetting(256); | 759 // http://httpwg.org/specs/rfc7541.html#rfc.section.C.6 |
| 760 TEST_P(HpackDecoder3Test, SectionC6ResponseHuffmanExamples) { |
| 761 // The example is based on a maximum dynamic table size of 256, |
| 762 // which allows for testing dynamic table evictions. |
| 763 decoder_peer_.set_header_table_size_limit(256); |
| 708 | 764 |
| 709 // 48 | == Literal indexed == | 765 // 48 | == Literal indexed == |
| 710 // | Indexed name (idx = 8) | 766 // | Indexed name (idx = 8) |
| 711 // | :status | 767 // | :status |
| 712 // 82 | Literal value (len = 3) | 768 // 82 | Literal value (len = 3) |
| 713 // | Huffman encoded: | 769 // | Huffman encoded: |
| 714 // 6402 | d. | 770 // 6402 | d. |
| 715 // | Decoded: | 771 // | Decoded: |
| 716 // | 302 | 772 // | 302 |
| 717 // | -> :status: 302 | 773 // | -> :status: 302 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 761 Pair(":status", "302"), | 817 Pair(":status", "302"), |
| 762 Pair("cache-control", "private"), | 818 Pair("cache-control", "private"), |
| 763 Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), | 819 Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), |
| 764 Pair("location", "https://www.example.com"))); | 820 Pair("location", "https://www.example.com"))); |
| 765 // clang-format on | 821 // clang-format on |
| 766 | 822 |
| 767 expectEntry(62, 63, "location", "https://www.example.com"); | 823 expectEntry(62, 63, "location", "https://www.example.com"); |
| 768 expectEntry(63, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT"); | 824 expectEntry(63, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT"); |
| 769 expectEntry(64, 52, "cache-control", "private"); | 825 expectEntry(64, 52, "cache-control", "private"); |
| 770 expectEntry(65, 42, ":status", "302"); | 826 expectEntry(65, 42, ":status", "302"); |
| 771 EXPECT_EQ(222u, decoder_peer_.header_table()->size()); | 827 EXPECT_EQ(222u, decoder_peer_.current_header_table_size()); |
| 772 | 828 |
| 773 // 48 | == Literal indexed == | 829 // 48 | == Literal indexed == |
| 774 // | Indexed name (idx = 8) | 830 // | Indexed name (idx = 8) |
| 775 // | :status | 831 // | :status |
| 776 // 83 | Literal value (len = 3) | 832 // 83 | Literal value (len = 3) |
| 777 // | Huffman encoded: | 833 // | Huffman encoded: |
| 778 // 640e ff | d.. | 834 // 640e ff | d.. |
| 779 // | Decoded: | 835 // | Decoded: |
| 780 // | 307 | 836 // | 307 |
| 781 // | - evict: :status: 302 | 837 // | - evict: :status: 302 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 801 Pair(":status", "307"), | 857 Pair(":status", "307"), |
| 802 Pair("cache-control", "private"), | 858 Pair("cache-control", "private"), |
| 803 Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), | 859 Pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"), |
| 804 Pair("location", "https://www.example.com"))); | 860 Pair("location", "https://www.example.com"))); |
| 805 // clang-format on | 861 // clang-format on |
| 806 | 862 |
| 807 expectEntry(62, 42, ":status", "307"); | 863 expectEntry(62, 42, ":status", "307"); |
| 808 expectEntry(63, 63, "location", "https://www.example.com"); | 864 expectEntry(63, 63, "location", "https://www.example.com"); |
| 809 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT"); | 865 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:21 GMT"); |
| 810 expectEntry(65, 52, "cache-control", "private"); | 866 expectEntry(65, 52, "cache-control", "private"); |
| 811 EXPECT_EQ(222u, decoder_peer_.header_table()->size()); | 867 EXPECT_EQ(222u, decoder_peer_.current_header_table_size()); |
| 812 | 868 |
| 813 // 88 | == Indexed - Add == | 869 // 88 | == Indexed - Add == |
| 814 // | idx = 8 | 870 // | idx = 8 |
| 815 // | -> :status: 200 | 871 // | -> :status: 200 |
| 816 // c1 | == Indexed - Add == | 872 // c1 | == Indexed - Add == |
| 817 // | idx = 65 | 873 // | idx = 65 |
| 818 // | -> cache-control: private | 874 // | -> cache-control: private |
| 819 // 61 | == Literal indexed == | 875 // 61 | == Literal indexed == |
| 820 // | Indexed name (idx = 33) | 876 // | Indexed name (idx = 33) |
| 821 // | date | 877 // | date |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 881 Pair("content-encoding", "gzip"), | 937 Pair("content-encoding", "gzip"), |
| 882 Pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" | 938 Pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" |
| 883 " max-age=3600; version=1"))); | 939 " max-age=3600; version=1"))); |
| 884 // clang-format on | 940 // clang-format on |
| 885 | 941 |
| 886 expectEntry(62, 98, "set-cookie", | 942 expectEntry(62, 98, "set-cookie", |
| 887 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" | 943 "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;" |
| 888 " max-age=3600; version=1"); | 944 " max-age=3600; version=1"); |
| 889 expectEntry(63, 52, "content-encoding", "gzip"); | 945 expectEntry(63, 52, "content-encoding", "gzip"); |
| 890 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT"); | 946 expectEntry(64, 65, "date", "Mon, 21 Oct 2013 20:13:22 GMT"); |
| 891 EXPECT_EQ(215u, decoder_peer_.header_table()->size()); | 947 EXPECT_EQ(215u, decoder_peer_.current_header_table_size()); |
| 892 } | 948 } |
| 893 | 949 |
| 894 // Regression test: Found that entries with dynamic indexed names and literal | 950 // Regression test: Found that entries with dynamic indexed names and literal |
| 895 // values caused "use after free" MSAN failures if the name was evicted as it | 951 // values caused "use after free" MSAN failures if the name was evicted as it |
| 896 // was being re-used. | 952 // was being re-used. |
| 897 TEST_P(HpackDecoder2Test, ReuseNameOfEvictedEntry) { | 953 TEST_P(HpackDecoder3Test, ReuseNameOfEvictedEntry) { |
| 898 // Each entry is measured as 32 bytes plus the sum of the lengths of the name | 954 // Each entry is measured as 32 bytes plus the sum of the lengths of the name |
| 899 // and the value. Set the size big enough for at most one entry, and a fairly | 955 // and the value. Set the size big enough for at most one entry, and a fairly |
| 900 // small one at that (31 ASCII characters). | 956 // small one at that (31 ASCII characters). |
| 901 decoder_.ApplyHeaderTableSizeSetting(63); | 957 decoder_.ApplyHeaderTableSizeSetting(63); |
| 902 | 958 |
| 903 HpackBlockBuilder hbb; | 959 HpackBlockBuilder hbb; |
| 960 hbb.AppendDynamicTableSizeUpdate(0); |
| 961 hbb.AppendDynamicTableSizeUpdate(63); |
| 904 | 962 |
| 905 const StringPiece name("some-name"); | 963 const StringPiece name("some-name"); |
| 906 const StringPiece value1("some-value"); | 964 const StringPiece value1("some-value"); |
| 907 const StringPiece value2("another-value"); | 965 const StringPiece value2("another-value"); |
| 908 const StringPiece value3("yet-another-value"); | 966 const StringPiece value3("yet-another-value"); |
| 909 | 967 |
| 910 // Add an entry that will become the first in the dynamic table, entry 62. | 968 // Add an entry that will become the first in the dynamic table, entry 62. |
| 911 hbb.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader, false, | 969 hbb.AppendLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader, false, |
| 912 name, false, value1); | 970 name, false, value1); |
| 913 | 971 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 945 string joined_values = expected_header_set[name].as_string(); | 1003 string joined_values = expected_header_set[name].as_string(); |
| 946 EXPECT_EQ(joined_values.size(), | 1004 EXPECT_EQ(joined_values.size(), |
| 947 2 * value1.size() + 2 * value2.size() + 2 * value3.size() + 5); | 1005 2 * value1.size() + 2 * value2.size() + 2 * value3.size() + 5); |
| 948 | 1006 |
| 949 EXPECT_EQ(expected_header_set, decoded_block()); | 1007 EXPECT_EQ(expected_header_set, decoded_block()); |
| 950 } | 1008 } |
| 951 | 1009 |
| 952 } // namespace | 1010 } // namespace |
| 953 } // namespace test | 1011 } // namespace test |
| 954 } // namespace net | 1012 } // namespace net |
| OLD | NEW |