1
2
3
4
5 package http3
6
7 import (
8 "reflect"
9 "strings"
10 "testing"
11 )
12
13 func TestQPACKDecode(t *testing.T) {
14 type header struct {
15 itype indexType
16 name, value string
17 }
18
19
20 for _, test := range []struct {
21 name string
22 enc []byte
23 want []header
24 }{{
25 name: "empty",
26 enc: unhex("0000"),
27 want: []header{},
28 }, {
29 name: "literal entry empty value",
30 enc: unhex("000023666f6f00"),
31 want: []header{
32 {mayIndex, "foo", ""},
33 },
34 }, {
35 name: "simple literal entry",
36 enc: unhex("000023666f6f03626172"),
37 want: []header{
38 {mayIndex, "foo", "bar"},
39 },
40 }, {
41 name: "multiple literal entries",
42 enc: unhex("0000" +
43
44 "23666f6f03626172" +
45
46
47 "2700666f6f62616172" +
48
49
50 "7f00616161616161616161616161616161616161616161616161616161616161616161" +
51 "6161616161616161616161616161616161616161616161616161616161616161616161" +
52 "6161616161616161616161616161616161616161616161616161616161616161616161" +
53 "616161616161616161616161616161616161616161616161",
54 ),
55 want: []header{
56 {mayIndex, "foo", "bar"},
57 {mayIndex, "foobaar", strings.Repeat("a", 127)},
58 },
59 }, {
60 name: "line feed in value",
61 enc: unhex("000023666f6f0462610a72"),
62 want: []header{
63 {mayIndex, "foo", "ba\nr"},
64 },
65 }, {
66 name: "huffman simple",
67 enc: unhex("00002f0125a849e95ba97d7f8925a849e95bb8e8b4bf"),
68 want: []header{
69 {mayIndex, "custom-key", "custom-value"},
70 },
71 }, {
72 name: "alternating huffman nonhuffman",
73 enc: unhex("0000" +
74 "2f0125a849e95ba97d7f" +
75 "8925a849e95bb8e8b4bf" +
76 "2703637573746f6d2d6b6579" +
77 "0c637573746f6d2d76616c7565" +
78 "2f0125a849e95ba97d7f" +
79 "0c637573746f6d2d76616c7565" +
80 "2703637573746f6d2d6b6579" +
81 "8925a849e95bb8e8b4bf",
82 ),
83 want: []header{
84 {mayIndex, "custom-key", "custom-value"},
85 {mayIndex, "custom-key", "custom-value"},
86 {mayIndex, "custom-key", "custom-value"},
87 {mayIndex, "custom-key", "custom-value"},
88 },
89 }, {
90 name: "static table",
91 enc: unhex("0000d1d45f00055452414345dfcc5f108621e9aec2a11f5c8294e75f1000"),
92 want: []header{
93 {mayIndex, ":method", "GET"},
94 {mayIndex, ":method", "POST"},
95 {mayIndex, ":method", "TRACE"},
96 {mayIndex, "accept-encoding", "gzip, deflate, br"},
97 {mayIndex, "location", ""},
98 {mayIndex, "accept-encoding", "compress"},
99 {mayIndex, "location", "foo"},
100 {mayIndex, "accept-encoding", ""},
101 },
102 }} {
103 synctestSubtest(t, test.name, func(t *testing.T) {
104 st1, st2 := newStreamPair(t)
105 st1.Write(test.enc)
106 st1.Flush()
107
108 st2.lim = int64(len(test.enc))
109
110 var dec qpackDecoder
111 got := []header{}
112 err := dec.decode(st2, func(itype indexType, name, value string) error {
113 got = append(got, header{itype, name, value})
114 return nil
115 })
116 if err != nil {
117 t.Fatalf("decode: %v", err)
118 }
119 if !reflect.DeepEqual(got, test.want) {
120 t.Errorf("encoded: %x", test.enc)
121 t.Errorf("got headers:")
122 for _, h := range got {
123 t.Errorf(" %v: %q", h.name, h.value)
124 }
125 t.Errorf("want headers:")
126 for _, h := range test.want {
127 t.Errorf(" %v: %q", h.name, h.value)
128 }
129 }
130 })
131 }
132 }
133
134 func TestQPACKDecodeErrors(t *testing.T) {
135
136
137 for _, test := range []struct {
138 name string
139 enc []byte
140 }{{
141 name: "literal entry empty name",
142 enc: unhex("00002003666f6f"),
143 }, {
144 name: "literal entry empty name and value",
145 enc: unhex("00002000"),
146 }, {
147 name: "name length too large for varint",
148 enc: unhex("000027ffffffffffffffffffff"),
149 }, {
150 name: "string literal too long",
151 enc: unhex("000027ffff7f"),
152 }, {
153 name: "value length too large for varint",
154 enc: unhex("000023666f6f7fffffffffffffffffffff"),
155 }, {
156 name: "value length too long",
157 enc: unhex("000023666f6f7fffff7f"),
158 }, {
159 name: "incomplete header block",
160 enc: unhex("00002366"),
161 }, {
162 name: "huffman name does not have eos prefix",
163 enc: unhex("00002f0125a849e95ba97d7e8925a849e95bb8e8b4bf"),
164 }, {
165 name: "huffman value does not have eos prefix",
166 enc: unhex("00002f0125a849e95ba97d7f8925a849e95bb8e8b4be"),
167 }, {
168 name: "huffman name eos prefix too long",
169 enc: unhex("00002f0225a849e95ba97d7fff8925a849e95bb8e8b4bf"),
170 }, {
171 name: "huffman value eos prefix too long",
172 enc: unhex("00002f0125a849e95ba97d7f8a25a849e95bb8e8b4bfff"),
173 }, {
174 name: "too high static table index",
175 enc: unhex("0000ff23ff24"),
176 }, {
177 name: "prefixed string length overflow",
178 enc: unhex("000027ffffffffffffffff7f"),
179 }, {
180 name: "prefixed static index overflow",
181 enc: unhex("0000ffffffffffffffffff7f"),
182 }} {
183 synctestSubtest(t, test.name, func(t *testing.T) {
184 st1, st2 := newStreamPair(t)
185 st1.Write(test.enc)
186 st1.Flush()
187
188 st2.lim = int64(len(test.enc))
189
190 var dec qpackDecoder
191 err := dec.decode(st2, func(itype indexType, name, value string) error {
192 return nil
193 })
194 if err == nil {
195 t.Errorf("encoded: %x", test.enc)
196 t.Fatalf("decode succeeded; want error")
197 }
198 })
199 }
200 }
201
View as plain text