blob: 4ed76ef071faa82734312ac47486f038fd668119 [file] [log] [blame]
Brad Fitzpatrick04061852014-09-16 13:58:00 -07001// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package http2
6
7import (
8 "bytes"
9 "reflect"
10 "testing"
11)
12
13func testFramer() (*Framer, *bytes.Buffer) {
14 buf := new(bytes.Buffer)
15 return NewFramer(buf, buf), buf
16}
17
18func TestWriteRST(t *testing.T) {
19 fr, buf := testFramer()
20 var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
21 var errCode uint32 = 7<<24 + 6<<16 + 5<<8 + 4
22 fr.WriteRSTStream(streamID, errCode)
23 const wantEnc = "\x00\x00\x04\x03\x00\x01\x02\x03\x04\x07\x06\x05\x04"
24 if buf.String() != wantEnc {
25 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
26 }
27 f, err := fr.ReadFrame()
28 if err != nil {
29 t.Fatal(err)
30 }
31 want := &RSTStreamFrame{
32 FrameHeader: FrameHeader{
33 valid: true,
34 Type: 0x3,
35 Flags: 0x0,
36 Length: 0x4,
37 StreamID: 0x1020304,
38 },
39 ErrCode: 0x7060504,
40 }
41 if !reflect.DeepEqual(f, want) {
42 t.Errorf("parsed back %#v; want %#v", f, want)
43 }
44}
45
46func TestWriteData(t *testing.T) {
47 fr, buf := testFramer()
48 var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
49 data := []byte("ABC")
50 fr.WriteData(streamID, true, data)
51 const wantEnc = "\x00\x00\x03\x00\x01\x01\x02\x03\x04ABC"
52 if buf.String() != wantEnc {
53 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
54 }
55 f, err := fr.ReadFrame()
56 if err != nil {
57 t.Fatal(err)
58 }
59 df, ok := f.(*DataFrame)
60 if !ok {
61 t.Fatalf("got %T; want *DataFrame", f)
62 }
63 if !bytes.Equal(df.Data(), data) {
64 t.Errorf("got %q; want %q", df.Data, data)
65 }
66 if f.Header().Flags&1 == 0 {
67 t.Errorf("didn't see END_STREAM flag")
68 }
69}
Brad Fitzpatrick50e23112014-09-17 11:22:56 -070070
71func TestWriteHeaders(t *testing.T) {
72 tests := []struct {
73 name string
74 p HeadersFrameParam
75 wantEnc string
76 wantFrame *HeadersFrame
77 }{
78 {
79 "basic",
80 HeadersFrameParam{
81 StreamID: 42,
82 BlockFragment: []byte("abc"),
83 Priority: PriorityParam{},
84 },
85 "\x00\x00\x03\x01\x00\x00\x00\x00*abc",
86 &HeadersFrame{
87 FrameHeader: FrameHeader{
88 valid: true,
89 StreamID: 42,
90 Type: FrameHeaders,
91 Length: uint32(len("abc")),
92 },
93 Priority: PriorityParam{},
94 headerFragBuf: []byte("abc"),
95 },
96 },
97 {
98 "basic + end flags",
99 HeadersFrameParam{
100 StreamID: 42,
101 BlockFragment: []byte("abc"),
102 EndStream: true,
103 EndHeaders: true,
104 Priority: PriorityParam{},
105 },
106 "\x00\x00\x03\x01\x05\x00\x00\x00*abc",
107 &HeadersFrame{
108 FrameHeader: FrameHeader{
109 valid: true,
110 StreamID: 42,
111 Type: FrameHeaders,
112 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders,
113 Length: uint32(len("abc")),
114 },
115 Priority: PriorityParam{},
116 headerFragBuf: []byte("abc"),
117 },
118 },
119 {
120 "with padding",
121 HeadersFrameParam{
122 StreamID: 42,
123 BlockFragment: []byte("abc"),
124 EndStream: true,
125 EndHeaders: true,
126 PadLength: 5,
127 Priority: PriorityParam{},
128 },
129 "\x00\x00\t\x01\r\x00\x00\x00*\x05abc\x00\x00\x00\x00\x00",
130 &HeadersFrame{
131 FrameHeader: FrameHeader{
132 valid: true,
133 StreamID: 42,
134 Type: FrameHeaders,
135 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded,
136 Length: uint32(1 + len("abc") + 5), // pad length + contents + padding
137 },
138 Priority: PriorityParam{},
139 headerFragBuf: []byte("abc"),
140 },
141 },
142 {
143 "with priority",
144 HeadersFrameParam{
145 StreamID: 42,
146 BlockFragment: []byte("abc"),
147 EndStream: true,
148 EndHeaders: true,
149 PadLength: 2,
150 Priority: PriorityParam{
Brad Fitzpatrick281fedb2014-09-17 12:53:09 -0700151 StreamDep: 15,
152 Exclusive: true,
153 Weight: 127,
Brad Fitzpatrick50e23112014-09-17 11:22:56 -0700154 },
155 },
156 "\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x0f\u007fabc\x00\x00",
157 &HeadersFrame{
158 FrameHeader: FrameHeader{
159 valid: true,
160 StreamID: 42,
161 Type: FrameHeaders,
162 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority,
163 Length: uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding
164 },
165 Priority: PriorityParam{
Brad Fitzpatrick281fedb2014-09-17 12:53:09 -0700166 StreamDep: 15,
167 Exclusive: true,
168 Weight: 127,
Brad Fitzpatrick50e23112014-09-17 11:22:56 -0700169 },
170 headerFragBuf: []byte("abc"),
171 },
172 },
173 }
174 for _, tt := range tests {
175 fr, buf := testFramer()
176 if err := fr.WriteHeaders(tt.p); err != nil {
177 t.Errorf("test %q: %v", tt.name, err)
178 continue
179 }
180 if buf.String() != tt.wantEnc {
181 t.Errorf("test %q: encoded %q; want %q", tt.name, buf.Bytes(), tt.wantEnc)
182 }
183 f, err := fr.ReadFrame()
184 if err != nil {
185 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
186 continue
187 }
188 if !reflect.DeepEqual(f, tt.wantFrame) {
189 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
190 }
191 }
192}
Brad Fitzpatrick28886262014-09-17 11:36:01 -0700193
194func TestWriteContinuation(t *testing.T) {
195 const streamID = 42
196 tests := []struct {
197 name string
198 end bool
199 frag []byte
200
201 wantFrame *ContinuationFrame
202 }{
203 {
204 "not end",
205 false,
206 []byte("abc"),
207 &ContinuationFrame{
208 FrameHeader: FrameHeader{
209 valid: true,
210 StreamID: streamID,
211 Type: FrameContinuation,
212 Length: uint32(len("abc")),
213 },
214 headerFragBuf: []byte("abc"),
215 },
216 },
217 {
218 "end",
219 true,
220 []byte("def"),
221 &ContinuationFrame{
222 FrameHeader: FrameHeader{
223 valid: true,
224 StreamID: streamID,
225 Type: FrameContinuation,
226 Flags: FlagContinuationEndHeaders,
227 Length: uint32(len("def")),
228 },
229 headerFragBuf: []byte("def"),
230 },
231 },
232 }
233 for _, tt := range tests {
234 fr, _ := testFramer()
235 if err := fr.WriteContinuation(streamID, tt.end, tt.frag); err != nil {
236 t.Errorf("test %q: %v", tt.name, err)
237 continue
238 }
239 f, err := fr.ReadFrame()
240 if err != nil {
241 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
242 continue
243 }
244 if !reflect.DeepEqual(f, tt.wantFrame) {
245 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
246 }
247 }
248}
Brad Fitzpatrick281fedb2014-09-17 12:53:09 -0700249
250func TestWritePriority(t *testing.T) {
251 const streamID = 42
252 tests := []struct {
253 name string
254 priority PriorityParam
255 wantFrame *PriorityFrame
256 }{
257 {
258 "not exclusive",
259 PriorityParam{
260 StreamDep: 2,
261 Exclusive: false,
262 Weight: 127,
263 },
264 &PriorityFrame{
265 FrameHeader{
266 valid: true,
267 StreamID: streamID,
268 Type: FramePriority,
269 Length: 5,
270 },
271 PriorityParam{
272 StreamDep: 2,
273 Exclusive: false,
274 Weight: 127,
275 },
276 },
277 },
278
279 {
280 "exclusive",
281 PriorityParam{
282 StreamDep: 3,
283 Exclusive: true,
284 Weight: 77,
285 },
286 &PriorityFrame{
287 FrameHeader{
288 valid: true,
289 StreamID: streamID,
290 Type: FramePriority,
291 Length: 5,
292 },
293 PriorityParam{
294 StreamDep: 3,
295 Exclusive: true,
296 Weight: 77,
297 },
298 },
299 },
300 }
301 for _, tt := range tests {
302 fr, _ := testFramer()
303 if err := fr.WritePriority(streamID, tt.priority); err != nil {
304 t.Errorf("test %q: %v", tt.name, err)
305 continue
306 }
307 f, err := fr.ReadFrame()
308 if err != nil {
309 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
310 continue
311 }
312 if !reflect.DeepEqual(f, tt.wantFrame) {
313 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
314 }
315 }
316}
Brad Fitzpatrick0a81e452014-09-17 13:32:15 -0700317
318func TestWriteSettings(t *testing.T) {
319 fr, buf := testFramer()
Brad Fitzpatrick2f1cccd2014-10-22 15:50:07 -0700320 settings := []Setting{{1, 2}, {3, 4}}
321 fr.WriteSettings(settings...)
Brad Fitzpatrick0a81e452014-09-17 13:32:15 -0700322 const wantEnc = "\x00\x00\f\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00\x04"
323 if buf.String() != wantEnc {
324 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
325 }
Brad Fitzpatrick2f1cccd2014-10-22 15:50:07 -0700326 f, err := fr.ReadFrame()
327 if err != nil {
328 t.Fatal(err)
329 }
330 sf, ok := f.(*SettingsFrame)
331 if !ok {
332 t.Fatalf("Got a %T; want a SettingsFrame", f)
333 }
334 var got []Setting
Brad Fitzpatrick03abeab2014-11-11 11:55:55 -0800335 sf.ForeachSetting(func(s Setting) error {
Brad Fitzpatrick2f1cccd2014-10-22 15:50:07 -0700336 got = append(got, s)
337 valBack, ok := sf.Value(s.ID)
338 if !ok || valBack != s.Val {
Brad Fitzpatrick15521312014-10-22 15:59:06 -0700339 t.Errorf("Value(%d) = %v, %v; want %v, true", s.ID, valBack, ok)
Brad Fitzpatrick2f1cccd2014-10-22 15:50:07 -0700340 }
Brad Fitzpatrick03abeab2014-11-11 11:55:55 -0800341 return nil
Brad Fitzpatrick2f1cccd2014-10-22 15:50:07 -0700342 })
343 if !reflect.DeepEqual(settings, got) {
344 t.Errorf("Read settings %+v != written settings %+v", got, settings)
345 }
Brad Fitzpatrick0a81e452014-09-17 13:32:15 -0700346}
347
348func TestWriteSettingsAck(t *testing.T) {
349 fr, buf := testFramer()
350 fr.WriteSettingsAck()
351 const wantEnc = "\x00\x00\x00\x04\x01\x00\x00\x00\x00"
352 if buf.String() != wantEnc {
353 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
354 }
355}
Brad Fitzpatrick111670c2014-10-19 15:23:35 +0200356
357func TestWriteWindowUpdate(t *testing.T) {
358 fr, buf := testFramer()
359 const streamID = 1<<24 + 2<<16 + 3<<8 + 4
360 const incr = 7<<24 + 6<<16 + 5<<8 + 4
361 if err := fr.WriteWindowUpdate(streamID, incr); err != nil {
362 t.Fatal(err)
363 }
364 const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04"
365 if buf.String() != wantEnc {
366 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
367 }
368 f, err := fr.ReadFrame()
369 if err != nil {
370 t.Fatal(err)
371 }
372 want := &WindowUpdateFrame{
373 FrameHeader: FrameHeader{
374 valid: true,
375 Type: 0x8,
376 Flags: 0x0,
377 Length: 0x4,
378 StreamID: 0x1020304,
379 },
380 Increment: 0x7060504,
381 }
382 if !reflect.DeepEqual(f, want) {
383 t.Errorf("parsed back %#v; want %#v", f, want)
384 }
385}
Brad Fitzpatricke3541932014-10-24 08:37:30 -0700386
Brad Fitzpatrick2e5b5042014-11-11 08:43:16 -0800387func TestWritePing(t *testing.T) { testWritePing(t, false) }
388func TestWritePingAck(t *testing.T) { testWritePing(t, true) }
389
390func testWritePing(t *testing.T, ack bool) {
391 fr, buf := testFramer()
392 if err := fr.WritePing(ack, [8]byte{1, 2, 3, 4, 5, 6, 7, 8}); err != nil {
393 t.Fatal(err)
394 }
395 var wantFlags Flags
396 if ack {
397 wantFlags = FlagPingAck
398 }
399 var wantEnc = "\x00\x00\x08\x06" + string(wantFlags) + "\x00\x00\x00\x00" + "\x01\x02\x03\x04\x05\x06\x07\x08"
400 if buf.String() != wantEnc {
401 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
402 }
403
404 f, err := fr.ReadFrame()
405 if err != nil {
406 t.Fatal(err)
407 }
408 want := &PingFrame{
409 FrameHeader: FrameHeader{
410 valid: true,
411 Type: 0x6,
412 Flags: wantFlags,
413 Length: 0x8,
414 StreamID: 0,
415 },
416 Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
417 }
418 if !reflect.DeepEqual(f, want) {
419 t.Errorf("parsed back %#v; want %#v", f, want)
420 }
421}
422
Brad Fitzpatricke3541932014-10-24 08:37:30 -0700423func TestReadFrameHeader(t *testing.T) {
424 tests := []struct {
425 len uint32
426 typ FrameType
427 flags Flags
428 streamID uint32
429 }{
430 {len: 0, typ: 255, flags: 1, streamID: 0},
431 {len: 0, typ: 255, flags: 1, streamID: 1},
432 {len: 0, typ: 255, flags: 1, streamID: 255},
433 {len: 0, typ: 255, flags: 1, streamID: 256},
434 {len: 0, typ: 255, flags: 1, streamID: 65535},
435 {len: 0, typ: 255, flags: 1, streamID: 65536},
436
437 {len: 0, typ: 1, flags: 255, streamID: 1},
438 {len: 255, typ: 1, flags: 255, streamID: 1},
439 {len: 256, typ: 1, flags: 255, streamID: 1},
440 {len: 65535, typ: 1, flags: 255, streamID: 1},
441 {len: 65536, typ: 1, flags: 255, streamID: 1},
442 {len: 16777215, typ: 1, flags: 255, streamID: 1},
443 }
444 for _, tt := range tests {
445 fr, buf := testFramer()
446 fr.startWrite(tt.typ, tt.flags, tt.streamID)
447 fr.writeBytes(make([]byte, tt.len))
448 fr.endWrite()
449 fh, err := ReadFrameHeader(buf)
450 if err != nil {
451 t.Errorf("ReadFrameHeader(%+v) = %v", tt, err)
452 continue
453 }
454 if fh.Type != tt.typ || fh.Flags != tt.flags || fh.Length != tt.len || fh.StreamID != tt.streamID {
455 t.Errorf("ReadFrameHeader(%+v) = %+v; mismatch", tt, fh)
456 }
457 }
458
459}
460
461func TestWriteTooLargeFrame(t *testing.T) {
462 fr, _ := testFramer()
463 fr.startWrite(0, 1, 1)
464 fr.writeBytes(make([]byte, 1<<24))
465 err := fr.endWrite()
466 if err != errFrameTooLarge {
467 t.Errorf("endWrite = %v; want errFrameTooLarge", err)
468 }
469}
Brad Fitzpatrick7eaffb42014-11-11 11:54:29 -0800470
471func TestWriteGoAway(t *testing.T) {
472 const debug = "foo"
473 fr, buf := testFramer()
474 if err := fr.WriteGoAway(0x01020304, 0x05060708, []byte(debug)); err != nil {
475 t.Fatal(err)
476 }
477 const wantEnc = "\x00\x00\v\a\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + debug
478 if buf.String() != wantEnc {
479 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
480 }
481 f, err := fr.ReadFrame()
482 if err != nil {
483 t.Fatal(err)
484 }
485 want := &GoAwayFrame{
486 FrameHeader: FrameHeader{
487 valid: true,
488 Type: 0x7,
489 Flags: 0,
490 Length: uint32(4 + 4 + len(debug)),
491 StreamID: 0,
492 },
493 LastStreamID: 0x01020304,
494 ErrCode: 0x05060708,
495 debugData: []byte(debug),
496 }
497 if !reflect.DeepEqual(f, want) {
498 t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
499 }
500 if got := string(f.(*GoAwayFrame).DebugData()); got != debug {
501 t.Errorf("debug data = %q; want %q", got, debug)
502 }
503}