proxy_test.go 7.2 KB

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