Skip to content

Commit a73020f

Browse files
committed
net/http: add more IDNA2008 tests and fix some omissions
It wasn't lowercasing the string, folding widths, and putting strings into NFC form. Do those. Fixes #13835 Change-Id: Ia3de6159417cacec203b48e206e51d79f945df58 Reviewed-on: https://go-review.googlesource.com/29860 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Marcel van Lohuizen <[email protected]>
1 parent 36c164e commit a73020f

File tree

5 files changed

+39
-5
lines changed

5 files changed

+39
-5
lines changed

src/go/build/deps_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ var pkgDeps = map[string][]string{
382382
"golang_org/x/net/http2/hpack",
383383
"golang_org/x/net/idna",
384384
"golang_org/x/net/lex/httplex",
385+
"golang_org/x/text/unicode/norm",
386+
"golang_org/x/text/width",
385387
"internal/nettrace",
386388
"net/http/httptrace",
387389
},

src/net/http/http.go

+10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package http
66

77
import (
88
"strings"
9+
"unicode/utf8"
910

1011
"golang_org/x/net/lex/httplex"
1112
)
@@ -41,3 +42,12 @@ func removeEmptyPort(host string) string {
4142
func isNotToken(r rune) bool {
4243
return !httplex.IsTokenRune(r)
4344
}
45+
46+
func isASCII(s string) bool {
47+
for i := 0; i < len(s); i++ {
48+
if s[i] >= utf8.RuneSelf {
49+
return false
50+
}
51+
}
52+
return true
53+
}

src/net/http/http_test.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,18 @@ func TestCleanHost(t *testing.T) {
5151
{"www.google.com foo", "www.google.com"},
5252
{"www.google.com/foo", "www.google.com"},
5353
{" first character is a space", ""},
54+
{"[1::6]:8080", "[1::6]:8080"},
55+
56+
// Punycode:
5457
{"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"},
5558
{"bücher.de", "xn--bcher-kva.de"},
5659
{"bücher.de:8080", "xn--bcher-kva.de:8080"},
57-
{"[1::6]:8080", "[1::6]:8080"},
60+
// Verify we convert to lowercase before punycode:
61+
{"BÜCHER.de", "xn--bcher-kva.de"},
62+
{"BÜCHER.de:8080", "xn--bcher-kva.de:8080"},
63+
// Verify we normalize to NFC before punycode:
64+
{"gophér.nfc", "xn--gophr-esa.nfc"}, // NFC input; no work needed
65+
{"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input
5866
}
5967
for _, tt := range tests {
6068
got := cleanHost(tt.in)

src/net/http/request.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import (
2727
"sync"
2828

2929
"golang_org/x/net/idna"
30+
"golang_org/x/text/unicode/norm"
31+
"golang_org/x/text/width"
3032
)
3133

3234
const (
@@ -581,6 +583,19 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
581583
return nil
582584
}
583585

586+
func idnaASCII(v string) (string, error) {
587+
if isASCII(v) {
588+
return v, nil
589+
}
590+
// The idna package doesn't do everything from
591+
// https://tools.ietf.org/html/rfc5895 so we do it here.
592+
// TODO(bradfitz): should the idna package do this instead?
593+
v = strings.ToLower(v)
594+
v = width.Fold.String(v)
595+
v = norm.NFC.String(v)
596+
return idna.ToASCII(v)
597+
}
598+
584599
// cleanHost cleans up the host sent in request's Host header.
585600
//
586601
// It both strips anything after '/' or ' ', and puts the value
@@ -600,13 +615,13 @@ func cleanHost(in string) string {
600615
}
601616
host, port, err := net.SplitHostPort(in)
602617
if err != nil { // input was just a host
603-
a, err := idna.ToASCII(in)
618+
a, err := idnaASCII(in)
604619
if err != nil {
605620
return in // garbage in, garbage out
606621
}
607622
return a
608623
}
609-
a, err := idna.ToASCII(host)
624+
a, err := idnaASCII(host)
610625
if err != nil {
611626
return in // garbage in, garbage out
612627
}

src/net/http/transport.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"sync"
2828
"time"
2929

30-
"golang_org/x/net/idna"
3130
"golang_org/x/net/lex/httplex"
3231
)
3332

@@ -1945,7 +1944,7 @@ var portMap = map[string]string{
19451944
// canonicalAddr returns url.Host but always with a ":port" suffix
19461945
func canonicalAddr(url *url.URL) string {
19471946
addr := url.Hostname()
1948-
if v, err := idna.ToASCII(addr); err == nil {
1947+
if v, err := idnaASCII(addr); err == nil {
19491948
addr = v
19501949
}
19511950
port := url.Port()

0 commit comments

Comments
 (0)