#include "net/spdy/alps_decoder.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "net/base/features.h"
#include "net/base/hex_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::spdy::AcceptChOriginValuePair;
using ::testing::ElementsAre;
using ::testing::IsEmpty;
using ::testing::Pair;
namespace net {
namespace {
TEST(AlpsDecoderTest, EmptyInput) {
AlpsDecoder decoder;
EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
EXPECT_THAT(decoder.GetSettings(), IsEmpty());
EXPECT_EQ(0, decoder.settings_frame_count());
AlpsDecoder::Error error = decoder.Decode({});
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
EXPECT_THAT(decoder.GetSettings(), IsEmpty());
EXPECT_EQ(0, decoder.settings_frame_count());
}
TEST(AlpsDecoderTest, EmptyAcceptChFrame) {
AlpsDecoder decoder;
AlpsDecoder::Error error =
decoder.Decode(HexDecode("000000"
"89"
"00"
"00000000"));
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
EXPECT_THAT(decoder.GetSettings(), IsEmpty());
EXPECT_EQ(0, decoder.settings_frame_count());
}
TEST(AlpsDecoderTest, EmptySettingsFrame) {
AlpsDecoder decoder;
AlpsDecoder::Error error =
decoder.Decode(HexDecode("000000"
"04"
"00"
"00000000"));
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
EXPECT_THAT(decoder.GetSettings(), IsEmpty());
EXPECT_EQ(1, decoder.settings_frame_count());
}
TEST(AlpsDecoderTest, ParseSettingsAndAcceptChFrames) {
AlpsDecoder decoder;
AlpsDecoder::Error error = decoder.Decode(HexDecode(
"00003d"
"89"
"00"
"00000000"
"0017"
"68747470733a2f2f7777772e"
"6578616d706c652e636f6d"
"0003"
"666f6f"
"0018"
"68747470733a2f2f6d61696c"
"2e6578616d706c652e636f6d"
"0003"
"626172"
"00000c"
"04"
"00"
"00000000"
"0dab"
"01020304"
"1234"
"fedcba98"));
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
EXPECT_THAT(
decoder.GetAcceptCh(),
ElementsAre(AcceptChOriginValuePair{"https://www.example.com", "foo"},
AcceptChOriginValuePair{"https://mail.example.com", "bar"}));
EXPECT_THAT(decoder.GetSettings(),
ElementsAre(Pair(0x0dab, 0x01020304), Pair(0x1234, 0xfedcba98)));
EXPECT_EQ(1, decoder.settings_frame_count());
}
TEST(AlpsDecoderTest, ParseLargeAcceptChFrame) {
std::string frame = HexDecode(
"0001ab"
"89"
"00"
"00000000"
"0017"
"68747470733a2f2f7777772e"
"6578616d706c652e636f6d"
"0190"
);
const std::string accept_ch_tokens(400, 'x');
frame += accept_ch_tokens;
AlpsDecoder decoder;
AlpsDecoder::Error error = decoder.Decode(frame);
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
EXPECT_THAT(decoder.GetAcceptCh(),
ElementsAre(AcceptChOriginValuePair{"https://www.example.com",
accept_ch_tokens}));
}
TEST(AlpsDecoderTest, DisableAlpsParsing) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(features::kAlpsParsing);
AlpsDecoder decoder;
AlpsDecoder::Error error = decoder.Decode(HexDecode(
"00003d"
"89"
"00"
"00000000"
"0017"
"68747470733a2f2f7777772e"
"6578616d706c652e636f6d"
"0003"
"666f6f"
"0018"
"68747470733a2f2f6d61696c"
"2e6578616d706c652e636f6d"
"0003"
"626172"
));
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
}
TEST(AlpsDecoderTest, DisableAlpsClientHintParsing) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(features::kAlpsClientHintParsing);
AlpsDecoder decoder;
AlpsDecoder::Error error = decoder.Decode(HexDecode(
"00003d"
"89"
"00"
"00000000"
"0017"
"68747470733a2f2f7777772e"
"6578616d706c652e636f6d"
"0003"
"666f6f"
"0018"
"68747470733a2f2f6d61696c"
"2e6578616d706c652e636f6d"
"0003"
"626172"
));
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
}
TEST(AlpsDecoderTest, IncompleteFrame) {
AlpsDecoder decoder;
AlpsDecoder::Error error =
decoder.Decode(HexDecode("00000c"
"04"
"00"
"00000000"
"0dab"
"01"));
EXPECT_EQ(AlpsDecoder::Error::kNotOnFrameBoundary, error);
}
TEST(AlpsDecoderTest, TwoSettingsFrames) {
AlpsDecoder decoder;
AlpsDecoder::Error error =
decoder.Decode(HexDecode("000006"
"04"
"00"
"00000000"
"0dab"
"01020304"
"000006"
"04"
"00"
"00000000"
"1234"
"fedcba98"));
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
EXPECT_EQ(2, decoder.settings_frame_count());
EXPECT_THAT(decoder.GetSettings(),
ElementsAre(Pair(0x0dab, 0x01020304), Pair(0x1234, 0xfedcba98)));
}
TEST(AlpsDecoderTest, AcceptChOnInvalidStream) {
AlpsDecoder decoder;
AlpsDecoder::Error error = decoder.Decode(
HexDecode("00001e"
"89"
"00"
"00000001"
"0017"
"68747470733a2f2f7777772e"
"6578616d706c652e636f6d"
"0003"
"666f6f"));
EXPECT_EQ(AlpsDecoder::Error::kAcceptChInvalidStream, error);
}
// draft-davidben-http-client-hint-reliability.html#name-http-2-accept_ch-frame
TEST(AlpsDecoderTest, AcceptChWithInvalidFlags) {
AlpsDecoder decoder;
AlpsDecoder::Error error = decoder.Decode(
HexDecode("00001e"
"89"
"02"
"00000000"
"0017"
"68747470733a2f2f7777772e"
"6578616d706c652e636f6d"
"0003"
"666f6f"));
EXPECT_EQ(AlpsDecoder::Error::kAcceptChWithFlags, error);
}
TEST(AlpsDecoderTest, SettingsOnInvalidStream) {
AlpsDecoder decoder;
AlpsDecoder::Error error =
decoder.Decode(HexDecode("000006"
"04"
"00"
"00000001"
"1234"
"fedcba98"));
EXPECT_EQ(AlpsDecoder::Error::kFramingError, error);
}
TEST(AlpsDecoderTest, SettingsAck) {
AlpsDecoder decoder;
AlpsDecoder::Error error =
decoder.Decode(HexDecode("000000"
"04"
"01"
"00000000"));
EXPECT_EQ(AlpsDecoder::Error::kSettingsWithAck, error);
}
TEST(AlpsDecoderTest, SettingsWithInvalidFlags) {
AlpsDecoder decoder;
AlpsDecoder::Error error =
decoder.Decode(HexDecode("000006"
"04"
"02"
"00000000"
"1234"
"fedcba98"));
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
}
TEST(AlpsDecoderTest, ForbiddenFrame) {
AlpsDecoder decoder;
AlpsDecoder::Error error =
decoder.Decode(HexDecode("000003"
"00"
"01"
"00000001"
"666f6f"));
EXPECT_EQ(AlpsDecoder::Error::kForbiddenFrame, error);
}
TEST(AlpsDecoderTest, UnknownFrame) {
AlpsDecoder decoder;
AlpsDecoder::Error error =
decoder.Decode(HexDecode("000003"
"2a"
"ff"
"00000008"
"666f6f"));
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
EXPECT_THAT(decoder.GetAcceptCh(), IsEmpty());
EXPECT_THAT(decoder.GetSettings(), IsEmpty());
EXPECT_EQ(0, decoder.settings_frame_count());
}
class AlpsDecoderTestWithFeature : public ::testing::TestWithParam<bool> {
public:
bool ShouldKillSessionOnAcceptChMalformed() { return GetParam(); }
private:
void SetUp() override {
feature_list_.InitWithFeatureState(
features::kShouldKillSessionOnAcceptChMalformed,
ShouldKillSessionOnAcceptChMalformed());
}
base::test::ScopedFeatureList feature_list_;
};
INSTANTIATE_TEST_SUITE_P(All, AlpsDecoderTestWithFeature, testing::Bool());
TEST_P(AlpsDecoderTestWithFeature, MalformedAcceptChFrame) {
std::string payload = HexDecode(
"0017"
"68747470733a2f2f7777772e"
"6578616d706c652e636f6d"
"0003"
"666f6f");
for (uint8_t payload_length = 1; payload_length < payload.length();
payload_length++) {
base::HistogramTester histogram_tester;
std::string frame = HexDecode("0000");
frame.push_back(static_cast<char>(payload_length));
frame.append(
HexDecode("89"
"00"
"00000000"));
frame.append(payload.data(), payload_length);
AlpsDecoder decoder;
AlpsDecoder::Error error = decoder.Decode(frame);
if (ShouldKillSessionOnAcceptChMalformed()) {
EXPECT_EQ(AlpsDecoder::Error::kAcceptChMalformed, error);
histogram_tester.ExpectUniqueSample(
"Net.SpdySession.AlpsDecoderStatus.Bypassed",
static_cast<int>(AlpsDecoder::Error::kNoError), 1);
} else {
EXPECT_EQ(AlpsDecoder::Error::kNoError, error);
histogram_tester.ExpectUniqueSample(
"Net.SpdySession.AlpsDecoderStatus.Bypassed",
static_cast<int>(AlpsDecoder::Error::kAcceptChMalformed), 1);
}
}
}
}
}