github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/net/http/http_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 // Tests of internal functions and things with no better homes. 6 7 package http 8 9 import ( 10 "bytes" 11 "internal/testenv" 12 "io/fs" 13 "net/url" 14 "os" 15 "reflect" 16 "regexp" 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 !reflect.DeepEqual(got, tt.want) { 45 t.Errorf("foreachHeaderElement(%q) = %q; want %q", tt.in, got, tt.want) 46 } 47 } 48 } 49 50 // Test that cmd/go doesn't link in the HTTP server. 51 // 52 // This catches accidental dependencies between the HTTP transport and 53 // server code. 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 // Verify these exist: (sanity checking this test) 63 "net/http.(*Client).do": true, 64 "net/http.(*Transport).RoundTrip": true, 65 66 // Verify these don't exist: 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 // Tests that the nethttpomithttp2 build tag doesn't rot too much, 84 // even if there's not a regular builder on it. 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 // Tests that the nethttpomithttp2 build tag at least type checks 98 // in short mode. 99 // The TestOmitHTTP2 test above actually runs tests (in long mode). 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 // Functions that use Unicode-aware case folding. 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 // Functions that use Unicode-aware spaces. 146 "Fields": true, 147 "TrimSpace": true, 148 } 149 150 // TestNoUnicodeStrings checks that nothing in net/http uses the Unicode-aware 151 // strings and bytes package functions. HTTP is mostly ASCII based, and doing 152 // Unicode-aware case folding or space stripping can introduce vulnerabilities. 153 func TestNoUnicodeStrings(t *testing.T) { 154 if !testenv.HasSrc() { 155 t.Skip("source code not available") 156 } 157 158 re := regexp.MustCompile(`(strings|bytes).([A-Za-z]+)`) 159 if err := fs.WalkDir(os.DirFS("."), ".", func(path string, d fs.DirEntry, err error) error { 160 if err != nil { 161 t.Fatal(err) 162 } 163 164 if path == "internal/ascii" { 165 return fs.SkipDir 166 } 167 if !strings.HasSuffix(path, ".go") || 168 strings.HasSuffix(path, "_test.go") || 169 path == "h2_bundle.go" || d.IsDir() { 170 return nil 171 } 172 173 contents, err := os.ReadFile(path) 174 if err != nil { 175 t.Fatal(err) 176 } 177 for lineNum, line := range strings.Split(string(contents), "\n") { 178 for _, match := range re.FindAllStringSubmatch(line, -1) { 179 if !forbiddenStringsFunctions[match[2]] { 180 continue 181 } 182 t.Errorf("disallowed call to %s at %s:%d", match[0], path, lineNum+1) 183 } 184 } 185 186 return nil 187 }); err != nil { 188 t.Fatal(err) 189 } 190 } 191 192 const redirectURL = "/thisaredirect细雪withasciilettersのけぶabcdefghijk.html" 193 194 func BenchmarkHexEscapeNonASCII(b *testing.B) { 195 b.ReportAllocs() 196 197 for i := 0; i < b.N; i++ { 198 hexEscapeNonASCII(redirectURL) 199 } 200 }