proxy_test.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // Copyright 2017 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 httpproxy_test
  5. import (
  6. "bytes"
  7. "errors"
  8. "fmt"
  9. "net/url"
  10. "os"
  11. "strings"
  12. "testing"
  13. "golang.org/x/net/http/httpproxy"
  14. )
  15. // setHelper calls t.Helper() for Go 1.9+ (see go19_test.go) and does nothing otherwise.
  16. var setHelper = func(t *testing.T) {}
  17. type proxyForURLTest struct {
  18. cfg httpproxy.Config
  19. req string // URL to fetch; blank means "http://example.com"
  20. want string
  21. wanterr error
  22. }
  23. func (t proxyForURLTest) String() string {
  24. var buf bytes.Buffer
  25. space := func() {
  26. if buf.Len() > 0 {
  27. buf.WriteByte(' ')
  28. }
  29. }
  30. if t.cfg.HTTPProxy != "" {
  31. fmt.Fprintf(&buf, "http_proxy=%q", t.cfg.HTTPProxy)
  32. }
  33. if t.cfg.HTTPSProxy != "" {
  34. space()
  35. fmt.Fprintf(&buf, "https_proxy=%q", t.cfg.HTTPSProxy)
  36. }
  37. if t.cfg.NoProxy != "" {
  38. space()
  39. fmt.Fprintf(&buf, "no_proxy=%q", t.cfg.NoProxy)
  40. }
  41. req := "http://example.com"
  42. if t.req != "" {
  43. req = t.req
  44. }
  45. space()
  46. fmt.Fprintf(&buf, "req=%q", req)
  47. return strings.TrimSpace(buf.String())
  48. }
  49. var proxyForURLTests = []proxyForURLTest{{
  50. cfg: httpproxy.Config{
  51. HTTPProxy: "127.0.0.1:8080",
  52. },
  53. want: "http://127.0.0.1:8080",
  54. }, {
  55. cfg: httpproxy.Config{
  56. HTTPProxy: "cache.corp.example.com:1234",
  57. },
  58. want: "http://cache.corp.example.com:1234",
  59. }, {
  60. cfg: httpproxy.Config{
  61. HTTPProxy: "cache.corp.example.com",
  62. },
  63. want: "http://cache.corp.example.com",
  64. }, {
  65. cfg: httpproxy.Config{
  66. HTTPProxy: "https://cache.corp.example.com",
  67. },
  68. want: "https://cache.corp.example.com",
  69. }, {
  70. cfg: httpproxy.Config{
  71. HTTPProxy: "http://127.0.0.1:8080",
  72. },
  73. want: "http://127.0.0.1:8080",
  74. }, {
  75. cfg: httpproxy.Config{
  76. HTTPProxy: "https://127.0.0.1:8080",
  77. },
  78. want: "https://127.0.0.1:8080",
  79. }, {
  80. cfg: httpproxy.Config{
  81. HTTPProxy: "socks5://127.0.0.1",
  82. },
  83. want: "socks5://127.0.0.1",
  84. }, {
  85. // Don't use secure for http
  86. cfg: httpproxy.Config{
  87. HTTPProxy: "http.proxy.tld",
  88. HTTPSProxy: "secure.proxy.tld",
  89. },
  90. req: "http://insecure.tld/",
  91. want: "http://http.proxy.tld",
  92. }, {
  93. // Use secure for https.
  94. cfg: httpproxy.Config{
  95. HTTPProxy: "http.proxy.tld",
  96. HTTPSProxy: "secure.proxy.tld",
  97. },
  98. req: "https://secure.tld/",
  99. want: "http://secure.proxy.tld",
  100. }, {
  101. cfg: httpproxy.Config{
  102. HTTPProxy: "http.proxy.tld",
  103. HTTPSProxy: "https://secure.proxy.tld",
  104. },
  105. req: "https://secure.tld/",
  106. want: "https://secure.proxy.tld",
  107. }, {
  108. // Issue 16405: don't use HTTP_PROXY in a CGI environment,
  109. // where HTTP_PROXY can be attacker-controlled.
  110. cfg: httpproxy.Config{
  111. HTTPProxy: "http://10.1.2.3:8080",
  112. CGI: true,
  113. },
  114. want: "<nil>",
  115. wanterr: errors.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy"),
  116. }, {
  117. // HTTPS proxy is still used even in CGI environment.
  118. // (perhaps dubious but it's the historical behaviour).
  119. cfg: httpproxy.Config{
  120. HTTPSProxy: "https://secure.proxy.tld",
  121. CGI: true,
  122. },
  123. req: "https://secure.tld/",
  124. want: "https://secure.proxy.tld",
  125. }, {
  126. want: "<nil>",
  127. }, {
  128. cfg: httpproxy.Config{
  129. NoProxy: "example.com",
  130. HTTPProxy: "proxy",
  131. },
  132. req: "http://example.com/",
  133. want: "<nil>",
  134. }, {
  135. cfg: httpproxy.Config{
  136. NoProxy: ".example.com",
  137. HTTPProxy: "proxy",
  138. },
  139. req: "http://example.com/",
  140. want: "<nil>",
  141. }, {
  142. cfg: httpproxy.Config{
  143. NoProxy: "ample.com",
  144. HTTPProxy: "proxy",
  145. },
  146. req: "http://example.com/",
  147. want: "http://proxy",
  148. }, {
  149. cfg: httpproxy.Config{
  150. NoProxy: "example.com",
  151. HTTPProxy: "proxy",
  152. },
  153. req: "http://foo.example.com/",
  154. want: "<nil>",
  155. }, {
  156. cfg: httpproxy.Config{
  157. NoProxy: ".foo.com",
  158. HTTPProxy: "proxy",
  159. },
  160. req: "http://example.com/",
  161. want: "http://proxy",
  162. }}
  163. func testProxyForURL(t *testing.T, tt proxyForURLTest) {
  164. setHelper(t)
  165. reqURLStr := tt.req
  166. if reqURLStr == "" {
  167. reqURLStr = "http://example.com"
  168. }
  169. reqURL, err := url.Parse(reqURLStr)
  170. if err != nil {
  171. t.Errorf("invalid URL %q", reqURLStr)
  172. return
  173. }
  174. cfg := tt.cfg
  175. proxyForURL := cfg.ProxyFunc()
  176. url, err := proxyForURL(reqURL)
  177. if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
  178. t.Errorf("%v: got error = %q, want %q", tt, g, e)
  179. return
  180. }
  181. if got := fmt.Sprintf("%s", url); got != tt.want {
  182. t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want)
  183. }
  184. // Check that changing the Config doesn't change the results
  185. // of the functuon.
  186. cfg = httpproxy.Config{}
  187. url, err = proxyForURL(reqURL)
  188. if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
  189. t.Errorf("(after mutating config) %v: got error = %q, want %q", tt, g, e)
  190. return
  191. }
  192. if got := fmt.Sprintf("%s", url); got != tt.want {
  193. t.Errorf("(after mutating config) %v: got URL = %q, want %q", tt, url, tt.want)
  194. }
  195. }
  196. func TestProxyForURL(t *testing.T) {
  197. for _, tt := range proxyForURLTests {
  198. testProxyForURL(t, tt)
  199. }
  200. }
  201. func TestFromEnvironment(t *testing.T) {
  202. os.Setenv("HTTP_PROXY", "httpproxy")
  203. os.Setenv("HTTPS_PROXY", "httpsproxy")
  204. os.Setenv("NO_PROXY", "noproxy")
  205. os.Setenv("REQUEST_METHOD", "")
  206. got := httpproxy.FromEnvironment()
  207. want := httpproxy.Config{
  208. HTTPProxy: "httpproxy",
  209. HTTPSProxy: "httpsproxy",
  210. NoProxy: "noproxy",
  211. }
  212. if *got != want {
  213. t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
  214. }
  215. }
  216. func TestFromEnvironmentWithRequestMethod(t *testing.T) {
  217. os.Setenv("HTTP_PROXY", "httpproxy")
  218. os.Setenv("HTTPS_PROXY", "httpsproxy")
  219. os.Setenv("NO_PROXY", "noproxy")
  220. os.Setenv("REQUEST_METHOD", "PUT")
  221. got := httpproxy.FromEnvironment()
  222. want := httpproxy.Config{
  223. HTTPProxy: "httpproxy",
  224. HTTPSProxy: "httpsproxy",
  225. NoProxy: "noproxy",
  226. CGI: true,
  227. }
  228. if *got != want {
  229. t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
  230. }
  231. }
  232. func TestFromEnvironmentLowerCase(t *testing.T) {
  233. os.Setenv("http_proxy", "httpproxy")
  234. os.Setenv("https_proxy", "httpsproxy")
  235. os.Setenv("no_proxy", "noproxy")
  236. os.Setenv("REQUEST_METHOD", "")
  237. got := httpproxy.FromEnvironment()
  238. want := httpproxy.Config{
  239. HTTPProxy: "httpproxy",
  240. HTTPSProxy: "httpsproxy",
  241. NoProxy: "noproxy",
  242. }
  243. if *got != want {
  244. t.Errorf("unexpected proxy config, got %#v want %#v", got, want)
  245. }
  246. }
  247. var UseProxyTests = []struct {
  248. host string
  249. match bool
  250. }{
  251. // Never proxy localhost:
  252. {"localhost", false},
  253. {"127.0.0.1", false},
  254. {"127.0.0.2", false},
  255. {"[::1]", false},
  256. {"[::2]", true}, // not a loopback address
  257. {"barbaz.net", false}, // match as .barbaz.net
  258. {"foobar.com", false}, // have a port but match
  259. {"foofoobar.com", true}, // not match as a part of foobar.com
  260. {"baz.com", true}, // not match as a part of barbaz.com
  261. {"localhost.net", true}, // not match as suffix of address
  262. {"local.localhost", true}, // not match as prefix as address
  263. {"barbarbaz.net", true}, // not match because NO_PROXY have a '.'
  264. {"www.foobar.com", false}, // match because NO_PROXY includes "foobar.com"
  265. }
  266. func TestUseProxy(t *testing.T) {
  267. cfg := &httpproxy.Config{
  268. NoProxy: "foobar.com, .barbaz.net",
  269. }
  270. for _, test := range UseProxyTests {
  271. if httpproxy.ExportUseProxy(cfg, test.host+":80") != test.match {
  272. t.Errorf("useProxy(%v) = %v, want %v", test.host, !test.match, test.match)
  273. }
  274. }
  275. }
  276. func TestInvalidNoProxy(t *testing.T) {
  277. cfg := &httpproxy.Config{
  278. NoProxy: ":1",
  279. }
  280. ok := httpproxy.ExportUseProxy(cfg, "example.com:80") // should not panic
  281. if !ok {
  282. t.Errorf("useProxy unexpected return; got false; want true")
  283. }
  284. }