xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/decoder/decode_buffer_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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