Update dependencies
This commit is contained in:
50
vendor/golang.org/x/net/http/httpguts/guts.go
generated
vendored
Normal file
50
vendor/golang.org/x/net/http/httpguts/guts.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package httpguts provides functions implementing various details
|
||||
// of the HTTP specification.
|
||||
//
|
||||
// This package is shared by the standard library (which vendors it)
|
||||
// and x/net/http2. It comes with no API stability promise.
|
||||
package httpguts
|
||||
|
||||
import (
|
||||
"net/textproto"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ValidTrailerHeader reports whether name is a valid header field name to appear
|
||||
// in trailers.
|
||||
// See RFC 7230, Section 4.1.2
|
||||
func ValidTrailerHeader(name string) bool {
|
||||
name = textproto.CanonicalMIMEHeaderKey(name)
|
||||
if strings.HasPrefix(name, "If-") || badTrailer[name] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var badTrailer = map[string]bool{
|
||||
"Authorization": true,
|
||||
"Cache-Control": true,
|
||||
"Connection": true,
|
||||
"Content-Encoding": true,
|
||||
"Content-Length": true,
|
||||
"Content-Range": true,
|
||||
"Content-Type": true,
|
||||
"Expect": true,
|
||||
"Host": true,
|
||||
"Keep-Alive": true,
|
||||
"Max-Forwards": true,
|
||||
"Pragma": true,
|
||||
"Proxy-Authenticate": true,
|
||||
"Proxy-Authorization": true,
|
||||
"Proxy-Connection": true,
|
||||
"Range": true,
|
||||
"Realm": true,
|
||||
"Te": true,
|
||||
"Trailer": true,
|
||||
"Transfer-Encoding": true,
|
||||
"Www-Authenticate": true,
|
||||
}
|
||||
347
vendor/golang.org/x/net/http/httpguts/httplex.go
generated
vendored
Normal file
347
vendor/golang.org/x/net/http/httpguts/httplex.go
generated
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package httpguts
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
var isTokenTable = [256]bool{
|
||||
'!': true,
|
||||
'#': true,
|
||||
'$': true,
|
||||
'%': true,
|
||||
'&': true,
|
||||
'\'': true,
|
||||
'*': true,
|
||||
'+': true,
|
||||
'-': true,
|
||||
'.': true,
|
||||
'0': true,
|
||||
'1': true,
|
||||
'2': true,
|
||||
'3': true,
|
||||
'4': true,
|
||||
'5': true,
|
||||
'6': true,
|
||||
'7': true,
|
||||
'8': true,
|
||||
'9': true,
|
||||
'A': true,
|
||||
'B': true,
|
||||
'C': true,
|
||||
'D': true,
|
||||
'E': true,
|
||||
'F': true,
|
||||
'G': true,
|
||||
'H': true,
|
||||
'I': true,
|
||||
'J': true,
|
||||
'K': true,
|
||||
'L': true,
|
||||
'M': true,
|
||||
'N': true,
|
||||
'O': true,
|
||||
'P': true,
|
||||
'Q': true,
|
||||
'R': true,
|
||||
'S': true,
|
||||
'T': true,
|
||||
'U': true,
|
||||
'W': true,
|
||||
'V': true,
|
||||
'X': true,
|
||||
'Y': true,
|
||||
'Z': true,
|
||||
'^': true,
|
||||
'_': true,
|
||||
'`': true,
|
||||
'a': true,
|
||||
'b': true,
|
||||
'c': true,
|
||||
'd': true,
|
||||
'e': true,
|
||||
'f': true,
|
||||
'g': true,
|
||||
'h': true,
|
||||
'i': true,
|
||||
'j': true,
|
||||
'k': true,
|
||||
'l': true,
|
||||
'm': true,
|
||||
'n': true,
|
||||
'o': true,
|
||||
'p': true,
|
||||
'q': true,
|
||||
'r': true,
|
||||
's': true,
|
||||
't': true,
|
||||
'u': true,
|
||||
'v': true,
|
||||
'w': true,
|
||||
'x': true,
|
||||
'y': true,
|
||||
'z': true,
|
||||
'|': true,
|
||||
'~': true,
|
||||
}
|
||||
|
||||
func IsTokenRune(r rune) bool {
|
||||
return r < utf8.RuneSelf && isTokenTable[byte(r)]
|
||||
}
|
||||
|
||||
// HeaderValuesContainsToken reports whether any string in values
|
||||
// contains the provided token, ASCII case-insensitively.
|
||||
func HeaderValuesContainsToken(values []string, token string) bool {
|
||||
for _, v := range values {
|
||||
if headerValueContainsToken(v, token) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isOWS reports whether b is an optional whitespace byte, as defined
|
||||
// by RFC 7230 section 3.2.3.
|
||||
func isOWS(b byte) bool { return b == ' ' || b == '\t' }
|
||||
|
||||
// trimOWS returns x with all optional whitespace removes from the
|
||||
// beginning and end.
|
||||
func trimOWS(x string) string {
|
||||
// TODO: consider using strings.Trim(x, " \t") instead,
|
||||
// if and when it's fast enough. See issue 10292.
|
||||
// But this ASCII-only code will probably always beat UTF-8
|
||||
// aware code.
|
||||
for len(x) > 0 && isOWS(x[0]) {
|
||||
x = x[1:]
|
||||
}
|
||||
for len(x) > 0 && isOWS(x[len(x)-1]) {
|
||||
x = x[:len(x)-1]
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// headerValueContainsToken reports whether v (assumed to be a
|
||||
// 0#element, in the ABNF extension described in RFC 7230 section 7)
|
||||
// contains token amongst its comma-separated tokens, ASCII
|
||||
// case-insensitively.
|
||||
func headerValueContainsToken(v string, token string) bool {
|
||||
for comma := strings.IndexByte(v, ','); comma != -1; comma = strings.IndexByte(v, ',') {
|
||||
if tokenEqual(trimOWS(v[:comma]), token) {
|
||||
return true
|
||||
}
|
||||
v = v[comma+1:]
|
||||
}
|
||||
return tokenEqual(trimOWS(v), token)
|
||||
}
|
||||
|
||||
// lowerASCII returns the ASCII lowercase version of b.
|
||||
func lowerASCII(b byte) byte {
|
||||
if 'A' <= b && b <= 'Z' {
|
||||
return b + ('a' - 'A')
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
|
||||
func tokenEqual(t1, t2 string) bool {
|
||||
if len(t1) != len(t2) {
|
||||
return false
|
||||
}
|
||||
for i, b := range t1 {
|
||||
if b >= utf8.RuneSelf {
|
||||
// No UTF-8 or non-ASCII allowed in tokens.
|
||||
return false
|
||||
}
|
||||
if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isLWS reports whether b is linear white space, according
|
||||
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
|
||||
//
|
||||
// LWS = [CRLF] 1*( SP | HT )
|
||||
func isLWS(b byte) bool { return b == ' ' || b == '\t' }
|
||||
|
||||
// isCTL reports whether b is a control byte, according
|
||||
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
|
||||
//
|
||||
// CTL = <any US-ASCII control character
|
||||
// (octets 0 - 31) and DEL (127)>
|
||||
func isCTL(b byte) bool {
|
||||
const del = 0x7f // a CTL
|
||||
return b < ' ' || b == del
|
||||
}
|
||||
|
||||
// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name.
|
||||
// HTTP/2 imposes the additional restriction that uppercase ASCII
|
||||
// letters are not allowed.
|
||||
//
|
||||
// RFC 7230 says:
|
||||
//
|
||||
// header-field = field-name ":" OWS field-value OWS
|
||||
// field-name = token
|
||||
// token = 1*tchar
|
||||
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
||||
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
||||
func ValidHeaderFieldName(v string) bool {
|
||||
if len(v) == 0 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(v); i++ {
|
||||
if !isTokenTable[v[i]] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ValidHostHeader reports whether h is a valid host header.
|
||||
func ValidHostHeader(h string) bool {
|
||||
// The latest spec is actually this:
|
||||
//
|
||||
// http://tools.ietf.org/html/rfc7230#section-5.4
|
||||
// Host = uri-host [ ":" port ]
|
||||
//
|
||||
// Where uri-host is:
|
||||
// http://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
//
|
||||
// But we're going to be much more lenient for now and just
|
||||
// search for any byte that's not a valid byte in any of those
|
||||
// expressions.
|
||||
for i := 0; i < len(h); i++ {
|
||||
if !validHostByte[h[i]] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// See the validHostHeader comment.
|
||||
var validHostByte = [256]bool{
|
||||
'0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
|
||||
'8': true, '9': true,
|
||||
|
||||
'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
|
||||
'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
|
||||
'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
|
||||
'y': true, 'z': true,
|
||||
|
||||
'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
|
||||
'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
|
||||
'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
|
||||
'Y': true, 'Z': true,
|
||||
|
||||
'!': true, // sub-delims
|
||||
'$': true, // sub-delims
|
||||
'%': true, // pct-encoded (and used in IPv6 zones)
|
||||
'&': true, // sub-delims
|
||||
'(': true, // sub-delims
|
||||
')': true, // sub-delims
|
||||
'*': true, // sub-delims
|
||||
'+': true, // sub-delims
|
||||
',': true, // sub-delims
|
||||
'-': true, // unreserved
|
||||
'.': true, // unreserved
|
||||
':': true, // IPv6address + Host expression's optional port
|
||||
';': true, // sub-delims
|
||||
'=': true, // sub-delims
|
||||
'[': true,
|
||||
'\'': true, // sub-delims
|
||||
']': true,
|
||||
'_': true, // unreserved
|
||||
'~': true, // unreserved
|
||||
}
|
||||
|
||||
// ValidHeaderFieldValue reports whether v is a valid "field-value" according to
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
|
||||
//
|
||||
// message-header = field-name ":" [ field-value ]
|
||||
// field-value = *( field-content | LWS )
|
||||
// field-content = <the OCTETs making up the field-value
|
||||
// and consisting of either *TEXT or combinations
|
||||
// of token, separators, and quoted-string>
|
||||
//
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
|
||||
//
|
||||
// TEXT = <any OCTET except CTLs,
|
||||
// but including LWS>
|
||||
// LWS = [CRLF] 1*( SP | HT )
|
||||
// CTL = <any US-ASCII control character
|
||||
// (octets 0 - 31) and DEL (127)>
|
||||
//
|
||||
// RFC 7230 says:
|
||||
//
|
||||
// field-value = *( field-content / obs-fold )
|
||||
// obj-fold = N/A to http2, and deprecated
|
||||
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
|
||||
// field-vchar = VCHAR / obs-text
|
||||
// obs-text = %x80-FF
|
||||
// VCHAR = "any visible [USASCII] character"
|
||||
//
|
||||
// http2 further says: "Similarly, HTTP/2 allows header field values
|
||||
// that are not valid. While most of the values that can be encoded
|
||||
// will not alter header field parsing, carriage return (CR, ASCII
|
||||
// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
|
||||
// 0x0) might be exploited by an attacker if they are translated
|
||||
// verbatim. Any request or response that contains a character not
|
||||
// permitted in a header field value MUST be treated as malformed
|
||||
// (Section 8.1.2.6). Valid characters are defined by the
|
||||
// field-content ABNF rule in Section 3.2 of [RFC7230]."
|
||||
//
|
||||
// This function does not (yet?) properly handle the rejection of
|
||||
// strings that begin or end with SP or HTAB.
|
||||
func ValidHeaderFieldValue(v string) bool {
|
||||
for i := 0; i < len(v); i++ {
|
||||
b := v[i]
|
||||
if isCTL(b) && !isLWS(b) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isASCII(s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] >= utf8.RuneSelf {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// PunycodeHostPort returns the IDNA Punycode version
|
||||
// of the provided "host" or "host:port" string.
|
||||
func PunycodeHostPort(v string) (string, error) {
|
||||
if isASCII(v) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
host, port, err := net.SplitHostPort(v)
|
||||
if err != nil {
|
||||
// The input 'v' argument was just a "host" argument,
|
||||
// without a port. This error should not be returned
|
||||
// to the caller.
|
||||
host = v
|
||||
port = ""
|
||||
}
|
||||
host, err = idna.ToASCII(host)
|
||||
if err != nil {
|
||||
// Non-UTF-8? Not representable in Punycode, in any
|
||||
// case.
|
||||
return "", err
|
||||
}
|
||||
if port == "" {
|
||||
return host, nil
|
||||
}
|
||||
return net.JoinHostPort(host, port), nil
|
||||
}
|
||||
367
vendor/golang.org/x/net/http/httpproxy/proxy.go
generated
vendored
Normal file
367
vendor/golang.org/x/net/http/httpproxy/proxy.go
generated
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package httpproxy provides support for HTTP proxy determination
|
||||
// based on environment variables, as provided by net/http's
|
||||
// ProxyFromEnvironment function.
|
||||
//
|
||||
// The API is not subject to the Go 1 compatibility promise and may change at
|
||||
// any time.
|
||||
package httpproxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/net/idna"
|
||||
)
|
||||
|
||||
// Config holds configuration for HTTP proxy settings. See
|
||||
// FromEnvironment for details.
|
||||
type Config struct {
|
||||
// HTTPProxy represents the value of the HTTP_PROXY or
|
||||
// http_proxy environment variable. It will be used as the proxy
|
||||
// URL for HTTP requests unless overridden by NoProxy.
|
||||
HTTPProxy string
|
||||
|
||||
// HTTPSProxy represents the HTTPS_PROXY or https_proxy
|
||||
// environment variable. It will be used as the proxy URL for
|
||||
// HTTPS requests unless overridden by NoProxy.
|
||||
HTTPSProxy string
|
||||
|
||||
// NoProxy represents the NO_PROXY or no_proxy environment
|
||||
// variable. It specifies a string that contains comma-separated values
|
||||
// specifying hosts that should be excluded from proxying. Each value is
|
||||
// represented by an IP address prefix (1.2.3.4), an IP address prefix in
|
||||
// CIDR notation (1.2.3.4/8), a domain name, or a special DNS label (*).
|
||||
// An IP address prefix and domain name can also include a literal port
|
||||
// number (1.2.3.4:80).
|
||||
// A domain name matches that name and all subdomains. A domain name with
|
||||
// a leading "." matches subdomains only. For example "foo.com" matches
|
||||
// "foo.com" and "bar.foo.com"; ".y.com" matches "x.y.com" but not "y.com".
|
||||
// A single asterisk (*) indicates that no proxying should be done.
|
||||
// A best effort is made to parse the string and errors are
|
||||
// ignored.
|
||||
NoProxy string
|
||||
|
||||
// CGI holds whether the current process is running
|
||||
// as a CGI handler (FromEnvironment infers this from the
|
||||
// presence of a REQUEST_METHOD environment variable).
|
||||
// When this is set, ProxyForURL will return an error
|
||||
// when HTTPProxy applies, because a client could be
|
||||
// setting HTTP_PROXY maliciously. See https://golang.org/s/cgihttpproxy.
|
||||
CGI bool
|
||||
}
|
||||
|
||||
// config holds the parsed configuration for HTTP proxy settings.
|
||||
type config struct {
|
||||
// Config represents the original configuration as defined above.
|
||||
Config
|
||||
|
||||
// httpsProxy is the parsed URL of the HTTPSProxy if defined.
|
||||
httpsProxy *url.URL
|
||||
|
||||
// httpProxy is the parsed URL of the HTTPProxy if defined.
|
||||
httpProxy *url.URL
|
||||
|
||||
// ipMatchers represent all values in the NoProxy that are IP address
|
||||
// prefixes or an IP address in CIDR notation.
|
||||
ipMatchers []matcher
|
||||
|
||||
// domainMatchers represent all values in the NoProxy that are a domain
|
||||
// name or hostname & domain name
|
||||
domainMatchers []matcher
|
||||
}
|
||||
|
||||
// FromEnvironment returns a Config instance populated from the
|
||||
// environment variables HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or the
|
||||
// lowercase versions thereof).
|
||||
//
|
||||
// The environment values may be either a complete URL or a
|
||||
// "host[:port]", in which case the "http" scheme is assumed. An error
|
||||
// is returned if the value is a different form.
|
||||
func FromEnvironment() *Config {
|
||||
return &Config{
|
||||
HTTPProxy: getEnvAny("HTTP_PROXY", "http_proxy"),
|
||||
HTTPSProxy: getEnvAny("HTTPS_PROXY", "https_proxy"),
|
||||
NoProxy: getEnvAny("NO_PROXY", "no_proxy"),
|
||||
CGI: os.Getenv("REQUEST_METHOD") != "",
|
||||
}
|
||||
}
|
||||
|
||||
func getEnvAny(names ...string) string {
|
||||
for _, n := range names {
|
||||
if val := os.Getenv(n); val != "" {
|
||||
return val
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ProxyFunc returns a function that determines the proxy URL to use for
|
||||
// a given request URL. Changing the contents of cfg will not affect
|
||||
// proxy functions created earlier.
|
||||
//
|
||||
// A nil URL and nil error are returned if no proxy is defined in the
|
||||
// environment, or a proxy should not be used for the given request, as
|
||||
// defined by NO_PROXY.
|
||||
//
|
||||
// As a special case, if req.URL.Host is "localhost" or a loopback address
|
||||
// (with or without a port number), then a nil URL and nil error will be returned.
|
||||
func (cfg *Config) ProxyFunc() func(reqURL *url.URL) (*url.URL, error) {
|
||||
// Preprocess the Config settings for more efficient evaluation.
|
||||
cfg1 := &config{
|
||||
Config: *cfg,
|
||||
}
|
||||
cfg1.init()
|
||||
return cfg1.proxyForURL
|
||||
}
|
||||
|
||||
func (cfg *config) proxyForURL(reqURL *url.URL) (*url.URL, error) {
|
||||
var proxy *url.URL
|
||||
if reqURL.Scheme == "https" {
|
||||
proxy = cfg.httpsProxy
|
||||
} else if reqURL.Scheme == "http" {
|
||||
proxy = cfg.httpProxy
|
||||
if proxy != nil && cfg.CGI {
|
||||
return nil, errors.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")
|
||||
}
|
||||
}
|
||||
if proxy == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if !cfg.useProxy(canonicalAddr(reqURL)) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return proxy, nil
|
||||
}
|
||||
|
||||
func parseProxy(proxy string) (*url.URL, error) {
|
||||
if proxy == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
proxyURL, err := url.Parse(proxy)
|
||||
if err != nil || proxyURL.Scheme == "" || proxyURL.Host == "" {
|
||||
// proxy was bogus. Try prepending "http://" to it and
|
||||
// see if that parses correctly. If not, we fall
|
||||
// through and complain about the original one.
|
||||
if proxyURL, err := url.Parse("http://" + proxy); err == nil {
|
||||
return proxyURL, nil
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid proxy address %q: %v", proxy, err)
|
||||
}
|
||||
return proxyURL, nil
|
||||
}
|
||||
|
||||
// useProxy reports whether requests to addr should use a proxy,
|
||||
// according to the NO_PROXY or no_proxy environment variable.
|
||||
// addr is always a canonicalAddr with a host and port.
|
||||
func (cfg *config) useProxy(addr string) bool {
|
||||
if len(addr) == 0 {
|
||||
return true
|
||||
}
|
||||
host, port, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if host == "localhost" {
|
||||
return false
|
||||
}
|
||||
ip := net.ParseIP(host)
|
||||
if ip != nil {
|
||||
if ip.IsLoopback() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
addr = strings.ToLower(strings.TrimSpace(host))
|
||||
|
||||
if ip != nil {
|
||||
for _, m := range cfg.ipMatchers {
|
||||
if m.match(addr, port, ip) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, m := range cfg.domainMatchers {
|
||||
if m.match(addr, port, ip) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *config) init() {
|
||||
if parsed, err := parseProxy(c.HTTPProxy); err == nil {
|
||||
c.httpProxy = parsed
|
||||
}
|
||||
if parsed, err := parseProxy(c.HTTPSProxy); err == nil {
|
||||
c.httpsProxy = parsed
|
||||
}
|
||||
|
||||
for _, p := range strings.Split(c.NoProxy, ",") {
|
||||
p = strings.ToLower(strings.TrimSpace(p))
|
||||
if len(p) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if p == "*" {
|
||||
c.ipMatchers = []matcher{allMatch{}}
|
||||
c.domainMatchers = []matcher{allMatch{}}
|
||||
return
|
||||
}
|
||||
|
||||
// IPv4/CIDR, IPv6/CIDR
|
||||
if _, pnet, err := net.ParseCIDR(p); err == nil {
|
||||
c.ipMatchers = append(c.ipMatchers, cidrMatch{cidr: pnet})
|
||||
continue
|
||||
}
|
||||
|
||||
// IPv4:port, [IPv6]:port
|
||||
phost, pport, err := net.SplitHostPort(p)
|
||||
if err == nil {
|
||||
if len(phost) == 0 {
|
||||
// There is no host part, likely the entry is malformed; ignore.
|
||||
continue
|
||||
}
|
||||
if phost[0] == '[' && phost[len(phost)-1] == ']' {
|
||||
phost = phost[1 : len(phost)-1]
|
||||
}
|
||||
} else {
|
||||
phost = p
|
||||
}
|
||||
// IPv4, IPv6
|
||||
if pip := net.ParseIP(phost); pip != nil {
|
||||
c.ipMatchers = append(c.ipMatchers, ipMatch{ip: pip, port: pport})
|
||||
continue
|
||||
}
|
||||
|
||||
if len(phost) == 0 {
|
||||
// There is no host part, likely the entry is malformed; ignore.
|
||||
continue
|
||||
}
|
||||
|
||||
// domain.com or domain.com:80
|
||||
// foo.com matches bar.foo.com
|
||||
// .domain.com or .domain.com:port
|
||||
// *.domain.com or *.domain.com:port
|
||||
if strings.HasPrefix(phost, "*.") {
|
||||
phost = phost[1:]
|
||||
}
|
||||
matchHost := false
|
||||
if phost[0] != '.' {
|
||||
matchHost = true
|
||||
phost = "." + phost
|
||||
}
|
||||
if v, err := idnaASCII(phost); err == nil {
|
||||
phost = v
|
||||
}
|
||||
c.domainMatchers = append(c.domainMatchers, domainMatch{host: phost, port: pport, matchHost: matchHost})
|
||||
}
|
||||
}
|
||||
|
||||
var portMap = map[string]string{
|
||||
"http": "80",
|
||||
"https": "443",
|
||||
"socks5": "1080",
|
||||
}
|
||||
|
||||
// canonicalAddr returns url.Host but always with a ":port" suffix
|
||||
func canonicalAddr(url *url.URL) string {
|
||||
addr := url.Hostname()
|
||||
if v, err := idnaASCII(addr); err == nil {
|
||||
addr = v
|
||||
}
|
||||
port := url.Port()
|
||||
if port == "" {
|
||||
port = portMap[url.Scheme]
|
||||
}
|
||||
return net.JoinHostPort(addr, port)
|
||||
}
|
||||
|
||||
// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
|
||||
// return true if the string includes a port.
|
||||
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
|
||||
|
||||
func idnaASCII(v string) (string, error) {
|
||||
// TODO: Consider removing this check after verifying performance is okay.
|
||||
// Right now punycode verification, length checks, context checks, and the
|
||||
// permissible character tests are all omitted. It also prevents the ToASCII
|
||||
// call from salvaging an invalid IDN, when possible. As a result it may be
|
||||
// possible to have two IDNs that appear identical to the user where the
|
||||
// ASCII-only version causes an error downstream whereas the non-ASCII
|
||||
// version does not.
|
||||
// Note that for correct ASCII IDNs ToASCII will only do considerably more
|
||||
// work, but it will not cause an allocation.
|
||||
if isASCII(v) {
|
||||
return v, nil
|
||||
}
|
||||
return idna.Lookup.ToASCII(v)
|
||||
}
|
||||
|
||||
func isASCII(s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] >= utf8.RuneSelf {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// matcher represents the matching rule for a given value in the NO_PROXY list
|
||||
type matcher interface {
|
||||
// match returns true if the host and optional port or ip and optional port
|
||||
// are allowed
|
||||
match(host, port string, ip net.IP) bool
|
||||
}
|
||||
|
||||
// allMatch matches on all possible inputs
|
||||
type allMatch struct{}
|
||||
|
||||
func (a allMatch) match(host, port string, ip net.IP) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type cidrMatch struct {
|
||||
cidr *net.IPNet
|
||||
}
|
||||
|
||||
func (m cidrMatch) match(host, port string, ip net.IP) bool {
|
||||
return m.cidr.Contains(ip)
|
||||
}
|
||||
|
||||
type ipMatch struct {
|
||||
ip net.IP
|
||||
port string
|
||||
}
|
||||
|
||||
func (m ipMatch) match(host, port string, ip net.IP) bool {
|
||||
if m.ip.Equal(ip) {
|
||||
return m.port == "" || m.port == port
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type domainMatch struct {
|
||||
host string
|
||||
port string
|
||||
|
||||
matchHost bool
|
||||
}
|
||||
|
||||
func (m domainMatch) match(host, port string, ip net.IP) bool {
|
||||
if strings.HasSuffix(host, m.host) || (m.matchHost && host == m.host[1:]) {
|
||||
return m.port == "" || m.port == port
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user