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