diff options
author | bnc <bnc@chromium.org> | 2014-09-05 09:39:06 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-05 16:41:15 +0000 |
commit | 37f06e622f3122a0f456fa8017d832f7e08b7457 (patch) | |
tree | 859135b80c9ba7a343a3ebb7836e43a79ddcf353 | |
parent | fa59d41da4ca15c6527776adc978dd21075d30d3 (diff) | |
download | chromium_src-37f06e622f3122a0f456fa8017d832f7e08b7457.zip chromium_src-37f06e622f3122a0f456fa8017d832f7e08b7457.tar.gz chromium_src-37f06e622f3122a0f456fa8017d832f7e08b7457.tar.bz2 |
HPACK: Check pseudo-header order in decoder.
Treat a header block with a pseudo-header field following a regular one as
malformed, as required by HTTP/2 draft-14 Section 8.1.2.1.
This lands server change 74067938 by bnc.
BUG=400336
Review URL: https://codereview.chromium.org/531253004
Cr-Commit-Position: refs/heads/master@{#293534}
-rw-r--r-- | net/data/spdy_tests/examples_07.hpack | bin | 5488 -> 9972 bytes | |||
-rw-r--r-- | net/spdy/hpack_decoder.cc | 19 | ||||
-rw-r--r-- | net/spdy/hpack_decoder.h | 9 | ||||
-rw-r--r-- | net/spdy/hpack_decoder_test.cc | 17 |
4 files changed, 40 insertions, 5 deletions
diff --git a/net/data/spdy_tests/examples_07.hpack b/net/data/spdy_tests/examples_07.hpack Binary files differindex 5ed7deb..2e006fb 100644 --- a/net/data/spdy_tests/examples_07.hpack +++ b/net/data/spdy_tests/examples_07.hpack diff --git a/net/spdy/hpack_decoder.cc b/net/spdy/hpack_decoder.cc index 162b33e..c53a91c 100644 --- a/net/spdy/hpack_decoder.cc +++ b/net/spdy/hpack_decoder.cc @@ -22,6 +22,7 @@ const char kCookieKey[] = "cookie"; HpackDecoder::HpackDecoder(const HpackHuffmanTable& table) : max_string_literal_size_(kDefaultMaxStringLiteralSize), + regular_header_seen_(false), huffman_table_(table) {} HpackDecoder::~HpackDecoder() {} @@ -44,6 +45,7 @@ bool HpackDecoder::HandleControlFrameHeadersData(SpdyStreamId id, bool HpackDecoder::HandleControlFrameHeadersComplete(SpdyStreamId id) { HpackInputStream input_stream(max_string_literal_size_, headers_block_buffer_); + regular_header_seen_ = false; while (input_stream.HasMoreData()) { if (!DecodeNextOpcode(&input_stream)) { headers_block_buffer_.clear(); @@ -60,10 +62,19 @@ bool HpackDecoder::HandleControlFrameHeadersComplete(SpdyStreamId id) { return true; } -void HpackDecoder::HandleHeaderRepresentation(StringPiece name, +bool HpackDecoder::HandleHeaderRepresentation(StringPiece name, StringPiece value) { typedef std::pair<std::map<string, string>::iterator, bool> InsertResult; + // Fail if pseudo-header follows regular header. + if (name.size() > 0) { + if (name[0] == kPseudoHeaderPrefix) { + if (regular_header_seen_) return false; + } else { + regular_header_seen_ = true; + } + } + if (name == kCookieKey) { if (cookie_value_.empty()) { cookie_value_.assign(value.data(), value.size()); @@ -81,6 +92,7 @@ void HpackDecoder::HandleHeaderRepresentation(StringPiece name, value.end()); } } + return true; } bool HpackDecoder::DecodeNextOpcode(HpackInputStream* input_stream) { @@ -131,8 +143,7 @@ bool HpackDecoder::DecodeNextIndexedHeader(HpackInputStream* input_stream) { if (entry == NULL) return false; - HandleHeaderRepresentation(entry->name(), entry->value()); - return true; + return HandleHeaderRepresentation(entry->name(), entry->value()); } bool HpackDecoder::DecodeNextLiteralHeader(HpackInputStream* input_stream, @@ -145,7 +156,7 @@ bool HpackDecoder::DecodeNextLiteralHeader(HpackInputStream* input_stream, if (!DecodeNextStringLiteral(input_stream, false, &value)) return false; - HandleHeaderRepresentation(name, value); + if (!HandleHeaderRepresentation(name, value)) return false; if (!should_index) return true; diff --git a/net/spdy/hpack_decoder.h b/net/spdy/hpack_decoder.h index 7a27615..a974058 100644 --- a/net/spdy/hpack_decoder.h +++ b/net/spdy/hpack_decoder.h @@ -77,9 +77,13 @@ class NET_EXPORT_PRIVATE HpackDecoder { // Note that this may be too accomodating, as the sender's HTTP2 layer // should have already joined and delimited these values. // + // Returns false if a pseudo-header field follows a regular header one, which + // MUST be treated as malformed, as per sections 8.1.2.1. of the HTTP2 draft + // specification. + // // TODO(jgraettinger): This method will eventually emit to the // SpdyHeadersHandlerInterface visitor. - void HandleHeaderRepresentation(base::StringPiece name, + bool HandleHeaderRepresentation(base::StringPiece name, base::StringPiece value); const uint32 max_string_literal_size_; @@ -94,6 +98,9 @@ class NET_EXPORT_PRIVATE HpackDecoder { std::string headers_block_buffer_; std::map<std::string, std::string> decoded_block_; + // Flag to keep track of having seen a regular header field. + bool regular_header_seen_; + // Huffman table to be applied to decoded Huffman literals, // and scratch space for storing those decoded literals. const HpackHuffmanTable& huffman_table_; diff --git a/net/spdy/hpack_decoder_test.cc b/net/spdy/hpack_decoder_test.cc index ace9ac7..877692c 100644 --- a/net/spdy/hpack_decoder_test.cc +++ b/net/spdy/hpack_decoder_test.cc @@ -257,6 +257,23 @@ TEST_F(HpackDecoderTest, InvalidIndexedHeader) { EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xbe", 1))); } +// Test that a header block with a pseudo-header field following a regular one +// is treated as malformed. (HTTP2 draft-14 8.1.2.1., HPACK draft-09 3.1.) + +TEST_F(HpackDecoderTest, InvalidPseudoHeaderPositionStatic) { + // Okay: ":path" (static entry 4) followed by "allow" (static entry 20). + EXPECT_TRUE(DecodeHeaderBlock(a2b_hex("8494"))); + // Malformed: "allow" (static entry 20) followed by ":path" (static entry 4). + EXPECT_FALSE(DecodeHeaderBlock(a2b_hex("9484"))); +} + +TEST_F(HpackDecoderTest, InvalidPseudoHeaderPositionLiteral) { + // Okay: literal ":bar" followed by literal "foo". + EXPECT_TRUE(DecodeHeaderBlock(a2b_hex("40043a626172004003666f6f00"))); + // Malformed: literal "foo" followed by literal ":bar". + EXPECT_FALSE(DecodeHeaderBlock(a2b_hex("4003666f6f0040043a62617200"))); +} + TEST_F(HpackDecoderTest, ContextUpdateMaximumSize) { EXPECT_EQ(kDefaultHeaderTableSizeSetting, decoder_peer_.header_table()->max_size()); |