@marcel91200 / caddy Mirror · read-only / commits / e3909cc3
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 13, 05:30 UTC

reverseproxy: refactor HTTP transport layer (#5369)

Co-authored-by: Francis Lavoie <lavofr@gmail.com> Co-authored-by: Weidi Deng <weidi_deng@icloud.com>

Mohammed Al Sahaf committed Feb 24, 2023 at 22:54 UTC e3909cc385f68a636cc8675dc12f6cd5185d722d
2 files changed +148 -140
caddytest/integration/reverseproxy_test.go
+134 -134
@@ -22,39 +22,39 @@ func TestSRVReverseProxy(t *testing.T) {
22 },
23 "apps": {
24 "pki": {
25 - "certificate_authorities" : {
26 - "local" : {
27 - "install_trust": false
25 + "certificate_authorities": {
26 + "local": {
27 + "install_trust": false
28 }
29 }
30 },
31 - "http": {
32 - "grace_period": 1,
33 - "servers": {
34 - "srv0": {
35 - "listen": [
36 - ":8080"
37 - ],
38 - "routes": [
39 - {
40 - "handle": [
41 - {
42 - "handler": "reverse_proxy",
43 - "upstreams": [
44 - {
45 - "lookup_srv": "srv.host.service.consul"
46 - }
31 + "http": {
32 + "grace_period": 1,
33 + "servers": {
34 + "srv0": {
35 + "listen": [
36 + ":18080"
37 + ],
38 + "routes": [
39 + {
40 + "handle": [
41 + {
42 + "handler": "reverse_proxy",
43 + "upstreams": [
44 + {
45 + "lookup_srv": "srv.host.service.consul"
46 + }
47 + ]
48 + }
49 + ]
50 + }
51 ]
48 - }
49 - ]
50 - }
51 - ]
52 - }
52 + }
53 + }
54 }
54 - }
55 }
56 - }
57 - `, "json")
56 + }
57 + `, "json")
58 }
59
60 func TestSRVWithDial(t *testing.T) {
@@ -62,39 +62,39 @@ func TestSRVWithDial(t *testing.T) {
62 {
63 "apps": {
64 "pki": {
65 - "certificate_authorities" : {
66 - "local" : {
67 - "install_trust": false
68 - }
65 + "certificate_authorities": {
66 + "local": {
67 + "install_trust": false
68 + }
69 }
70 - },
71 - "http": {
72 - "grace_period": 1,
73 - "servers": {
74 - "srv0": {
75 - "listen": [
76 - ":8080"
77 - ],
78 - "routes": [
79 - {
80 - "handle": [
81 - {
82 - "handler": "reverse_proxy",
83 - "upstreams": [
84 - {
85 - "dial": "tcp/address.to.upstream:80",
86 - "lookup_srv": "srv.host.service.consul"
87 - }
70 + },
71 + "http": {
72 + "grace_period": 1,
73 + "servers": {
74 + "srv0": {
75 + "listen": [
76 + ":18080"
77 + ],
78 + "routes": [
79 + {
80 + "handle": [
81 + {
82 + "handler": "reverse_proxy",
83 + "upstreams": [
84 + {
85 + "dial": "tcp/address.to.upstream:80",
86 + "lookup_srv": "srv.host.service.consul"
87 + }
88 + ]
89 + }
90 + ]
91 + }
92 ]
89 - }
90 - ]
91 - }
92 - ]
93 - }
93 + }
94 + }
95 }
95 - }
96 }
97 - }
97 + }
98 `, "json", `upstream: specifying dial address is incompatible with lookup_srv: 0: {\"dial\": \"tcp/address.to.upstream:80\", \"lookup_srv\": \"srv.host.service.consul\"}`)
99 }
100
@@ -138,41 +138,41 @@ func TestDialWithPlaceholderUnix(t *testing.T) {
138 },
139 "apps": {
140 "pki": {
141 - "certificate_authorities" : {
142 - "local" : {
143 - "install_trust": false
144 - }
141 + "certificate_authorities": {
142 + "local": {
143 + "install_trust": false
144 + }
145 }
146 - },
147 - "http": {
148 - "grace_period": 1,
149 - "servers": {
150 - "srv0": {
151 - "listen": [
152 - ":8080"
153 - ],
154 - "routes": [
155 - {
156 - "handle": [
157 - {
158 - "handler": "reverse_proxy",
159 - "upstreams": [
160 - {
161 - "dial": "unix/{http.request.header.X-Caddy-Upstream-Dial}"
162 - }
146 + },
147 + "http": {
148 + "grace_period": 1,
149 + "servers": {
150 + "srv0": {
151 + "listen": [
152 + ":18080"
153 + ],
154 + "routes": [
155 + {
156 + "handle": [
157 + {
158 + "handler": "reverse_proxy",
159 + "upstreams": [
160 + {
161 + "dial": "unix/{http.request.header.X-Caddy-Upstream-Dial}"
162 + }
163 + ]
164 + }
165 + ]
166 + }
167 ]
164 - }
165 - ]
166 - }
167 - ]
168 - }
169 - }
170 - }
168 + }
169 + }
170 + }
171 }
172 - }
172 + }
173 `, "json")
174
175 - req, err := http.NewRequest(http.MethodGet, "http://localhost:8080", nil)
175 + req, err := http.NewRequest(http.MethodGet, "http://localhost:18080", nil)
176 if err != nil {
177 t.Fail()
178 return
@@ -190,18 +190,18 @@ func TestReverseProxyWithPlaceholderDialAddress(t *testing.T) {
190 },
191 "apps": {
192 "pki": {
193 - "certificate_authorities" : {
194 - "local" : {
195 - "install_trust": false
196 - }
193 + "certificate_authorities": {
194 + "local": {
195 + "install_trust": false
196 + }
197 }
198 - },
198 + },
199 "http": {
200 "grace_period": 1,
201 "servers": {
202 "srv0": {
203 "listen": [
204 - ":8080"
204 + ":18080"
205 ],
206 "routes": [
207 {
@@ -264,14 +264,14 @@ func TestReverseProxyWithPlaceholderDialAddress(t *testing.T) {
264 }
265 }
266 }
267 - `, "json")
267 + `, "json")
268
269 req, err := http.NewRequest(http.MethodGet, "http://localhost:9080", nil)
270 if err != nil {
271 t.Fail()
272 return
273 }
274 - req.Header.Set("X-Caddy-Upstream-Dial", "localhost:8080")
274 + req.Header.Set("X-Caddy-Upstream-Dial", "localhost:18080")
275 tester.AssertResponse(req, 200, "Hello, World!")
276 }
277
@@ -284,18 +284,18 @@ func TestReverseProxyWithPlaceholderTCPDialAddress(t *testing.T) {
284 },
285 "apps": {
286 "pki": {
287 - "certificate_authorities" : {
288 - "local" : {
289 - "install_trust": false
290 - }
287 + "certificate_authorities": {
288 + "local": {
289 + "install_trust": false
290 + }
291 }
292 - },
292 + },
293 "http": {
294 "grace_period": 1,
295 "servers": {
296 "srv0": {
297 "listen": [
298 - ":8080"
298 + ":18080"
299 ],
300 "routes": [
301 {
@@ -340,7 +340,7 @@ func TestReverseProxyWithPlaceholderTCPDialAddress(t *testing.T) {
340 "handler": "reverse_proxy",
341 "upstreams": [
342 {
343 - "dial": "tcp/{http.request.header.X-Caddy-Upstream-Dial}:8080"
343 + "dial": "tcp/{http.request.header.X-Caddy-Upstream-Dial}:18080"
344 }
345 ]
346 }
@@ -358,7 +358,7 @@ func TestReverseProxyWithPlaceholderTCPDialAddress(t *testing.T) {
358 }
359 }
360 }
361 - `, "json")
361 + `, "json")
362
363 req, err := http.NewRequest(http.MethodGet, "http://localhost:9080", nil)
364 if err != nil {
@@ -375,42 +375,42 @@ func TestSRVWithActiveHealthcheck(t *testing.T) {
375 "apps": {
376 "pki": {
377 "certificate_authorities" : {
378 - "local" : {
379 - "install_trust": false
380 - }
378 + "local" : {
379 + "install_trust": false
380 + }
381 }
382 - },
383 - "http": {
384 - "grace_period": 1,
385 - "servers": {
386 - "srv0": {
387 - "listen": [
388 - ":8080"
389 - ],
390 - "routes": [
391 - {
392 - "handle": [
393 - {
394 - "handler": "reverse_proxy",
395 - "health_checks": {
396 - "active": {
397 - "path": "/ok"
382 + },
383 + "http": {
384 + "grace_period": 1,
385 + "servers": {
386 + "srv0": {
387 + "listen": [
388 + ":18080"
389 + ],
390 + "routes": [
391 + {
392 + "handle": [
393 + {
394 + "handler": "reverse_proxy",
395 + "health_checks": {
396 + "active": {
397 + "path": "/ok"
398 + }
399 + },
400 + "upstreams": [
401 + {
402 + "lookup_srv": "srv.host.service.consul"
403 + }
404 + ]
405 + }
406 + ]
407 }
399 - },
400 - "upstreams": [
401 - {
402 - "lookup_srv": "srv.host.service.consul"
403 - }
408 ]
405 - }
406 - ]
407 - }
408 - ]
409 - }
409 + }
410 + }
411 }
411 - }
412 }
413 - }
413 + }
414 `, "json", `upstream: lookup_srv is incompatible with active health checks: 0: {\"dial\": \"\", \"lookup_srv\": \"srv.host.service.consul\"}`)
415 }
416
@@ -440,7 +440,7 @@ func TestReverseProxyHealthCheck(t *testing.T) {
440 health_timeout 100ms
441 }
442 }
443 - `, "caddyfile")
443 + `, "caddyfile")
444
445 time.Sleep(100 * time.Millisecond) // TODO: for some reason this test seems particularly flaky, getting 503 when it should be 200, unless we wait
446 tester.AssertGetResponse("http://localhost:9080/", 200, "Hello, World!")
modules/caddyhttp/reverseproxy/httptransport.go
+14 -6
@@ -172,12 +172,19 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
172 }
173 }
174
175 - // Set up the dialer to pull the correct information from the context
175 dialContext := func(ctx context.Context, network, address string) (net.Conn, error) {
177 - // the proper dialing information should be embedded into the request's context
176 + // For unix socket upstreams, we need to recover the dial info from
177 + // the request's context, because the Host on the request's URL
178 + // will have been modified by directing the request, overwriting
179 + // the unix socket filename.
180 + // Also, we need to avoid overwriting the address at this point
181 + // when not necessary, because http.ProxyFromEnvironment may have
182 + // modified the address according to the user's env proxy config.
183 if dialInfo, ok := GetDialInfo(ctx); ok {
179 - network = dialInfo.Network
180 - address = dialInfo.Address
184 + if strings.HasPrefix(dialInfo.Network, "unix") {
185 + network = dialInfo.Network
186 + address = dialInfo.Address
187 + }
188 }
189
190 conn, err := dialer.DialContext(ctx, network, address)
@@ -188,8 +195,8 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
195 return nil, DialError{err}
196 }
197
191 - // if read/write timeouts are configured and this is a TCP connection, enforce the timeouts
192 - // by wrapping the connection with our own type
198 + // if read/write timeouts are configured and this is a TCP connection,
199 + // enforce the timeouts by wrapping the connection with our own type
200 if tcpConn, ok := conn.(*net.TCPConn); ok && (h.ReadTimeout > 0 || h.WriteTimeout > 0) {
201 conn = &tcpRWTimeoutConn{
202 TCPConn: tcpConn,
@@ -203,6 +210,7 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
210 }
211
212 rt := &http.Transport{
213 + Proxy: http.ProxyFromEnvironment,
214 DialContext: dialContext,
215 MaxConnsPerHost: h.MaxConnsPerHost,
216 ResponseHeaderTimeout: time.Duration(h.ResponseHeaderTimeout),