123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- // Copyright 2011 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 proxy provides support for a variety of protocols to proxy network
- // data.
- package proxy // import "golang.org/x/net/proxy"
-
- import (
- "errors"
- "net"
- "net/url"
- "os"
- "sync"
- )
-
- // A Dialer is a means to establish a connection.
- type Dialer interface {
- // Dial connects to the given address via the proxy.
- Dial(network, addr string) (c net.Conn, err error)
- }
-
- // Auth contains authentication parameters that specific Dialers may require.
- type Auth struct {
- User, Password string
- }
-
- // FromEnvironment returns the dialer specified by the proxy related variables in
- // the environment.
- func FromEnvironment() Dialer {
- allProxy := allProxyEnv.Get()
- if len(allProxy) == 0 {
- return Direct
- }
-
- proxyURL, err := url.Parse(allProxy)
- if err != nil {
- return Direct
- }
- proxy, err := FromURL(proxyURL, Direct)
- if err != nil {
- return Direct
- }
-
- noProxy := noProxyEnv.Get()
- if len(noProxy) == 0 {
- return proxy
- }
-
- perHost := NewPerHost(proxy, Direct)
- perHost.AddFromString(noProxy)
- return perHost
- }
-
- // proxySchemes is a map from URL schemes to a function that creates a Dialer
- // from a URL with such a scheme.
- var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
-
- // RegisterDialerType takes a URL scheme and a function to generate Dialers from
- // a URL with that scheme and a forwarding Dialer. Registered schemes are used
- // by FromURL.
- func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
- if proxySchemes == nil {
- proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
- }
- proxySchemes[scheme] = f
- }
-
- // FromURL returns a Dialer given a URL specification and an underlying
- // Dialer for it to make network requests.
- func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
- var auth *Auth
- if u.User != nil {
- auth = new(Auth)
- auth.User = u.User.Username()
- if p, ok := u.User.Password(); ok {
- auth.Password = p
- }
- }
-
- switch u.Scheme {
- case "socks5":
- return SOCKS5("tcp", u.Host, auth, forward)
- }
-
- // If the scheme doesn't match any of the built-in schemes, see if it
- // was registered by another package.
- if proxySchemes != nil {
- if f, ok := proxySchemes[u.Scheme]; ok {
- return f(u, forward)
- }
- }
-
- return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
- }
-
- var (
- allProxyEnv = &envOnce{
- names: []string{"ALL_PROXY", "all_proxy"},
- }
- noProxyEnv = &envOnce{
- names: []string{"NO_PROXY", "no_proxy"},
- }
- )
-
- // envOnce looks up an environment variable (optionally by multiple
- // names) once. It mitigates expensive lookups on some platforms
- // (e.g. Windows).
- // (Borrowed from net/http/transport.go)
- type envOnce struct {
- names []string
- once sync.Once
- val string
- }
-
- func (e *envOnce) Get() string {
- e.once.Do(e.init)
- return e.val
- }
-
- func (e *envOnce) init() {
- for _, n := range e.names {
- e.val = os.Getenv(n)
- if e.val != "" {
- return
- }
- }
- }
-
- // reset is used by tests
- func (e *envOnce) reset() {
- e.once = sync.Once{}
- e.val = ""
- }
|