Skip to content

Commit

Permalink
net/http: check that Unicode-aware functions are not used
Browse files Browse the repository at this point in the history
Change-Id: I398aff06bec95077bfff02bfb067aa949b70c184
Reviewed-on: https://go-review.googlesource.com/c/go/+/318429
Run-TryBot: Filippo Valsorda <[email protected]>
TryBot-Result: Go Bot <[email protected]>
Reviewed-by: Roberto Clapis <[email protected]>
Trust: Filippo Valsorda <[email protected]>
  • Loading branch information
FiloSottile committed May 11, 2021
1 parent 2520e72 commit 9b84814
Showing 1 changed file with 62 additions and 0 deletions.
62 changes: 62 additions & 0 deletions src/net/http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ package http
import (
"bytes"
"internal/testenv"
"io/fs"
"net/url"
"os"
"os/exec"
"reflect"
"regexp"
"strings"
"testing"
)

Expand Down Expand Up @@ -156,3 +160,61 @@ func BenchmarkCopyValues(b *testing.B) {
b.Fatal("Benchmark wasn't run")
}
}

var forbiddenStringsFunctions = map[string]bool{
// Functions that use Unicode-aware case folding.
"EqualFold": true,
"Title": true,
"ToLower": true,
"ToLowerSpecial": true,
"ToTitle": true,
"ToTitleSpecial": true,
"ToUpper": true,
"ToUpperSpecial": true,

// Functions that use Unicode-aware spaces.
"Fields": true,
"TrimSpace": true,
}

// TestNoUnicodeStrings checks that nothing in net/http uses the Unicode-aware
// strings and bytes package functions. HTTP is mostly ASCII based, and doing
// Unicode-aware case folding or space stripping can introduce vulnerabilities.
func TestNoUnicodeStrings(t *testing.T) {
if !testenv.HasSrc() {
t.Skip("source code not available")
}

re := regexp.MustCompile(`(strings|bytes).([A-Za-z]+)`)
if err := fs.WalkDir(os.DirFS("."), ".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
t.Fatal(err)
}

if path == "internal/ascii" {
return fs.SkipDir
}
if !strings.HasSuffix(path, ".go") ||
strings.HasSuffix(path, "_test.go") ||
path == "h2_bundle.go" || d.IsDir() {
return nil
}

contents, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
for lineNum, line := range strings.Split(string(contents), "\n") {
for _, match := range re.FindAllStringSubmatch(line, -1) {
if !forbiddenStringsFunctions[match[2]] {
continue
}
t.Errorf("disallowed call to %s at %s:%d", match[0], path, lineNum+1)
}
}

return nil
}); err != nil {
t.Fatal(err)
}
}

0 comments on commit 9b84814

Please sign in to comment.