proxy.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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 variables in
  25. // the environment.
  26. func FromEnvironment() Dialer {
  27. allProxy := allProxyEnv.Get()
  28. if len(allProxy) == 0 {
  29. return Direct
  30. }
  31. proxyURL, err := url.Parse(allProxy)
  32. if err != nil {
  33. return Direct
  34. }
  35. proxy, err := FromURL(proxyURL, Direct)
  36. if err != nil {
  37. return Direct
  38. }
  39. noProxy := noProxyEnv.Get()
  40. if len(noProxy) == 0 {
  41. return proxy
  42. }
  43. perHost := NewPerHost(proxy, Direct)
  44. perHost.AddFromString(noProxy)
  45. return perHost
  46. }
  47. // proxySchemes is a map from URL schemes to a function that creates a Dialer
  48. // from a URL with such a scheme.
  49. var proxySchemes map[string]func(*url.URL, Dialer) (Dialer, error)
  50. // RegisterDialerType takes a URL scheme and a function to generate Dialers from
  51. // a URL with that scheme and a forwarding Dialer. Registered schemes are used
  52. // by FromURL.
  53. func RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
  54. if proxySchemes == nil {
  55. proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
  56. }
  57. proxySchemes[scheme] = f
  58. }
  59. // FromURL returns a Dialer given a URL specification and an underlying
  60. // Dialer for it to make network requests.
  61. func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
  62. var auth *Auth
  63. if u.User != nil {
  64. auth = new(Auth)
  65. auth.User = u.User.Username()
  66. if p, ok := u.User.Password(); ok {
  67. auth.Password = p
  68. }
  69. }
  70. switch u.Scheme {
  71. case "socks5", "socks5h":
  72. addr := u.Hostname()
  73. port := u.Port()
  74. if port == "" {
  75. port = "1080"
  76. }
  77. return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward)
  78. }
  79. // If the scheme doesn't match any of the built-in schemes, see if it
  80. // was registered by another package.
  81. if proxySchemes != nil {
  82. if f, ok := proxySchemes[u.Scheme]; ok {
  83. return f(u, forward)
  84. }
  85. }
  86. return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
  87. }
  88. var (
  89. allProxyEnv = &envOnce{
  90. names: []string{"ALL_PROXY", "all_proxy"},
  91. }
  92. noProxyEnv = &envOnce{
  93. names: []string{"NO_PROXY", "no_proxy"},
  94. }
  95. )
  96. // envOnce looks up an environment variable (optionally by multiple
  97. // names) once. It mitigates expensive lookups on some platforms
  98. // (e.g. Windows).
  99. // (Borrowed from net/http/transport.go)
  100. type envOnce struct {
  101. names []string
  102. once sync.Once
  103. val string
  104. }
  105. func (e *envOnce) Get() string {
  106. e.once.Do(e.init)
  107. return e.val
  108. }
  109. func (e *envOnce) init() {
  110. for _, n := range e.names {
  111. e.val = os.Getenv(n)
  112. if e.val != "" {
  113. return
  114. }
  115. }
  116. }
  117. // reset is used by tests
  118. func (e *envOnce) reset() {
  119. e.once = sync.Once{}
  120. e.val = ""
  121. }