proxy.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // Copyright 2011 The Go Authors. 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. // Package proxy provides support for a variety of protocols to proxy network
  5. // data.
  6. package proxy // import "golang.org/x/net/proxy"
  7. import (
  8. "errors"
  9. "net"
  10. "net/url"
  11. "os"
  12. "sync"
  13. )
  14. // A Dialer is a means to establish a connection.
  15. // Custom dialers should also implement ContextDialer.
  16. type Dialer interface {
  17. // Dial connects to the given address via the proxy.
  18. Dial(network, addr string) (c net.Conn, err error)
  19. }
  20. // Auth contains authentication parameters that specific Dialers may require.
  21. type Auth struct {
  22. User, Password string
  23. }
  24. // FromEnvironment returns the dialer specified by the proxy-related
  25. // variables in the environment and makes underlying connections
  26. // directly.
  27. func FromEnvironment() Dialer {
  28. return FromEnvironmentUsing(Direct)
  29. }
  30. // FromEnvironmentUsing returns the dialer specify by the proxy-related
  31. // variables in the environment and makes underlying connections
  32. // using the provided forwarding Dialer (for instance, a *net.Dialer
  33. // with desired configuration).
  34. func FromEnvironmentUsing(forward Dialer) Dialer {
  35. allProxy := allProxyEnv.Get()
  36. if len(allProxy) == 0 {
  37. return forward
  38. }
  39. proxyURL, err := url.Parse(allProxy)
  40. if err != nil {
  41. return forward
  42. }
  43. proxy, err := FromURL(proxyURL, forward)
  44. if err != nil {
  45. return forward
  46. }
  47. noProxy := noProxyEnv.Get()
  48. if len(noProxy) == 0 {
  49. return proxy
  50. }
  51. perHost := NewPerHost(proxy, forward)
  52. perHost.AddFromString(noProxy)
  53. return perHost
  54. }
  55. // proxySchemes is a map from URL schemes to a function that creates a Dialer
  56. // from a URL with such a scheme.
  57. var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
  58. // RegisterDialerType takes a URL scheme and a function to generate Dialers from
  59. // a URL with that scheme and a forwarding Dialer. Registered schemes are used
  60. // by FromURL.
  61. func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
  62. if proxySchemes == nil {
  63. proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
  64. }
  65. proxySchemes[scheme] = f
  66. }
  67. // FromURL returns a Dialer given a URL specification and an underlying
  68. // Dialer for it to make network requests.
  69. func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
  70. var auth *Auth
  71. if u.User != nil {
  72. auth = new(Auth)
  73. auth.User = u.User.Username()
  74. if p, ok := u.User.Password(); ok {
  75. auth.Password = p
  76. }
  77. }
  78. switch u.Scheme {
  79. case "socks5", "socks5h":
  80. addr := u.Hostname()
  81. port := u.Port()
  82. if port == "" {
  83. port = "1080"
  84. }
  85. return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward)
  86. }
  87. // If the scheme doesn't match any of the built-in schemes, see if it
  88. // was registered by another package.
  89. if proxySchemes != nil {
  90. if f, ok := proxySchemes[u.Scheme]; ok {
  91. return f(u, forward)
  92. }
  93. }
  94. return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
  95. }
  96. var (
  97. allProxyEnv = &envOnce{
  98. names: []string{"ALL_PROXY", "all_proxy"},
  99. }
  100. noProxyEnv = &envOnce{
  101. names: []string{"NO_PROXY", "no_proxy"},
  102. }
  103. )
  104. // envOnce looks up an environment variable (optionally by multiple
  105. // names) once. It mitigates expensive lookups on some platforms
  106. // (e.g. Windows).
  107. // (Borrowed from net/http/transport.go)
  108. type envOnce struct {
  109. names []string
  110. once sync.Once
  111. val string
  112. }
  113. func (e *envOnce) Get() string {
  114. e.once.Do(e.init)
  115. return e.val
  116. }
  117. func (e *envOnce) init() {
  118. for _, n := range e.names {
  119. e.val = os.Getenv(n)
  120. if e.val != "" {
  121. return
  122. }
  123. }
  124. }
  125. // reset is used by tests
  126. func (e *envOnce) reset() {
  127. e.once = sync.Once{}
  128. e.val = ""
  129. }