You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.1 KiB

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