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 }