1// 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 "fmt" 10 "io" 11 "reflect" 12 "strings" 13 "testing" 14 "unsafe" 15 16 "golang.org/x/net/http2/hpack" 17) 18 19func testFramer() (*Framer, *bytes.Buffer) { 20 buf := new(bytes.Buffer) 21 return NewFramer(buf, buf), buf 22} 23 24func TestFrameSizes(t *testing.T) { 25 // Catch people rearranging the FrameHeader fields. 26 if got, want := int(unsafe.Sizeof(FrameHeader{})), 12; got != want { 27 t.Errorf("FrameHeader size = %d; want %d", got, want) 28 } 29} 30 31func TestFrameTypeString(t *testing.T) { 32 tests := []struct { 33 ft FrameType 34 want string 35 }{ 36 {FrameData, "DATA"}, 37 {FramePing, "PING"}, 38 {FrameGoAway, "GOAWAY"}, 39 {0xf, "UNKNOWN_FRAME_TYPE_15"}, 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 50func 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 78func 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 103func TestWriteDataPadded(t *testing.T) { 104 tests := [...]struct { 105 streamID uint32 106 endStream bool 107 data []byte 108 pad []byte 109 wantHeader FrameHeader 110 }{ 111 // Unpadded: 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 // Padded bit set, but no padding: 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 // Padded bit set, with padding: 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 174func (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 182func 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), // pad length + contents + padding 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), // pad length + priority + contents + padding 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", // golang.org/issue/15444 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), // pad length + priority + contents + padding 306 }, 307 Priority: PriorityParam{ 308 StreamDep: 0, 309 Exclusive: true, 310 Weight: 127, 311 }, 312 headerFragBuf: []byte("abc"), 313 }, 314 }, 315 } 316 for _, tt := range tests { 317 fr, buf := testFramer() 318 if err := fr.WriteHeaders(tt.p); err != nil { 319 t.Errorf("test %q: %v", tt.name, err) 320 continue 321 } 322 if buf.String() != tt.wantEnc { 323 t.Errorf("test %q: encoded %q; want %q", tt.name, buf.Bytes(), tt.wantEnc) 324 } 325 f, err := fr.ReadFrame() 326 if err != nil { 327 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err) 328 continue 329 } 330 if !reflect.DeepEqual(f, tt.wantFrame) { 331 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame) 332 } 333 } 334} 335 336func TestWriteInvalidStreamDep(t *testing.T) { 337 fr, _ := testFramer() 338 err := fr.WriteHeaders(HeadersFrameParam{ 339 StreamID: 42, 340 Priority: PriorityParam{ 341 StreamDep: 1 << 31, 342 }, 343 }) 344 if err != errDepStreamID { 345 t.Errorf("header error = %v; want %q", err, errDepStreamID) 346 } 347 348 err = fr.WritePriority(2, PriorityParam{StreamDep: 1 << 31}) 349 if err != errDepStreamID { 350 t.Errorf("priority error = %v; want %q", err, errDepStreamID) 351 } 352} 353 354func TestWriteContinuation(t *testing.T) { 355 const streamID = 42 356 tests := []struct { 357 name string 358 end bool 359 frag []byte 360 361 wantFrame *ContinuationFrame 362 }{ 363 { 364 "not end", 365 false, 366 []byte("abc"), 367 &ContinuationFrame{ 368 FrameHeader: FrameHeader{ 369 valid: true, 370 StreamID: streamID, 371 Type: FrameContinuation, 372 Length: uint32(len("abc")), 373 }, 374 headerFragBuf: []byte("abc"), 375 }, 376 }, 377 { 378 "end", 379 true, 380 []byte("def"), 381 &ContinuationFrame{ 382 FrameHeader: FrameHeader{ 383 valid: true, 384 StreamID: streamID, 385 Type: FrameContinuation, 386 Flags: FlagContinuationEndHeaders, 387 Length: uint32(len("def")), 388 }, 389 headerFragBuf: []byte("def"), 390 }, 391 }, 392 } 393 for _, tt := range tests { 394 fr, _ := testFramer() 395 if err := fr.WriteContinuation(streamID, tt.end, tt.frag); err != nil { 396 t.Errorf("test %q: %v", tt.name, err) 397 continue 398 } 399 fr.AllowIllegalReads = true 400 f, err := fr.ReadFrame() 401 if err != nil { 402 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err) 403 continue 404 } 405 if !reflect.DeepEqual(f, tt.wantFrame) { 406 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame) 407 } 408 } 409} 410 411func TestWritePriority(t *testing.T) { 412 const streamID = 42 413 tests := []struct { 414 name string 415 priority PriorityParam 416 wantFrame *PriorityFrame 417 }{ 418 { 419 "not exclusive", 420 PriorityParam{ 421 StreamDep: 2, 422 Exclusive: false, 423 Weight: 127, 424 }, 425 &PriorityFrame{ 426 FrameHeader{ 427 valid: true, 428 StreamID: streamID, 429 Type: FramePriority, 430 Length: 5, 431 }, 432 PriorityParam{ 433 StreamDep: 2, 434 Exclusive: false, 435 Weight: 127, 436 }, 437 }, 438 }, 439 440 { 441 "exclusive", 442 PriorityParam{ 443 StreamDep: 3, 444 Exclusive: true, 445 Weight: 77, 446 }, 447 &PriorityFrame{ 448 FrameHeader{ 449 valid: true, 450 StreamID: streamID, 451 Type: FramePriority, 452 Length: 5, 453 }, 454 PriorityParam{ 455 StreamDep: 3, 456 Exclusive: true, 457 Weight: 77, 458 }, 459 }, 460 }, 461 } 462 for _, tt := range tests { 463 fr, _ := testFramer() 464 if err := fr.WritePriority(streamID, tt.priority); err != nil { 465 t.Errorf("test %q: %v", tt.name, err) 466 continue 467 } 468 f, err := fr.ReadFrame() 469 if err != nil { 470 t.Errorf("test %q: failed to read the frame back: %v", tt.name, err) 471 continue 472 } 473 if !reflect.DeepEqual(f, tt.wantFrame) { 474 t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame) 475 } 476 } 477} 478 479func TestWriteSettings(t *testing.T) { 480 fr, buf := testFramer() 481 settings := []Setting{{1, 2}, {3, 4}} 482 fr.WriteSettings(settings...) 483 const wantEnc = "\x00\x00\f\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00\x04" 484 if buf.String() != wantEnc { 485 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 486 } 487 f, err := fr.ReadFrame() 488 if err != nil { 489 t.Fatal(err) 490 } 491 sf, ok := f.(*SettingsFrame) 492 if !ok { 493 t.Fatalf("Got a %T; want a SettingsFrame", f) 494 } 495 var got []Setting 496 sf.ForeachSetting(func(s Setting) error { 497 got = append(got, s) 498 valBack, ok := sf.Value(s.ID) 499 if !ok || valBack != s.Val { 500 t.Errorf("Value(%d) = %v, %v; want %v, true", s.ID, valBack, ok, s.Val) 501 } 502 return nil 503 }) 504 if !reflect.DeepEqual(settings, got) { 505 t.Errorf("Read settings %+v != written settings %+v", got, settings) 506 } 507} 508 509func TestWriteSettingsAck(t *testing.T) { 510 fr, buf := testFramer() 511 fr.WriteSettingsAck() 512 const wantEnc = "\x00\x00\x00\x04\x01\x00\x00\x00\x00" 513 if buf.String() != wantEnc { 514 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 515 } 516} 517 518func TestWriteWindowUpdate(t *testing.T) { 519 fr, buf := testFramer() 520 const streamID = 1<<24 + 2<<16 + 3<<8 + 4 521 const incr = 7<<24 + 6<<16 + 5<<8 + 4 522 if err := fr.WriteWindowUpdate(streamID, incr); err != nil { 523 t.Fatal(err) 524 } 525 const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04" 526 if buf.String() != wantEnc { 527 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 528 } 529 f, err := fr.ReadFrame() 530 if err != nil { 531 t.Fatal(err) 532 } 533 want := &WindowUpdateFrame{ 534 FrameHeader: FrameHeader{ 535 valid: true, 536 Type: 0x8, 537 Flags: 0x0, 538 Length: 0x4, 539 StreamID: 0x1020304, 540 }, 541 Increment: 0x7060504, 542 } 543 if !reflect.DeepEqual(f, want) { 544 t.Errorf("parsed back %#v; want %#v", f, want) 545 } 546} 547 548func TestWritePing(t *testing.T) { testWritePing(t, false) } 549func TestWritePingAck(t *testing.T) { testWritePing(t, true) } 550 551func testWritePing(t *testing.T, ack bool) { 552 fr, buf := testFramer() 553 if err := fr.WritePing(ack, [8]byte{1, 2, 3, 4, 5, 6, 7, 8}); err != nil { 554 t.Fatal(err) 555 } 556 var wantFlags Flags 557 if ack { 558 wantFlags = FlagPingAck 559 } 560 var wantEnc = "\x00\x00\x08\x06" + string(wantFlags) + "\x00\x00\x00\x00" + "\x01\x02\x03\x04\x05\x06\x07\x08" 561 if buf.String() != wantEnc { 562 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 563 } 564 565 f, err := fr.ReadFrame() 566 if err != nil { 567 t.Fatal(err) 568 } 569 want := &PingFrame{ 570 FrameHeader: FrameHeader{ 571 valid: true, 572 Type: 0x6, 573 Flags: wantFlags, 574 Length: 0x8, 575 StreamID: 0, 576 }, 577 Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, 578 } 579 if !reflect.DeepEqual(f, want) { 580 t.Errorf("parsed back %#v; want %#v", f, want) 581 } 582} 583 584func TestReadFrameHeader(t *testing.T) { 585 tests := []struct { 586 in string 587 want FrameHeader 588 }{ 589 {in: "\x00\x00\x00" + "\x00" + "\x00" + "\x00\x00\x00\x00", want: FrameHeader{}}, 590 {in: "\x01\x02\x03" + "\x04" + "\x05" + "\x06\x07\x08\x09", want: FrameHeader{ 591 Length: 66051, Type: 4, Flags: 5, StreamID: 101124105, 592 }}, 593 // Ignore high bit: 594 {in: "\xff\xff\xff" + "\xff" + "\xff" + "\xff\xff\xff\xff", want: FrameHeader{ 595 Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}}, 596 {in: "\xff\xff\xff" + "\xff" + "\xff" + "\x7f\xff\xff\xff", want: FrameHeader{ 597 Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}}, 598 } 599 for i, tt := range tests { 600 got, err := readFrameHeader(make([]byte, 9), strings.NewReader(tt.in)) 601 if err != nil { 602 t.Errorf("%d. readFrameHeader(%q) = %v", i, tt.in, err) 603 continue 604 } 605 tt.want.valid = true 606 if !got.Equal(tt.want) { 607 t.Errorf("%d. readFrameHeader(%q) = %+v; want %+v", i, tt.in, got, tt.want) 608 } 609 } 610} 611 612func TestReadWriteFrameHeader(t *testing.T) { 613 tests := []struct { 614 len uint32 615 typ FrameType 616 flags Flags 617 streamID uint32 618 }{ 619 {len: 0, typ: 255, flags: 1, streamID: 0}, 620 {len: 0, typ: 255, flags: 1, streamID: 1}, 621 {len: 0, typ: 255, flags: 1, streamID: 255}, 622 {len: 0, typ: 255, flags: 1, streamID: 256}, 623 {len: 0, typ: 255, flags: 1, streamID: 65535}, 624 {len: 0, typ: 255, flags: 1, streamID: 65536}, 625 626 {len: 0, typ: 1, flags: 255, streamID: 1}, 627 {len: 255, typ: 1, flags: 255, streamID: 1}, 628 {len: 256, typ: 1, flags: 255, streamID: 1}, 629 {len: 65535, typ: 1, flags: 255, streamID: 1}, 630 {len: 65536, typ: 1, flags: 255, streamID: 1}, 631 {len: 16777215, typ: 1, flags: 255, streamID: 1}, 632 } 633 for _, tt := range tests { 634 fr, buf := testFramer() 635 fr.startWrite(tt.typ, tt.flags, tt.streamID) 636 fr.writeBytes(make([]byte, tt.len)) 637 fr.endWrite() 638 fh, err := ReadFrameHeader(buf) 639 if err != nil { 640 t.Errorf("ReadFrameHeader(%+v) = %v", tt, err) 641 continue 642 } 643 if fh.Type != tt.typ || fh.Flags != tt.flags || fh.Length != tt.len || fh.StreamID != tt.streamID { 644 t.Errorf("ReadFrameHeader(%+v) = %+v; mismatch", tt, fh) 645 } 646 } 647 648} 649 650func TestWriteTooLargeFrame(t *testing.T) { 651 fr, _ := testFramer() 652 fr.startWrite(0, 1, 1) 653 fr.writeBytes(make([]byte, 1<<24)) 654 err := fr.endWrite() 655 if err != ErrFrameTooLarge { 656 t.Errorf("endWrite = %v; want errFrameTooLarge", err) 657 } 658} 659 660func TestWriteGoAway(t *testing.T) { 661 const debug = "foo" 662 fr, buf := testFramer() 663 if err := fr.WriteGoAway(0x01020304, 0x05060708, []byte(debug)); err != nil { 664 t.Fatal(err) 665 } 666 const wantEnc = "\x00\x00\v\a\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + debug 667 if buf.String() != wantEnc { 668 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 669 } 670 f, err := fr.ReadFrame() 671 if err != nil { 672 t.Fatal(err) 673 } 674 want := &GoAwayFrame{ 675 FrameHeader: FrameHeader{ 676 valid: true, 677 Type: 0x7, 678 Flags: 0, 679 Length: uint32(4 + 4 + len(debug)), 680 StreamID: 0, 681 }, 682 LastStreamID: 0x01020304, 683 ErrCode: 0x05060708, 684 debugData: []byte(debug), 685 } 686 if !reflect.DeepEqual(f, want) { 687 t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want) 688 } 689 if got := string(f.(*GoAwayFrame).DebugData()); got != debug { 690 t.Errorf("debug data = %q; want %q", got, debug) 691 } 692} 693 694func TestWritePushPromise(t *testing.T) { 695 pp := PushPromiseParam{ 696 StreamID: 42, 697 PromiseID: 42, 698 BlockFragment: []byte("abc"), 699 } 700 fr, buf := testFramer() 701 if err := fr.WritePushPromise(pp); err != nil { 702 t.Fatal(err) 703 } 704 const wantEnc = "\x00\x00\x07\x05\x00\x00\x00\x00*\x00\x00\x00*abc" 705 if buf.String() != wantEnc { 706 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 707 } 708 f, err := fr.ReadFrame() 709 if err != nil { 710 t.Fatal(err) 711 } 712 _, ok := f.(*PushPromiseFrame) 713 if !ok { 714 t.Fatalf("got %T; want *PushPromiseFrame", f) 715 } 716 want := &PushPromiseFrame{ 717 FrameHeader: FrameHeader{ 718 valid: true, 719 Type: 0x5, 720 Flags: 0x0, 721 Length: 0x7, 722 StreamID: 42, 723 }, 724 PromiseID: 42, 725 headerFragBuf: []byte("abc"), 726 } 727 if !reflect.DeepEqual(f, want) { 728 t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want) 729 } 730} 731 732// test checkFrameOrder and that HEADERS and CONTINUATION frames can't be intermingled. 733func TestReadFrameOrder(t *testing.T) { 734 head := func(f *Framer, id uint32, end bool) { 735 f.WriteHeaders(HeadersFrameParam{ 736 StreamID: id, 737 BlockFragment: []byte("foo"), // unused, but non-empty 738 EndHeaders: end, 739 }) 740 } 741 cont := func(f *Framer, id uint32, end bool) { 742 f.WriteContinuation(id, end, []byte("foo")) 743 } 744 745 tests := [...]struct { 746 name string 747 w func(*Framer) 748 atLeast int 749 wantErr string 750 }{ 751 0: { 752 w: func(f *Framer) { 753 head(f, 1, true) 754 }, 755 }, 756 1: { 757 w: func(f *Framer) { 758 head(f, 1, true) 759 head(f, 2, true) 760 }, 761 }, 762 2: { 763 wantErr: "got HEADERS for stream 2; expected CONTINUATION following HEADERS for stream 1", 764 w: func(f *Framer) { 765 head(f, 1, false) 766 head(f, 2, true) 767 }, 768 }, 769 3: { 770 wantErr: "got DATA for stream 1; expected CONTINUATION following HEADERS for stream 1", 771 w: func(f *Framer) { 772 head(f, 1, false) 773 }, 774 }, 775 4: { 776 w: func(f *Framer) { 777 head(f, 1, false) 778 cont(f, 1, true) 779 head(f, 2, true) 780 }, 781 }, 782 5: { 783 wantErr: "got CONTINUATION for stream 2; expected stream 1", 784 w: func(f *Framer) { 785 head(f, 1, false) 786 cont(f, 2, true) 787 head(f, 2, true) 788 }, 789 }, 790 6: { 791 wantErr: "unexpected CONTINUATION for stream 1", 792 w: func(f *Framer) { 793 cont(f, 1, true) 794 }, 795 }, 796 7: { 797 wantErr: "unexpected CONTINUATION for stream 1", 798 w: func(f *Framer) { 799 cont(f, 1, false) 800 }, 801 }, 802 8: { 803 wantErr: "HEADERS frame with stream ID 0", 804 w: func(f *Framer) { 805 head(f, 0, true) 806 }, 807 }, 808 9: { 809 wantErr: "CONTINUATION frame with stream ID 0", 810 w: func(f *Framer) { 811 cont(f, 0, true) 812 }, 813 }, 814 10: { 815 wantErr: "unexpected CONTINUATION for stream 1", 816 atLeast: 5, 817 w: func(f *Framer) { 818 head(f, 1, false) 819 cont(f, 1, false) 820 cont(f, 1, false) 821 cont(f, 1, false) 822 cont(f, 1, true) 823 cont(f, 1, false) 824 }, 825 }, 826 } 827 for i, tt := range tests { 828 buf := new(bytes.Buffer) 829 f := NewFramer(buf, buf) 830 f.AllowIllegalWrites = true 831 tt.w(f) 832 f.WriteData(1, true, nil) // to test transition away from last step 833 834 var err error 835 n := 0 836 var log bytes.Buffer 837 for { 838 var got Frame 839 got, err = f.ReadFrame() 840 fmt.Fprintf(&log, " read %v, %v\n", got, err) 841 if err != nil { 842 break 843 } 844 n++ 845 } 846 if err == io.EOF { 847 err = nil 848 } 849 ok := tt.wantErr == "" 850 if ok && err != nil { 851 t.Errorf("%d. after %d good frames, ReadFrame = %v; want success\n%s", i, n, err, log.Bytes()) 852 continue 853 } 854 if !ok && err != ConnectionError(ErrCodeProtocol) { 855 t.Errorf("%d. after %d good frames, ReadFrame = %v; want ConnectionError(ErrCodeProtocol)\n%s", i, n, err, log.Bytes()) 856 continue 857 } 858 if !((f.errDetail == nil && tt.wantErr == "") || (fmt.Sprint(f.errDetail) == tt.wantErr)) { 859 t.Errorf("%d. framer eror = %q; want %q\n%s", i, f.errDetail, tt.wantErr, log.Bytes()) 860 } 861 if n < tt.atLeast { 862 t.Errorf("%d. framer only read %d frames; want at least %d\n%s", i, n, tt.atLeast, log.Bytes()) 863 } 864 } 865} 866 867func TestMetaFrameHeader(t *testing.T) { 868 write := func(f *Framer, frags ...[]byte) { 869 for i, frag := range frags { 870 end := (i == len(frags)-1) 871 if i == 0 { 872 f.WriteHeaders(HeadersFrameParam{ 873 StreamID: 1, 874 BlockFragment: frag, 875 EndHeaders: end, 876 }) 877 } else { 878 f.WriteContinuation(1, end, frag) 879 } 880 } 881 } 882 883 want := func(flags Flags, length uint32, pairs ...string) *MetaHeadersFrame { 884 mh := &MetaHeadersFrame{ 885 HeadersFrame: &HeadersFrame{ 886 FrameHeader: FrameHeader{ 887 Type: FrameHeaders, 888 Flags: flags, 889 Length: length, 890 StreamID: 1, 891 }, 892 }, 893 Fields: []hpack.HeaderField(nil), 894 } 895 for len(pairs) > 0 { 896 mh.Fields = append(mh.Fields, hpack.HeaderField{ 897 Name: pairs[0], 898 Value: pairs[1], 899 }) 900 pairs = pairs[2:] 901 } 902 return mh 903 } 904 truncated := func(mh *MetaHeadersFrame) *MetaHeadersFrame { 905 mh.Truncated = true 906 return mh 907 } 908 909 const noFlags Flags = 0 910 911 oneKBString := strings.Repeat("a", 1<<10) 912 913 tests := [...]struct { 914 name string 915 w func(*Framer) 916 want interface{} // *MetaHeaderFrame or error 917 wantErrReason string 918 maxHeaderListSize uint32 919 }{ 920 0: { 921 name: "single_headers", 922 w: func(f *Framer) { 923 var he hpackEncoder 924 all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/") 925 write(f, all) 926 }, 927 want: want(FlagHeadersEndHeaders, 2, ":method", "GET", ":path", "/"), 928 }, 929 1: { 930 name: "with_continuation", 931 w: func(f *Framer) { 932 var he hpackEncoder 933 all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar") 934 write(f, all[:1], all[1:]) 935 }, 936 want: want(noFlags, 1, ":method", "GET", ":path", "/", "foo", "bar"), 937 }, 938 2: { 939 name: "with_two_continuation", 940 w: func(f *Framer) { 941 var he hpackEncoder 942 all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar") 943 write(f, all[:2], all[2:4], all[4:]) 944 }, 945 want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", "bar"), 946 }, 947 3: { 948 name: "big_string_okay", 949 w: func(f *Framer) { 950 var he hpackEncoder 951 all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString) 952 write(f, all[:2], all[2:]) 953 }, 954 want: want(noFlags, 2, ":method", "GET", ":path", "/", "foo", oneKBString), 955 }, 956 4: { 957 name: "big_string_error", 958 w: func(f *Framer) { 959 var he hpackEncoder 960 all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString) 961 write(f, all[:2], all[2:]) 962 }, 963 maxHeaderListSize: (1 << 10) / 2, 964 want: ConnectionError(ErrCodeCompression), 965 }, 966 5: { 967 name: "max_header_list_truncated", 968 w: func(f *Framer) { 969 var he hpackEncoder 970 var pairs = []string{":method", "GET", ":path", "/"} 971 for i := 0; i < 100; i++ { 972 pairs = append(pairs, "foo", "bar") 973 } 974 all := he.encodeHeaderRaw(t, pairs...) 975 write(f, all[:2], all[2:]) 976 }, 977 maxHeaderListSize: (1 << 10) / 2, 978 want: truncated(want(noFlags, 2, 979 ":method", "GET", 980 ":path", "/", 981 "foo", "bar", 982 "foo", "bar", 983 "foo", "bar", 984 "foo", "bar", 985 "foo", "bar", 986 "foo", "bar", 987 "foo", "bar", 988 "foo", "bar", 989 "foo", "bar", 990 "foo", "bar", 991 "foo", "bar", // 11 992 )), 993 }, 994 6: { 995 name: "pseudo_order", 996 w: func(f *Framer) { 997 write(f, encodeHeaderRaw(t, 998 ":method", "GET", 999 "foo", "bar", 1000 ":path", "/", // bogus 1001 )) 1002 }, 1003 want: streamError(1, ErrCodeProtocol), 1004 wantErrReason: "pseudo header field after regular", 1005 }, 1006 7: { 1007 name: "pseudo_unknown", 1008 w: func(f *Framer) { 1009 write(f, encodeHeaderRaw(t, 1010 ":unknown", "foo", // bogus 1011 "foo", "bar", 1012 )) 1013 }, 1014 want: streamError(1, ErrCodeProtocol), 1015 wantErrReason: "invalid pseudo-header \":unknown\"", 1016 }, 1017 8: { 1018 name: "pseudo_mix_request_response", 1019 w: func(f *Framer) { 1020 write(f, encodeHeaderRaw(t, 1021 ":method", "GET", 1022 ":status", "100", 1023 )) 1024 }, 1025 want: streamError(1, ErrCodeProtocol), 1026 wantErrReason: "mix of request and response pseudo headers", 1027 }, 1028 9: { 1029 name: "pseudo_dup", 1030 w: func(f *Framer) { 1031 write(f, encodeHeaderRaw(t, 1032 ":method", "GET", 1033 ":method", "POST", 1034 )) 1035 }, 1036 want: streamError(1, ErrCodeProtocol), 1037 wantErrReason: "duplicate pseudo-header \":method\"", 1038 }, 1039 10: { 1040 name: "trailer_okay_no_pseudo", 1041 w: func(f *Framer) { write(f, encodeHeaderRaw(t, "foo", "bar")) }, 1042 want: want(FlagHeadersEndHeaders, 8, "foo", "bar"), 1043 }, 1044 11: { 1045 name: "invalid_field_name", 1046 w: func(f *Framer) { write(f, encodeHeaderRaw(t, "CapitalBad", "x")) }, 1047 want: streamError(1, ErrCodeProtocol), 1048 wantErrReason: "invalid header field name \"CapitalBad\"", 1049 }, 1050 12: { 1051 name: "invalid_field_value", 1052 w: func(f *Framer) { write(f, encodeHeaderRaw(t, "key", "bad_null\x00")) }, 1053 want: streamError(1, ErrCodeProtocol), 1054 wantErrReason: "invalid header field value \"bad_null\\x00\"", 1055 }, 1056 } 1057 for i, tt := range tests { 1058 buf := new(bytes.Buffer) 1059 f := NewFramer(buf, buf) 1060 f.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil) 1061 f.MaxHeaderListSize = tt.maxHeaderListSize 1062 tt.w(f) 1063 1064 name := tt.name 1065 if name == "" { 1066 name = fmt.Sprintf("test index %d", i) 1067 } 1068 1069 var got interface{} 1070 var err error 1071 got, err = f.ReadFrame() 1072 if err != nil { 1073 got = err 1074 1075 // Ignore the StreamError.Cause field, if it matches the wantErrReason. 1076 // The test table above predates the Cause field. 1077 if se, ok := err.(StreamError); ok && se.Cause != nil && se.Cause.Error() == tt.wantErrReason { 1078 se.Cause = nil 1079 got = se 1080 } 1081 } 1082 if !reflect.DeepEqual(got, tt.want) { 1083 if mhg, ok := got.(*MetaHeadersFrame); ok { 1084 if mhw, ok := tt.want.(*MetaHeadersFrame); ok { 1085 hg := mhg.HeadersFrame 1086 hw := mhw.HeadersFrame 1087 if hg != nil && hw != nil && !reflect.DeepEqual(*hg, *hw) { 1088 t.Errorf("%s: headers differ:\n got: %+v\nwant: %+v\n", name, *hg, *hw) 1089 } 1090 } 1091 } 1092 str := func(v interface{}) string { 1093 if _, ok := v.(error); ok { 1094 return fmt.Sprintf("error %v", v) 1095 } else { 1096 return fmt.Sprintf("value %#v", v) 1097 } 1098 } 1099 t.Errorf("%s:\n got: %v\nwant: %s", name, str(got), str(tt.want)) 1100 } 1101 if tt.wantErrReason != "" && tt.wantErrReason != fmt.Sprint(f.errDetail) { 1102 t.Errorf("%s: got error reason %q; want %q", name, f.errDetail, tt.wantErrReason) 1103 } 1104 } 1105} 1106 1107func TestSetReuseFrames(t *testing.T) { 1108 fr, buf := testFramer() 1109 fr.SetReuseFrames() 1110 1111 // Check that DataFrames are reused. Note that 1112 // SetReuseFrames only currently implements reuse of DataFrames. 1113 firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t) 1114 1115 for i := 0; i < 10; i++ { 1116 df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t) 1117 if df != firstDf { 1118 t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) 1119 } 1120 } 1121 1122 for i := 0; i < 10; i++ { 1123 df := readAndVerifyDataFrame("", 0, fr, buf, t) 1124 if df != firstDf { 1125 t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) 1126 } 1127 } 1128 1129 for i := 0; i < 10; i++ { 1130 df := readAndVerifyDataFrame("HHH", 3, fr, buf, t) 1131 if df != firstDf { 1132 t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) 1133 } 1134 } 1135} 1136 1137func TestSetReuseFramesMoreThanOnce(t *testing.T) { 1138 fr, buf := testFramer() 1139 fr.SetReuseFrames() 1140 1141 firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t) 1142 fr.SetReuseFrames() 1143 1144 for i := 0; i < 10; i++ { 1145 df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t) 1146 // SetReuseFrames should be idempotent 1147 fr.SetReuseFrames() 1148 if df != firstDf { 1149 t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf) 1150 } 1151 } 1152} 1153 1154func TestNoSetReuseFrames(t *testing.T) { 1155 fr, buf := testFramer() 1156 const numNewDataFrames = 10 1157 dfSoFar := make([]interface{}, numNewDataFrames) 1158 1159 // Check that DataFrames are not reused if SetReuseFrames wasn't called. 1160 // SetReuseFrames only currently implements reuse of DataFrames. 1161 for i := 0; i < numNewDataFrames; i++ { 1162 df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t) 1163 for _, item := range dfSoFar { 1164 if df == item { 1165 t.Errorf("Expected Framer to return new DataFrames since SetNoReuseFrames not set.") 1166 } 1167 } 1168 dfSoFar[i] = df 1169 } 1170} 1171 1172func readAndVerifyDataFrame(data string, length byte, fr *Framer, buf *bytes.Buffer, t *testing.T) *DataFrame { 1173 var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4 1174 fr.WriteData(streamID, true, []byte(data)) 1175 wantEnc := "\x00\x00" + string(length) + "\x00\x01\x01\x02\x03\x04" + data 1176 if buf.String() != wantEnc { 1177 t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc) 1178 } 1179 f, err := fr.ReadFrame() 1180 if err != nil { 1181 t.Fatal(err) 1182 } 1183 df, ok := f.(*DataFrame) 1184 if !ok { 1185 t.Fatalf("got %T; want *DataFrame", f) 1186 } 1187 if !bytes.Equal(df.Data(), []byte(data)) { 1188 t.Errorf("got %q; want %q", df.Data(), []byte(data)) 1189 } 1190 if f.Header().Flags&1 == 0 { 1191 t.Errorf("didn't see END_STREAM flag") 1192 } 1193 return df 1194} 1195 1196func encodeHeaderRaw(t *testing.T, pairs ...string) []byte { 1197 var he hpackEncoder 1198 return he.encodeHeaderRaw(t, pairs...) 1199} 1200 1201func TestSettingsDuplicates(t *testing.T) { 1202 tests := []struct { 1203 settings []Setting 1204 want bool 1205 }{ 1206 {nil, false}, 1207 {[]Setting{{ID: 1}}, false}, 1208 {[]Setting{{ID: 1}, {ID: 2}}, false}, 1209 {[]Setting{{ID: 1}, {ID: 2}}, false}, 1210 {[]Setting{{ID: 1}, {ID: 2}, {ID: 3}}, false}, 1211 {[]Setting{{ID: 1}, {ID: 2}, {ID: 3}}, false}, 1212 {[]Setting{{ID: 1}, {ID: 2}, {ID: 3}, {ID: 4}}, false}, 1213 1214 {[]Setting{{ID: 1}, {ID: 2}, {ID: 3}, {ID: 2}}, true}, 1215 {[]Setting{{ID: 4}, {ID: 2}, {ID: 3}, {ID: 4}}, true}, 1216 1217 {[]Setting{ 1218 {ID: 1}, {ID: 2}, {ID: 3}, {ID: 4}, 1219 {ID: 5}, {ID: 6}, {ID: 7}, {ID: 8}, 1220 {ID: 9}, {ID: 10}, {ID: 11}, {ID: 12}, 1221 }, false}, 1222 1223 {[]Setting{ 1224 {ID: 1}, {ID: 2}, {ID: 3}, {ID: 4}, 1225 {ID: 5}, {ID: 6}, {ID: 7}, {ID: 8}, 1226 {ID: 9}, {ID: 10}, {ID: 11}, {ID: 11}, 1227 }, true}, 1228 } 1229 for i, tt := range tests { 1230 fr, _ := testFramer() 1231 fr.WriteSettings(tt.settings...) 1232 f, err := fr.ReadFrame() 1233 if err != nil { 1234 t.Fatalf("%d. ReadFrame: %v", i, err) 1235 } 1236 sf := f.(*SettingsFrame) 1237 got := sf.HasDuplicates() 1238 if got != tt.want { 1239 t.Errorf("%d. HasDuplicates = %v; want %v", i, got, tt.want) 1240 } 1241 } 1242 1243} 1244