"golang_org/x/net/http2/hpack",
"golang_org/x/net/idna",
"golang_org/x/net/lex/httplex",
+ "golang_org/x/text/unicode/norm",
+ "golang_org/x/text/width",
"internal/nettrace",
"net/http/httptrace",
},
import (
"strings"
+ "unicode/utf8"
"golang_org/x/net/lex/httplex"
)
func isNotToken(r rune) bool {
return !httplex.IsTokenRune(r)
}
+
+func isASCII(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
{"www.google.com foo", "www.google.com"},
{"www.google.com/foo", "www.google.com"},
{" first character is a space", ""},
+ {"[1::6]:8080", "[1::6]:8080"},
+
+ // Punycode:
{"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"},
{"bücher.de", "xn--bcher-kva.de"},
{"bücher.de:8080", "xn--bcher-kva.de:8080"},
- {"[1::6]:8080", "[1::6]:8080"},
+ // Verify we convert to lowercase before punycode:
+ {"BÜCHER.de", "xn--bcher-kva.de"},
+ {"BÜCHER.de:8080", "xn--bcher-kva.de:8080"},
+ // Verify we normalize to NFC before punycode:
+ {"gophér.nfc", "xn--gophr-esa.nfc"}, // NFC input; no work needed
+ {"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input
}
for _, tt := range tests {
got := cleanHost(tt.in)
"sync"
"golang_org/x/net/idna"
+ "golang_org/x/text/unicode/norm"
+ "golang_org/x/text/width"
)
const (
return nil
}
+func idnaASCII(v string) (string, error) {
+ if isASCII(v) {
+ return v, nil
+ }
+ // The idna package doesn't do everything from
+ // https://tools.ietf.org/html/rfc5895 so we do it here.
+ // TODO(bradfitz): should the idna package do this instead?
+ v = strings.ToLower(v)
+ v = width.Fold.String(v)
+ v = norm.NFC.String(v)
+ return idna.ToASCII(v)
+}
+
// cleanHost cleans up the host sent in request's Host header.
//
// It both strips anything after '/' or ' ', and puts the value
}
host, port, err := net.SplitHostPort(in)
if err != nil { // input was just a host
- a, err := idna.ToASCII(in)
+ a, err := idnaASCII(in)
if err != nil {
return in // garbage in, garbage out
}
return a
}
- a, err := idna.ToASCII(host)
+ a, err := idnaASCII(host)
if err != nil {
return in // garbage in, garbage out
}
"sync"
"time"
- "golang_org/x/net/idna"
"golang_org/x/net/lex/httplex"
)
// canonicalAddr returns url.Host but always with a ":port" suffix
func canonicalAddr(url *url.URL) string {
addr := url.Hostname()
- if v, err := idna.ToASCII(addr); err == nil {
+ if v, err := idnaASCII(addr); err == nil {
addr = v
}
port := url.Port()