blob: 9097458f5cd4bce256638e4c82bee9733c6ee99a [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 "quiche/http2/test_tools/http2_frame_builder.h"
#include "absl/strings/escaping.h"
#include "quiche/common/platform/api/quiche_test.h"
namespace http2 {
namespace test {
namespace {
const char kHighBitSetMsg[] = "High-bit of uint32_t should be clear";
TEST(Http2FrameBuilderTest, Constructors) {
{
Http2FrameBuilder fb;
EXPECT_EQ(0u, fb.size());
}
{
Http2FrameBuilder fb(Http2FrameType::DATA, 0, 123);
EXPECT_EQ(9u, fb.size());
const std::string kData = absl::HexStringToBytes(
"000000" // Payload length: 0 (unset)
"00" // Frame type: DATA
"00" // Flags: none
"0000007b"); // Stream ID: 123
EXPECT_EQ(kData, fb.buffer());
}
{
Http2FrameHeader header;
header.payload_length = (1 << 24) - 1;
header.type = Http2FrameType::HEADERS;
header.flags = Http2FrameFlag::END_HEADERS;
header.stream_id = StreamIdMask();
Http2FrameBuilder fb(header);
EXPECT_EQ(9u, fb.size());
const std::string kData = absl::HexStringToBytes(
"ffffff" // Payload length: 2^24 - 1 (max uint24)
"01" // Frame type: HEADER
"04" // Flags: END_HEADERS
"7fffffff"); // Stream ID: stream id mask
EXPECT_EQ(kData, fb.buffer());
}
}
TEST(Http2FrameBuilderTest, SetPayloadLength) {
Http2FrameBuilder fb(Http2FrameType::DATA, PADDED, 20000);
EXPECT_EQ(9u, fb.size());
fb.AppendUInt8(50); // Trailing payload length
EXPECT_EQ(10u, fb.size());
fb.Append("ten bytes.");
EXPECT_EQ(20u, fb.size());
fb.AppendZeroes(50);
EXPECT_EQ(70u, fb.size());
fb.SetPayloadLength();
EXPECT_EQ(70u, fb.size());
const std::string kData = absl::HexStringToBytes(
"00003d" // Payload length: 61
"00" // Frame type: DATA
"08" // Flags: PADDED
"00004e20" // Stream ID: 20000
"32" // Padding Length: 50
"74656e2062797465732e" // "ten bytes."
"00000000000000000000" // Padding bytes
"00000000000000000000" // Padding bytes
"00000000000000000000" // Padding bytes
"00000000000000000000" // Padding bytes
"00000000000000000000"); // Padding bytes
EXPECT_EQ(kData, fb.buffer());
}
TEST(Http2FrameBuilderTest, Settings) {
Http2FrameBuilder fb(Http2FrameType::SETTINGS, 0, 0);
Http2SettingFields sf;
sf.parameter = Http2SettingsParameter::HEADER_TABLE_SIZE;
sf.value = 1 << 12;
fb.Append(sf);
sf.parameter = Http2SettingsParameter::ENABLE_PUSH;
sf.value = 0;
fb.Append(sf);
sf.parameter = Http2SettingsParameter::MAX_CONCURRENT_STREAMS;
sf.value = ~0;
fb.Append(sf);
sf.parameter = Http2SettingsParameter::INITIAL_WINDOW_SIZE;
sf.value = 1 << 16;
fb.Append(sf);
sf.parameter = Http2SettingsParameter::MAX_FRAME_SIZE;
sf.value = 1 << 14;
fb.Append(sf);
sf.parameter = Http2SettingsParameter::MAX_HEADER_LIST_SIZE;
sf.value = 1 << 10;
fb.Append(sf);
size_t payload_size = 6 * Http2SettingFields::EncodedSize();
EXPECT_EQ(Http2FrameHeader::EncodedSize() + payload_size, fb.size());
fb.SetPayloadLength(payload_size);
const std::string kData = absl::HexStringToBytes(
"000024" // Payload length: 36
"04" // Frame type: SETTINGS
"00" // Flags: none
"00000000" // Stream ID: 0
"0001" // HEADER_TABLE_SIZE
"00001000" // 4096
"0002" // ENABLE_PUSH
"00000000" // 0
"0003" // MAX_CONCURRENT_STREAMS
"ffffffff" // 0xffffffff (max uint32)
"0004" // INITIAL_WINDOW_SIZE
"00010000" // 4096
"0005" // MAX_FRAME_SIZE
"00004000" // 4096
"0006" // MAX_HEADER_LIST_SIZE
"00000400"); // 1024
EXPECT_EQ(kData, fb.buffer());
}
TEST(Http2FrameBuilderTest, EnhanceYourCalm) {
const std::string kData = absl::HexStringToBytes("0000000b");
{
Http2FrameBuilder fb;
fb.Append(Http2ErrorCode::ENHANCE_YOUR_CALM);
EXPECT_EQ(kData, fb.buffer());
}
{
Http2FrameBuilder fb;
Http2RstStreamFields rsp;
rsp.error_code = Http2ErrorCode::ENHANCE_YOUR_CALM;
fb.Append(rsp);
EXPECT_EQ(kData, fb.buffer());
}
}
TEST(Http2FrameBuilderTest, PushPromise) {
const std::string kData = absl::HexStringToBytes("7fffffff");
{
Http2FrameBuilder fb;
fb.Append(Http2PushPromiseFields{0x7fffffff});
EXPECT_EQ(kData, fb.buffer());
}
{
Http2FrameBuilder fb;
// Will generate an error if the high-bit of the stream id is set.
EXPECT_NONFATAL_FAILURE(fb.Append(Http2PushPromiseFields{0xffffffff}),
kHighBitSetMsg);
EXPECT_EQ(kData, fb.buffer());
}
}
TEST(Http2FrameBuilderTest, Ping) {
Http2FrameBuilder fb;
Http2PingFields ping{"8 bytes"};
fb.Append(ping);
const absl::string_view kData{"8 bytes\0", 8};
EXPECT_EQ(kData.size(), Http2PingFields::EncodedSize());
EXPECT_EQ(kData, fb.buffer());
}
TEST(Http2FrameBuilderTest, GoAway) {
const std::string kData = absl::HexStringToBytes(
"12345678" // Last Stream Id
"00000001"); // Error code
EXPECT_EQ(kData.size(), Http2GoAwayFields::EncodedSize());
{
Http2FrameBuilder fb;
Http2GoAwayFields ga(0x12345678, Http2ErrorCode::PROTOCOL_ERROR);
fb.Append(ga);
EXPECT_EQ(kData, fb.buffer());
}
{
Http2FrameBuilder fb;
// Will generate a test failure if the high-bit of the stream id is set.
Http2GoAwayFields ga(0x92345678, Http2ErrorCode::PROTOCOL_ERROR);
EXPECT_NONFATAL_FAILURE(fb.Append(ga), kHighBitSetMsg);
EXPECT_EQ(kData, fb.buffer());
}
}
TEST(Http2FrameBuilderTest, WindowUpdate) {
Http2FrameBuilder fb;
fb.Append(Http2WindowUpdateFields{123456});
// Will generate a test failure if the high-bit of the increment is set.
EXPECT_NONFATAL_FAILURE(fb.Append(Http2WindowUpdateFields{0x80000001}),
kHighBitSetMsg);
// Will generate a test failure if the increment is zero.
EXPECT_NONFATAL_FAILURE(fb.Append(Http2WindowUpdateFields{0}), "non-zero");
const std::string kData = absl::HexStringToBytes(
"0001e240" // Valid Window Size Increment
"00000001" // High-bit cleared
"00000000"); // Invalid Window Size Increment
EXPECT_EQ(kData.size(), 3 * Http2WindowUpdateFields::EncodedSize());
EXPECT_EQ(kData, fb.buffer());
}
TEST(Http2FrameBuilderTest, AltSvc) {
Http2FrameBuilder fb;
fb.Append(Http2AltSvcFields{99});
fb.Append(Http2AltSvcFields{0}); // No optional origin
const std::string kData = absl::HexStringToBytes(
"0063" // Has origin.
"0000"); // Doesn't have origin.
EXPECT_EQ(kData.size(), 2 * Http2AltSvcFields::EncodedSize());
EXPECT_EQ(kData, fb.buffer());
}
} // namespace
} // namespace test
} // namespace http2