github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/http2/hpack/encode_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 hpack
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/hex"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  )
    14  
    15  func TestEncoderTableSizeUpdate(t *testing.T) {
    16  	tests := []struct {
    17  		size1, size2 uint32
    18  		wantHex      string
    19  	}{
    20  		// Should emit 2 table size updates (2048 and 4096)
    21  		{2048, 4096, "3fe10f 3fe11f 82"},
    22  
    23  		// Should emit 1 table size update (2048)
    24  		{16384, 2048, "3fe10f 82"},
    25  	}
    26  	for _, tt := range tests {
    27  		var buf bytes.Buffer
    28  		e := NewEncoder(&buf)
    29  		e.SetMaxDynamicTableSize(tt.size1)
    30  		e.SetMaxDynamicTableSize(tt.size2)
    31  		if err := e.WriteField(pair(":method", "GET")); err != nil {
    32  			t.Fatal(err)
    33  		}
    34  		want := removeSpace(tt.wantHex)
    35  		if got := hex.EncodeToString(buf.Bytes()); got != want {
    36  			t.Errorf("e.SetDynamicTableSize %v, %v = %q; want %q", tt.size1, tt.size2, got, want)
    37  		}
    38  	}
    39  }
    40  
    41  func TestEncoderWriteField(t *testing.T) {
    42  	var buf bytes.Buffer
    43  	e := NewEncoder(&buf)
    44  	var got []HeaderField
    45  	d := NewDecoder(4<<10, func(f HeaderField) {
    46  		got = append(got, f)
    47  	})
    48  
    49  	tests := []struct {
    50  		hdrs []HeaderField
    51  	}{
    52  		{[]HeaderField{
    53  			pair(":method", "GET"),
    54  			pair(":scheme", "http"),
    55  			pair(":path", "/"),
    56  			pair(":authority", "www.example.com"),
    57  		}},
    58  		{[]HeaderField{
    59  			pair(":method", "GET"),
    60  			pair(":scheme", "http"),
    61  			pair(":path", "/"),
    62  			pair(":authority", "www.example.com"),
    63  			pair("cache-control", "no-cache"),
    64  		}},
    65  		{[]HeaderField{
    66  			pair(":method", "GET"),
    67  			pair(":scheme", "https"),
    68  			pair(":path", "/index.html"),
    69  			pair(":authority", "www.example.com"),
    70  			pair("custom-key", "custom-value"),
    71  		}},
    72  	}
    73  	for i, tt := range tests {
    74  		buf.Reset()
    75  		got = got[:0]
    76  		for _, hf := range tt.hdrs {
    77  			if err := e.WriteField(hf); err != nil {
    78  				t.Fatal(err)
    79  			}
    80  		}
    81  		_, err := d.Write(buf.Bytes())
    82  		if err != nil {
    83  			t.Errorf("%d. Decoder Write = %v", i, err)
    84  		}
    85  		if !reflect.DeepEqual(got, tt.hdrs) {
    86  			t.Errorf("%d. Decoded %+v; want %+v", i, got, tt.hdrs)
    87  		}
    88  	}
    89  }
    90  
    91  func TestEncoderSearchTable(t *testing.T) {
    92  	e := NewEncoder(nil)
    93  
    94  	e.dynTab.add(pair("foo", "bar"))
    95  	e.dynTab.add(pair("blake", "miz"))
    96  	e.dynTab.add(pair(":method", "GET"))
    97  
    98  	tests := []struct {
    99  		hf        HeaderField
   100  		wantI     uint64
   101  		wantMatch bool
   102  	}{
   103  		// Name and Value match
   104  		{pair("foo", "bar"), uint64(len(staticTable) + 3), true},
   105  		{pair("blake", "miz"), uint64(len(staticTable) + 2), true},
   106  		{pair(":method", "GET"), 2, true},
   107  
   108  		// Only name match because Sensitive == true
   109  		{HeaderField{":method", "GET", true}, 2, false},
   110  
   111  		// Only Name matches
   112  		{pair("foo", "..."), uint64(len(staticTable) + 3), false},
   113  		{pair("blake", "..."), uint64(len(staticTable) + 2), false},
   114  		{pair(":method", "..."), 2, false},
   115  
   116  		// None match
   117  		{pair("foo-", "bar"), 0, false},
   118  	}
   119  	for _, tt := range tests {
   120  		if gotI, gotMatch := e.searchTable(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
   121  			t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
   122  		}
   123  	}
   124  }
   125  
   126  func TestAppendVarInt(t *testing.T) {
   127  	tests := []struct {
   128  		n    byte
   129  		i    uint64
   130  		want []byte
   131  	}{
   132  		// Fits in a byte:
   133  		{1, 0, []byte{0}},
   134  		{2, 2, []byte{2}},
   135  		{3, 6, []byte{6}},
   136  		{4, 14, []byte{14}},
   137  		{5, 30, []byte{30}},
   138  		{6, 62, []byte{62}},
   139  		{7, 126, []byte{126}},
   140  		{8, 254, []byte{254}},
   141  
   142  		// Multiple bytes:
   143  		{5, 1337, []byte{31, 154, 10}},
   144  	}
   145  	for _, tt := range tests {
   146  		got := appendVarInt(nil, tt.n, tt.i)
   147  		if !bytes.Equal(got, tt.want) {
   148  			t.Errorf("appendVarInt(nil, %v, %v) = %v; want %v", tt.n, tt.i, got, tt.want)
   149  		}
   150  	}
   151  }
   152  
   153  func TestAppendHpackString(t *testing.T) {
   154  	tests := []struct {
   155  		s, wantHex string
   156  	}{
   157  		// Huffman encoded
   158  		{"www.example.com", "8c f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
   159  
   160  		// Not Huffman encoded
   161  		{"a", "01 61"},
   162  
   163  		// zero length
   164  		{"", "00"},
   165  	}
   166  	for _, tt := range tests {
   167  		want := removeSpace(tt.wantHex)
   168  		buf := appendHpackString(nil, tt.s)
   169  		if got := hex.EncodeToString(buf); want != got {
   170  			t.Errorf("appendHpackString(nil, %q) = %q; want %q", tt.s, got, want)
   171  		}
   172  	}
   173  }
   174  
   175  func TestAppendIndexed(t *testing.T) {
   176  	tests := []struct {
   177  		i       uint64
   178  		wantHex string
   179  	}{
   180  		// 1 byte
   181  		{1, "81"},
   182  		{126, "fe"},
   183  
   184  		// 2 bytes
   185  		{127, "ff00"},
   186  		{128, "ff01"},
   187  	}
   188  	for _, tt := range tests {
   189  		want := removeSpace(tt.wantHex)
   190  		buf := appendIndexed(nil, tt.i)
   191  		if got := hex.EncodeToString(buf); want != got {
   192  			t.Errorf("appendIndex(nil, %v) = %q; want %q", tt.i, got, want)
   193  		}
   194  	}
   195  }
   196  
   197  func TestAppendNewName(t *testing.T) {
   198  	tests := []struct {
   199  		f        HeaderField
   200  		indexing bool
   201  		wantHex  string
   202  	}{
   203  		// Incremental indexing
   204  		{HeaderField{"custom-key", "custom-value", false}, true, "40 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
   205  
   206  		// Without indexing
   207  		{HeaderField{"custom-key", "custom-value", false}, false, "00 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
   208  
   209  		// Never indexed
   210  		{HeaderField{"custom-key", "custom-value", true}, true, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
   211  		{HeaderField{"custom-key", "custom-value", true}, false, "10 88 25a8 49e9 5ba9 7d7f 89 25a8 49e9 5bb8 e8b4 bf"},
   212  	}
   213  	for _, tt := range tests {
   214  		want := removeSpace(tt.wantHex)
   215  		buf := appendNewName(nil, tt.f, tt.indexing)
   216  		if got := hex.EncodeToString(buf); want != got {
   217  			t.Errorf("appendNewName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want)
   218  		}
   219  	}
   220  }
   221  
   222  func TestAppendIndexedName(t *testing.T) {
   223  	tests := []struct {
   224  		f        HeaderField
   225  		i        uint64
   226  		indexing bool
   227  		wantHex  string
   228  	}{
   229  		// Incremental indexing
   230  		{HeaderField{":status", "302", false}, 8, true, "48 82 6402"},
   231  
   232  		// Without indexing
   233  		{HeaderField{":status", "302", false}, 8, false, "08 82 6402"},
   234  
   235  		// Never indexed
   236  		{HeaderField{":status", "302", true}, 8, true, "18 82 6402"},
   237  		{HeaderField{":status", "302", true}, 8, false, "18 82 6402"},
   238  	}
   239  	for _, tt := range tests {
   240  		want := removeSpace(tt.wantHex)
   241  		buf := appendIndexedName(nil, tt.f, tt.i, tt.indexing)
   242  		if got := hex.EncodeToString(buf); want != got {
   243  			t.Errorf("appendIndexedName(nil, %+v, %v) = %q; want %q", tt.f, tt.indexing, got, want)
   244  		}
   245  	}
   246  }
   247  
   248  func TestAppendTableSize(t *testing.T) {
   249  	tests := []struct {
   250  		i       uint32
   251  		wantHex string
   252  	}{
   253  		// Fits into 1 byte
   254  		{30, "3e"},
   255  
   256  		// Extra byte
   257  		{31, "3f00"},
   258  		{32, "3f01"},
   259  	}
   260  	for _, tt := range tests {
   261  		want := removeSpace(tt.wantHex)
   262  		buf := appendTableSize(nil, tt.i)
   263  		if got := hex.EncodeToString(buf); want != got {
   264  			t.Errorf("appendTableSize(nil, %v) = %q; want %q", tt.i, got, want)
   265  		}
   266  	}
   267  }
   268  
   269  func TestEncoderSetMaxDynamicTableSize(t *testing.T) {
   270  	var buf bytes.Buffer
   271  	e := NewEncoder(&buf)
   272  	tests := []struct {
   273  		v           uint32
   274  		wantUpdate  bool
   275  		wantMinSize uint32
   276  		wantMaxSize uint32
   277  	}{
   278  		// Set new table size to 2048
   279  		{2048, true, 2048, 2048},
   280  
   281  		// Set new table size to 16384, but still limited to
   282  		// 4096
   283  		{16384, true, 2048, 4096},
   284  	}
   285  	for _, tt := range tests {
   286  		e.SetMaxDynamicTableSize(tt.v)
   287  		if got := e.tableSizeUpdate; tt.wantUpdate != got {
   288  			t.Errorf("e.tableSizeUpdate = %v; want %v", got, tt.wantUpdate)
   289  		}
   290  		if got := e.minSize; tt.wantMinSize != got {
   291  			t.Errorf("e.minSize = %v; want %v", got, tt.wantMinSize)
   292  		}
   293  		if got := e.dynTab.maxSize; tt.wantMaxSize != got {
   294  			t.Errorf("e.maxSize = %v; want %v", got, tt.wantMaxSize)
   295  		}
   296  	}
   297  }
   298  
   299  func TestEncoderSetMaxDynamicTableSizeLimit(t *testing.T) {
   300  	e := NewEncoder(nil)
   301  	// 4095 < initialHeaderTableSize means maxSize is truncated to
   302  	// 4095.
   303  	e.SetMaxDynamicTableSizeLimit(4095)
   304  	if got, want := e.dynTab.maxSize, uint32(4095); got != want {
   305  		t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
   306  	}
   307  	if got, want := e.maxSizeLimit, uint32(4095); got != want {
   308  		t.Errorf("e.maxSizeLimit = %v; want %v", got, want)
   309  	}
   310  	if got, want := e.tableSizeUpdate, true; got != want {
   311  		t.Errorf("e.tableSizeUpdate = %v; want %v", got, want)
   312  	}
   313  	// maxSize will be truncated to maxSizeLimit
   314  	e.SetMaxDynamicTableSize(16384)
   315  	if got, want := e.dynTab.maxSize, uint32(4095); got != want {
   316  		t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
   317  	}
   318  	// 8192 > current maxSizeLimit, so maxSize does not change.
   319  	e.SetMaxDynamicTableSizeLimit(8192)
   320  	if got, want := e.dynTab.maxSize, uint32(4095); got != want {
   321  		t.Errorf("e.dynTab.maxSize = %v; want %v", got, want)
   322  	}
   323  	if got, want := e.maxSizeLimit, uint32(8192); got != want {
   324  		t.Errorf("e.maxSizeLimit = %v; want %v", got, want)
   325  	}
   326  }
   327  
   328  func removeSpace(s string) string {
   329  	return strings.Replace(s, " ", "", -1)
   330  }