github.com/useflyent/fhttp@v0.0.0-20211004035111-333f430cfbbf/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  	"github.com/useflyent/fhttp/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  	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  
   336  func 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  
   354  func 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  
   411  func 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  
   479  func 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  
   509  func 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  
   518  func 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  
   548  func TestWritePing(t *testing.T)    { testWritePing(t, false) }
   549  func TestWritePingAck(t *testing.T) { testWritePing(t, true) }
   550  
   551  func 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  
   584  func 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  
   612  func 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  
   650  func 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  
   660  func 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  
   694  func 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/PUSH_PROMISE and CONTINUATION frames can't be intermingled.
   733  func 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  	push := func(f *Framer, id uint32, end bool) {
   742  		f.WritePushPromise(PushPromiseParam{
   743  			StreamID:      id,
   744  			BlockFragment: []byte("foo"),
   745  			EndHeaders:    end,
   746  		})
   747  	}
   748  	cont := func(f *Framer, id uint32, end bool) {
   749  		f.WriteContinuation(id, end, []byte("foo"))
   750  	}
   751  
   752  	tests := [...]struct {
   753  		name    string
   754  		w       func(*Framer)
   755  		atLeast int
   756  		wantErr string
   757  	}{
   758  		0: {
   759  			w: func(f *Framer) {
   760  				head(f, 1, true)
   761  			},
   762  		},
   763  		1: {
   764  			w: func(f *Framer) {
   765  				push(f, 1, true)
   766  			},
   767  		},
   768  		2: {
   769  			w: func(f *Framer) {
   770  				head(f, 1, true)
   771  				head(f, 2, true)
   772  			},
   773  		},
   774  		3: {
   775  			w: func(f *Framer) {
   776  				push(f, 1, true)
   777  				push(f, 2, true)
   778  			},
   779  		},
   780  		4: {
   781  			wantErr: "got HEADERS for stream 2; expected CONTINUATION following HEADERS for stream 1",
   782  			w: func(f *Framer) {
   783  				head(f, 1, false)
   784  				head(f, 2, true)
   785  			},
   786  		},
   787  		5: {
   788  			wantErr: "got PUSH_PROMISE for stream 2; expected CONTINUATION following PUSH_PROMISE for stream 1",
   789  			w: func(f *Framer) {
   790  				push(f, 1, false)
   791  				push(f, 2, true)
   792  			},
   793  		},
   794  		6: {
   795  			wantErr: "got DATA for stream 1; expected CONTINUATION following HEADERS for stream 1",
   796  			w: func(f *Framer) {
   797  				head(f, 1, false)
   798  			},
   799  		},
   800  		7: {
   801  			wantErr: "got DATA for stream 1; expected CONTINUATION following PUSH_PROMISE for stream 1",
   802  			w: func(f *Framer) {
   803  				push(f, 1, false)
   804  			},
   805  		},
   806  		8: {
   807  			w: func(f *Framer) {
   808  				head(f, 1, false)
   809  				cont(f, 1, true)
   810  				head(f, 2, true)
   811  			},
   812  		},
   813  		9: {
   814  			w: func(f *Framer) {
   815  				push(f, 1, false)
   816  				cont(f, 1, true)
   817  				push(f, 2, true)
   818  			},
   819  		},
   820  		10: {
   821  			wantErr: "got CONTINUATION for stream 2; expected stream 1",
   822  			w: func(f *Framer) {
   823  				head(f, 1, false)
   824  				cont(f, 2, true)
   825  				head(f, 2, true)
   826  			},
   827  		},
   828  		11: {
   829  			wantErr: "got CONTINUATION for stream 2; expected stream 1",
   830  			w: func(f *Framer) {
   831  				push(f, 1, false)
   832  				cont(f, 2, true)
   833  				push(f, 2, true)
   834  			},
   835  		},
   836  		12: {
   837  			wantErr: "unexpected CONTINUATION for stream 1",
   838  			w: func(f *Framer) {
   839  				cont(f, 1, true)
   840  			},
   841  		},
   842  		13: {
   843  			wantErr: "unexpected CONTINUATION for stream 1",
   844  			w: func(f *Framer) {
   845  				cont(f, 1, false)
   846  			},
   847  		},
   848  		14: {
   849  			wantErr: "HEADERS frame with stream ID 0",
   850  			w: func(f *Framer) {
   851  				head(f, 0, true)
   852  			},
   853  		},
   854  		15: {
   855  			wantErr: "PUSH_PROMISE frame with stream ID 0",
   856  			w: func(f *Framer) {
   857  				push(f, 0, true)
   858  			},
   859  		},
   860  		16: {
   861  			wantErr: "CONTINUATION frame with stream ID 0",
   862  			w: func(f *Framer) {
   863  				cont(f, 0, true)
   864  			},
   865  		},
   866  		17: {
   867  			wantErr: "unexpected CONTINUATION for stream 1",
   868  			atLeast: 5,
   869  			w: func(f *Framer) {
   870  				head(f, 1, false)
   871  				cont(f, 1, false)
   872  				cont(f, 1, false)
   873  				cont(f, 1, false)
   874  				cont(f, 1, true)
   875  				cont(f, 1, false)
   876  			},
   877  		},
   878  		18: {
   879  			wantErr: "unexpected CONTINUATION for stream 1",
   880  			atLeast: 5,
   881  			w: func(f *Framer) {
   882  				push(f, 1, false)
   883  				cont(f, 1, false)
   884  				cont(f, 1, false)
   885  				cont(f, 1, false)
   886  				cont(f, 1, true)
   887  				cont(f, 1, false)
   888  			},
   889  		},
   890  	}
   891  
   892  	for i, tt := range tests {
   893  		buf := new(bytes.Buffer)
   894  		f := NewFramer(buf, buf)
   895  		f.AllowIllegalWrites = true
   896  		tt.w(f)
   897  		f.WriteData(1, true, nil) // to test transition away from last step
   898  
   899  		var err error
   900  		n := 0
   901  		var log bytes.Buffer
   902  		for {
   903  			var got Frame
   904  			got, err = f.ReadFrame()
   905  			fmt.Fprintf(&log, "  read %v, %v\n", got, err)
   906  			if err != nil {
   907  				break
   908  			}
   909  			n++
   910  		}
   911  		if err == io.EOF {
   912  			err = nil
   913  		}
   914  		ok := tt.wantErr == ""
   915  		if ok && err != nil {
   916  			t.Errorf("%d. after %d good frames, ReadFrame = %v; want success\n%s", i, n, err, log.Bytes())
   917  			continue
   918  		}
   919  		if !ok && err != ConnectionError(ErrCodeProtocol) {
   920  			t.Errorf("%d. after %d good frames, ReadFrame = %v; want ConnectionError(ErrCodeProtocol)\n%s", i, n, err, log.Bytes())
   921  			continue
   922  		}
   923  		if !((f.errDetail == nil && tt.wantErr == "") || (fmt.Sprint(f.errDetail) == tt.wantErr)) {
   924  			t.Errorf("%d. framer error = %q; want %q\n%s", i, f.errDetail, tt.wantErr, log.Bytes())
   925  		}
   926  		if n < tt.atLeast {
   927  			t.Errorf("%d. framer only read %d frames; want at least %d\n%s", i, n, tt.atLeast, log.Bytes())
   928  		}
   929  	}
   930  }
   931  
   932  func testMetaFrame(t *testing.T,
   933  	write func(f *Framer, frags ...[]byte),
   934  	want func(flags Flags, length uint32, pairs ...string) Frame,
   935  	headersCmp func(t *testing.T, testName string, gotMetaFrame, wantMetaFrame interface{}),
   936  	lengthIncrementBeyondMetaHeaderFrame uint32) {
   937  
   938  	truncated := func(f Frame) Frame {
   939  		switch f := f.(type) {
   940  		case *MetaHeadersFrame:
   941  			f.Truncated = true
   942  		case *MetaPushPromiseFrame:
   943  			f.Truncated = true
   944  		default:
   945  			panic("not a meta frame")
   946  		}
   947  		return f
   948  
   949  	}
   950  	const flagEndHeaders Flags = 0x4 // same for all end headers flag
   951  	const noFlags Flags = 0
   952  
   953  	oneKBString := strings.Repeat("a", 1<<10)
   954  
   955  	tests := [...]struct {
   956  		name              string
   957  		w                 func(*Framer)
   958  		want              interface{} // meta frame or error
   959  		wantErrReason     string
   960  		maxHeaderListSize uint32
   961  	}{
   962  		0: {
   963  			name: "single_headers",
   964  			w: func(f *Framer) {
   965  				var he hpackEncoder
   966  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/")
   967  				write(f, all)
   968  			},
   969  			want: want(flagEndHeaders, 2+lengthIncrementBeyondMetaHeaderFrame, ":method", "GET", ":path", "/"),
   970  		},
   971  		1: {
   972  			name: "with_continuation",
   973  			w: func(f *Framer) {
   974  				var he hpackEncoder
   975  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar")
   976  				write(f, all[:1], all[1:])
   977  			},
   978  			want: want(noFlags, 1+lengthIncrementBeyondMetaHeaderFrame, ":method", "GET", ":path", "/", "foo", "bar"),
   979  		},
   980  		2: {
   981  			name: "with_two_continuation",
   982  			w: func(f *Framer) {
   983  				var he hpackEncoder
   984  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", "bar")
   985  				write(f, all[:2], all[2:4], all[4:])
   986  			},
   987  			want: want(noFlags, 2+lengthIncrementBeyondMetaHeaderFrame, ":method", "GET", ":path", "/", "foo", "bar"),
   988  		},
   989  		3: {
   990  			name: "big_string_okay",
   991  			w: func(f *Framer) {
   992  				var he hpackEncoder
   993  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString)
   994  				write(f, all[:2], all[2:])
   995  			},
   996  			want: want(noFlags, 2+lengthIncrementBeyondMetaHeaderFrame, ":method", "GET", ":path", "/", "foo", oneKBString),
   997  		},
   998  		4: {
   999  			name: "big_string_error",
  1000  			w: func(f *Framer) {
  1001  				var he hpackEncoder
  1002  				all := he.encodeHeaderRaw(t, ":method", "GET", ":path", "/", "foo", oneKBString)
  1003  				write(f, all[:2], all[2:])
  1004  			},
  1005  			maxHeaderListSize: (1 << 10) / 2,
  1006  			want:              ConnectionError(ErrCodeCompression),
  1007  		},
  1008  		5: {
  1009  			name: "max_header_list_truncated",
  1010  			w: func(f *Framer) {
  1011  				var he hpackEncoder
  1012  				var pairs = []string{":method", "GET", ":path", "/"}
  1013  				for i := 0; i < 100; i++ {
  1014  					pairs = append(pairs, "foo", "bar")
  1015  				}
  1016  				all := he.encodeHeaderRaw(t, pairs...)
  1017  				write(f, all[:2], all[2:])
  1018  			},
  1019  			maxHeaderListSize: (1 << 10) / 2,
  1020  			want: truncated(want(noFlags, 2+lengthIncrementBeyondMetaHeaderFrame,
  1021  				":method", "GET",
  1022  				":path", "/",
  1023  				"foo", "bar",
  1024  				"foo", "bar",
  1025  				"foo", "bar",
  1026  				"foo", "bar",
  1027  				"foo", "bar",
  1028  				"foo", "bar",
  1029  				"foo", "bar",
  1030  				"foo", "bar",
  1031  				"foo", "bar",
  1032  				"foo", "bar",
  1033  				"foo", "bar", // 11
  1034  			)),
  1035  		},
  1036  		6: {
  1037  			name: "pseudo_order",
  1038  			w: func(f *Framer) {
  1039  				write(f, encodeHeaderRaw(t,
  1040  					":method", "GET",
  1041  					"foo", "bar",
  1042  					":path", "/", // bogus
  1043  				))
  1044  			},
  1045  			want:          streamError(1, ErrCodeProtocol),
  1046  			wantErrReason: "pseudo header field after regular",
  1047  		},
  1048  		7: {
  1049  			name: "pseudo_unknown",
  1050  			w: func(f *Framer) {
  1051  				write(f, encodeHeaderRaw(t,
  1052  					":unknown", "foo", // bogus
  1053  					"foo", "bar",
  1054  				))
  1055  			},
  1056  			want:          streamError(1, ErrCodeProtocol),
  1057  			wantErrReason: "invalid pseudo-header \":unknown\"",
  1058  		},
  1059  		8: {
  1060  			name: "pseudo_mix_request_response",
  1061  			w: func(f *Framer) {
  1062  				write(f, encodeHeaderRaw(t,
  1063  					":method", "GET",
  1064  					":status", "100",
  1065  				))
  1066  			},
  1067  			want:          streamError(1, ErrCodeProtocol),
  1068  			wantErrReason: "mix of request and response pseudo headers",
  1069  		},
  1070  		9: {
  1071  			name: "pseudo_dup",
  1072  			w: func(f *Framer) {
  1073  				write(f, encodeHeaderRaw(t,
  1074  					":method", "GET",
  1075  					":method", "POST",
  1076  				))
  1077  			},
  1078  			want:          streamError(1, ErrCodeProtocol),
  1079  			wantErrReason: "duplicate pseudo-header \":method\"",
  1080  		},
  1081  		10: {
  1082  			name: "trailer_okay_no_pseudo",
  1083  			w:    func(f *Framer) { write(f, encodeHeaderRaw(t, "foo", "bar")) },
  1084  			want: want(flagEndHeaders, 8+lengthIncrementBeyondMetaHeaderFrame, "foo", "bar"),
  1085  		},
  1086  		11: {
  1087  			name:          "invalid_field_name",
  1088  			w:             func(f *Framer) { write(f, encodeHeaderRaw(t, "CapitalBad", "x")) },
  1089  			want:          streamError(1, ErrCodeProtocol),
  1090  			wantErrReason: "invalid header field name \"CapitalBad\"",
  1091  		},
  1092  		12: {
  1093  			name:          "invalid_field_value",
  1094  			w:             func(f *Framer) { write(f, encodeHeaderRaw(t, "key", "bad_null\x00")) },
  1095  			want:          streamError(1, ErrCodeProtocol),
  1096  			wantErrReason: "invalid header field value \"bad_null\\x00\"",
  1097  		},
  1098  	}
  1099  	for i, tt := range tests {
  1100  		buf := new(bytes.Buffer)
  1101  		f := NewFramer(buf, buf)
  1102  		f.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil)
  1103  		f.MaxHeaderListSize = tt.maxHeaderListSize
  1104  		tt.w(f)
  1105  
  1106  		name := tt.name
  1107  		if name == "" {
  1108  			name = fmt.Sprintf("test index %d", i)
  1109  		}
  1110  
  1111  		var got interface{}
  1112  		var err error
  1113  		got, err = f.ReadFrame()
  1114  		if err != nil {
  1115  			got = err
  1116  
  1117  			// Ignore the StreamError.Cause field, if it matches the wantErrReason.
  1118  			// The test table above predates the Cause field.
  1119  			if se, ok := err.(StreamError); ok && se.Cause != nil && se.Cause.Error() == tt.wantErrReason {
  1120  				se.Cause = nil
  1121  				got = se
  1122  			}
  1123  		}
  1124  		if !reflect.DeepEqual(got, tt.want) {
  1125  			headersCmp(t, name, got, want)
  1126  			str := func(v interface{}) string {
  1127  				if _, ok := v.(error); ok {
  1128  					return fmt.Sprintf("error %v", v)
  1129  				} else {
  1130  					return fmt.Sprintf("value %#v", v)
  1131  				}
  1132  			}
  1133  			t.Errorf("%s:\n got: %v\nwant: %s", name, str(got), str(tt.want))
  1134  		}
  1135  		if tt.wantErrReason != "" && tt.wantErrReason != fmt.Sprint(f.errDetail) {
  1136  			t.Errorf("%s: got error reason %q; want %q", name, f.errDetail, tt.wantErrReason)
  1137  		}
  1138  	}
  1139  }
  1140  
  1141  func TestMetaHeaderFrame(t *testing.T) {
  1142  	write := func(f *Framer, frags ...[]byte) {
  1143  		for i, frag := range frags {
  1144  			end := (i == len(frags)-1)
  1145  			if i == 0 {
  1146  				f.WriteHeaders(HeadersFrameParam{
  1147  					StreamID:      1,
  1148  					BlockFragment: frag,
  1149  					EndHeaders:    end,
  1150  				})
  1151  			} else {
  1152  				f.WriteContinuation(1, end, frag)
  1153  			}
  1154  		}
  1155  	}
  1156  	want := func(flags Flags, length uint32, pairs ...string) Frame {
  1157  		mh := &MetaHeadersFrame{
  1158  			HeadersFrame: &HeadersFrame{
  1159  				FrameHeader: FrameHeader{
  1160  					Type:     FrameHeaders,
  1161  					Flags:    flags,
  1162  					Length:   length,
  1163  					StreamID: 1,
  1164  				},
  1165  			},
  1166  			Fields: []hpack.HeaderField(nil),
  1167  		}
  1168  		for len(pairs) > 0 {
  1169  			mh.Fields = append(mh.Fields, hpack.HeaderField{
  1170  				Name:  pairs[0],
  1171  				Value: pairs[1],
  1172  			})
  1173  			pairs = pairs[2:]
  1174  		}
  1175  		return mh
  1176  	}
  1177  	headersCmp := func(t *testing.T, testName string, got, want interface{}) {
  1178  		if mhg, ok := got.(*MetaHeadersFrame); ok {
  1179  			if mhw, ok := want.(*MetaHeadersFrame); ok {
  1180  				hg := mhg.HeadersFrame
  1181  				hw := mhw.HeadersFrame
  1182  				if hg != nil && hw != nil && !reflect.DeepEqual(*hg, *hw) {
  1183  					t.Errorf("%s: headers differ:\n got: %+v\nwant: %+v\n", testName, *hg, *hw)
  1184  				}
  1185  			}
  1186  		}
  1187  	}
  1188  	testMetaFrame(t, write, want, headersCmp, 0)
  1189  }
  1190  func TestMetaPushPromiseFrame(t *testing.T) {
  1191  	write := func(f *Framer, frags ...[]byte) {
  1192  		for i, frag := range frags {
  1193  			end := (i == len(frags)-1)
  1194  			if i == 0 {
  1195  				err := f.WritePushPromise(PushPromiseParam{
  1196  					StreamID:      1,
  1197  					PromiseID:     2,
  1198  					BlockFragment: frag,
  1199  					EndHeaders:    end,
  1200  				})
  1201  				if err != nil {
  1202  					t.Error(err)
  1203  				}
  1204  			} else {
  1205  				f.WriteContinuation(1, end, frag)
  1206  			}
  1207  		}
  1208  	}
  1209  	want := func(flags Flags, length uint32, pairs ...string) Frame {
  1210  		mh := &MetaPushPromiseFrame{
  1211  			PushPromiseFrame: &PushPromiseFrame{
  1212  				FrameHeader: FrameHeader{
  1213  					Type:     FramePushPromise,
  1214  					Flags:    flags,
  1215  					Length:   length,
  1216  					StreamID: 1,
  1217  				},
  1218  				PromiseID: 2,
  1219  			},
  1220  			Fields: []hpack.HeaderField(nil),
  1221  		}
  1222  		for len(pairs) > 0 {
  1223  			mh.Fields = append(mh.Fields, hpack.HeaderField{
  1224  				Name:  pairs[0],
  1225  				Value: pairs[1],
  1226  			})
  1227  			pairs = pairs[2:]
  1228  		}
  1229  		return mh
  1230  	}
  1231  	headersCmp := func(t *testing.T, testName string, got, want interface{}) {
  1232  		if mhg, ok := got.(*MetaPushPromiseFrame); ok {
  1233  			if mhw, ok := want.(*MetaPushPromiseFrame); ok {
  1234  				hg := mhg.PushPromiseFrame
  1235  				hw := mhw.PushPromiseFrame
  1236  				if hg != nil && hw != nil && !reflect.DeepEqual(*hg, *hw) {
  1237  					t.Errorf("%s: headers differ:\n got: %+v\nwant: %+v\n", testName, *hg, *hw)
  1238  				}
  1239  			}
  1240  		}
  1241  	}
  1242  	testMetaFrame(t, write, want, headersCmp, 4)
  1243  }
  1244  
  1245  func TestSetReuseFrames(t *testing.T) {
  1246  	fr, buf := testFramer()
  1247  	fr.SetReuseFrames()
  1248  
  1249  	// Check that DataFrames are reused. Note that
  1250  	// SetReuseFrames only currently implements reuse of DataFrames.
  1251  	firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t)
  1252  
  1253  	for i := 0; i < 10; i++ {
  1254  		df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
  1255  		if df != firstDf {
  1256  			t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
  1257  		}
  1258  	}
  1259  
  1260  	for i := 0; i < 10; i++ {
  1261  		df := readAndVerifyDataFrame("", 0, fr, buf, t)
  1262  		if df != firstDf {
  1263  			t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
  1264  		}
  1265  	}
  1266  
  1267  	for i := 0; i < 10; i++ {
  1268  		df := readAndVerifyDataFrame("HHH", 3, fr, buf, t)
  1269  		if df != firstDf {
  1270  			t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
  1271  		}
  1272  	}
  1273  }
  1274  
  1275  func TestSetReuseFramesMoreThanOnce(t *testing.T) {
  1276  	fr, buf := testFramer()
  1277  	fr.SetReuseFrames()
  1278  
  1279  	firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t)
  1280  	fr.SetReuseFrames()
  1281  
  1282  	for i := 0; i < 10; i++ {
  1283  		df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
  1284  		// SetReuseFrames should be idempotent
  1285  		fr.SetReuseFrames()
  1286  		if df != firstDf {
  1287  			t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
  1288  		}
  1289  	}
  1290  }
  1291  
  1292  func TestNoSetReuseFrames(t *testing.T) {
  1293  	fr, buf := testFramer()
  1294  	const numNewDataFrames = 10
  1295  	dfSoFar := make([]interface{}, numNewDataFrames)
  1296  
  1297  	// Check that DataFrames are not reused if SetReuseFrames wasn't called.
  1298  	// SetReuseFrames only currently implements reuse of DataFrames.
  1299  	for i := 0; i < numNewDataFrames; i++ {
  1300  		df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
  1301  		for _, item := range dfSoFar {
  1302  			if df == item {
  1303  				t.Errorf("Expected Framer to return new DataFrames since SetNoReuseFrames not set.")
  1304  			}
  1305  		}
  1306  		dfSoFar[i] = df
  1307  	}
  1308  }
  1309  
  1310  func readAndVerifyDataFrame(data string, length byte, fr *Framer, buf *bytes.Buffer, t *testing.T) *DataFrame {
  1311  	var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
  1312  	fr.WriteData(streamID, true, []byte(data))
  1313  	wantEnc := "\x00\x00" + string(length) + "\x00\x01\x01\x02\x03\x04" + data
  1314  	if buf.String() != wantEnc {
  1315  		t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
  1316  	}
  1317  	f, err := fr.ReadFrame()
  1318  	if err != nil {
  1319  		t.Fatal(err)
  1320  	}
  1321  	df, ok := f.(*DataFrame)
  1322  	if !ok {
  1323  		t.Fatalf("got %T; want *DataFrame", f)
  1324  	}
  1325  	if !bytes.Equal(df.Data(), []byte(data)) {
  1326  		t.Errorf("got %q; want %q", df.Data(), []byte(data))
  1327  	}
  1328  	if f.Header().Flags&1 == 0 {
  1329  		t.Errorf("didn't see END_STREAM flag")
  1330  	}
  1331  	return df
  1332  }
  1333  
  1334  func encodeHeaderRaw(t *testing.T, pairs ...string) []byte {
  1335  	var he hpackEncoder
  1336  	return he.encodeHeaderRaw(t, pairs...)
  1337  }
  1338  
  1339  func TestSettingsDuplicates(t *testing.T) {
  1340  	tests := []struct {
  1341  		settings []Setting
  1342  		want     bool
  1343  	}{
  1344  		{nil, false},
  1345  		{[]Setting{{ID: 1}}, false},
  1346  		{[]Setting{{ID: 1}, {ID: 2}}, false},
  1347  		{[]Setting{{ID: 1}, {ID: 2}}, false},
  1348  		{[]Setting{{ID: 1}, {ID: 2}, {ID: 3}}, false},
  1349  		{[]Setting{{ID: 1}, {ID: 2}, {ID: 3}}, false},
  1350  		{[]Setting{{ID: 1}, {ID: 2}, {ID: 3}, {ID: 4}}, false},
  1351  
  1352  		{[]Setting{{ID: 1}, {ID: 2}, {ID: 3}, {ID: 2}}, true},
  1353  		{[]Setting{{ID: 4}, {ID: 2}, {ID: 3}, {ID: 4}}, true},
  1354  
  1355  		{[]Setting{
  1356  			{ID: 1}, {ID: 2}, {ID: 3}, {ID: 4},
  1357  			{ID: 5}, {ID: 6}, {ID: 7}, {ID: 8},
  1358  			{ID: 9}, {ID: 10}, {ID: 11}, {ID: 12},
  1359  		}, false},
  1360  
  1361  		{[]Setting{
  1362  			{ID: 1}, {ID: 2}, {ID: 3}, {ID: 4},
  1363  			{ID: 5}, {ID: 6}, {ID: 7}, {ID: 8},
  1364  			{ID: 9}, {ID: 10}, {ID: 11}, {ID: 11},
  1365  		}, true},
  1366  	}
  1367  	for i, tt := range tests {
  1368  		fr, _ := testFramer()
  1369  		fr.WriteSettings(tt.settings...)
  1370  		f, err := fr.ReadFrame()
  1371  		if err != nil {
  1372  			t.Fatalf("%d. ReadFrame: %v", i, err)
  1373  		}
  1374  		sf := f.(*SettingsFrame)
  1375  		got := sf.HasDuplicates()
  1376  		if got != tt.want {
  1377  			t.Errorf("%d. HasDuplicates = %v; want %v", i, got, tt.want)
  1378  		}
  1379  	}
  1380  
  1381  }