Source file
src/net/http/http_test.go
1
2
3
4
5
6
7 package http
8
9 import (
10 "bytes"
11 "internal/testenv"
12 "io/fs"
13 "net/url"
14 "os"
15 "regexp"
16 "slices"
17 "strings"
18 "testing"
19 )
20
21 func TestForeachHeaderElement(t *testing.T) {
22 tests := []struct {
23 in string
24 want []string
25 }{
26 {"Foo", []string{"Foo"}},
27 {" Foo", []string{"Foo"}},
28 {"Foo ", []string{"Foo"}},
29 {" Foo ", []string{"Foo"}},
30
31 {"foo", []string{"foo"}},
32 {"anY-cAsE", []string{"anY-cAsE"}},
33
34 {"", nil},
35 {",,,, , ,, ,,, ,", nil},
36
37 {" Foo,Bar, Baz,lower,,Quux ", []string{"Foo", "Bar", "Baz", "lower", "Quux"}},
38 }
39 for _, tt := range tests {
40 var got []string
41 foreachHeaderElement(tt.in, func(v string) {
42 got = append(got, v)
43 })
44 if !slices.Equal(got, tt.want) {
45 t.Errorf("foreachHeaderElement(%q) = %q; want %q", tt.in, got, tt.want)
46 }
47 }
48 }
49
50
51
52
53
54 func TestCmdGoNoHTTPServer(t *testing.T) {
55 t.Parallel()
56 goBin := testenv.GoToolPath(t)
57 out, err := testenv.Command(t, goBin, "tool", "nm", goBin).CombinedOutput()
58 if err != nil {
59 t.Fatalf("go tool nm: %v: %s", err, out)
60 }
61 wantSym := map[string]bool{
62
63 "net/http.(*Client).do": true,
64 "net/http.(*Transport).RoundTrip": true,
65
66
67 "net/http.http2Server": false,
68 "net/http.(*Server).Serve": false,
69 "net/http.(*ServeMux).ServeHTTP": false,
70 "net/http.DefaultServeMux": false,
71 }
72 for sym, want := range wantSym {
73 got := bytes.Contains(out, []byte(sym))
74 if !want && got {
75 t.Errorf("cmd/go unexpectedly links in HTTP server code; found symbol %q in cmd/go", sym)
76 }
77 if want && !got {
78 t.Errorf("expected to find symbol %q in cmd/go; not found", sym)
79 }
80 }
81 }
82
83
84
85 func TestOmitHTTP2(t *testing.T) {
86 if testing.Short() {
87 t.Skip("skipping in short mode")
88 }
89 t.Parallel()
90 goTool := testenv.GoToolPath(t)
91 out, err := testenv.Command(t, goTool, "test", "-short", "-tags=nethttpomithttp2", "net/http").CombinedOutput()
92 if err != nil {
93 t.Fatalf("go test -short failed: %v, %s", err, out)
94 }
95 }
96
97
98
99
100 func TestOmitHTTP2Vet(t *testing.T) {
101 t.Parallel()
102 goTool := testenv.GoToolPath(t)
103 out, err := testenv.Command(t, goTool, "vet", "-tags=nethttpomithttp2", "net/http").CombinedOutput()
104 if err != nil {
105 t.Fatalf("go vet failed: %v, %s", err, out)
106 }
107 }
108
109 var valuesCount int
110
111 func BenchmarkCopyValues(b *testing.B) {
112 b.ReportAllocs()
113 src := url.Values{
114 "a": {"1", "2", "3", "4", "5"},
115 "b": {"2", "2", "3", "4", "5"},
116 "c": {"3", "2", "3", "4", "5"},
117 "d": {"4", "2", "3", "4", "5"},
118 "e": {"1", "1", "2", "3", "4", "5", "6", "7", "abcdef", "l", "a", "b", "c", "d", "z"},
119 "j": {"1", "2"},
120 "m": nil,
121 }
122 for i := 0; i < b.N; i++ {
123 dst := url.Values{"a": {"b"}, "b": {"2"}, "c": {"3"}, "d": {"4"}, "j": nil, "m": {"x"}}
124 copyValues(dst, src)
125 if valuesCount = len(dst["a"]); valuesCount != 6 {
126 b.Fatalf(`%d items in dst["a"] but expected 6`, valuesCount)
127 }
128 }
129 if valuesCount == 0 {
130 b.Fatal("Benchmark wasn't run")
131 }
132 }
133
134 var forbiddenStringsFunctions = map[string]bool{
135
136 "EqualFold": true,
137 "Title": true,
138 "ToLower": true,
139 "ToLowerSpecial": true,
140 "ToTitle": true,
141 "ToTitleSpecial": true,
142 "ToUpper": true,
143 "ToUpperSpecial": true,
144
145
146 "Fields": true,
147 "TrimSpace": true,
148 }
149
150
151
152
153 func TestNoUnicodeStrings(t *testing.T) {
154 testenv.MustHaveSource(t)
155
156 re := regexp.MustCompile(`(strings|bytes).([A-Za-z]+)`)
157 if err := fs.WalkDir(os.DirFS("."), ".", func(path string, d fs.DirEntry, err error) error {
158 if err != nil {
159 t.Fatal(err)
160 }
161
162 if path == "internal/ascii" {
163 return fs.SkipDir
164 }
165 if !strings.HasSuffix(path, ".go") ||
166 strings.HasSuffix(path, "_test.go") ||
167 path == "h2_bundle.go" || d.IsDir() {
168 return nil
169 }
170
171 contents, err := os.ReadFile(path)
172 if err != nil {
173 t.Fatal(err)
174 }
175 for lineNum, line := range strings.Split(string(contents), "\n") {
176 for _, match := range re.FindAllStringSubmatch(line, -1) {
177 if !forbiddenStringsFunctions[match[2]] {
178 continue
179 }
180 t.Errorf("disallowed call to %s at %s:%d", match[0], path, lineNum+1)
181 }
182 }
183
184 return nil
185 }); err != nil {
186 t.Fatal(err)
187 }
188 }
189
190 func TestProtocols(t *testing.T) {
191 var p Protocols
192 if p.HTTP1() {
193 t.Errorf("zero-value protocols: p.HTTP1() = true, want false")
194 }
195 p.SetHTTP1(true)
196 p.SetHTTP2(true)
197 if !p.HTTP1() {
198 t.Errorf("initialized protocols: p.HTTP1() = false, want true")
199 }
200 if !p.HTTP2() {
201 t.Errorf("initialized protocols: p.HTTP2() = false, want true")
202 }
203 p.SetHTTP1(false)
204 if p.HTTP1() {
205 t.Errorf("after unsetting HTTP1: p.HTTP1() = true, want false")
206 }
207 if !p.HTTP2() {
208 t.Errorf("after unsetting HTTP1: p.HTTP2() = false, want true")
209 }
210 }
211
212 const redirectURL = "/thisaredirect细雪withasciilettersのけぶabcdefghijk.html"
213
214 func BenchmarkHexEscapeNonASCII(b *testing.B) {
215 b.ReportAllocs()
216
217 for i := 0; i < b.N; i++ {
218 hexEscapeNonASCII(redirectURL)
219 }
220 }
221
View as plain text