github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/http2/hpack/tables_test.go (about) 1 // Copyright 2017 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 "bufio" 9 "regexp" 10 "strconv" 11 "strings" 12 "testing" 13 ) 14 15 func TestHeaderFieldTable(t *testing.T) { 16 table := &headerFieldTable{} 17 table.init() 18 table.addEntry(pair("key1", "value1-1")) 19 table.addEntry(pair("key2", "value2-1")) 20 table.addEntry(pair("key1", "value1-2")) 21 table.addEntry(pair("key3", "value3-1")) 22 table.addEntry(pair("key4", "value4-1")) 23 table.addEntry(pair("key2", "value2-2")) 24 25 // Tests will be run twice: once before evicting anything, and 26 // again after evicting the three oldest entries. 27 tests := []struct { 28 f HeaderField 29 beforeWantStaticI uint64 30 beforeWantMatch bool 31 afterWantStaticI uint64 32 afterWantMatch bool 33 }{ 34 {HeaderField{"key1", "value1-1", false}, 1, true, 0, false}, 35 {HeaderField{"key1", "value1-2", false}, 3, true, 0, false}, 36 {HeaderField{"key1", "value1-3", false}, 3, false, 0, false}, 37 {HeaderField{"key2", "value2-1", false}, 2, true, 3, false}, 38 {HeaderField{"key2", "value2-2", false}, 6, true, 3, true}, 39 {HeaderField{"key2", "value2-3", false}, 6, false, 3, false}, 40 {HeaderField{"key4", "value4-1", false}, 5, true, 2, true}, 41 // Name match only, because sensitive. 42 {HeaderField{"key4", "value4-1", true}, 5, false, 2, false}, 43 // Key not found. 44 {HeaderField{"key5", "value5-x", false}, 0, false, 0, false}, 45 } 46 47 staticToDynamic := func(i uint64) uint64 { 48 if i == 0 { 49 return 0 50 } 51 return uint64(table.len()) - i + 1 // dynamic is the reversed table 52 } 53 54 searchStatic := func(f HeaderField) (uint64, bool) { 55 old := staticTable 56 staticTable = table 57 defer func() { staticTable = old }() 58 return staticTable.search(f) 59 } 60 61 searchDynamic := func(f HeaderField) (uint64, bool) { 62 return table.search(f) 63 } 64 65 for _, test := range tests { 66 gotI, gotMatch := searchStatic(test.f) 67 if wantI, wantMatch := test.beforeWantStaticI, test.beforeWantMatch; gotI != wantI || gotMatch != wantMatch { 68 t.Errorf("before evictions: searchStatic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch) 69 } 70 gotI, gotMatch = searchDynamic(test.f) 71 wantDynamicI := staticToDynamic(test.beforeWantStaticI) 72 if wantI, wantMatch := wantDynamicI, test.beforeWantMatch; gotI != wantI || gotMatch != wantMatch { 73 t.Errorf("before evictions: searchDynamic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch) 74 } 75 } 76 77 table.evictOldest(3) 78 79 for _, test := range tests { 80 gotI, gotMatch := searchStatic(test.f) 81 if wantI, wantMatch := test.afterWantStaticI, test.afterWantMatch; gotI != wantI || gotMatch != wantMatch { 82 t.Errorf("after evictions: searchStatic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch) 83 } 84 gotI, gotMatch = searchDynamic(test.f) 85 wantDynamicI := staticToDynamic(test.afterWantStaticI) 86 if wantI, wantMatch := wantDynamicI, test.afterWantMatch; gotI != wantI || gotMatch != wantMatch { 87 t.Errorf("after evictions: searchDynamic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch) 88 } 89 } 90 } 91 92 func TestHeaderFieldTable_LookupMapEviction(t *testing.T) { 93 table := &headerFieldTable{} 94 table.init() 95 table.addEntry(pair("key1", "value1-1")) 96 table.addEntry(pair("key2", "value2-1")) 97 table.addEntry(pair("key1", "value1-2")) 98 table.addEntry(pair("key3", "value3-1")) 99 table.addEntry(pair("key4", "value4-1")) 100 table.addEntry(pair("key2", "value2-2")) 101 102 // evict all pairs 103 table.evictOldest(table.len()) 104 105 if l := table.len(); l > 0 { 106 t.Errorf("table.len() = %d, want 0", l) 107 } 108 109 if l := len(table.byName); l > 0 { 110 t.Errorf("len(table.byName) = %d, want 0", l) 111 } 112 113 if l := len(table.byNameValue); l > 0 { 114 t.Errorf("len(table.byNameValue) = %d, want 0", l) 115 } 116 } 117 118 func TestStaticTable(t *testing.T) { 119 fromSpec := ` 120 +-------+-----------------------------+---------------+ 121 | 1 | :authority | | 122 | 2 | :method | GET | 123 | 3 | :method | POST | 124 | 4 | :path | / | 125 | 5 | :path | /index.html | 126 | 6 | :scheme | http | 127 | 7 | :scheme | https | 128 | 8 | :status | 200 | 129 | 9 | :status | 204 | 130 | 10 | :status | 206 | 131 | 11 | :status | 304 | 132 | 12 | :status | 400 | 133 | 13 | :status | 404 | 134 | 14 | :status | 500 | 135 | 15 | accept-charset | | 136 | 16 | accept-encoding | gzip, deflate | 137 | 17 | accept-language | | 138 | 18 | accept-ranges | | 139 | 19 | accept | | 140 | 20 | access-control-allow-origin | | 141 | 21 | age | | 142 | 22 | allow | | 143 | 23 | authorization | | 144 | 24 | cache-control | | 145 | 25 | content-disposition | | 146 | 26 | content-encoding | | 147 | 27 | content-language | | 148 | 28 | content-length | | 149 | 29 | content-location | | 150 | 30 | content-range | | 151 | 31 | content-type | | 152 | 32 | cookie | | 153 | 33 | date | | 154 | 34 | etag | | 155 | 35 | expect | | 156 | 36 | expires | | 157 | 37 | from | | 158 | 38 | host | | 159 | 39 | if-match | | 160 | 40 | if-modified-since | | 161 | 41 | if-none-match | | 162 | 42 | if-range | | 163 | 43 | if-unmodified-since | | 164 | 44 | last-modified | | 165 | 45 | link | | 166 | 46 | location | | 167 | 47 | max-forwards | | 168 | 48 | proxy-authenticate | | 169 | 49 | proxy-authorization | | 170 | 50 | range | | 171 | 51 | referer | | 172 | 52 | refresh | | 173 | 53 | retry-after | | 174 | 54 | server | | 175 | 55 | set-cookie | | 176 | 56 | strict-transport-security | | 177 | 57 | transfer-encoding | | 178 | 58 | user-agent | | 179 | 59 | vary | | 180 | 60 | via | | 181 | 61 | www-authenticate | | 182 +-------+-----------------------------+---------------+ 183 ` 184 bs := bufio.NewScanner(strings.NewReader(fromSpec)) 185 re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`) 186 for bs.Scan() { 187 l := bs.Text() 188 if !strings.Contains(l, "|") { 189 continue 190 } 191 m := re.FindStringSubmatch(l) 192 if m == nil { 193 continue 194 } 195 i, err := strconv.Atoi(m[1]) 196 if err != nil { 197 t.Errorf("Bogus integer on line %q", l) 198 continue 199 } 200 if i < 1 || i > staticTable.len() { 201 t.Errorf("Bogus index %d on line %q", i, l) 202 continue 203 } 204 if got, want := staticTable.ents[i-1].Name, m[2]; got != want { 205 t.Errorf("header index %d name = %q; want %q", i, got, want) 206 } 207 if got, want := staticTable.ents[i-1].Value, m[3]; got != want { 208 t.Errorf("header index %d value = %q; want %q", i, got, want) 209 } 210 } 211 if err := bs.Err(); err != nil { 212 t.Error(err) 213 } 214 }