github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/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  
    17  func testFramer() (*Framer, *bytes.Buffer) {
    18  	buf := new(bytes.Buffer)
    19  	return NewFramer(buf, buf), buf
    20  }
    21  
    22  func TestFrameSizes(t *testing.T) {
    23  	// Catch people rearranging the FrameHeader fields.
    24  	if got, want := int(unsafe.Sizeof(FrameHeader{})), 12; got != want {
    25  		t.Errorf("FrameHeader size = %d; want %d", got, want)
    26  	}
    27  }
    28  
    29  func TestFrameTypeString(t *testing.T) {
    30  	tests := []struct {
    31  		ft   FrameType
    32  		want string
    33  	}{
    34  		{FrameData, "DATA"},
    35  		{FramePing, "PING"},
    36  		{FrameGoAway, "GOAWAY"},
    37  		{0xf, "UNKNOWN_FRAME_TYPE_15"},
    38  	}
    39  
    40  	for i, tt := range tests {
    41  		got := tt.ft.String()
    42  		if got != tt.want {
    43  			t.Errorf("%d. String(FrameType %d) = %q; want %q", i, int(tt.ft), got, tt.want)
    44  		}
    45  	}
    46  }
    47  
    48  func TestWriteRST(t *testing.T) {
    49  	fr, buf := testFramer()
    50  	var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
    51  	var errCode uint32 = 7<<24 + 6<<16 + 5<<8 + 4
    52  	fr.WriteRSTStream(streamID, ErrCode(errCode))
    53  	const wantEnc = "\x00\x00\x04\x03\x00\x01\x02\x03\x04\x07\x06\x05\x04"
    54  	if buf.String() != wantEnc {
    55  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
    56  	}
    57  	f, err := fr.ReadFrame()
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  	want := &RSTStreamFrame{
    62  		FrameHeader: FrameHeader{
    63  			valid:    true,
    64  			Type:     0x3,
    65  			Flags:    0x0,
    66  			Length:   0x4,
    67  			StreamID: 0x1020304,
    68  		},
    69  		ErrCode: 0x7060504,
    70  	}
    71  	if !reflect.DeepEqual(f, want) {
    72  		t.Errorf("parsed back %#v; want %#v", f, want)
    73  	}
    74  }
    75  
    76  func TestWriteData(t *testing.T) {
    77  	fr, buf := testFramer()
    78  	var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
    79  	data := []byte("ABC")
    80  	fr.WriteData(streamID, true, data)
    81  	const wantEnc = "\x00\x00\x03\x00\x01\x01\x02\x03\x04ABC"
    82  	if buf.String() != wantEnc {
    83  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
    84  	}
    85  	f, err := fr.ReadFrame()
    86  	if err != nil {
    87  		t.Fatal(err)
    88  	}
    89  	df, ok := f.(*DataFrame)
    90  	if !ok {
    91  		t.Fatalf("got %T; want *DataFrame", f)
    92  	}
    93  	if !bytes.Equal(df.Data(), data) {
    94  		t.Errorf("got %q; want %q", df.Data(), data)
    95  	}
    96  	if f.Header().Flags&1 == 0 {
    97  		t.Errorf("didn't see END_STREAM flag")
    98  	}
    99  }
   100  
   101  func TestWriteHeaders(t *testing.T) {
   102  	tests := []struct {
   103  		name      string
   104  		p         HeadersFrameParam
   105  		wantEnc   string
   106  		wantFrame *HeadersFrame
   107  	}{
   108  		{
   109  			"basic",
   110  			HeadersFrameParam{
   111  				StreamID:      42,
   112  				BlockFragment: []byte("abc"),
   113  				Priority:      PriorityParam{},
   114  			},
   115  			"\x00\x00\x03\x01\x00\x00\x00\x00*abc",
   116  			&HeadersFrame{
   117  				FrameHeader: FrameHeader{
   118  					valid:    true,
   119  					StreamID: 42,
   120  					Type:     FrameHeaders,
   121  					Length:   uint32(len("abc")),
   122  				},
   123  				Priority:      PriorityParam{},
   124  				headerFragBuf: []byte("abc"),
   125  			},
   126  		},
   127  		{
   128  			"basic + end flags",
   129  			HeadersFrameParam{
   130  				StreamID:      42,
   131  				BlockFragment: []byte("abc"),
   132  				EndStream:     true,
   133  				EndHeaders:    true,
   134  				Priority:      PriorityParam{},
   135  			},
   136  			"\x00\x00\x03\x01\x05\x00\x00\x00*abc",
   137  			&HeadersFrame{
   138  				FrameHeader: FrameHeader{
   139  					valid:    true,
   140  					StreamID: 42,
   141  					Type:     FrameHeaders,
   142  					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders,
   143  					Length:   uint32(len("abc")),
   144  				},
   145  				Priority:      PriorityParam{},
   146  				headerFragBuf: []byte("abc"),
   147  			},
   148  		},
   149  		{
   150  			"with padding",
   151  			HeadersFrameParam{
   152  				StreamID:      42,
   153  				BlockFragment: []byte("abc"),
   154  				EndStream:     true,
   155  				EndHeaders:    true,
   156  				PadLength:     5,
   157  				Priority:      PriorityParam{},
   158  			},
   159  			"\x00\x00\t\x01\r\x00\x00\x00*\x05abc\x00\x00\x00\x00\x00",
   160  			&HeadersFrame{
   161  				FrameHeader: FrameHeader{
   162  					valid:    true,
   163  					StreamID: 42,
   164  					Type:     FrameHeaders,
   165  					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded,
   166  					Length:   uint32(1 + len("abc") + 5), // pad length + contents + padding
   167  				},
   168  				Priority:      PriorityParam{},
   169  				headerFragBuf: []byte("abc"),
   170  			},
   171  		},
   172  		{
   173  			"with priority",
   174  			HeadersFrameParam{
   175  				StreamID:      42,
   176  				BlockFragment: []byte("abc"),
   177  				EndStream:     true,
   178  				EndHeaders:    true,
   179  				PadLength:     2,
   180  				Priority: PriorityParam{
   181  					StreamDep: 15,
   182  					Exclusive: true,
   183  					Weight:    127,
   184  				},
   185  			},
   186  			"\x00\x00\v\x01-\x00\x00\x00*\x02\x80\x00\x00\x0f\u007fabc\x00\x00",
   187  			&HeadersFrame{
   188  				FrameHeader: FrameHeader{
   189  					valid:    true,
   190  					StreamID: 42,
   191  					Type:     FrameHeaders,
   192  					Flags:    FlagHeadersEndStream | FlagHeadersEndHeaders | FlagHeadersPadded | FlagHeadersPriority,
   193  					Length:   uint32(1 + 5 + len("abc") + 2), // pad length + priority + contents + padding
   194  				},
   195  				Priority: PriorityParam{
   196  					StreamDep: 15,
   197  					Exclusive: true,
   198  					Weight:    127,
   199  				},
   200  				headerFragBuf: []byte("abc"),
   201  			},
   202  		},
   203  	}
   204  	for _, tt := range tests {
   205  		fr, buf := testFramer()
   206  		if err := fr.WriteHeaders(tt.p); err != nil {
   207  			t.Errorf("test %q: %v", tt.name, err)
   208  			continue
   209  		}
   210  		if buf.String() != tt.wantEnc {
   211  			t.Errorf("test %q: encoded %q; want %q", tt.name, buf.Bytes(), tt.wantEnc)
   212  		}
   213  		f, err := fr.ReadFrame()
   214  		if err != nil {
   215  			t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
   216  			continue
   217  		}
   218  		if !reflect.DeepEqual(f, tt.wantFrame) {
   219  			t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
   220  		}
   221  	}
   222  }
   223  
   224  func TestWriteContinuation(t *testing.T) {
   225  	const streamID = 42
   226  	tests := []struct {
   227  		name string
   228  		end  bool
   229  		frag []byte
   230  
   231  		wantFrame *ContinuationFrame
   232  	}{
   233  		{
   234  			"not end",
   235  			false,
   236  			[]byte("abc"),
   237  			&ContinuationFrame{
   238  				FrameHeader: FrameHeader{
   239  					valid:    true,
   240  					StreamID: streamID,
   241  					Type:     FrameContinuation,
   242  					Length:   uint32(len("abc")),
   243  				},
   244  				headerFragBuf: []byte("abc"),
   245  			},
   246  		},
   247  		{
   248  			"end",
   249  			true,
   250  			[]byte("def"),
   251  			&ContinuationFrame{
   252  				FrameHeader: FrameHeader{
   253  					valid:    true,
   254  					StreamID: streamID,
   255  					Type:     FrameContinuation,
   256  					Flags:    FlagContinuationEndHeaders,
   257  					Length:   uint32(len("def")),
   258  				},
   259  				headerFragBuf: []byte("def"),
   260  			},
   261  		},
   262  	}
   263  	for _, tt := range tests {
   264  		fr, _ := testFramer()
   265  		if err := fr.WriteContinuation(streamID, tt.end, tt.frag); err != nil {
   266  			t.Errorf("test %q: %v", tt.name, err)
   267  			continue
   268  		}
   269  		fr.AllowIllegalReads = true
   270  		f, err := fr.ReadFrame()
   271  		if err != nil {
   272  			t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
   273  			continue
   274  		}
   275  		if !reflect.DeepEqual(f, tt.wantFrame) {
   276  			t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
   277  		}
   278  	}
   279  }
   280  
   281  func TestWritePriority(t *testing.T) {
   282  	const streamID = 42
   283  	tests := []struct {
   284  		name      string
   285  		priority  PriorityParam
   286  		wantFrame *PriorityFrame
   287  	}{
   288  		{
   289  			"not exclusive",
   290  			PriorityParam{
   291  				StreamDep: 2,
   292  				Exclusive: false,
   293  				Weight:    127,
   294  			},
   295  			&PriorityFrame{
   296  				FrameHeader{
   297  					valid:    true,
   298  					StreamID: streamID,
   299  					Type:     FramePriority,
   300  					Length:   5,
   301  				},
   302  				PriorityParam{
   303  					StreamDep: 2,
   304  					Exclusive: false,
   305  					Weight:    127,
   306  				},
   307  			},
   308  		},
   309  
   310  		{
   311  			"exclusive",
   312  			PriorityParam{
   313  				StreamDep: 3,
   314  				Exclusive: true,
   315  				Weight:    77,
   316  			},
   317  			&PriorityFrame{
   318  				FrameHeader{
   319  					valid:    true,
   320  					StreamID: streamID,
   321  					Type:     FramePriority,
   322  					Length:   5,
   323  				},
   324  				PriorityParam{
   325  					StreamDep: 3,
   326  					Exclusive: true,
   327  					Weight:    77,
   328  				},
   329  			},
   330  		},
   331  	}
   332  	for _, tt := range tests {
   333  		fr, _ := testFramer()
   334  		if err := fr.WritePriority(streamID, tt.priority); err != nil {
   335  			t.Errorf("test %q: %v", tt.name, err)
   336  			continue
   337  		}
   338  		f, err := fr.ReadFrame()
   339  		if err != nil {
   340  			t.Errorf("test %q: failed to read the frame back: %v", tt.name, err)
   341  			continue
   342  		}
   343  		if !reflect.DeepEqual(f, tt.wantFrame) {
   344  			t.Errorf("test %q: mismatch.\n got: %#v\nwant: %#v\n", tt.name, f, tt.wantFrame)
   345  		}
   346  	}
   347  }
   348  
   349  func TestWriteSettings(t *testing.T) {
   350  	fr, buf := testFramer()
   351  	settings := []Setting{{1, 2}, {3, 4}}
   352  	fr.WriteSettings(settings...)
   353  	const wantEnc = "\x00\x00\f\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00\x00\x04"
   354  	if buf.String() != wantEnc {
   355  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   356  	}
   357  	f, err := fr.ReadFrame()
   358  	if err != nil {
   359  		t.Fatal(err)
   360  	}
   361  	sf, ok := f.(*SettingsFrame)
   362  	if !ok {
   363  		t.Fatalf("Got a %T; want a SettingsFrame", f)
   364  	}
   365  	var got []Setting
   366  	sf.ForeachSetting(func(s Setting) error {
   367  		got = append(got, s)
   368  		valBack, ok := sf.Value(s.ID)
   369  		if !ok || valBack != s.Val {
   370  			t.Errorf("Value(%d) = %v, %v; want %v, true", s.ID, valBack, ok, s.Val)
   371  		}
   372  		return nil
   373  	})
   374  	if !reflect.DeepEqual(settings, got) {
   375  		t.Errorf("Read settings %+v != written settings %+v", got, settings)
   376  	}
   377  }
   378  
   379  func TestWriteSettingsAck(t *testing.T) {
   380  	fr, buf := testFramer()
   381  	fr.WriteSettingsAck()
   382  	const wantEnc = "\x00\x00\x00\x04\x01\x00\x00\x00\x00"
   383  	if buf.String() != wantEnc {
   384  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   385  	}
   386  }
   387  
   388  func TestWriteWindowUpdate(t *testing.T) {
   389  	fr, buf := testFramer()
   390  	const streamID = 1<<24 + 2<<16 + 3<<8 + 4
   391  	const incr = 7<<24 + 6<<16 + 5<<8 + 4
   392  	if err := fr.WriteWindowUpdate(streamID, incr); err != nil {
   393  		t.Fatal(err)
   394  	}
   395  	const wantEnc = "\x00\x00\x04\x08\x00\x01\x02\x03\x04\x07\x06\x05\x04"
   396  	if buf.String() != wantEnc {
   397  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   398  	}
   399  	f, err := fr.ReadFrame()
   400  	if err != nil {
   401  		t.Fatal(err)
   402  	}
   403  	want := &WindowUpdateFrame{
   404  		FrameHeader: FrameHeader{
   405  			valid:    true,
   406  			Type:     0x8,
   407  			Flags:    0x0,
   408  			Length:   0x4,
   409  			StreamID: 0x1020304,
   410  		},
   411  		Increment: 0x7060504,
   412  	}
   413  	if !reflect.DeepEqual(f, want) {
   414  		t.Errorf("parsed back %#v; want %#v", f, want)
   415  	}
   416  }
   417  
   418  func TestWritePing(t *testing.T)    { testWritePing(t, false) }
   419  func TestWritePingAck(t *testing.T) { testWritePing(t, true) }
   420  
   421  func testWritePing(t *testing.T, ack bool) {
   422  	fr, buf := testFramer()
   423  	if err := fr.WritePing(ack, [8]byte{1, 2, 3, 4, 5, 6, 7, 8}); err != nil {
   424  		t.Fatal(err)
   425  	}
   426  	var wantFlags Flags
   427  	if ack {
   428  		wantFlags = FlagPingAck
   429  	}
   430  	var wantEnc = "\x00\x00\x08\x06" + string(wantFlags) + "\x00\x00\x00\x00" + "\x01\x02\x03\x04\x05\x06\x07\x08"
   431  	if buf.String() != wantEnc {
   432  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   433  	}
   434  
   435  	f, err := fr.ReadFrame()
   436  	if err != nil {
   437  		t.Fatal(err)
   438  	}
   439  	want := &PingFrame{
   440  		FrameHeader: FrameHeader{
   441  			valid:    true,
   442  			Type:     0x6,
   443  			Flags:    wantFlags,
   444  			Length:   0x8,
   445  			StreamID: 0,
   446  		},
   447  		Data: [8]byte{1, 2, 3, 4, 5, 6, 7, 8},
   448  	}
   449  	if !reflect.DeepEqual(f, want) {
   450  		t.Errorf("parsed back %#v; want %#v", f, want)
   451  	}
   452  }
   453  
   454  func TestReadFrameHeader(t *testing.T) {
   455  	tests := []struct {
   456  		in   string
   457  		want FrameHeader
   458  	}{
   459  		{in: "\x00\x00\x00" + "\x00" + "\x00" + "\x00\x00\x00\x00", want: FrameHeader{}},
   460  		{in: "\x01\x02\x03" + "\x04" + "\x05" + "\x06\x07\x08\x09", want: FrameHeader{
   461  			Length: 66051, Type: 4, Flags: 5, StreamID: 101124105,
   462  		}},
   463  		// Ignore high bit:
   464  		{in: "\xff\xff\xff" + "\xff" + "\xff" + "\xff\xff\xff\xff", want: FrameHeader{
   465  			Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
   466  		{in: "\xff\xff\xff" + "\xff" + "\xff" + "\x7f\xff\xff\xff", want: FrameHeader{
   467  			Length: 16777215, Type: 255, Flags: 255, StreamID: 2147483647}},
   468  	}
   469  	for i, tt := range tests {
   470  		got, err := readFrameHeader(make([]byte, 9), strings.NewReader(tt.in))
   471  		if err != nil {
   472  			t.Errorf("%d. readFrameHeader(%q) = %v", i, tt.in, err)
   473  			continue
   474  		}
   475  		tt.want.valid = true
   476  		if got != tt.want {
   477  			t.Errorf("%d. readFrameHeader(%q) = %+v; want %+v", i, tt.in, got, tt.want)
   478  		}
   479  	}
   480  }
   481  
   482  func TestReadWriteFrameHeader(t *testing.T) {
   483  	tests := []struct {
   484  		len      uint32
   485  		typ      FrameType
   486  		flags    Flags
   487  		streamID uint32
   488  	}{
   489  		{len: 0, typ: 255, flags: 1, streamID: 0},
   490  		{len: 0, typ: 255, flags: 1, streamID: 1},
   491  		{len: 0, typ: 255, flags: 1, streamID: 255},
   492  		{len: 0, typ: 255, flags: 1, streamID: 256},
   493  		{len: 0, typ: 255, flags: 1, streamID: 65535},
   494  		{len: 0, typ: 255, flags: 1, streamID: 65536},
   495  
   496  		{len: 0, typ: 1, flags: 255, streamID: 1},
   497  		{len: 255, typ: 1, flags: 255, streamID: 1},
   498  		{len: 256, typ: 1, flags: 255, streamID: 1},
   499  		{len: 65535, typ: 1, flags: 255, streamID: 1},
   500  		{len: 65536, typ: 1, flags: 255, streamID: 1},
   501  		{len: 16777215, typ: 1, flags: 255, streamID: 1},
   502  	}
   503  	for _, tt := range tests {
   504  		fr, buf := testFramer()
   505  		fr.startWrite(tt.typ, tt.flags, tt.streamID)
   506  		fr.writeBytes(make([]byte, tt.len))
   507  		fr.endWrite()
   508  		fh, err := ReadFrameHeader(buf)
   509  		if err != nil {
   510  			t.Errorf("ReadFrameHeader(%+v) = %v", tt, err)
   511  			continue
   512  		}
   513  		if fh.Type != tt.typ || fh.Flags != tt.flags || fh.Length != tt.len || fh.StreamID != tt.streamID {
   514  			t.Errorf("ReadFrameHeader(%+v) = %+v; mismatch", tt, fh)
   515  		}
   516  	}
   517  
   518  }
   519  
   520  func TestWriteTooLargeFrame(t *testing.T) {
   521  	fr, _ := testFramer()
   522  	fr.startWrite(0, 1, 1)
   523  	fr.writeBytes(make([]byte, 1<<24))
   524  	err := fr.endWrite()
   525  	if err != ErrFrameTooLarge {
   526  		t.Errorf("endWrite = %v; want errFrameTooLarge", err)
   527  	}
   528  }
   529  
   530  func TestWriteGoAway(t *testing.T) {
   531  	const debug = "foo"
   532  	fr, buf := testFramer()
   533  	if err := fr.WriteGoAway(0x01020304, 0x05060708, []byte(debug)); err != nil {
   534  		t.Fatal(err)
   535  	}
   536  	const wantEnc = "\x00\x00\v\a\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + debug
   537  	if buf.String() != wantEnc {
   538  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   539  	}
   540  	f, err := fr.ReadFrame()
   541  	if err != nil {
   542  		t.Fatal(err)
   543  	}
   544  	want := &GoAwayFrame{
   545  		FrameHeader: FrameHeader{
   546  			valid:    true,
   547  			Type:     0x7,
   548  			Flags:    0,
   549  			Length:   uint32(4 + 4 + len(debug)),
   550  			StreamID: 0,
   551  		},
   552  		LastStreamID: 0x01020304,
   553  		ErrCode:      0x05060708,
   554  		debugData:    []byte(debug),
   555  	}
   556  	if !reflect.DeepEqual(f, want) {
   557  		t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
   558  	}
   559  	if got := string(f.(*GoAwayFrame).DebugData()); got != debug {
   560  		t.Errorf("debug data = %q; want %q", got, debug)
   561  	}
   562  }
   563  
   564  func TestWritePushPromise(t *testing.T) {
   565  	pp := PushPromiseParam{
   566  		StreamID:      42,
   567  		PromiseID:     42,
   568  		BlockFragment: []byte("abc"),
   569  	}
   570  	fr, buf := testFramer()
   571  	if err := fr.WritePushPromise(pp); err != nil {
   572  		t.Fatal(err)
   573  	}
   574  	const wantEnc = "\x00\x00\x07\x05\x00\x00\x00\x00*\x00\x00\x00*abc"
   575  	if buf.String() != wantEnc {
   576  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
   577  	}
   578  	f, err := fr.ReadFrame()
   579  	if err != nil {
   580  		t.Fatal(err)
   581  	}
   582  	_, ok := f.(*PushPromiseFrame)
   583  	if !ok {
   584  		t.Fatalf("got %T; want *PushPromiseFrame", f)
   585  	}
   586  	want := &PushPromiseFrame{
   587  		FrameHeader: FrameHeader{
   588  			valid:    true,
   589  			Type:     0x5,
   590  			Flags:    0x0,
   591  			Length:   0x7,
   592  			StreamID: 42,
   593  		},
   594  		PromiseID:     42,
   595  		headerFragBuf: []byte("abc"),
   596  	}
   597  	if !reflect.DeepEqual(f, want) {
   598  		t.Fatalf("parsed back:\n%#v\nwant:\n%#v", f, want)
   599  	}
   600  }
   601  
   602  // test checkFrameOrder and that HEADERS and CONTINUATION frames can't be intermingled.
   603  func TestReadFrameOrder(t *testing.T) {
   604  	head := func(f *Framer, id uint32, end bool) {
   605  		f.WriteHeaders(HeadersFrameParam{
   606  			StreamID:      id,
   607  			BlockFragment: []byte("foo"), // unused, but non-empty
   608  			EndHeaders:    end,
   609  		})
   610  	}
   611  	cont := func(f *Framer, id uint32, end bool) {
   612  		f.WriteContinuation(id, end, []byte("foo"))
   613  	}
   614  
   615  	tests := [...]struct {
   616  		name    string
   617  		w       func(*Framer)
   618  		atLeast int
   619  		wantErr string
   620  	}{
   621  		0: {
   622  			w: func(f *Framer) {
   623  				head(f, 1, true)
   624  			},
   625  		},
   626  		1: {
   627  			w: func(f *Framer) {
   628  				head(f, 1, true)
   629  				head(f, 2, true)
   630  			},
   631  		},
   632  		2: {
   633  			wantErr: "got HEADERS for stream 2; expected CONTINUATION following HEADERS for stream 1",
   634  			w: func(f *Framer) {
   635  				head(f, 1, false)
   636  				head(f, 2, true)
   637  			},
   638  		},
   639  		3: {
   640  			wantErr: "got DATA for stream 1; expected CONTINUATION following HEADERS for stream 1",
   641  			w: func(f *Framer) {
   642  				head(f, 1, false)
   643  			},
   644  		},
   645  		4: {
   646  			w: func(f *Framer) {
   647  				head(f, 1, false)
   648  				cont(f, 1, true)
   649  				head(f, 2, true)
   650  			},
   651  		},
   652  		5: {
   653  			wantErr: "got CONTINUATION for stream 2; expected stream 1",
   654  			w: func(f *Framer) {
   655  				head(f, 1, false)
   656  				cont(f, 2, true)
   657  				head(f, 2, true)
   658  			},
   659  		},
   660  		6: {
   661  			wantErr: "unexpected CONTINUATION for stream 1",
   662  			w: func(f *Framer) {
   663  				cont(f, 1, true)
   664  			},
   665  		},
   666  		7: {
   667  			wantErr: "unexpected CONTINUATION for stream 1",
   668  			w: func(f *Framer) {
   669  				cont(f, 1, false)
   670  			},
   671  		},
   672  		8: {
   673  			wantErr: "HEADERS frame with stream ID 0",
   674  			w: func(f *Framer) {
   675  				head(f, 0, true)
   676  			},
   677  		},
   678  		9: {
   679  			wantErr: "CONTINUATION frame with stream ID 0",
   680  			w: func(f *Framer) {
   681  				cont(f, 0, true)
   682  			},
   683  		},
   684  		10: {
   685  			wantErr: "unexpected CONTINUATION for stream 1",
   686  			atLeast: 5,
   687  			w: func(f *Framer) {
   688  				head(f, 1, false)
   689  				cont(f, 1, false)
   690  				cont(f, 1, false)
   691  				cont(f, 1, false)
   692  				cont(f, 1, true)
   693  				cont(f, 1, false)
   694  			},
   695  		},
   696  	}
   697  	for i, tt := range tests {
   698  		buf := new(bytes.Buffer)
   699  		f := NewFramer(buf, buf)
   700  		f.AllowIllegalWrites = true
   701  		tt.w(f)
   702  		f.WriteData(1, true, nil) // to test transition away from last step
   703  
   704  		var err error
   705  		n := 0
   706  		var log bytes.Buffer
   707  		for {
   708  			var got Frame
   709  			got, err = f.ReadFrame()
   710  			fmt.Fprintf(&log, "  read %v, %v\n", got, err)
   711  			if err != nil {
   712  				break
   713  			}
   714  			n++
   715  		}
   716  		if err == io.EOF {
   717  			err = nil
   718  		}
   719  		ok := tt.wantErr == ""
   720  		if ok && err != nil {
   721  			t.Errorf("%d. after %d good frames, ReadFrame = %v; want success\n%s", i, n, err, log.Bytes())
   722  			continue
   723  		}
   724  		if !ok && err != ConnectionError(ErrCodeProtocol) {
   725  			t.Errorf("%d. after %d good frames, ReadFrame = %v; want ConnectionError(ErrCodeProtocol)\n%s", i, n, err, log.Bytes())
   726  			continue
   727  		}
   728  		if f.errReason != tt.wantErr {
   729  			t.Errorf("%d. framer eror = %q; want %q\n%s", i, f.errReason, tt.wantErr, log.Bytes())
   730  		}
   731  		if n < tt.atLeast {
   732  			t.Errorf("%d. framer only read %d frames; want at least %d\n%s", i, n, tt.atLeast, log.Bytes())
   733  		}
   734  	}
   735  }