| Index: net/http2/hpack/decoder/hpack_decoder_state_test.cc
|
| diff --git a/net/http2/hpack/decoder/hpack_decoder_state_test.cc b/net/http2/hpack/decoder/hpack_decoder_state_test.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a9a6c50a9d25c8f93b1c5a603083aa24982cc7f3
|
| --- /dev/null
|
| +++ b/net/http2/hpack/decoder/hpack_decoder_state_test.cc
|
| @@ -0,0 +1,548 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "net/http2/hpack/decoder/hpack_decoder_state.h"
|
| +
|
| +// Tests of HpackDecoderState.
|
| +
|
| +#include <algorithm>
|
| +#include <map>
|
| +#include <string>
|
| +#include <utility>
|
| +#include <vector>
|
| +
|
| +#include "base/logging.h"
|
| +#include "net/http2/tools/failure.h"
|
| +#include "net/test/gtest_util.h"
|
| +#include "testing/gmock/include/gmock/gmock-matchers.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +
|
| +using ::testing::AssertionResult;
|
| +using ::testing::AssertionSuccess;
|
| +using ::testing::Eq;
|
| +using ::testing::Mock;
|
| +using ::testing::StrictMock;
|
| +using base::StringPiece;
|
| +
|
| +namespace net {
|
| +namespace test {
|
| +class HpackDecoderStatePeer {
|
| + public:
|
| + static HpackDecoderTables* GetDecoderTables(HpackDecoderState* state) {
|
| + return &state->decoder_tables_;
|
| + }
|
| +};
|
| +
|
| +namespace {
|
| +
|
| +// Define HasSubstr() for base::StringPiece arguments.
|
| +// This shadows ::testing::HasSubstr(), which only works on argument types
|
| +// that can be implicilty converted to a std::string.
|
| +inline ::testing::PolymorphicMatcher<StringPieceHasSubstrMatcher> HasSubstr(
|
| + const std::string& substring) {
|
| + return ::testing::MakePolymorphicMatcher(
|
| + StringPieceHasSubstrMatcher(substring));
|
| +}
|
| +
|
| +class MockHpackDecoderListener : public HpackDecoderListener {
|
| + public:
|
| + MOCK_METHOD0(OnHeaderListStart, void());
|
| + MOCK_METHOD3(OnHeader,
|
| + void(HpackEntryType entry_type,
|
| + const HpackString& name,
|
| + const HpackString& value));
|
| + MOCK_METHOD0(OnHeaderListEnd, void());
|
| + MOCK_METHOD1(OnHeaderErrorDetected, void(StringPiece error_message));
|
| +};
|
| +
|
| +enum StringBacking { STATIC, UNBUFFERED, BUFFERED };
|
| +
|
| +class HpackDecoderStateTest : public ::testing::Test {
|
| + protected:
|
| + HpackDecoderStateTest() : decoder_state_(&listener_) {}
|
| +
|
| + HpackDecoderTables* GetDecoderTables() {
|
| + return HpackDecoderStatePeer::GetDecoderTables(&decoder_state_);
|
| + }
|
| +
|
| + const HpackStringPair* Lookup(size_t index) {
|
| + return GetDecoderTables()->Lookup(index);
|
| + }
|
| +
|
| + size_t current_header_table_size() {
|
| + return GetDecoderTables()->current_header_table_size();
|
| + }
|
| +
|
| + size_t header_table_size_limit() {
|
| + return GetDecoderTables()->header_table_size_limit();
|
| + }
|
| +
|
| + void set_header_table_size_limit(size_t size) {
|
| + GetDecoderTables()->DynamicTableSizeUpdate(size);
|
| + }
|
| +
|
| + void SetStringBuffer(const char* s,
|
| + StringBacking backing,
|
| + HpackDecoderStringBuffer* string_buffer) {
|
| + switch (backing) {
|
| + case STATIC:
|
| + string_buffer->Set(s, true);
|
| + break;
|
| + case UNBUFFERED:
|
| + string_buffer->Set(s, false);
|
| + break;
|
| + case BUFFERED:
|
| + string_buffer->Set(s, false);
|
| + string_buffer->BufferStringIfUnbuffered();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + void SetName(const char* s, StringBacking backing) {
|
| + SetStringBuffer(s, backing, &name_buffer_);
|
| + }
|
| +
|
| + void SetValue(const char* s, StringBacking backing) {
|
| + SetStringBuffer(s, backing, &value_buffer_);
|
| + }
|
| +
|
| + void SendStartAndVerifyCallback() {
|
| + EXPECT_CALL(listener_, OnHeaderListStart());
|
| + decoder_state_.OnHeaderBlockStart();
|
| + Mock::VerifyAndClearExpectations(&listener_);
|
| + }
|
| +
|
| + void SendSizeUpdate(size_t size) {
|
| + decoder_state_.OnDynamicTableSizeUpdate(size);
|
| + Mock::VerifyAndClearExpectations(&listener_);
|
| + }
|
| +
|
| + void SendIndexAndVerifyCallback(size_t index,
|
| + HpackEntryType expected_type,
|
| + const char* expected_name,
|
| + const char* expected_value) {
|
| + EXPECT_CALL(listener_,
|
| + OnHeader(expected_type, Eq(expected_name), Eq(expected_value)));
|
| + decoder_state_.OnIndexedHeader(index);
|
| + Mock::VerifyAndClearExpectations(&listener_);
|
| + }
|
| +
|
| + void SendValueAndVerifyCallback(size_t name_index,
|
| + HpackEntryType entry_type,
|
| + const char* name,
|
| + const char* value,
|
| + StringBacking value_backing) {
|
| + SetValue(value, value_backing);
|
| + EXPECT_CALL(listener_, OnHeader(entry_type, Eq(name), Eq(value)));
|
| + decoder_state_.OnNameIndexAndLiteralValue(entry_type, name_index,
|
| + &value_buffer_);
|
| + Mock::VerifyAndClearExpectations(&listener_);
|
| + }
|
| +
|
| + void SendNameAndValueAndVerifyCallback(HpackEntryType entry_type,
|
| + const char* name,
|
| + StringBacking name_backing,
|
| + const char* value,
|
| + StringBacking value_backing) {
|
| + SetName(name, name_backing);
|
| + SetValue(value, value_backing);
|
| + EXPECT_CALL(listener_, OnHeader(entry_type, Eq(name), Eq(value)));
|
| + decoder_state_.OnLiteralNameAndValue(entry_type, &name_buffer_,
|
| + &value_buffer_);
|
| + Mock::VerifyAndClearExpectations(&listener_);
|
| + }
|
| +
|
| + void SendEndAndVerifyCallback() {
|
| + EXPECT_CALL(listener_, OnHeaderListEnd());
|
| + decoder_state_.OnHeaderBlockEnd();
|
| + Mock::VerifyAndClearExpectations(&listener_);
|
| + }
|
| +
|
| + // dynamic_index is one-based, because that is the way RFC 7541 shows it.
|
| + AssertionResult VerifyEntry(size_t dynamic_index,
|
| + const char* name,
|
| + const char* value) {
|
| + const HpackStringPair* entry =
|
| + Lookup(dynamic_index + kFirstDynamicTableIndex - 1);
|
| + VERIFY_NE(entry, nullptr);
|
| + VERIFY_EQ(static_cast<StringPiece>(entry->name), name);
|
| + VERIFY_EQ(static_cast<StringPiece>(entry->value), value);
|
| + return AssertionSuccess();
|
| + }
|
| + AssertionResult VerifyNoEntry(size_t dynamic_index) {
|
| + const HpackStringPair* entry =
|
| + Lookup(dynamic_index + kFirstDynamicTableIndex - 1);
|
| + VERIFY_EQ(entry, nullptr);
|
| + return AssertionSuccess();
|
| + }
|
| + AssertionResult VerifyDynamicTableContents(
|
| + const std::vector<std::pair<const char*, const char*>>& entries) {
|
| + size_t index = 1;
|
| + for (const auto& entry : entries) {
|
| + VERIFY_SUCCESS(VerifyEntry(index, entry.first, entry.second));
|
| + ++index;
|
| + }
|
| + VERIFY_SUCCESS(VerifyNoEntry(index));
|
| + return AssertionSuccess();
|
| + }
|
| +
|
| + StrictMock<MockHpackDecoderListener> listener_;
|
| + HpackDecoderState decoder_state_;
|
| + HpackDecoderStringBuffer name_buffer_, value_buffer_;
|
| +};
|
| +
|
| +// Test based on RFC 7541, section C.3: Request Examples without Huffman Coding.
|
| +// This section shows several consecutive header lists, corresponding to HTTP
|
| +// requests, on the same connection.
|
| +TEST_F(HpackDecoderStateTest, C3_RequestExamples) {
|
| + // C.3.1 First Request
|
| + //
|
| + // Header list to encode:
|
| + //
|
| + // :method: GET
|
| + // :scheme: http
|
| + // :path: /
|
| + // :authority: www.example.com
|
| +
|
| + SendStartAndVerifyCallback();
|
| + SendIndexAndVerifyCallback(2, HpackEntryType::kIndexedHeader, ":method",
|
| + "GET");
|
| + SendIndexAndVerifyCallback(6, HpackEntryType::kIndexedHeader, ":scheme",
|
| + "http");
|
| + SendIndexAndVerifyCallback(4, HpackEntryType::kIndexedHeader, ":path", "/");
|
| + SendValueAndVerifyCallback(1, HpackEntryType::kIndexedLiteralHeader,
|
| + ":authority", "www.example.com", UNBUFFERED);
|
| + SendEndAndVerifyCallback();
|
| +
|
| + // Dynamic Table (after decoding):
|
| + //
|
| + // [ 1] (s = 57) :authority: www.example.com
|
| + // Table size: 57
|
| +
|
| + ASSERT_TRUE(VerifyDynamicTableContents({{":authority", "www.example.com"}}));
|
| + ASSERT_EQ(57u, current_header_table_size());
|
| +
|
| + // C.3.2 Second Request
|
| + //
|
| + // Header list to encode:
|
| + //
|
| + // :method: GET
|
| + // :scheme: http
|
| + // :path: /
|
| + // :authority: www.example.com
|
| + // cache-control: no-cache
|
| +
|
| + SendStartAndVerifyCallback();
|
| + SendIndexAndVerifyCallback(2, HpackEntryType::kIndexedHeader, ":method",
|
| + "GET");
|
| + SendIndexAndVerifyCallback(6, HpackEntryType::kIndexedHeader, ":scheme",
|
| + "http");
|
| + SendIndexAndVerifyCallback(4, HpackEntryType::kIndexedHeader, ":path", "/");
|
| + SendIndexAndVerifyCallback(62, HpackEntryType::kIndexedHeader, ":authority",
|
| + "www.example.com");
|
| + SendValueAndVerifyCallback(24, HpackEntryType::kIndexedLiteralHeader,
|
| + "cache-control", "no-cache", UNBUFFERED);
|
| + SendEndAndVerifyCallback();
|
| +
|
| + // Dynamic Table (after decoding):
|
| + //
|
| + // [ 1] (s = 53) cache-control: no-cache
|
| + // [ 2] (s = 57) :authority: www.example.com
|
| + // Table size: 110
|
| +
|
| + ASSERT_TRUE(VerifyDynamicTableContents(
|
| + {{"cache-control", "no-cache"}, {":authority", "www.example.com"}}));
|
| + ASSERT_EQ(110u, current_header_table_size());
|
| +
|
| + // C.3.3 Third Request
|
| + //
|
| + // Header list to encode:
|
| + //
|
| + // :method: GET
|
| + // :scheme: https
|
| + // :path: /index.html
|
| + // :authority: www.example.com
|
| + // custom-key: custom-value
|
| +
|
| + SendStartAndVerifyCallback();
|
| + SendIndexAndVerifyCallback(2, HpackEntryType::kIndexedHeader, ":method",
|
| + "GET");
|
| + SendIndexAndVerifyCallback(7, HpackEntryType::kIndexedHeader, ":scheme",
|
| + "https");
|
| + SendIndexAndVerifyCallback(5, HpackEntryType::kIndexedHeader, ":path",
|
| + "/index.html");
|
| + SendIndexAndVerifyCallback(63, HpackEntryType::kIndexedHeader, ":authority",
|
| + "www.example.com");
|
| + SendNameAndValueAndVerifyCallback(HpackEntryType::kIndexedLiteralHeader,
|
| + "custom-key", UNBUFFERED, "custom-value",
|
| + UNBUFFERED);
|
| + SendEndAndVerifyCallback();
|
| +
|
| + // Dynamic Table (after decoding):
|
| + //
|
| + // [ 1] (s = 54) custom-key: custom-value
|
| + // [ 2] (s = 53) cache-control: no-cache
|
| + // [ 3] (s = 57) :authority: www.example.com
|
| + // Table size: 164
|
| +
|
| + ASSERT_TRUE(VerifyDynamicTableContents({{"custom-key", "custom-value"},
|
| + {"cache-control", "no-cache"},
|
| + {":authority", "www.example.com"}}));
|
| + ASSERT_EQ(164u, current_header_table_size());
|
| +}
|
| +
|
| +// Test based on RFC 7541, section C.5: Response Examples without Huffman
|
| +// Coding. This section shows several consecutive header lists, corresponding
|
| +// to HTTP responses, on the same connection. The HTTP/2 setting parameter
|
| +// SETTINGS_HEADER_TABLE_SIZE is set to the value of 256 octets, causing
|
| +// some evictions to occur.
|
| +TEST_F(HpackDecoderStateTest, C5_ResponseExamples) {
|
| + set_header_table_size_limit(256);
|
| +
|
| + // C.5.1 First Response
|
| + //
|
| + // Header list to encode:
|
| + //
|
| + // :status: 302
|
| + // cache-control: private
|
| + // date: Mon, 21 Oct 2013 20:13:21 GMT
|
| + // location: https://www.example.com
|
| +
|
| + SendStartAndVerifyCallback();
|
| + SendValueAndVerifyCallback(8, HpackEntryType::kIndexedLiteralHeader,
|
| + ":status", "302", BUFFERED);
|
| + SendValueAndVerifyCallback(24, HpackEntryType::kIndexedLiteralHeader,
|
| + "cache-control", "private", UNBUFFERED);
|
| + SendValueAndVerifyCallback(33, HpackEntryType::kIndexedLiteralHeader, "date",
|
| + "Mon, 21 Oct 2013 20:13:21 GMT", UNBUFFERED);
|
| + SendValueAndVerifyCallback(46, HpackEntryType::kIndexedLiteralHeader,
|
| + "location", "https://www.example.com", UNBUFFERED);
|
| + SendEndAndVerifyCallback();
|
| +
|
| + // Dynamic Table (after decoding):
|
| + //
|
| + // [ 1] (s = 63) location: https://www.example.com
|
| + // [ 2] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT
|
| + // [ 3] (s = 52) cache-control: private
|
| + // [ 4] (s = 42) :status: 302
|
| + // Table size: 222
|
| +
|
| + ASSERT_TRUE(
|
| + VerifyDynamicTableContents({{"location", "https://www.example.com"},
|
| + {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
|
| + {"cache-control", "private"},
|
| + {":status", "302"}}));
|
| + ASSERT_EQ(222u, current_header_table_size());
|
| +
|
| + // C.5.2 Second Response
|
| + //
|
| + // The (":status", "302") header field is evicted from the dynamic table to
|
| + // free space to allow adding the (":status", "307") header field.
|
| + //
|
| + // Header list to encode:
|
| + //
|
| + // :status: 307
|
| + // cache-control: private
|
| + // date: Mon, 21 Oct 2013 20:13:21 GMT
|
| + // location: https://www.example.com
|
| +
|
| + SendStartAndVerifyCallback();
|
| + SendValueAndVerifyCallback(8, HpackEntryType::kIndexedLiteralHeader,
|
| + ":status", "307", BUFFERED);
|
| + SendIndexAndVerifyCallback(65, HpackEntryType::kIndexedHeader,
|
| + "cache-control", "private");
|
| + SendIndexAndVerifyCallback(64, HpackEntryType::kIndexedHeader, "date",
|
| + "Mon, 21 Oct 2013 20:13:21 GMT");
|
| + SendIndexAndVerifyCallback(63, HpackEntryType::kIndexedHeader, "location",
|
| + "https://www.example.com");
|
| + SendEndAndVerifyCallback();
|
| +
|
| + // Dynamic Table (after decoding):
|
| + //
|
| + // [ 1] (s = 42) :status: 307
|
| + // [ 2] (s = 63) location: https://www.example.com
|
| + // [ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:21 GMT
|
| + // [ 4] (s = 52) cache-control: private
|
| + // Table size: 222
|
| +
|
| + ASSERT_TRUE(
|
| + VerifyDynamicTableContents({{":status", "307"},
|
| + {"location", "https://www.example.com"},
|
| + {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
|
| + {"cache-control", "private"}}));
|
| + ASSERT_EQ(222u, current_header_table_size());
|
| +
|
| + // C.5.3 Third Response
|
| + //
|
| + // Several header fields are evicted from the dynamic table during the
|
| + // processing of this header list.
|
| + //
|
| + // Header list to encode:
|
| + //
|
| + // :status: 200
|
| + // cache-control: private
|
| + // date: Mon, 21 Oct 2013 20:13:22 GMT
|
| + // location: https://www.example.com
|
| + // content-encoding: gzip
|
| + // set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1
|
| +
|
| + SendStartAndVerifyCallback();
|
| + SendIndexAndVerifyCallback(8, HpackEntryType::kIndexedHeader, ":status",
|
| + "200");
|
| + SendIndexAndVerifyCallback(65, HpackEntryType::kIndexedHeader,
|
| + "cache-control", "private");
|
| + SendValueAndVerifyCallback(33, HpackEntryType::kIndexedLiteralHeader, "date",
|
| + "Mon, 21 Oct 2013 20:13:22 GMT", BUFFERED);
|
| + SendIndexAndVerifyCallback(64, HpackEntryType::kIndexedHeader, "location",
|
| + "https://www.example.com");
|
| + SendValueAndVerifyCallback(26, HpackEntryType::kIndexedLiteralHeader,
|
| + "content-encoding", "gzip", UNBUFFERED);
|
| + SendValueAndVerifyCallback(
|
| + 55, HpackEntryType::kIndexedLiteralHeader, "set-cookie",
|
| + "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", BUFFERED);
|
| + SendEndAndVerifyCallback();
|
| +
|
| + // Dynamic Table (after decoding):
|
| + //
|
| + // [ 1] (s = 98) set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;
|
| + // max-age=3600; version=1
|
| + // [ 2] (s = 52) content-encoding: gzip
|
| + // [ 3] (s = 65) date: Mon, 21 Oct 2013 20:13:22 GMT
|
| + // Table size: 215
|
| +
|
| + ASSERT_TRUE(VerifyDynamicTableContents(
|
| + {{"set-cookie",
|
| + "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
|
| + {"content-encoding", "gzip"},
|
| + {"date", "Mon, 21 Oct 2013 20:13:22 GMT"}}));
|
| + ASSERT_EQ(215u, current_header_table_size());
|
| +}
|
| +
|
| +// Confirm that the table size can be changed, but at most twice.
|
| +TEST_F(HpackDecoderStateTest, OptionalTableSizeChanges) {
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
|
| + header_table_size_limit());
|
| + SendSizeUpdate(1024);
|
| + EXPECT_EQ(1024u, header_table_size_limit());
|
| + SendSizeUpdate(0);
|
| + EXPECT_EQ(0u, header_table_size_limit());
|
| +
|
| + // Three updates aren't allowed.
|
| + EXPECT_CALL(listener_,
|
| + OnHeaderErrorDetected(HasSubstr("size update not allowed")));
|
| + SendSizeUpdate(0);
|
| +}
|
| +
|
| +// Confirm that required size updates are indeed required before headers.
|
| +TEST_F(HpackDecoderStateTest, RequiredTableSizeChangeBeforeHeader) {
|
| + decoder_state_.ApplyHeaderTableSizeSetting(1024);
|
| + decoder_state_.ApplyHeaderTableSizeSetting(2048);
|
| +
|
| + // First provide the required update, and an allowed second update.
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
|
| + header_table_size_limit());
|
| + SendSizeUpdate(1024);
|
| + EXPECT_EQ(1024u, header_table_size_limit());
|
| + SendSizeUpdate(1500);
|
| + EXPECT_EQ(1500u, header_table_size_limit());
|
| + SendEndAndVerifyCallback();
|
| +
|
| + // Another HPACK block, but this time missing the required size update.
|
| + decoder_state_.ApplyHeaderTableSizeSetting(1024);
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_CALL(listener_, OnHeaderErrorDetected(
|
| + HasSubstr("Missing dynamic table size update")));
|
| + decoder_state_.OnIndexedHeader(1);
|
| +
|
| + // Further decoded entries are ignored.
|
| + decoder_state_.OnIndexedHeader(1);
|
| + decoder_state_.OnDynamicTableSizeUpdate(1);
|
| + SetValue("value", UNBUFFERED);
|
| + decoder_state_.OnNameIndexAndLiteralValue(
|
| + HpackEntryType::kIndexedLiteralHeader, 4, &value_buffer_);
|
| + SetName("name", UNBUFFERED);
|
| + decoder_state_.OnLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader,
|
| + &name_buffer_, &value_buffer_);
|
| + decoder_state_.OnHeaderBlockEnd();
|
| + decoder_state_.OnHpackDecodeError("NOT FORWARDED");
|
| +}
|
| +
|
| +// Confirm that required size updates are validated.
|
| +TEST_F(HpackDecoderStateTest, InvalidRequiredSizeUpdate) {
|
| + // Require a size update, but provide one that isn't small enough.
|
| + decoder_state_.ApplyHeaderTableSizeSetting(1024);
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
|
| + header_table_size_limit());
|
| + EXPECT_CALL(listener_,
|
| + OnHeaderErrorDetected(HasSubstr("above low water mark")));
|
| + SendSizeUpdate(2048);
|
| +}
|
| +
|
| +// Confirm that required size updates are indeed required before the end.
|
| +TEST_F(HpackDecoderStateTest, RequiredTableSizeChangeBeforeEnd) {
|
| + decoder_state_.ApplyHeaderTableSizeSetting(1024);
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_CALL(listener_, OnHeaderErrorDetected(
|
| + HasSubstr("Missing dynamic table size update")));
|
| + decoder_state_.OnHeaderBlockEnd();
|
| +}
|
| +
|
| +// Confirm that optional size updates are validated.
|
| +TEST_F(HpackDecoderStateTest, InvalidOptionalSizeUpdate) {
|
| + // Require a size update, but provide one that isn't small enough.
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_EQ(Http2SettingsInfo::DefaultHeaderTableSize(),
|
| + header_table_size_limit());
|
| + EXPECT_CALL(listener_,
|
| + OnHeaderErrorDetected(HasSubstr("size update is above")));
|
| + SendSizeUpdate(Http2SettingsInfo::DefaultHeaderTableSize() + 1);
|
| +}
|
| +
|
| +TEST_F(HpackDecoderStateTest, InvalidStaticIndex) {
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_CALL(listener_, OnHeaderErrorDetected(HasSubstr("Invalid index")));
|
| + decoder_state_.OnIndexedHeader(0);
|
| +}
|
| +
|
| +TEST_F(HpackDecoderStateTest, InvalidDynamicIndex) {
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_CALL(listener_, OnHeaderErrorDetected(HasSubstr("Invalid index")));
|
| + decoder_state_.OnIndexedHeader(kFirstDynamicTableIndex);
|
| +}
|
| +
|
| +TEST_F(HpackDecoderStateTest, InvalidNameIndex) {
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_CALL(listener_,
|
| + OnHeaderErrorDetected(HasSubstr("Invalid name index")));
|
| + SetValue("value", UNBUFFERED);
|
| + decoder_state_.OnNameIndexAndLiteralValue(
|
| + HpackEntryType::kIndexedLiteralHeader, kFirstDynamicTableIndex,
|
| + &value_buffer_);
|
| +}
|
| +
|
| +TEST_F(HpackDecoderStateTest, ErrorsSuppressCallbacks) {
|
| + SendStartAndVerifyCallback();
|
| + EXPECT_CALL(listener_,
|
| + OnHeaderErrorDetected(StringPiece("Huffman decode error.")));
|
| + decoder_state_.OnHpackDecodeError("Huffman decode error.");
|
| +
|
| + // Further decoded entries are ignored.
|
| + decoder_state_.OnIndexedHeader(1);
|
| + decoder_state_.OnDynamicTableSizeUpdate(1);
|
| + SetValue("value", UNBUFFERED);
|
| + decoder_state_.OnNameIndexAndLiteralValue(
|
| + HpackEntryType::kIndexedLiteralHeader, 4, &value_buffer_);
|
| + SetName("name", UNBUFFERED);
|
| + decoder_state_.OnLiteralNameAndValue(HpackEntryType::kIndexedLiteralHeader,
|
| + &name_buffer_, &value_buffer_);
|
| + decoder_state_.OnHeaderBlockEnd();
|
| + decoder_state_.OnHpackDecodeError("NOT FORWARDED");
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace test
|
| +} // namespace net
|
|
|