reverseproxy: Configurable forward proxy URL (#6114)

Co-authored-by: WeidiDeng <weidi_deng@icloud.com>
This commit is contained in:
Justin Angel 2024-03-18 00:07:25 -04:00 committed by GitHub
parent 52822a41cb
commit a9768d2fde
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 1 deletions

View file

@ -907,6 +907,7 @@ func (h *Handler) FinalizeUnmarshalCaddyfile(helper httpcaddyfile.Helper) error
// read_buffer <size> // read_buffer <size>
// write_buffer <size> // write_buffer <size>
// max_response_header <size> // max_response_header <size>
// forward_proxy_url <url>
// dial_timeout <duration> // dial_timeout <duration>
// dial_fallback_delay <duration> // dial_fallback_delay <duration>
// response_header_timeout <duration> // response_header_timeout <duration>
@ -994,6 +995,12 @@ func (h *HTTPTransport) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.Errf("invalid proxy protocol version '%s'", proxyProtocol) return d.Errf("invalid proxy protocol version '%s'", proxyProtocol)
} }
case "forward_proxy_url":
if !d.NextArg() {
return d.ArgErr()
}
h.ForwardProxyURL = d.Val()
case "dial_timeout": case "dial_timeout":
if !d.NextArg() { if !d.NextArg() {
return d.ArgErr() return d.ArgErr()

View file

@ -23,6 +23,7 @@ import (
weakrand "math/rand" weakrand "math/rand"
"net" "net"
"net/http" "net/http"
"net/url"
"os" "os"
"reflect" "reflect"
"strings" "strings"
@ -71,6 +72,22 @@ type HTTPTransport struct {
// connecting to an upstream. Default: off. // connecting to an upstream. Default: off.
ProxyProtocol string `json:"proxy_protocol,omitempty"` ProxyProtocol string `json:"proxy_protocol,omitempty"`
// URL to the server that the HTTP transport will use to proxy
// requests to the upstream. See http.Transport.Proxy for
// information regarding supported protocols. This value takes
// precedence over `HTTP_PROXY`, etc.
//
// Providing a value to this parameter results in
// requests flowing through the reverse_proxy in the following
// way:
//
// User Agent ->
// reverse_proxy ->
// forward_proxy_url -> upstream
//
// Default: http.ProxyFromEnvironment
ForwardProxyURL string `json:"forward_proxy_url,omitempty"`
// How long to wait before timing out trying to connect to // How long to wait before timing out trying to connect to
// an upstream. Default: `3s`. // an upstream. Default: `3s`.
DialTimeout caddy.Duration `json:"dial_timeout,omitempty"` DialTimeout caddy.Duration `json:"dial_timeout,omitempty"`
@ -265,8 +282,21 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
return conn, nil return conn, nil
} }
// negotiate any HTTP/SOCKS proxy for the HTTP transport
var proxy func(*http.Request) (*url.URL, error)
if h.ForwardProxyURL != "" {
pUrl, err := url.Parse(h.ForwardProxyURL)
if err != nil {
return nil, fmt.Errorf("failed to parse transport proxy url: %v", err)
}
caddyCtx.Logger().Info("setting transport proxy url", zap.String("url", h.ForwardProxyURL))
proxy = http.ProxyURL(pUrl)
} else {
proxy = http.ProxyFromEnvironment
}
rt := &http.Transport{ rt := &http.Transport{
Proxy: http.ProxyFromEnvironment, Proxy: proxy,
DialContext: dialContext, DialContext: dialContext,
MaxConnsPerHost: h.MaxConnsPerHost, MaxConnsPerHost: h.MaxConnsPerHost,
ResponseHeaderTimeout: time.Duration(h.ResponseHeaderTimeout), ResponseHeaderTimeout: time.Duration(h.ResponseHeaderTimeout),