@@ -1,6 +1,8 @@
1package upstream
1package upstream
5 "net/http/httputil"
7 "net/http/httputil"
@@ -18,6 +20,7 @@ const (
19 httpScheme = "http"
21 httpScheme = "http"
20 httpsScheme = "https"
22 httpsScheme = "https"
23// SignatureHeaders contains the headers to be signed by the hmac algorithm
26// SignatureHeaders contains the headers to be signed by the hmac algorithm
@@ -40,7 +43,10 @@ var SignatureHeaders = []string{
40// to a single upstream host.
43// to a single upstream host.
41func newHTTPUpstreamProxy(upstream options.Upstream, u *url.URL, sigData *options.SignatureData, errorHandler ProxyErrorHandler) http.Handler {
44func newHTTPUpstreamProxy(upstream options.Upstream, u *url.URL, sigData *options.SignatureData, errorHandler ProxyErrorHandler) http.Handler {
42 // Set path to empty so that request paths start at the server root
45 // Set path to empty so that request paths start at the server root
46+ // Unix scheme need the path to find the socket
47+ if u.Scheme != "unix" {
43− u.Path = ""
48+ u.Path = ""
45 // Create a ReverseProxy
51 // Create a ReverseProxy
46 proxy := newReverseProxy(u, upstream, errorHandler)
52 proxy := newReverseProxy(u, upstream, errorHandler)
@@ -92,6 +98,25 @@ func (h *httpUpstreamProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)
101+// Unix implementation of http.RoundTripper, required to register unix protocol in reverse proxy
102+type unixRoundTripper struct {
103+ Transport *http.Transport
106+// Implementation of https://pkg.go.dev/net/http#RoundTripper interface to support http protocol over unix socket
107+func (t *unixRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
108+ // Inspired by https://github.com/tv42/httpunix
109+ // Not having a Host, even if not used, makes the reverseproxy fail with a "no Host in request URL"
111+ req.Host = "localhost"
113+ req.URL.Host = req.Host
115+ req = req.Clone(req.Context())
116+ req.URL.Scheme = "http"
117+ return tt.RoundTrip(req)
95// newReverseProxy creates a new reverse proxy for proxying requests to upstream
120// newReverseProxy creates a new reverse proxy for proxying requests to upstream
96// servers based on the upstream configuration provided.
121// servers based on the upstream configuration provided.
97// The proxy should render an error page if there are failures connecting to the
122// The proxy should render an error page if there are failures connecting to the
@@ -102,6 +127,14 @@ func newReverseProxy(target *url.URL, upstream options.Upstream, errorHandler Pr
102 // Inherit default transport options from Go's stdlib
127 // Inherit default transport options from Go's stdlib
103 transport := http.DefaultTransport.(*http.Transport).Clone()
128 transport := http.DefaultTransport.(*http.Transport).Clone()
130+ if target.Scheme == "unix" {
131+ transport.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
132+ dialer := net.Dialer{}
133+ return dialer.DialContext(ctx, target.Scheme, target.Path)
135+ transport.RegisterProtocol(target.Scheme, &unixRoundTripper{Transport: transport})
105 // Change default duration for waiting for an upstream response
138 // Change default duration for waiting for an upstream response
106 if upstream.Timeout != nil {
139 if upstream.Timeout != nil {
107 transport.ResponseHeaderTimeout = upstream.Timeout.Duration()
140 transport.ResponseHeaderTimeout = upstream.Timeout.Duration()