Source File
proxy.go
Belonging Package
vendor/golang.org/x/net/http/httpproxy
// 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 (
)
// 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). HTTPS_PROXY takes precedence over
// HTTP_PROXY for https requests.
//
// 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 () *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 ( ...string) string {
for , := range {
if := os.Getenv(); != "" {
return
}
}
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 ( *Config) () func( *url.URL) (*url.URL, error) {
// Preprocess the Config settings for more efficient evaluation.
:= &config{
Config: *,
}
.init()
return .proxyForURL
}
func ( *config) ( *url.URL) (*url.URL, error) {
var *url.URL
if .Scheme == "https" {
= .httpsProxy
} else if .Scheme == "http" {
= .httpProxy
if != nil && .CGI {
return nil, errors.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")
}
}
if == nil {
return nil, nil
}
if !.useProxy(canonicalAddr()) {
return nil, nil
}
return , nil
}
func ( string) (*url.URL, error) {
if == "" {
return nil, nil
}
, := url.Parse()
if != nil ||
(.Scheme != "http" &&
.Scheme != "https" &&
.Scheme != "socks5") {
// 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 , := url.Parse("http://" + ); == nil {
return , nil
}
}
if != nil {
return nil, fmt.Errorf("invalid proxy address %q: %v", , )
}
return , 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 ( *config) ( string) bool {
if len() == 0 {
return true
}
, , := net.SplitHostPort()
if != nil {
return false
}
if == "localhost" {
return false
}
:= net.ParseIP()
if != nil {
if .IsLoopback() {
return false
}
}
= strings.ToLower(strings.TrimSpace())
if != nil {
for , := range .ipMatchers {
if .match(, , ) {
return false
}
}
}
for , := range .domainMatchers {
if .match(, , ) {
return false
}
}
return true
}
func ( *config) () {
if , := parseProxy(.HTTPProxy); == nil {
.httpProxy =
}
if , := parseProxy(.HTTPSProxy); == nil {
.httpsProxy =
}
for , := range strings.Split(.NoProxy, ",") {
= strings.ToLower(strings.TrimSpace())
if len() == 0 {
continue
}
if == "*" {
.ipMatchers = []matcher{allMatch{}}
.domainMatchers = []matcher{allMatch{}}
return
}
// IPv4/CIDR, IPv6/CIDR
if , , := net.ParseCIDR(); == nil {
.ipMatchers = append(.ipMatchers, cidrMatch{cidr: })
continue
}
// IPv4:port, [IPv6]:port
, , := net.SplitHostPort()
if == nil {
if len() == 0 {
// There is no host part, likely the entry is malformed; ignore.
continue
}
if [0] == '[' && [len()-1] == ']' {
= [1 : len()-1]
}
} else {
=
}
// IPv4, IPv6
if := net.ParseIP(); != nil {
.ipMatchers = append(.ipMatchers, ipMatch{ip: , port: })
continue
}
if len() == 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(, "*.") {
= [1:]
}
:= false
if [0] != '.' {
= true
= "." +
}
.domainMatchers = append(.domainMatchers, domainMatch{host: , port: , matchHost: })
}
}
var portMap = map[string]string{
"http": "80",
"https": "443",
"socks5": "1080",
}
// canonicalAddr returns url.Host but always with a ":port" suffix
func ( *url.URL) string {
:= .Hostname()
if , := idnaASCII(); == nil {
=
}
:= .Port()
if == "" {
= portMap[.Scheme]
}
return net.JoinHostPort(, )
}
// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func ( string) bool { return strings.LastIndex(, ":") > strings.LastIndex(, "]") }
func ( 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() {
return , nil
}
return idna.Lookup.ToASCII()
}
func ( string) bool {
for := 0; < len(); ++ {
if [] >= 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 ( allMatch) (, string, net.IP) bool {
return true
}
type cidrMatch struct {
cidr *net.IPNet
}
func ( cidrMatch) (, string, net.IP) bool {
return .cidr.Contains()
}
type ipMatch struct {
ip net.IP
port string
}
func ( ipMatch) (, string, net.IP) bool {
if .ip.Equal() {
return .port == "" || .port ==
}
return false
}
type domainMatch struct {
host string
port string
matchHost bool
}
func ( domainMatch) (, string, net.IP) bool {
if strings.HasSuffix(, .host) || (.matchHost && == .host[1:]) {
return .port == "" || .port ==
}
return false
}
The pages are generated with Golds v0.4.9. (GOOS=linux GOARCH=amd64)