1
2
3
4
5 package http2
6
7 import (
8 "bytes"
9 "flag"
10 "fmt"
11 "net/http"
12 "os"
13 "path/filepath"
14 "regexp"
15 "strings"
16 "testing"
17 "time"
18
19 "golang.org/x/net/http2/hpack"
20 )
21
22 var knownFailing = flag.Bool("known_failing", false, "Run known-failing tests.")
23
24 func condSkipFailingTest(t *testing.T) {
25 if !*knownFailing {
26 t.Skip("Skipping known-failing test without --known_failing")
27 }
28 }
29
30 func init() {
31 inTests = true
32 DebugGoroutines = true
33 flag.BoolVar(&VerboseLogs, "verboseh2", VerboseLogs, "Verbose HTTP/2 debug logging")
34 }
35
36 func TestSettingString(t *testing.T) {
37 tests := []struct {
38 s Setting
39 want string
40 }{
41 {Setting{SettingMaxFrameSize, 123}, "[MAX_FRAME_SIZE = 123]"},
42 {Setting{1<<16 - 1, 123}, "[UNKNOWN_SETTING_65535 = 123]"},
43 }
44 for i, tt := range tests {
45 got := fmt.Sprint(tt.s)
46 if got != tt.want {
47 t.Errorf("%d. for %#v, string = %q; want %q", i, tt.s, got, tt.want)
48 }
49 }
50 }
51
52 type twriter struct {
53 t testing.TB
54 st *serverTester
55 }
56
57 func (w twriter) Write(p []byte) (n int, err error) {
58 if w.st != nil {
59 ps := string(p)
60 for _, phrase := range w.st.logFilter {
61 if strings.Contains(ps, phrase) {
62 return len(p), nil
63 }
64 }
65 }
66 w.t.Logf("%s", p)
67 return len(p), nil
68 }
69
70
71 func encodeHeaderNoImplicit(t *testing.T, headers ...string) []byte {
72 var buf bytes.Buffer
73 enc := hpack.NewEncoder(&buf)
74 for len(headers) > 0 {
75 k, v := headers[0], headers[1]
76 headers = headers[2:]
77 if err := enc.WriteField(hpack.HeaderField{Name: k, Value: v}); err != nil {
78 t.Fatalf("HPACK encoding error for %q/%q: %v", k, v, err)
79 }
80 }
81 return buf.Bytes()
82 }
83
84 type puppetCommand struct {
85 fn func(w http.ResponseWriter, r *http.Request)
86 done chan<- bool
87 }
88
89 type handlerPuppet struct {
90 ch chan puppetCommand
91 }
92
93 func newHandlerPuppet() *handlerPuppet {
94 return &handlerPuppet{
95 ch: make(chan puppetCommand),
96 }
97 }
98
99 func (p *handlerPuppet) act(w http.ResponseWriter, r *http.Request) {
100 for cmd := range p.ch {
101 cmd.fn(w, r)
102 cmd.done <- true
103 }
104 }
105
106 func (p *handlerPuppet) done() { close(p.ch) }
107 func (p *handlerPuppet) do(fn func(http.ResponseWriter, *http.Request)) {
108 done := make(chan bool)
109 p.ch <- puppetCommand{fn, done}
110 <-done
111 }
112
113 func cleanDate(res *http.Response) {
114 if d := res.Header["Date"]; len(d) == 1 {
115 d[0] = "XXX"
116 }
117 }
118
119 func TestSorterPoolAllocs(t *testing.T) {
120 ss := []string{"a", "b", "c"}
121 h := http.Header{
122 "a": nil,
123 "b": nil,
124 "c": nil,
125 }
126 sorter := new(sorter)
127
128 if allocs := testing.AllocsPerRun(100, func() {
129 sorter.SortStrings(ss)
130 }); allocs >= 1 {
131 t.Logf("SortStrings allocs = %v; want <1", allocs)
132 }
133
134 if allocs := testing.AllocsPerRun(5, func() {
135 if len(sorter.Keys(h)) != 3 {
136 t.Fatal("wrong result")
137 }
138 }); allocs > 0 {
139 t.Logf("Keys allocs = %v; want <1", allocs)
140 }
141 }
142
143
144
145
146 func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
147 deadline := time.Now().Add(waitFor)
148 for time.Now().Before(deadline) {
149 if fn() {
150 return true
151 }
152 time.Sleep(checkEvery)
153 }
154 return false
155 }
156
157
158 func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
159 deadline := time.Now().Add(waitFor)
160 var err error
161 for time.Now().Before(deadline) {
162 if err = fn(); err == nil {
163 return nil
164 }
165 time.Sleep(checkEvery)
166 }
167 return err
168 }
169
170 func equalError(a, b error) bool {
171 if a == nil {
172 return b == nil
173 }
174 if b == nil {
175 return a == nil
176 }
177 return a.Error() == b.Error()
178 }
179
180
181
182
183 func TestConfigureServerIdleTimeout_Go18(t *testing.T) {
184 const timeout = 5 * time.Second
185 const notThisOne = 1 * time.Second
186
187
188 {
189 s1 := &http.Server{
190 IdleTimeout: timeout,
191 ReadTimeout: notThisOne,
192 }
193 s2 := &Server{}
194 if err := ConfigureServer(s1, s2); err != nil {
195 t.Fatal(err)
196 }
197 if s2.IdleTimeout != timeout {
198 t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
199 }
200 }
201
202
203 {
204 s1 := &http.Server{
205 ReadTimeout: timeout,
206 }
207 s2 := &Server{}
208 if err := ConfigureServer(s1, s2); err != nil {
209 t.Fatal(err)
210 }
211 if s2.IdleTimeout != timeout {
212 t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
213 }
214 }
215
216
217 {
218 s1 := &http.Server{
219 IdleTimeout: notThisOne,
220 }
221 s2 := &Server{
222 IdleTimeout: timeout,
223 }
224 if err := ConfigureServer(s1, s2); err != nil {
225 t.Fatal(err)
226 }
227 if s2.IdleTimeout != timeout {
228 t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
229 }
230 }
231 }
232
233 var forbiddenStringsFunctions = map[string]bool{
234
235 "EqualFold": true,
236 "Title": true,
237 "ToLower": true,
238 "ToLowerSpecial": true,
239 "ToTitle": true,
240 "ToTitleSpecial": true,
241 "ToUpper": true,
242 "ToUpperSpecial": true,
243
244
245 "Fields": true,
246 "TrimSpace": true,
247 }
248
249
250
251
252 func TestNoUnicodeStrings(t *testing.T) {
253 re := regexp.MustCompile(`(strings|bytes).([A-Za-z]+)`)
254 if err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
255 if err != nil {
256 t.Fatal(err)
257 }
258
259 if path == "h2i" || path == "h2c" {
260 return filepath.SkipDir
261 }
262 if !strings.HasSuffix(path, ".go") ||
263 strings.HasSuffix(path, "_test.go") ||
264 path == "ascii.go" || info.IsDir() {
265 return nil
266 }
267
268 contents, err := os.ReadFile(path)
269 if err != nil {
270 t.Fatal(err)
271 }
272 for lineNum, line := range strings.Split(string(contents), "\n") {
273 for _, match := range re.FindAllStringSubmatch(line, -1) {
274 if !forbiddenStringsFunctions[match[2]] {
275 continue
276 }
277 t.Errorf("disallowed call to %s at %s:%d", match[0], path, lineNum+1)
278 }
279 }
280
281 return nil
282 }); err != nil {
283 t.Fatal(err)
284 }
285 }
286
287
288 func must[T any](v T, err error) T {
289 if err != nil {
290 panic(err)
291 }
292 return v
293 }
294
View as plain text