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.
15 func TestHeaderFieldTable(t
*testing
.T
) {
16 table
:= &headerFieldTable
{}
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"))
25 // Tests will be run twice: once before evicting anything, and
26 // again after evicting the three oldest entries.
29 beforeWantStaticI
uint64
31 afterWantStaticI
uint64
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},
44 {HeaderField
{"key5", "value5-x", false}, 0, false, 0, false},
47 staticToDynamic
:= func(i
uint64) uint64 {
51 return uint64(table
.len()) - i
+ 1 // dynamic is the reversed table
54 searchStatic
:= func(f HeaderField
) (uint64, bool) {
57 defer func() { staticTable
= old
}()
58 return staticTable
.search(f
)
61 searchDynamic
:= func(f HeaderField
) (uint64, bool) {
62 return table
.search(f
)
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
)
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
)
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
)
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
)
92 func TestHeaderFieldTable_LookupMapEviction(t
*testing
.T
) {
93 table
:= &headerFieldTable
{}
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"))
103 table
.evictOldest(table
.len())
105 if l
:= table
.len(); l
> 0 {
106 t
.Errorf("table.len() = %d, want 0", l
)
109 if l
:= len(table
.byName
); l
> 0 {
110 t
.Errorf("len(table.byName) = %d, want 0", l
)
113 if l
:= len(table
.byNameValue
); l
> 0 {
114 t
.Errorf("len(table.byNameValue) = %d, want 0", l
)
118 func TestStaticTable(t
*testing
.T
) {
120 +-------+-----------------------------+---------------+
122 | 2 | :method | GET |
123 | 3 | :method | POST |
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 | |
140 | 20 | access-control-allow-origin | |
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 | |
160 | 40 | if-modified-since | |
161 | 41 | if-none-match | |
163 | 43 | if-unmodified-since | |
164 | 44 | last-modified | |
167 | 47 | max-forwards | |
168 | 48 | proxy-authenticate | |
169 | 49 | proxy-authorization | |
173 | 53 | retry-after | |
175 | 55 | set-cookie | |
176 | 56 | strict-transport-security | |
177 | 57 | transfer-encoding | |
178 | 58 | user-agent | |
181 | 61 | www-authenticate | |
182 +-------+-----------------------------+---------------+
184 bs
:= bufio
.NewScanner(strings
.NewReader(fromSpec
))
185 re
:= regexp
.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
188 if !strings
.Contains(l
, "|") {
191 m
:= re
.FindStringSubmatch(l
)
195 i
, err
:= strconv
.Atoi(m
[1])
197 t
.Errorf("Bogus integer on line %q", l
)
200 if i
< 1 || i
> staticTable
.len() {
201 t
.Errorf("Bogus index %d on line %q", i
, l
)
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
)
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
)
211 if err
:= bs
.Err(); err
!= nil {