1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/http2/decoder/decode_buffer.h"
6
7 #include <functional>
8
9 #include "quiche/http2/test_tools/http2_random.h"
10 #include "quiche/common/platform/api/quiche_logging.h"
11 #include "quiche/common/platform/api/quiche_test.h"
12
13 namespace http2 {
14 namespace test {
15 namespace {
16
17 enum class TestEnumClass32 {
18 kValue1 = 1,
19 kValue99 = 99,
20 kValue1M = 1000000,
21 };
22
23 enum class TestEnumClass8 {
24 kValue1 = 1,
25 kValue2 = 1,
26 kValue99 = 99,
27 kValue255 = 255,
28 };
29
30 enum TestEnum8 {
31 kMaskLo = 0x01,
32 kMaskHi = 0x80,
33 };
34
35 struct TestStruct {
36 uint8_t f1;
37 uint16_t f2;
38 uint32_t f3; // Decoded as a uint24
39 uint32_t f4;
40 uint32_t f5; // Decoded as if uint31
41 TestEnumClass32 f6;
42 TestEnumClass8 f7;
43 TestEnum8 f8;
44 };
45
46 class DecodeBufferTest : public quiche::test::QuicheTest {
47 protected:
48 Http2Random random_;
49 uint32_t decode_offset_;
50 };
51
TEST_F(DecodeBufferTest,DecodesFixedInts)52 TEST_F(DecodeBufferTest, DecodesFixedInts) {
53 const char data[] = "\x01\x12\x23\x34\x45\x56\x67\x78\x89\x9a";
54 DecodeBuffer b1(data, strlen(data));
55 EXPECT_EQ(1, b1.DecodeUInt8());
56 EXPECT_EQ(0x1223u, b1.DecodeUInt16());
57 EXPECT_EQ(0x344556u, b1.DecodeUInt24());
58 EXPECT_EQ(0x6778899Au, b1.DecodeUInt32());
59 }
60
61 // Make sure that DecodeBuffer is not copying input, just pointing into
62 // provided input buffer.
TEST_F(DecodeBufferTest,HasNotCopiedInput)63 TEST_F(DecodeBufferTest, HasNotCopiedInput) {
64 const char data[] = "ab";
65 DecodeBuffer b1(data, 2);
66
67 EXPECT_EQ(2u, b1.Remaining());
68 EXPECT_EQ(0u, b1.Offset());
69 EXPECT_FALSE(b1.Empty());
70 EXPECT_EQ(data, b1.cursor()); // cursor points to input buffer
71 EXPECT_TRUE(b1.HasData());
72
73 b1.AdvanceCursor(1);
74
75 EXPECT_EQ(1u, b1.Remaining());
76 EXPECT_EQ(1u, b1.Offset());
77 EXPECT_FALSE(b1.Empty());
78 EXPECT_EQ(&data[1], b1.cursor());
79 EXPECT_TRUE(b1.HasData());
80
81 b1.AdvanceCursor(1);
82
83 EXPECT_EQ(0u, b1.Remaining());
84 EXPECT_EQ(2u, b1.Offset());
85 EXPECT_TRUE(b1.Empty());
86 EXPECT_EQ(&data[2], b1.cursor());
87 EXPECT_FALSE(b1.HasData());
88
89 DecodeBuffer b2(data, 0);
90
91 EXPECT_EQ(0u, b2.Remaining());
92 EXPECT_EQ(0u, b2.Offset());
93 EXPECT_TRUE(b2.Empty());
94 EXPECT_EQ(data, b2.cursor());
95 EXPECT_FALSE(b2.HasData());
96 }
97
98 // DecodeBufferSubset can't go beyond the end of the base buffer.
TEST_F(DecodeBufferTest,DecodeBufferSubsetLimited)99 TEST_F(DecodeBufferTest, DecodeBufferSubsetLimited) {
100 const char data[] = "abc";
101 DecodeBuffer base(data, 3);
102 base.AdvanceCursor(1);
103 DecodeBufferSubset subset(&base, 100);
104 EXPECT_EQ(2u, subset.FullSize());
105 }
106
107 // DecodeBufferSubset advances the cursor of its base upon destruction.
TEST_F(DecodeBufferTest,DecodeBufferSubsetAdvancesCursor)108 TEST_F(DecodeBufferTest, DecodeBufferSubsetAdvancesCursor) {
109 const char data[] = "abc";
110 const size_t size = sizeof(data) - 1;
111 EXPECT_EQ(3u, size);
112 DecodeBuffer base(data, size);
113 {
114 // First no change to the cursor.
115 DecodeBufferSubset subset(&base, size + 100);
116 EXPECT_EQ(size, subset.FullSize());
117 EXPECT_EQ(base.FullSize(), subset.FullSize());
118 EXPECT_EQ(0u, subset.Offset());
119 }
120 EXPECT_EQ(0u, base.Offset());
121 EXPECT_EQ(size, base.Remaining());
122 }
123
124 // Make sure that DecodeBuffer ctor complains about bad args.
125 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
TEST(DecodeBufferDeathTest,NonNullBufferRequired)126 TEST(DecodeBufferDeathTest, NonNullBufferRequired) {
127 EXPECT_QUICHE_DEBUG_DEATH({ DecodeBuffer b(nullptr, 3); }, "nullptr");
128 }
129
130 // Make sure that DecodeBuffer ctor complains about bad args.
TEST(DecodeBufferDeathTest,ModestBufferSizeRequired)131 TEST(DecodeBufferDeathTest, ModestBufferSizeRequired) {
132 EXPECT_QUICHE_DEBUG_DEATH(
133 {
134 constexpr size_t kLength = DecodeBuffer::kMaxDecodeBufferLength + 1;
135 auto data = std::make_unique<char[]>(kLength);
136 DecodeBuffer b(data.get(), kLength);
137 },
138 "Max.*Length");
139 }
140
141 // Make sure that DecodeBuffer detects advance beyond end, in debug mode.
TEST(DecodeBufferDeathTest,LimitedAdvance)142 TEST(DecodeBufferDeathTest, LimitedAdvance) {
143 {
144 // Advance right up to end is OK.
145 const char data[] = "abc";
146 DecodeBuffer b(data, 3);
147 b.AdvanceCursor(3); // OK
148 EXPECT_TRUE(b.Empty());
149 }
150 EXPECT_QUICHE_DEBUG_DEATH(
151 {
152 // Going beyond is not OK.
153 const char data[] = "abc";
154 DecodeBuffer b(data, 3);
155 b.AdvanceCursor(4);
156 },
157 "Remaining");
158 }
159
160 // Make sure that DecodeBuffer detects decode beyond end, in debug mode.
TEST(DecodeBufferDeathTest,DecodeUInt8PastEnd)161 TEST(DecodeBufferDeathTest, DecodeUInt8PastEnd) {
162 const char data[] = {0x12, 0x23};
163 DecodeBuffer b(data, sizeof data);
164 EXPECT_EQ(2u, b.FullSize());
165 EXPECT_EQ(0x1223, b.DecodeUInt16());
166 EXPECT_QUICHE_DEBUG_DEATH({ b.DecodeUInt8(); }, "Remaining");
167 }
168
169 // Make sure that DecodeBuffer detects decode beyond end, in debug mode.
TEST(DecodeBufferDeathTest,DecodeUInt16OverEnd)170 TEST(DecodeBufferDeathTest, DecodeUInt16OverEnd) {
171 const char data[] = {0x12, 0x23, 0x34};
172 DecodeBuffer b(data, sizeof data);
173 EXPECT_EQ(3u, b.FullSize());
174 EXPECT_EQ(0x1223, b.DecodeUInt16());
175 EXPECT_QUICHE_DEBUG_DEATH({ b.DecodeUInt16(); }, "Remaining");
176 }
177
178 // Make sure that DecodeBuffer doesn't agree with having two subsets.
TEST(DecodeBufferSubsetDeathTest,TwoSubsets)179 TEST(DecodeBufferSubsetDeathTest, TwoSubsets) {
180 const char data[] = "abc";
181 DecodeBuffer base(data, 3);
182 DecodeBufferSubset subset1(&base, 1);
183 EXPECT_QUICHE_DEBUG_DEATH({ DecodeBufferSubset subset2(&base, 1); },
184 "There is already a subset");
185 }
186
187 // Make sure that DecodeBufferSubset notices when the base's cursor has moved.
TEST(DecodeBufferSubsetDeathTest,BaseCursorAdvanced)188 TEST(DecodeBufferSubsetDeathTest, BaseCursorAdvanced) {
189 const char data[] = "abc";
190 DecodeBuffer base(data, 3);
191 base.AdvanceCursor(1);
192 EXPECT_QUICHE_DEBUG_DEATH(
193 {
194 DecodeBufferSubset subset1(&base, 2);
195 base.AdvanceCursor(1);
196 },
197 "Access via subset only when present");
198 }
199 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
200
201 } // namespace
202 } // namespace test
203 } // namespace http2
204