1
2
3
4
5 package http2
6
7 import (
8 "bytes"
9 "fmt"
10 "io"
11 "reflect"
12 "strings"
13 "testing"
14 "unsafe"
15
16 "golang.org/x/net/http2/hpack"
17 )
18
19 func testFramer() (*Framer, *bytes.Buffer) {
20 buf := new(bytes.Buffer)
21 return NewFramer(buf, buf), buf
22 }
23
24 func TestFrameSizes(t *testing.T) {
25
26 if got, want := int(unsafe.Sizeof(FrameHeader{})), 12; got != want {
27 t.Errorf("FrameHeader size = %d; want %d", got, want)
28 }
29 }
30
31 func TestFrameTypeString(t *testing.T) {
32 tests := []struct {
33 ft FrameType
34 want string
35 }{
36 {FrameData, "DATA"},
37 {FramePing, "PING"},
38 {FrameGoAway, "GOAWAY"},
39 {0x20, "UNKNOWN_FRAME_TYPE_32"},
40 }
41
42 for i, tt := range tests {
43 got := tt.ft.String()
44 if got != tt.want {
45 t.Errorf("%d. String(FrameType %d) = %q; want %q", i, int(tt.ft), got, tt.want)
46 }
47 }
48 }
49
50 func TestWriteRST(t *testing.T) {
51 fr, buf := testFramer()
52 var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
53 var errCode uint32 = 7<<24 + 6<<16 + 5<<8 + 4
54 fr.WriteRSTStream(streamID, ErrCode(errCode))
55 const wantEnc = "\x00\x00\x04\x03\x00\x01\x02\x03\x04\x07\x06\x05\x04"
56 if buf.String() != wantEnc {
57 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
58 }
59 f, err := fr.ReadFrame()
60 if err != nil {
61 t.Fatal(err)
62 }
63 want := &RSTStreamFrame{
64 FrameHeader: FrameHeader{
65 valid: true,
66 Type: 0x3,
67 Flags: 0x0,
68 Length: 0x4,
69 StreamID: 0x1020304,
70 },
71 ErrCode: 0x7060504,
72 }
73 if !reflect.DeepEqual(f, want) {
74 t.Errorf("parsed back %#v; want %#v", f, want)
75 }
76 }
77
78 func TestWriteData(t *testing.T) {
79 fr, buf := testFramer()
80 var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
81 data := []byte("ABC")
82 fr.WriteData(streamID, true, data)
83 const wantEnc = "\x00\x00\x03\x00\x01\x01\x02\x03\x04ABC"
84 if buf.String() != wantEnc {
85 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
86 }
87 f, err := fr.ReadFrame()
88 if err != nil {
89 t.Fatal(err)
90 }
91 df, ok := f.(*DataFrame)
92 if !ok {
93 t.Fatalf("got %T; want *DataFrame", f)
94 }
95 if !bytes.Equal(df.Data(), data) {
96 t.Errorf("got %q; want %q", df.Data(), data)
97 }
98 if f.Header().Flags&1 == 0 {
99 t.Errorf("didn't see END_STREAM flag")
100 }
101 }
102
103 func TestWriteDataPadded(t *testing.T) {
104 tests := [...]struct {
105 streamID uint32
106 endStream bool
107 data []byte
108 pad []byte
109 wantHeader FrameHeader
110 }{
111
112 0: {
113 streamID: 1,
114 endStream: true,
115 data: []byte("foo"),
116 pad: nil,
117 wantHeader: FrameHeader{
118 Type: FrameData,
119 Flags: FlagDataEndStream,
120 Length: 3,
121 StreamID: 1,
122 },
123 },
124
125
126 1: {
127 streamID: 1,
128 endStream: true,
129 data: []byte("foo"),
130 pad: []byte{},
131 wantHeader: FrameHeader{
132 Type: FrameData,
133 Flags: FlagDataEndStream | FlagDataPadded,
134 Length: 4,
135 StreamID: 1,
136 },
137 },
138
139
140 2: {
141 streamID: 1,
142 endStream: false,
143 data: []byte("foo"),
144 pad: []byte{0, 0, 0},
145 wantHeader: FrameHeader{
146 Type: FrameData,
147 Flags: FlagDataPadded,
148 Length: 7,
149 StreamID: 1,
150 },
151 },
152 }
153 for i, tt := range tests {
154 fr, _ := testFramer()
155 fr.WriteDataPadded(tt.streamID, tt.endStream, tt.data, tt.pad)
156 f, err := fr.ReadFrame()
157 if err != nil {
158 t.Errorf("%d. ReadFrame: %v", i, err)
159 continue
160 }
161 got := f.Header()
162 tt.wantHeader.valid = true
163 if !got.Equal(tt.wantHeader) {
164 t.Errorf("%d. read %+v; want %+v", i, got, tt.wantHeader)
165 continue
166 }
167 df := f.(*DataFrame)
168 if !bytes.Equal(df.Data(), tt.data) {
169 t.Errorf("%d. got %q; want %q", i, df.Data(), tt.data)
170 }
171 }
172 }
173
174 func (fh FrameHeader) Equal(b FrameHeader) bool {
175 return fh.valid == b.valid &&
176 fh.Type == b.Type &&
177 fh.Flags == b.Flags &&
178 fh.Length == b.Length &&
179 fh.StreamID == b.StreamID
180 }
181
182 func TestWriteHeaders(t *testing.T) {
183 tests := []struct {
184 name string
185 p HeadersFrameParam
186 wantEnc string
187 wantFrame *HeadersFrame
188 }{
189 {
190 "basic",
191 HeadersFrameParam{
192 StreamID: 42,
193 BlockFragment: []byte("abc"),
194 Priority: PriorityParam{},
195 },
196 "\x00\x00\x03\x01\x00\x00\x00\x00*abc",
197 &HeadersFrame{
198 FrameHeader: FrameHeader{
199 valid: true,
200 StreamID: 42,
201 Type: FrameHeaders,
202 Length: uint32(len("abc")),
203 },
204 Priority: PriorityParam{},
205 headerFragBuf: []byte("abc"),
206 },
207 },
208 {
209 "basic + end flags",
210 HeadersFrameParam{
211 StreamID: 42,
212 BlockFragment: []byte("abc"),
213 EndStream: true,
214 EndHeaders: true,
215 Priority: PriorityParam{},
216 },
217 "\x00\x00\x03\x01\x05\x00\x00\x00*abc",
218 &HeadersFrame{
219 FrameHeader: FrameHeader{
220 valid: true,
221 StreamID: 42,
222 Type: FrameHeaders,
223 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders,
224 Length: uint32(len("abc")),
225 },
226 Priority: PriorityParam{},
227 headerFragBuf: []byte("abc"),
228 },
229 },
230 {
231 "with padding",
232 HeadersFrameParam{
233 StreamID: 42,
234 BlockFragment: []byte("abc"),
235 EndStream: true,
236 EndHeaders: true,
237 PadLength: 5,
238 Priority: PriorityParam{},
239 },
240 "\x00\x00\t\x01\r\x00\x00\x00*\x05abc\x00\x00\x00\x00\x00",
241 &HeadersFrame{
242 FrameHeader: FrameHeader{
243 valid: true,
244 StreamID: 42,
245 Type: FrameHeaders,
246 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded,
247 Length: uint32(1 + len("abc") + 5),
248 },
249 Priority: PriorityParam{},
250 headerFragBuf: []byte("abc"),
251 },
252 },
253 {
254 "with priority",
255 HeadersFrameParam{
256 StreamID: 42,
257 BlockFragment: []byte("abc"),
258 EndStream: true,
259 EndHeaders: true,
260 PadLength: 2,
261 Priority: PriorityParam{
262 StreamDep: 15,
263 Exclusive: true,
264 Weight: 127,
265 },
266 },
267 "\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x0f\u007fabc\x00\x00",
268 &HeadersFrame{
269 FrameHeader: FrameHeader{
270 valid: true,
271 StreamID: 42,
272 Type: FrameHeaders,
273 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority,
274 Length: uint32(1 + 5 + len("abc") + 2),
275 },
276 Priority: PriorityParam{
277 StreamDep: 15,
278 Exclusive: true,
279 Weight: 127,
280 },
281 headerFragBuf: []byte("abc"),
282 },
283 },
284 {
285 "with priority stream dep zero",
286 HeadersFrameParam{
287 StreamID: 42,
288 BlockFragment: []byte("abc"),
289 EndStream: true,
290 EndHeaders: true,
291 PadLength: 2,
292 Priority: PriorityParam{
293 StreamDep: 0,
294 Exclusive: true,
295 Weight: 127,
296 },
297 },
298 "\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x00\u007fabc\x00\x00",
299 &HeadersFrame{
300 FrameHeader: FrameHeader{
301 valid: true,
302 StreamID: 42,
303 Type: FrameHeaders,
304 Flags: FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority,
305 Length: uint32(1 + 5 + len("abc") + 2),
306 },
307 Priority: PriorityParam{
308 StreamDep: 0,
309 Exclusive: true,
310 Weight: 127,
311 },
312 headerFragBuf: []byte("abc"),
313 },
314 },
315 {
316 "zero length",
317 HeadersFrameParam{
318 StreamID: 42,
319 Priority: PriorityParam{},
320 },
321 "\x00\x00\x00\x01\x00\x00\x00\x00*",
322 &HeadersFrame{
323 FrameHeader: FrameHeader{
324 valid: true,
325 StreamID: 42,
326 Type: FrameHeaders,
327 Length: 0,
328 },
329 Priority: PriorityParam{},
330 },
331 },
332 }
333 for _, tt := range tests {
334 fr, buf := testFramer()
335 if err := fr.WriteHeaders(tt.p); err != nil {
336 t.Errorf("test %q: %v", tt.name, err)
337 continue
338 }
339 if buf.String() != tt.wantEnc {
340 t.Errorf("test %q: encoded %q; want %q", tt.name, buf.Bytes(), tt.wantEnc)
341 }
342 f, err := fr.ReadFrame()
343 if err != nil {
344 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
345 continue
346 }
347 if !reflect.DeepEqual(f, tt.wantFrame) {
348 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
349 }
350 }
351 }
352
353 func TestWriteInvalidStreamDep(t *testing.T) {
354 fr, _ := testFramer()
355 err := fr.WriteHeaders(HeadersFrameParam{
356 StreamID: 42,
357 Priority: PriorityParam{
358 StreamDep: 1 << 31,
359 },
360 })
361 if err != errDepStreamID {
362 t.Errorf("header error = %v; want %q", err, errDepStreamID)
363 }
364
365 err = fr.WritePriority(2, PriorityParam{StreamDep: 1 << 31})
366 if err != errDepStreamID {
367 t.Errorf("priority error = %v; want %q", err, errDepStreamID)
368 }
369 }
370
371 func TestWriteContinuation(t *testing.T) {
372 const streamID = 42
373 tests := []struct {
374 name string
375 end bool
376 frag []byte
377
378 wantFrame *ContinuationFrame
379 }{
380 {
381 "not end",
382 false,
383 []byte("abc"),
384 &ContinuationFrame{
385 FrameHeader: FrameHeader{
386 valid: true,
387 StreamID: streamID,
388 Type: FrameContinuation,
389 Length: uint32(len("abc")),
390 },
391 headerFragBuf: []byte("abc"),
392 },
393 },
394 {
395 "end",
396 true,
397 []byte("def"),
398 &ContinuationFrame{
399 FrameHeader: FrameHeader{
400 valid: true,
401 StreamID: streamID,
402 Type: FrameContinuation,
403 Flags: FlagContinuationEndHeaders,
404 Length: uint32(len("def")),
405 },
406 headerFragBuf: []byte("def"),
407 },
408 },
409 }
410 for _, tt := range tests {
411 fr, _ := testFramer()
412 if err := fr.WriteContinuation(streamID, tt.end, tt.frag); err != nil {
413 t.Errorf("test %q: %v", tt.name, err)
414 continue
415 }
416 fr.AllowIllegalReads = true
417 f, err := fr.ReadFrame()
418 if err != nil {
419 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
420 continue
421 }
422 if !reflect.DeepEqual(f, tt.wantFrame) {
423 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
424 }
425 }
426 }
427
428 func TestParseRFC9218Priority(t *testing.T) {
429 tests := []struct {
430 name string
431 priorityStr string
432 want PriorityParam
433 wantOk bool
434 }{
435 {
436 name: "with urgency",
437 priorityStr: "u=0",
438 want: PriorityParam{
439 urgency: 0,
440 incremental: 0,
441 },
442 wantOk: true,
443 },
444 {
445 name: "with implicit incremental",
446 priorityStr: "i",
447 want: PriorityParam{
448 urgency: 3,
449 incremental: 1,
450 },
451 wantOk: true,
452 },
453 {
454 name: "with explicit incremental",
455 priorityStr: "i=?1",
456 want: PriorityParam{
457 urgency: 3,
458 incremental: 1,
459 },
460 wantOk: true,
461 },
462 {
463 name: "with urgency and incremental",
464 priorityStr: "i=?0, u=4",
465 want: PriorityParam{
466 urgency: 4,
467 incremental: 0,
468 },
469 wantOk: true,
470 },
471 {
472 name: "with other valid dictionary data",
473 priorityStr: "some=data;someparam;u=fake, u=1;foo, i;bar",
474 want: PriorityParam{
475 urgency: 1,
476 incremental: 1,
477 },
478 wantOk: true,
479 },
480 {
481 name: "repeated field",
482 priorityStr: "u=1,i,u=5,i=?0",
483 want: PriorityParam{
484 urgency: 5,
485 incremental: 0,
486 },
487 wantOk: true,
488 },
489 {
490 name: "wrong field type",
491 priorityStr: `u="urgency will be ignored", i`,
492 want: PriorityParam{
493 urgency: 3,
494 incremental: 1,
495 },
496 wantOk: true,
497 },
498 {
499 name: "invalid dictionary",
500 priorityStr: `u=1,i, but this is not a valid dictionary"`,
501 want: defaultRFC9218Priority(true),
502 },
503 {
504 name: "out of range value",
505 priorityStr: "u=8",
506 want: defaultRFC9218Priority(true),
507 wantOk: true,
508 },
509 }
510 for _, tt := range tests {
511 got, gotOk := parseRFC9218Priority(tt.priorityStr, true)
512 if gotOk != tt.wantOk {
513 t.Errorf("test %q: mismatch.\n got ok: %#v\nwant ok: %#v\n", tt.name, got, tt.want)
514 }
515 if got != tt.want {
516 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, got, tt.want)
517 }
518 }
519 }
520
521 func TestWritePriority(t *testing.T) {
522 const streamID = 42
523 tests := []struct {
524 name string
525 priority PriorityParam
526 wantFrame *PriorityFrame
527 }{
528 {
529 "not exclusive",
530 PriorityParam{
531 StreamDep: 2,
532 Exclusive: false,
533 Weight: 127,
534 },
535 &PriorityFrame{
536 FrameHeader{
537 valid: true,
538 StreamID: streamID,
539 Type: FramePriority,
540 Length: 5,
541 },
542 PriorityParam{
543 StreamDep: 2,
544 Exclusive: false,
545 Weight: 127,
546 },
547 },
548 },
549
550 {
551 "exclusive",
552 PriorityParam{
553 StreamDep: 3,
554 Exclusive: true,
555 Weight: 77,
556 },
557 &PriorityFrame{
558 FrameHeader{
559 valid: true,
560 StreamID: streamID,
561 Type: FramePriority,
562 Length: 5,
563 },
564 PriorityParam{
565 StreamDep: 3,
566 Exclusive: true,
567 Weight: 77,
568 },
569 },
570 },
571 }
572 for _, tt := range tests {
573 fr, _ := testFramer()
574 if err := fr.WritePriority(streamID, tt.priority); err != nil {
575 t.Errorf("test %q: %v", tt.name, err)
576 continue
577 }
578 f, err := fr.ReadFrame()
579 if err != nil {
580 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
581 continue
582 }
583 if !reflect.DeepEqual(f, tt.wantFrame) {
584 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
585 }
586 }
587 }
588
589 func TestWritePriorityUpdate(t *testing.T) {
590 const streamID = 42
591 tests := []struct {
592 name string
593 priority string
594 wantFrame *PriorityUpdateFrame
595 }{
596 {
597 name: "with urgency",
598 priority: "u=0",
599 wantFrame: &PriorityUpdateFrame{
600 FrameHeader: FrameHeader{
601 valid: true,
602 StreamID: 0,
603 Type: FramePriorityUpdate,
604 Length: 7,
605 },
606 Priority: "u=0",
607 PrioritizedStreamID: streamID,
608 },
609 },
610 {
611 name: "with incremental",
612 priority: "i",
613 wantFrame: &PriorityUpdateFrame{
614 FrameHeader: FrameHeader{
615 valid: true,
616 StreamID: 0,
617 Type: FramePriorityUpdate,
618 Length: 5,
619 },
620 Priority: "i",
621 PrioritizedStreamID: streamID,
622 },
623 },
624 {
625 name: "with urgency and incremental",
626 priority: "u=7,i",
627 wantFrame: &PriorityUpdateFrame{
628 FrameHeader: FrameHeader{
629 valid: true,
630 StreamID: 0,
631 Type: FramePriorityUpdate,
632 Length: 9,
633 },
634 Priority: "u=7,i",
635 PrioritizedStreamID: streamID,
636 },
637 },
638 {
639 name: "with other fields",
640 priority: "a=123,u=7,i,b;a;b",
641 wantFrame: &PriorityUpdateFrame{
642 FrameHeader: FrameHeader{
643 valid: true,
644 StreamID: 0,
645 Type: FramePriorityUpdate,
646 Length: 21,
647 },
648 Priority: "a=123,u=7,i,b;a;b",
649 PrioritizedStreamID: streamID,
650 },
651 },
652 {
653 name: "with string escapes",
654 priority: "u=\"invalid\" , i",
655 wantFrame: &PriorityUpdateFrame{
656 FrameHeader: FrameHeader{
657 valid: true,
658 StreamID: 0,
659 Type: FramePriorityUpdate,
660 Length: 19,
661 },
662 Priority: "u=\"invalid\" , i",
663 PrioritizedStreamID: streamID,
664 },
665 },
666 {
667 name: "with empty payload",
668 priority: "",
669 wantFrame: &PriorityUpdateFrame{
670 FrameHeader: FrameHeader{
671 valid: true,
672 StreamID: 0,
673 Type: FramePriorityUpdate,
674 Length: 4,
675 },
676 Priority: "",
677 PrioritizedStreamID: streamID,
678 },
679 },
680 }
681 for _, tt := range tests {
682 fr, _ := testFramer()
683 if err := fr.WritePriorityUpdate(streamID, tt.priority); err != nil {
684 t.Errorf("test %q: %v", tt.name, err)
685 continue
686 }
687 f, err := fr.ReadFrame()
688 if err != nil {
689 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
690 continue
691 }
692 if !reflect.DeepEqual(f, tt.wantFrame) {
693 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
694 }
695 }
696 }
697
698 func TestWriteSettings(t *testing.T) {
699 fr, buf := testFramer()
700 settings := []Setting{{1, 2}, {3, 4}}
701 fr.WriteSettings(settings...)
702 const wantEnc = "\x00\x00\f\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00\x04"
703 if buf.String() != wantEnc {
704 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
705 }
706 f, err := fr.ReadFrame()
707 if err != nil {
708 t.Fatal(err)
709 }
710 sf, ok := f.(*SettingsFrame)
711 if !ok {
712 t.Fatalf("Got a %T; want a SettingsFrame", f)
713 }
714 var got []Setting
715 sf.ForeachSetting(func(s Setting) error {
716 got = append(got, s)
717 valBack, ok := sf.Value(s.ID)
718 if !ok || valBack != s.Val {
719 t.Errorf("Value(%d) = %v, %v; want %v, true", s.ID, valBack, ok, s.Val)
720 }
721 return nil
722 })
723 if !reflect.DeepEqual(settings, got) {
724 t.Errorf("Read settings %+v != written settings %+v", got, settings)
725 }
726 }
727
728 func TestWriteSettingsAck(t *testing.T) {
729 fr, buf := testFramer()
730 fr.WriteSettingsAck()
731 const wantEnc = "\x00\x00\x00\x04\x01\x00\x00\x00\x00"
732 if buf.String() != wantEnc {
733 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
734 }
735 }
736
737 func TestWriteWindowUpdate(t *testing.T) {
738 fr, buf := testFramer()
739 const streamID = 1<<24 + 2<<16 + 3<<8 + 4
740 const incr = 7<<24 + 6<<16 + 5<<8 + 4
741 if err := fr.WriteWindowUpdate(streamID, incr); err != nil {
742 t.Fatal(err)
743 }
744 const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04"
745 if buf.String() != wantEnc {
746 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
747 }
748 f, err := fr.ReadFrame()
749 if err != nil {
750 t.Fatal(err)
751 }
752 want := &WindowUpdateFrame{
753 FrameHeader: FrameHeader{
754 valid: true,
755 Type: 0x8,
756 Flags: 0x0,
757 Length: 0x4,
758 StreamID: 0x1020304,
759 },
760 Increment: 0x7060504,
761 }
762 if !reflect.DeepEqual(f, want) {
763 t.Errorf("parsed back %#v; want %#v", f, want)
764 }
765 }
766
767 func TestWritePing(t *testing.T) { testWritePing(t, false) }
768 func TestWritePingAck(t *testing.T) { testWritePing(t, true) }
769
770 func testWritePing(t *testing.T, ack bool) {
771 fr, buf := testFramer()
772 if err := fr.WritePing(ack, [8]byte{1, 2, 3, 4, 5, 6, 7, 8}); err != nil {
773 t.Fatal(err)
774 }
775 var wantFlags Flags
776 if ack {
777 wantFlags = FlagPingAck
778 }
779 var wantEnc = "\x00\x00\x08\x06" + string(wantFlags) + "\x00\x00\x00\x00" + "\x01\x02\x03\x04\x05\x06\x07\x08"
780 if buf.String() != wantEnc {
781 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
782 }
783
784 f, err := fr.ReadFrame()
785 if err != nil {
786 t.Fatal(err)
787 }
788 want := &PingFrame{
789 FrameHeader: FrameHeader{
790 valid: true,
791 Type: 0x6,
792 Flags: wantFlags,
793 Length: 0x8,
794 StreamID: 0,
795 },
796 Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
797 }
798 if !reflect.DeepEqual(f, want) {
799 t.Errorf("parsed back %#v; want %#v", f, want)
800 }
801 }
802
803 func TestReadFrameHeader(t *testing.T) {
804 tests := []struct {
805 in string
806 want FrameHeader
807 }{
808 {in: "\x00\x00\x00" + "\x00" + "\x00" + "\x00\x00\x00\x00", want: FrameHeader{}},
809 {in: "\x01\x02\x03" + "\x04" + "\x05" + "\x06\x07\x08\x09", want: FrameHeader{
810 Length: 66051, Type: 4, Flags: 5, StreamID: 101124105,
811 }},
812
813 {in: "\xff\xff\xff" + "\xff" + "\xff" + "\xff\xff\xff\xff", want: FrameHeader{
814 Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
815 {in: "\xff\xff\xff" + "\xff" + "\xff" + "\x7f\xff\xff\xff", want: FrameHeader{
816 Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
817 }
818 for i, tt := range tests {
819 got, err := readFrameHeader(make([]byte, 9), strings.NewReader(tt.in))
820 if err != nil {
821 t.Errorf("%d. readFrameHeader(%q) = %v", i, tt.in, err)
822 continue
823 }
824 tt.want.valid = true
825 if !got.Equal(tt.want) {
826 t.Errorf("%d. readFrameHeader(%q) = %+v; want %+v", i, tt.in, got, tt.want)
827 }
828 }
829 }
830
831 func TestReadWriteFrameHeader(t *testing.T) {
832 tests := []struct {
833 len uint32
834 typ FrameType
835 flags Flags
836 streamID uint32
837 }{
838 {len: 0, typ: 255, flags: 1, streamID: 0},
839 {len: 0, typ: 255, flags: 1, streamID: 1},
840 {len: 0, typ: 255, flags: 1, streamID: 255},
841 {len: 0, typ: 255, flags: 1, streamID: 256},
842 {len: 0, typ: 255, flags: 1, streamID: 65535},
843 {len: 0, typ: 255, flags: 1, streamID: 65536},
844
845 {len: 0, typ: 1, flags: 255, streamID: 1},
846 {len: 255, typ: 1, flags: 255, streamID: 1},
847 {len: 256, typ: 1, flags: 255, streamID: 1},
848 {len: 65535, typ: 1, flags: 255, streamID: 1},
849 {len: 65536, typ: 1, flags: 255, streamID: 1},
850 {len: 16777215, typ: 1, flags: 255, streamID: 1},
851 }
852 for _, tt := range tests {
853 fr, buf := testFramer()
854 fr.startWrite(tt.typ, tt.flags, tt.streamID)
855 fr.writeBytes(make([]byte, tt.len))
856 fr.endWrite()
857 fh, err := ReadFrameHeader(buf)
858 if err != nil {
859 t.Errorf("ReadFrameHeader(%+v) = %v", tt, err)
860 continue
861 }
862 if fh.Type != tt.typ || fh.Flags != tt.flags || fh.Length != tt.len || fh.StreamID != tt.streamID {
863 t.Errorf("ReadFrameHeader(%+v) = %+v; mismatch", tt, fh)
864 }
865 }
866
867 }
868
869 func TestWriteTooLargeFrame(t *testing.T) {
870 fr, _ := testFramer()
871 fr.startWrite(0, 1, 1)
872 fr.writeBytes(make([]byte, 1<<24))
873 err := fr.endWrite()
874 if err != ErrFrameTooLarge {
875 t.Errorf("endWrite = %v; want errFrameTooLarge", err)
876 }
877 }
878
879 func TestWriteGoAway(t *testing.T) {
880 const debug = "foo"
881 fr, buf := testFramer()
882 if err := fr.WriteGoAway(0x01020304, 0x05060708, []byte(debug)); err != nil {
883 t.Fatal(err)
884 }
885 const wantEnc = "\x00\x00\v\a\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + debug
886 if buf.String() != wantEnc {
887 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
888 }
889 f, err := fr.ReadFrame()
890 if err != nil {
891 t.Fatal(err)
892 }
893 want := &GoAwayFrame{
894 FrameHeader: FrameHeader{
895 valid: true,
896 Type: 0x7,
897 Flags: 0,
898 Length: uint32(4 + 4 + len(debug)),
899 StreamID: 0,
900 },
901 LastStreamID: 0x01020304,
902 ErrCode: 0x05060708,
903 debugData: []byte(debug),
904 }
905 if !reflect.DeepEqual(f, want) {
906 t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
907 }
908 if got := string(f.(*GoAwayFrame).DebugData()); got != debug {
909 t.Errorf("debug data = %q; want %q", got, debug)
910 }
911 }
912
913 func TestWritePushPromise(t *testing.T) {
914 pp := PushPromiseParam{
915 StreamID: 42,
916 PromiseID: 42,
917 BlockFragment: []byte("abc"),
918 }
919 fr, buf := testFramer()
920 if err := fr.WritePushPromise(pp); err != nil {
921 t.Fatal(err)
922 }
923 const wantEnc = "\x00\x00\x07\x05\x00\x00\x00\x00*\x00\x00\x00*abc"
924 if buf.String() != wantEnc {
925 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
926 }
927 f, err := fr.ReadFrame()
928 if err != nil {
929 t.Fatal(err)
930 }
931 _, ok := f.(*PushPromiseFrame)
932 if !ok {
933 t.Fatalf("got %T; want *PushPromiseFrame", f)
934 }
935 want := &PushPromiseFrame{
936 FrameHeader: FrameHeader{
937 valid: true,
938 Type: 0x5,
939 Flags: 0x0,
940 Length: 0x7,
941 StreamID: 42,
942 },
943 PromiseID: 42,
944 headerFragBuf: []byte("abc"),
945 }
946 if !reflect.DeepEqual(f, want) {
947 t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
948 }
949 }
950
951
952 func TestReadFrameOrder(t *testing.T) {
953 head := func(f *Framer, id uint32, end bool) {
954 f.WriteHeaders(HeadersFrameParam{
955 StreamID: id,
956 BlockFragment: []byte("foo"),
957 EndHeaders: end,
958 })
959 }
960 cont := func(f *Framer, id uint32, end bool) {
961 f.WriteContinuation(id, end, []byte("foo"))
962 }
963
964 tests := [...]struct {
965 name string
966 w func(*Framer)
967 atLeast int
968 wantErr string
969 }{
970 0: {
971 w: func(f *Framer) {
972 head(f, 1, true)
973 },
974 },
975 1: {
976 w: func(f *Framer) {
977 head(f, 1, true)
978 head(f, 2, true)
979 },
980 },
981 2: {
982 wantErr: "got HEADERS for stream 2; expected CONTINUATION following HEADERS for stream 1",
983 w: func(f *Framer) {
984 head(f, 1, false)
985 head(f, 2, true)
986 },
987 },
988 3: {
989 wantErr: "got DATA for stream 1; expected CONTINUATION following HEADERS for stream 1",
990 w: func(f *Framer) {
991 head(f, 1, false)
992 },
993 },
994 4: {
995 w: func(f *Framer) {
996 head(f, 1, false)
997 cont(f, 1, true)
998 head(f, 2, true)
999 },
1000 },
1001 5: {
1002 wantErr: "got CONTINUATION for stream 2; expected stream 1",
1003 w: func(f *Framer) {
1004 head(f, 1, false)
1005 cont(f, 2, true)
1006 head(f, 2, true)
1007 },
1008 },
1009 6: {
1010 wantErr: "unexpected CONTINUATION for stream 1",
1011 w: func(f *Framer) {
1012 cont(f, 1, true)
1013 },
1014 },
1015 7: {
1016 wantErr: "unexpected CONTINUATION for stream 1",
1017 w: func(f *Framer) {
1018 cont(f, 1, false)
1019 },
1020 },
1021 8: {
1022 wantErr: "HEADERS frame with stream ID 0",
1023 w: func(f *Framer) {
1024 head(f, 0, true)
1025 },
1026 },
1027 9: {
1028 wantErr: "unexpected CONTINUATION for stream 0",
1029 w: func(f *Framer) {
1030 cont(f, 0, true)
1031 },
1032 },
1033 10: {
1034 wantErr: "unexpected CONTINUATION for stream 1",
1035 atLeast: 5,
1036 w: func(f *Framer) {
1037 head(f, 1, false)
1038 cont(f, 1, false)
1039 cont(f, 1, false)
1040 cont(f, 1, false)
1041 cont(f, 1, true)
1042 cont(f, 1, false)
1043 },
1044 },
1045 }
1046 for i, tt := range tests {
1047 buf := new(bytes.Buffer)
1048 f := NewFramer(buf, buf)
1049 f.AllowIllegalWrites = true
1050 tt.w(f)
1051 f.WriteData(1, true, nil)
1052
1053 var err error
1054 n := 0
1055 var log bytes.Buffer
1056 for {
1057 var got Frame
1058 got, err = f.ReadFrame()
1059 fmt.Fprintf(&log, " read %v, %v\n", got, err)
1060 if err != nil {
1061 break
1062 }
1063 n++
1064 }
1065 if err == io.EOF {
1066 err = nil
1067 }
1068 ok := tt.wantErr == ""
1069 if ok && err != nil {
1070 t.Errorf("%d. after %d good frames, ReadFrame = %v; want success\n%s", i, n, err, log.Bytes())
1071 continue
1072 }
1073 if !ok && err != ConnectionError(ErrCodeProtocol) {
1074 t.Errorf("%d. after %d good frames, ReadFrame = %v; want ConnectionError(ErrCodeProtocol)\n%s", i, n, err, log.Bytes())
1075 continue
1076 }
1077 if !((f.errDetail == nil && tt.wantErr == "") || (fmt.Sprint(f.errDetail) == tt.wantErr)) {
1078 t.Errorf("%d. framer error = %q; want %q\n%s", i, f.errDetail, tt.wantErr, log.Bytes())
1079 }
1080 if n < tt.atLeast {
1081 t.Errorf("%d. framer only read %d frames; want at least %d\n%s", i, n, tt.atLeast, log.Bytes())
1082 }
1083 }
1084 }
1085
1086 func TestMetaFrameHeader(t *testing.T) {
1087 write := func(f *Framer, frags ...[]byte) {
1088 for i, frag := range frags {
1089 end := (i == len(frags)-1)
1090 if i == 0 {
1091 f.WriteHeaders(HeadersFrameParam{
1092 StreamID: 1,
1093 BlockFragment: frag,
1094 EndHeaders: end,
1095 })
1096 } else {
1097 f.WriteContinuation(1, end, frag)
1098 }
1099 }
1100 }
1101
1102 want := func(flags Flags, length uint32, pairs ...string) *MetaHeadersFrame {
1103 mh := &MetaHeadersFrame{
1104 HeadersFrame: &HeadersFrame{
1105 FrameHeader: FrameHeader{
1106 Type: FrameHeaders,
1107 Flags: flags,
1108 Length: length,
1109 StreamID: 1,
1110 },
1111 },
1112 Fields: []hpack.HeaderField(nil),
1113 }
1114 for len(pairs) > 0 {
1115 mh.Fields = append(mh.Fields, hpack.HeaderField{
1116 Name: pairs[0],
1117 Value: pairs[1],
1118 })
1119 pairs = pairs[2:]
1120 }
1121 return mh
1122 }
1123 truncated := func(mh *MetaHeadersFrame) *MetaHeadersFrame {
1124 mh.Truncated = true
1125 return mh
1126 }
1127
1128 const noFlags Flags = 0
1129
1130 oneKBString := strings.Repeat("a", 1<<10)
1131
1132 tests := [...]struct {
1133 name string
1134 w func(*Framer)
1135 want interface{}
1136 wantErrReason string
1137 maxHeaderListSize uint32
1138 }{
1139 0: {
1140 name: "single_headers",
1141 w: func(f *Framer) {
1142 all := encodeHeaderRaw(t, ":method", "GET", ":path", "/")
1143 write(f, all)
1144 },
1145 want: want(FlagHeadersEndHeaders, 2, ":method", "GET", ":path", "/"),
1146 },
1147 1: {
1148 name: "with_continuation",
1149 w: func(f *Framer) {
1150 all := encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar")
1151 write(f, all[:1], all[1:])
1152 },
1153 want: want(noFlags, 1, ":method", "GET", ":path", "/", "foo", "bar"),
1154 },
1155 2: {
1156 name: "with_two_continuation",
1157 w: func(f *Framer) {
1158 all := encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar")
1159 write(f, all[:2], all[2:4], all[4:])
1160 },
1161 want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", "bar"),
1162 },
1163 3: {
1164 name: "big_string_okay",
1165 w: func(f *Framer) {
1166 all := encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString)
1167 write(f, all[:2], all[2:])
1168 },
1169 want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", oneKBString),
1170 },
1171 4: {
1172 name: "big_string_error",
1173 w: func(f *Framer) {
1174 all := encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString)
1175 write(f, all[:2], all[2:])
1176 },
1177 maxHeaderListSize: (1 << 10) / 2,
1178 want: ConnectionError(ErrCodeCompression),
1179 },
1180 5: {
1181 name: "max_header_list_truncated",
1182 w: func(f *Framer) {
1183 var pairs = []string{":method", "GET", ":path", "/"}
1184 for i := 0; i < 100; i++ {
1185 pairs = append(pairs, "foo", "bar")
1186 }
1187 all := encodeHeaderRaw(t, pairs...)
1188 write(f, all[:2], all[2:])
1189 },
1190 maxHeaderListSize: (1 << 10) / 2,
1191 want: truncated(want(noFlags, 2,
1192 ":method", "GET",
1193 ":path", "/",
1194 "foo", "bar",
1195 "foo", "bar",
1196 "foo", "bar",
1197 "foo", "bar",
1198 "foo", "bar",
1199 "foo", "bar",
1200 "foo", "bar",
1201 "foo", "bar",
1202 "foo", "bar",
1203 "foo", "bar",
1204 "foo", "bar",
1205 )),
1206 },
1207 6: {
1208 name: "pseudo_order",
1209 w: func(f *Framer) {
1210 write(f, encodeHeaderRaw(t,
1211 ":method", "GET",
1212 "foo", "bar",
1213 ":path", "/",
1214 ))
1215 },
1216 want: streamError(1, ErrCodeProtocol),
1217 wantErrReason: "pseudo header field after regular",
1218 },
1219 7: {
1220 name: "pseudo_unknown",
1221 w: func(f *Framer) {
1222 write(f, encodeHeaderRaw(t,
1223 ":unknown", "foo",
1224 "foo", "bar",
1225 ))
1226 },
1227 want: streamError(1, ErrCodeProtocol),
1228 wantErrReason: "invalid pseudo-header \":unknown\"",
1229 },
1230 8: {
1231 name: "pseudo_mix_request_response",
1232 w: func(f *Framer) {
1233 write(f, encodeHeaderRaw(t,
1234 ":method", "GET",
1235 ":status", "100",
1236 ))
1237 },
1238 want: streamError(1, ErrCodeProtocol),
1239 wantErrReason: "mix of request and response pseudo headers",
1240 },
1241 9: {
1242 name: "pseudo_dup",
1243 w: func(f *Framer) {
1244 write(f, encodeHeaderRaw(t,
1245 ":method", "GET",
1246 ":method", "POST",
1247 ))
1248 },
1249 want: streamError(1, ErrCodeProtocol),
1250 wantErrReason: "duplicate pseudo-header \":method\"",
1251 },
1252 10: {
1253 name: "trailer_okay_no_pseudo",
1254 w: func(f *Framer) { write(f, encodeHeaderRaw(t, "foo", "bar")) },
1255 want: want(FlagHeadersEndHeaders, 8, "foo", "bar"),
1256 },
1257 11: {
1258 name: "invalid_field_name",
1259 w: func(f *Framer) { write(f, encodeHeaderRaw(t, "CapitalBad", "x")) },
1260 want: streamError(1, ErrCodeProtocol),
1261 wantErrReason: "invalid header field name \"CapitalBad\"",
1262 },
1263 12: {
1264 name: "invalid_field_value",
1265 w: func(f *Framer) { write(f, encodeHeaderRaw(t, "key", "bad_null\x00")) },
1266 want: streamError(1, ErrCodeProtocol),
1267 wantErrReason: `invalid header field value for "key"`,
1268 },
1269 }
1270 for i, tt := range tests {
1271 buf := new(bytes.Buffer)
1272 f := NewFramer(buf, buf)
1273 f.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
1274 f.MaxHeaderListSize = tt.maxHeaderListSize
1275 tt.w(f)
1276
1277 name := tt.name
1278 if name == "" {
1279 name = fmt.Sprintf("test index %d", i)
1280 }
1281
1282 var got interface{}
1283 var err error
1284 got, err = f.ReadFrame()
1285 if err != nil {
1286 got = err
1287
1288
1289
1290 if se, ok := err.(StreamError); ok && se.Cause != nil && se.Cause.Error() == tt.wantErrReason {
1291 se.Cause = nil
1292 got = se
1293 }
1294 }
1295 if !reflect.DeepEqual(got, tt.want) {
1296 if mhg, ok := got.(*MetaHeadersFrame); ok {
1297 if mhw, ok := tt.want.(*MetaHeadersFrame); ok {
1298 hg := mhg.HeadersFrame
1299 hw := mhw.HeadersFrame
1300 if hg != nil && hw != nil && !reflect.DeepEqual(*hg, *hw) {
1301 t.Errorf("%s: headers differ:\n got: %+v\nwant: %+v\n", name, *hg, *hw)
1302 }
1303 }
1304 }
1305 str := func(v interface{}) string {
1306 if _, ok := v.(error); ok {
1307 return fmt.Sprintf("error %v", v)
1308 } else {
1309 return fmt.Sprintf("value %#v", v)
1310 }
1311 }
1312 t.Errorf("%s:\n got: %v\nwant: %s", name, str(got), str(tt.want))
1313 }
1314 if tt.wantErrReason != "" && tt.wantErrReason != fmt.Sprint(f.errDetail) {
1315 t.Errorf("%s: got error reason %q; want %q", name, f.errDetail, tt.wantErrReason)
1316 }
1317 }
1318 }
1319
1320 func TestSetReuseFrames(t *testing.T) {
1321 fr, buf := testFramer()
1322 fr.SetReuseFrames()
1323
1324
1325
1326 firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t)
1327
1328 for i := 0; i < 10; i++ {
1329 df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
1330 if df != firstDf {
1331 t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
1332 }
1333 }
1334
1335 for i := 0; i < 10; i++ {
1336 df := readAndVerifyDataFrame("", 0, fr, buf, t)
1337 if df != firstDf {
1338 t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
1339 }
1340 }
1341
1342 for i := 0; i < 10; i++ {
1343 df := readAndVerifyDataFrame("HHH", 3, fr, buf, t)
1344 if df != firstDf {
1345 t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
1346 }
1347 }
1348 }
1349
1350 func TestSetReuseFramesMoreThanOnce(t *testing.T) {
1351 fr, buf := testFramer()
1352 fr.SetReuseFrames()
1353
1354 firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t)
1355 fr.SetReuseFrames()
1356
1357 for i := 0; i < 10; i++ {
1358 df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
1359
1360 fr.SetReuseFrames()
1361 if df != firstDf {
1362 t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
1363 }
1364 }
1365 }
1366
1367 func TestNoSetReuseFrames(t *testing.T) {
1368 fr, buf := testFramer()
1369 const numNewDataFrames = 10
1370 dfSoFar := make([]interface{}, numNewDataFrames)
1371
1372
1373
1374 for i := 0; i < numNewDataFrames; i++ {
1375 df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
1376 for _, item := range dfSoFar {
1377 if df == item {
1378 t.Errorf("Expected Framer to return new DataFrames since SetNoReuseFrames not set.")
1379 }
1380 }
1381 dfSoFar[i] = df
1382 }
1383 }
1384
1385 func readAndVerifyDataFrame(data string, length byte, fr *Framer, buf *bytes.Buffer, t *testing.T) *DataFrame {
1386 var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
1387 fr.WriteData(streamID, true, []byte(data))
1388 wantEnc := "\x00\x00" + string(length) + "\x00\x01\x01\x02\x03\x04" + data
1389 if buf.String() != wantEnc {
1390 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
1391 }
1392 f, err := fr.ReadFrame()
1393 if err != nil {
1394 t.Fatal(err)
1395 }
1396 df, ok := f.(*DataFrame)
1397 if !ok {
1398 t.Fatalf("got %T; want *DataFrame", f)
1399 }
1400 if !bytes.Equal(df.Data(), []byte(data)) {
1401 t.Errorf("got %q; want %q", df.Data(), []byte(data))
1402 }
1403 if f.Header().Flags&1 == 0 {
1404 t.Errorf("didn't see END_STREAM flag")
1405 }
1406 return df
1407 }
1408
1409 func encodeHeaderRaw(t testing.TB, headers ...string) []byte {
1410 var buf bytes.Buffer
1411 enc := hpack.NewEncoder(&buf)
1412 for len(headers) > 0 {
1413 k, v := headers[0], headers[1]
1414 err := enc.WriteField(hpack.HeaderField{Name: k, Value: v})
1415 if err != nil {
1416 t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
1417 }
1418 headers = headers[2:]
1419 }
1420 return buf.Bytes()
1421 }
1422
1423 func TestSettingsDuplicates(t *testing.T) {
1424 tests := []struct {
1425 settings []Setting
1426 want bool
1427 }{
1428 {nil, false},
1429 {[]Setting{{ID: 1}}, false},
1430 {[]Setting{{ID: 1}, {ID: 2}}, false},
1431 {[]Setting{{ID: 1}, {ID: 2}}, false},
1432 {[]Setting{{ID: 1}, {ID: 2}, {ID: 3}}, false},
1433 {[]Setting{{ID: 1}, {ID: 2}, {ID: 3}}, false},
1434 {[]Setting{{ID: 1}, {ID: 2}, {ID: 3}, {ID: 4}}, false},
1435
1436 {[]Setting{{ID: 1}, {ID: 2}, {ID: 3}, {ID: 2}}, true},
1437 {[]Setting{{ID: 4}, {ID: 2}, {ID: 3}, {ID: 4}}, true},
1438
1439 {[]Setting{
1440 {ID: 1}, {ID: 2}, {ID: 3}, {ID: 4},
1441 {ID: 5}, {ID: 6}, {ID: 7}, {ID: 8},
1442 {ID: 9}, {ID: 10}, {ID: 11}, {ID: 12},
1443 }, false},
1444
1445 {[]Setting{
1446 {ID: 1}, {ID: 2}, {ID: 3}, {ID: 4},
1447 {ID: 5}, {ID: 6}, {ID: 7}, {ID: 8},
1448 {ID: 9}, {ID: 10}, {ID: 11}, {ID: 11},
1449 }, true},
1450 }
1451 for i, tt := range tests {
1452 fr, _ := testFramer()
1453 fr.WriteSettings(tt.settings...)
1454 f, err := fr.ReadFrame()
1455 if err != nil {
1456 t.Fatalf("%d. ReadFrame: %v", i, err)
1457 }
1458 sf := f.(*SettingsFrame)
1459 got := sf.HasDuplicates()
1460 if got != tt.want {
1461 t.Errorf("%d. HasDuplicates = %v; want %v", i, got, tt.want)
1462 }
1463 }
1464
1465 }
1466
1467 func TestTypeFrameParser(t *testing.T) {
1468 if len(frameNames) != len(frameParsers) {
1469 t.Errorf("expected len(frameNames)=%d to equal len(frameParsers)=%d",
1470 len(frameNames), len(frameParsers))
1471 }
1472
1473
1474 unknownFrameType := FrameType(FramePriorityUpdate + 1)
1475 unknownParser := typeFrameParser(unknownFrameType)
1476 frame, err := unknownParser(nil, FrameHeader{}, nil, nil)
1477 if err != nil {
1478 t.Errorf("unknownParser() must not return an error: %v", err)
1479 }
1480 if _, isUnknown := frame.(*UnknownFrame); !isUnknown {
1481 t.Errorf("expected UnknownFrame, got %T", frame)
1482 }
1483 }
1484
1485 func TestReadFrameHeaderAndBody(t *testing.T) {
1486 fr, _ := testFramer()
1487 var streamID uint32 = 1
1488 data := []byte("ABC")
1489 if err := fr.WriteData(streamID, true, data); err != nil {
1490 t.Fatalf("WriteData(%d, true, %q) failed: %v", streamID, data, err)
1491 }
1492
1493 fh, err := fr.ReadFrameHeader()
1494 if err != nil {
1495 t.Fatalf("ReadFrameHeader failed: %v", err)
1496 }
1497 wantHeader := FrameHeader{
1498 Type: FrameData,
1499 Flags: FlagDataEndStream,
1500 Length: 3,
1501 StreamID: 1,
1502 valid: true,
1503 }
1504 if !fh.Equal(wantHeader) {
1505 t.Fatalf("ReadFrameHeader = %+v; want %+v", fh, wantHeader)
1506 }
1507
1508 f, err := fr.ReadFrameForHeader(fh)
1509 if err != nil {
1510 t.Fatalf("ReadFrameForHeader failed: %v", err)
1511 }
1512
1513 if !fh.Equal(f.Header()) {
1514 t.Fatalf("Frame.Header() = %+v; want %+v", f.Header(), fh)
1515 }
1516
1517 df, ok := f.(*DataFrame)
1518 if !ok {
1519 t.Fatalf("got %T; want *DataFrame", f)
1520 }
1521 if got, want := df.Data(), data; !bytes.Equal(got, want) {
1522 t.Errorf("DataFrame.Data() = %q; want %q", string(got), string(want))
1523 }
1524 if got, want := df.StreamEnded(), true; got != want {
1525 t.Errorf("DataFrame.StreamEnded() = %v; want %v", got, want)
1526 }
1527 }
1528
1529 func TestReadFrameHeaderFrameTooLarge(t *testing.T) {
1530 fr, _ := testFramer()
1531 fr.SetMaxReadFrameSize(2)
1532 if err := fr.WriteData(1, true, []byte("ABC")); err != nil {
1533 t.Fatalf("WriteData failed: %v", err)
1534 }
1535 fh, err := fr.ReadFrameHeader()
1536 if gotErr, wantErr := err, ErrFrameTooLarge; gotErr != wantErr {
1537 t.Fatalf("ReadFrameHeader returned error %v; want %v", gotErr, wantErr)
1538 }
1539 if fh.StreamID != 1 {
1540 t.Errorf("ReadFrameHeader = %v, %v; want StreamID 1", fh, err)
1541 }
1542 }
1543
1544 func TestReadFrameHeaderBadFrameOrder(t *testing.T) {
1545 fr, _ := testFramer()
1546 if err := fr.WriteHeaders(HeadersFrameParam{
1547 StreamID: 1,
1548 BlockFragment: []byte("foo"),
1549 EndHeaders: false,
1550 }); err != nil {
1551 t.Fatalf("WriteHeaders failed: %v", err)
1552 }
1553
1554
1555 if err := fr.WriteContinuation(2, true, []byte("foo")); err != nil {
1556 t.Fatalf("WriteContinuation failed: %v", err)
1557 }
1558
1559 fh, err := fr.ReadFrameHeader()
1560 if err != nil {
1561 t.Fatalf("ReadFrameHeader failed: %v", err)
1562 }
1563 if _, err = fr.ReadFrameForHeader(fh); err != nil {
1564 t.Fatalf("ReadFrameForHeader failed: %v", err)
1565 }
1566
1567 if _, err := fr.ReadFrameHeader(); err != ConnectionError(ErrCodeProtocol) {
1568 t.Fatalf("ReadFrameHeader returned error %v; want ConnectionError(ErrCodeProtocol)", err)
1569 }
1570 }
1571
1572 func TestReadFrameForHeaderUnexpectedEOF(t *testing.T) {
1573 fr, b := testFramer()
1574 if err := fr.WriteData(1, true, []byte("ABC")); err != nil {
1575 t.Fatalf("WriteData failed: %v", err)
1576 }
1577
1578 fh, err := fr.ReadFrameHeader()
1579 if err != nil {
1580 t.Fatalf("ReadFrameHeader failed: %v", err)
1581 }
1582
1583
1584 b.Truncate(b.Len() - 1)
1585
1586 _, err = fr.ReadFrameForHeader(fh)
1587 if err != io.ErrUnexpectedEOF {
1588 t.Fatalf("ReadFrameForHeader with short body = %v; want io.ErrUnexpectedEOF", err)
1589 }
1590 }
1591
1592 func TestTypeFrameParserHolePanic(t *testing.T) {
1593
1594 fr, _ := testFramer()
1595 if err := fr.WriteRawFrame(FrameType(0x0a), 0, 1, nil); err != nil {
1596 t.Fatal(err)
1597 }
1598
1599 f, err := fr.ReadFrame()
1600 if err != nil {
1601 t.Fatal(err)
1602 }
1603
1604 if _, ok := f.(*UnknownFrame); !ok {
1605 t.Errorf("got %T; want *UnknownFrame", f)
1606 }
1607 }
1608
View as plain text