github.com/searKing/golang/go@v1.2.117/net/url/host.go (about) 1 // Copyright 2020 The searKing Author. 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 package url 6 7 import ( 8 "net" 9 "strings" 10 "unicode/utf8" 11 12 "golang.org/x/net/idna" 13 ) 14 15 // cleanHost cleans up the host sent in request's Host header. 16 // 17 // It both strips anything after '/' or ' ', and puts the value 18 // into Punycode form, if necessary. 19 // 20 // Ideally we'd clean the Host header according to the spec: 21 // 22 // https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]") 23 // https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host) 24 // https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host) 25 // 26 // But practically, what we are trying to avoid is the situation in 27 // issue 11206, where a malformed Host header used in the proxy context 28 // would create a bad request. So it is enough to just truncate at the 29 // first offending character. 30 func CleanHost(in string) string { 31 if i := strings.IndexAny(in, " /"); i != -1 { 32 in = in[:i] 33 } 34 host, port, err := net.SplitHostPort(in) 35 if err != nil { // input was just a host 36 a, err := idnaASCII(in) 37 if err != nil { 38 return in // garbage in, garbage out 39 } 40 return a 41 } 42 a, err := idnaASCII(host) 43 if err != nil { 44 return in // garbage in, garbage out 45 } 46 return net.JoinHostPort(a, port) 47 } 48 49 // removeZone removes IPv6 zone identifier from host. 50 // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" 51 func RemoveZone(host string) string { 52 if !strings.HasPrefix(host, "[") { 53 return host 54 } 55 i := strings.LastIndex(host, "]") 56 if i < 0 { 57 return host 58 } 59 j := strings.LastIndex(host[:i], "%") 60 if j < 0 { 61 return host 62 } 63 return host[:j] + host[i:] 64 } 65 66 func idnaASCII(v string) (string, error) { 67 // TODO: Consider removing this check after verifying performance is okay. 68 // Right now punycode verification, length checks, context checks, and the 69 // permissible character tests are all omitted. It also prevents the ToASCII 70 // call from salvaging an invalid IDN, when possible. As a result it may be 71 // possible to have two IDNs that appear identical to the user where the 72 // ASCII-only version causes an error downstream whereas the non-ASCII 73 // version does not. 74 // Note that for correct ASCII IDNs ToASCII will only do considerably more 75 // work, but it will not cause an allocation. 76 if isASCII(v) { 77 return v, nil 78 } 79 return idna.Lookup.ToASCII(v) 80 } 81 82 func isASCII(s string) bool { 83 for i := 0; i < len(s); i++ { 84 if s[i] >= utf8.RuneSelf { 85 return false 86 } 87 } 88 return true 89 }