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/hpack/decoder/hpack_string_decoder.h"
6
7 // Tests of HpackStringDecoder.
8
9 #include "absl/strings/string_view.h"
10 #include "quiche/http2/hpack/decoder/hpack_string_decoder_listener.h"
11 #include "quiche/http2/test_tools/hpack_block_builder.h"
12 #include "quiche/http2/test_tools/hpack_string_collector.h"
13 #include "quiche/http2/test_tools/http2_random.h"
14 #include "quiche/http2/test_tools/random_decoder_test_base.h"
15 #include "quiche/http2/test_tools/verify_macros.h"
16 #include "quiche/common/platform/api/quiche_test.h"
17
18 namespace http2 {
19 namespace test {
20 namespace {
21
22 const bool kMayReturnZeroOnFirst = false;
23 const bool kCompressed = true;
24 const bool kUncompressed = false;
25
26 class HpackStringDecoderTest : public RandomDecoderTest {
27 protected:
HpackStringDecoderTest()28 HpackStringDecoderTest() : listener_(&collector_) {}
29
StartDecoding(DecodeBuffer * b)30 DecodeStatus StartDecoding(DecodeBuffer* b) override {
31 ++start_decoding_calls_;
32 collector_.Clear();
33 return decoder_.Start(b, &listener_);
34 }
35
ResumeDecoding(DecodeBuffer * b)36 DecodeStatus ResumeDecoding(DecodeBuffer* b) override {
37 // Provides coverage of DebugString and StateToString.
38 // Not validating output.
39 QUICHE_VLOG(1) << decoder_.DebugString();
40 QUICHE_VLOG(2) << collector_;
41 return decoder_.Resume(b, &listener_);
42 }
43
Collected(absl::string_view s,bool huffman_encoded)44 AssertionResult Collected(absl::string_view s, bool huffman_encoded) {
45 QUICHE_VLOG(1) << collector_;
46 return collector_.Collected(s, huffman_encoded);
47 }
48
49 // expected_str is a std::string rather than a const std::string& or
50 // absl::string_view so that the lambda makes a copy of the string, and thus
51 // the string to be passed to Collected outlives the call to MakeValidator.
MakeValidator(const std::string & expected_str,bool expected_huffman)52 Validator MakeValidator(const std::string& expected_str,
53 bool expected_huffman) {
54 return [expected_str, expected_huffman, this](
55 const DecodeBuffer& /*input*/,
56 DecodeStatus /*status*/) -> AssertionResult {
57 AssertionResult result = Collected(expected_str, expected_huffman);
58 if (result) {
59 HTTP2_VERIFY_EQ(collector_,
60 HpackStringCollector(expected_str, expected_huffman));
61 } else {
62 HTTP2_VERIFY_NE(collector_,
63 HpackStringCollector(expected_str, expected_huffman));
64 }
65 QUICHE_VLOG(2) << collector_.ToString();
66 collector_.Clear();
67 QUICHE_VLOG(2) << collector_;
68 return result;
69 };
70 }
71
72 HpackStringDecoder decoder_;
73 HpackStringCollector collector_;
74 HpackStringDecoderVLoggingListener listener_;
75 size_t start_decoding_calls_ = 0;
76 };
77
TEST_F(HpackStringDecoderTest,DecodeEmptyString)78 TEST_F(HpackStringDecoderTest, DecodeEmptyString) {
79 {
80 Validator validator = ValidateDoneAndEmpty(MakeValidator("", kCompressed));
81 const char kData[] = {'\x80'};
82 DecodeBuffer b(kData);
83 EXPECT_TRUE(
84 DecodeAndValidateSeveralWays(&b, kMayReturnZeroOnFirst, validator));
85 }
86 {
87 // Make sure it stops after decoding the empty string.
88 Validator validator =
89 ValidateDoneAndOffset(1, MakeValidator("", kUncompressed));
90 const char kData[] = {'\x00', '\xff'};
91 DecodeBuffer b(kData);
92 EXPECT_EQ(2u, b.Remaining());
93 EXPECT_TRUE(
94 DecodeAndValidateSeveralWays(&b, kMayReturnZeroOnFirst, validator));
95 EXPECT_EQ(1u, b.Remaining());
96 }
97 }
98
TEST_F(HpackStringDecoderTest,DecodeShortString)99 TEST_F(HpackStringDecoderTest, DecodeShortString) {
100 {
101 // Make sure it stops after decoding the non-empty string.
102 Validator validator =
103 ValidateDoneAndOffset(11, MakeValidator("start end.", kCompressed));
104 const char kData[] = "\x8astart end.Don't peek at this.";
105 DecodeBuffer b(kData);
106 EXPECT_TRUE(
107 DecodeAndValidateSeveralWays(&b, kMayReturnZeroOnFirst, validator));
108 }
109 {
110 Validator validator =
111 ValidateDoneAndOffset(11, MakeValidator("start end.", kUncompressed));
112 absl::string_view data("\x0astart end.");
113 DecodeBuffer b(data);
114 EXPECT_TRUE(
115 DecodeAndValidateSeveralWays(&b, kMayReturnZeroOnFirst, validator));
116 }
117 }
118
TEST_F(HpackStringDecoderTest,DecodeLongStrings)119 TEST_F(HpackStringDecoderTest, DecodeLongStrings) {
120 std::string name = Random().RandString(1024);
121 std::string value = Random().RandString(65536);
122 HpackBlockBuilder hbb;
123
124 hbb.AppendString(false, name);
125 uint32_t offset_after_name = hbb.size();
126 EXPECT_EQ(3 + name.size(), offset_after_name);
127
128 hbb.AppendString(true, value);
129 uint32_t offset_after_value = hbb.size();
130 EXPECT_EQ(3 + name.size() + 4 + value.size(), offset_after_value);
131
132 DecodeBuffer b(hbb.buffer());
133
134 // Decode the name...
135 EXPECT_TRUE(DecodeAndValidateSeveralWays(
136 &b, kMayReturnZeroOnFirst,
137 ValidateDoneAndOffset(offset_after_name,
138 MakeValidator(name, kUncompressed))));
139 EXPECT_EQ(offset_after_name, b.Offset());
140 EXPECT_EQ(offset_after_value - offset_after_name, b.Remaining());
141
142 // Decode the value...
143 EXPECT_TRUE(DecodeAndValidateSeveralWays(
144 &b, kMayReturnZeroOnFirst,
145 ValidateDoneAndOffset(offset_after_value - offset_after_name,
146 MakeValidator(value, kCompressed))));
147 EXPECT_EQ(offset_after_value, b.Offset());
148 EXPECT_EQ(0u, b.Remaining());
149 }
150
151 } // namespace
152 } // namespace test
153 } // namespace http2
154