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