blob: 75b281c062ddf42d96401376537d425de0a8dc3f [file] [log] [blame]
// 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/third_party/quiche/src/http2/hpack/decoder/hpack_whole_entry_buffer.h"
// Tests of HpackWholeEntryBuffer: does it buffer correctly, and does it
// detect Huffman decoding errors and oversize string errors?
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::AllOf;
using ::testing::HasSubstr;
using ::testing::InSequence;
using ::testing::Property;
using ::testing::StrictMock;
namespace http2 {
namespace test {
namespace {
constexpr size_t kMaxStringSize = 20;
class MockHpackWholeEntryListener : public HpackWholeEntryListener {
public:
~MockHpackWholeEntryListener() override = default;
MOCK_METHOD1(OnIndexedHeader, void(size_t index));
MOCK_METHOD3(OnNameIndexAndLiteralValue,
void(HpackEntryType entry_type,
size_t name_index,
HpackDecoderStringBuffer* value_buffer));
MOCK_METHOD3(OnLiteralNameAndValue,
void(HpackEntryType entry_type,
HpackDecoderStringBuffer* name_buffer,
HpackDecoderStringBuffer* value_buffer));
MOCK_METHOD1(OnDynamicTableSizeUpdate, void(size_t size));
MOCK_METHOD1(OnHpackDecodeError, void(Http2StringPiece error_message));
};
class HpackWholeEntryBufferTest : public ::testing::Test {
protected:
HpackWholeEntryBufferTest() : entry_buffer_(&listener_, kMaxStringSize) {}
~HpackWholeEntryBufferTest() override = default;
StrictMock<MockHpackWholeEntryListener> listener_;
HpackWholeEntryBuffer entry_buffer_;
};
// OnIndexedHeader is an immediate pass through.
TEST_F(HpackWholeEntryBufferTest, OnIndexedHeader) {
{
InSequence seq;
EXPECT_CALL(listener_, OnIndexedHeader(17));
entry_buffer_.OnIndexedHeader(17);
}
{
InSequence seq;
EXPECT_CALL(listener_, OnIndexedHeader(62));
entry_buffer_.OnIndexedHeader(62);
}
{
InSequence seq;
EXPECT_CALL(listener_, OnIndexedHeader(62));
entry_buffer_.OnIndexedHeader(62);
}
{
InSequence seq;
EXPECT_CALL(listener_, OnIndexedHeader(128));
entry_buffer_.OnIndexedHeader(128);
}
StrictMock<MockHpackWholeEntryListener> listener2;
entry_buffer_.set_listener(&listener2);
{
InSequence seq;
EXPECT_CALL(listener2, OnIndexedHeader(100));
entry_buffer_.OnIndexedHeader(100);
}
}
// OnDynamicTableSizeUpdate is an immediate pass through.
TEST_F(HpackWholeEntryBufferTest, OnDynamicTableSizeUpdate) {
{
InSequence seq;
EXPECT_CALL(listener_, OnDynamicTableSizeUpdate(4096));
entry_buffer_.OnDynamicTableSizeUpdate(4096);
}
{
InSequence seq;
EXPECT_CALL(listener_, OnDynamicTableSizeUpdate(0));
entry_buffer_.OnDynamicTableSizeUpdate(0);
}
{
InSequence seq;
EXPECT_CALL(listener_, OnDynamicTableSizeUpdate(1024));
entry_buffer_.OnDynamicTableSizeUpdate(1024);
}
{
InSequence seq;
EXPECT_CALL(listener_, OnDynamicTableSizeUpdate(1024));
entry_buffer_.OnDynamicTableSizeUpdate(1024);
}
StrictMock<MockHpackWholeEntryListener> listener2;
entry_buffer_.set_listener(&listener2);
{
InSequence seq;
EXPECT_CALL(listener2, OnDynamicTableSizeUpdate(0));
entry_buffer_.OnDynamicTableSizeUpdate(0);
}
}
TEST_F(HpackWholeEntryBufferTest, OnNameIndexAndLiteralValue) {
entry_buffer_.OnStartLiteralHeader(HpackEntryType::kNeverIndexedLiteralHeader,
123);
entry_buffer_.OnValueStart(false, 10);
entry_buffer_.OnValueData("some data.", 10);
// Force the value to be buffered.
entry_buffer_.BufferStringsIfUnbuffered();
EXPECT_CALL(
listener_,
OnNameIndexAndLiteralValue(
HpackEntryType::kNeverIndexedLiteralHeader, 123,
AllOf(Property(&HpackDecoderStringBuffer::str, "some data."),
Property(&HpackDecoderStringBuffer::BufferedLength, 10))));
entry_buffer_.OnValueEnd();
}
TEST_F(HpackWholeEntryBufferTest, OnLiteralNameAndValue) {
entry_buffer_.OnStartLiteralHeader(HpackEntryType::kIndexedLiteralHeader, 0);
// Force the name to be buffered by delivering it in two pieces.
entry_buffer_.OnNameStart(false, 9);
entry_buffer_.OnNameData("some-", 5);
entry_buffer_.OnNameData("name", 4);
entry_buffer_.OnNameEnd();
entry_buffer_.OnValueStart(false, 12);
entry_buffer_.OnValueData("Header Value", 12);
EXPECT_CALL(
listener_,
OnLiteralNameAndValue(
HpackEntryType::kIndexedLiteralHeader,
AllOf(Property(&HpackDecoderStringBuffer::str, "some-name"),
Property(&HpackDecoderStringBuffer::BufferedLength, 9)),
AllOf(Property(&HpackDecoderStringBuffer::str, "Header Value"),
Property(&HpackDecoderStringBuffer::BufferedLength, 0))));
entry_buffer_.OnValueEnd();
}
// Verify that a name longer than the allowed size generates an error.
TEST_F(HpackWholeEntryBufferTest, NameTooLong) {
entry_buffer_.OnStartLiteralHeader(HpackEntryType::kIndexedLiteralHeader, 0);
EXPECT_CALL(listener_, OnHpackDecodeError(HasSubstr("HPACK entry name")));
entry_buffer_.OnNameStart(false, kMaxStringSize + 1);
}
// Verify that a name longer than the allowed size generates an error.
TEST_F(HpackWholeEntryBufferTest, ValueTooLong) {
entry_buffer_.OnStartLiteralHeader(HpackEntryType::kIndexedLiteralHeader, 1);
EXPECT_CALL(listener_, OnHpackDecodeError(HasSubstr("HPACK entry value")));
entry_buffer_.OnValueStart(false, kMaxStringSize + 1);
}
// Verify that a Huffman encoded name with an explicit EOS generates an error
// for an explicit EOS.
TEST_F(HpackWholeEntryBufferTest, NameHuffmanError) {
const char data[] = "\xff\xff\xff";
entry_buffer_.OnStartLiteralHeader(HpackEntryType::kUnindexedLiteralHeader,
0);
entry_buffer_.OnNameStart(true, 4);
entry_buffer_.OnNameData(data, 3);
EXPECT_CALL(listener_, OnHpackDecodeError(HasSubstr("HPACK entry name")));
entry_buffer_.OnNameData(data, 1);
// After an error is reported, the listener is not called again.
EXPECT_CALL(listener_, OnDynamicTableSizeUpdate(8096)).Times(0);
entry_buffer_.OnDynamicTableSizeUpdate(8096);
}
// Verify that a Huffman encoded value that isn't properly terminated with
// a partial EOS symbol generates an error.
TEST_F(HpackWholeEntryBufferTest, ValueeHuffmanError) {
const char data[] = "\x00\x00\x00";
entry_buffer_.OnStartLiteralHeader(HpackEntryType::kNeverIndexedLiteralHeader,
61);
entry_buffer_.OnValueStart(true, 3);
entry_buffer_.OnValueData(data, 3);
EXPECT_CALL(listener_, OnHpackDecodeError(HasSubstr("HPACK entry value")));
entry_buffer_.OnValueEnd();
// After an error is reported, the listener is not called again.
EXPECT_CALL(listener_, OnIndexedHeader(17)).Times(0);
entry_buffer_.OnIndexedHeader(17);
}
} // namespace
} // namespace test
} // namespace http2