1
0
Fork 0

Add an option to preserve server path

This commit is contained in:
Michael 2024-10-17 09:12:04 +02:00 committed by GitHub
parent 6e1f5dc071
commit 83871f27dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 251 additions and 44 deletions

View file

@ -68,7 +68,7 @@ func (r *ProxyBuilder) Update(newConfigs map[string]*dynamic.ServersTransport) {
}
// Build builds a new ReverseProxy with the given configuration.
func (r *ProxyBuilder) Build(cfgName string, targetURL *url.URL, passHostHeader bool) (http.Handler, error) {
func (r *ProxyBuilder) Build(cfgName string, targetURL *url.URL, passHostHeader, preservePath bool) (http.Handler, error) {
proxyURL, err := r.proxy(&http.Request{URL: targetURL})
if err != nil {
return nil, fmt.Errorf("getting proxy: %w", err)
@ -90,7 +90,7 @@ func (r *ProxyBuilder) Build(cfgName string, targetURL *url.URL, passHostHeader
}
pool := r.getPool(cfgName, cfg, tlsConfig, targetURL, proxyURL)
return NewReverseProxy(targetURL, proxyURL, r.debug, passHostHeader, responseHeaderTimeout, pool)
return NewReverseProxy(targetURL, proxyURL, r.debug, passHostHeader, preservePath, responseHeaderTimeout, pool)
}
func (r *ProxyBuilder) getPool(cfgName string, config *dynamic.ServersTransport, tlsConfig *tls.Config, targetURL *url.URL, proxyURL *url.URL) *connPool {

View file

@ -121,11 +121,12 @@ type ReverseProxy struct {
targetURL *url.URL
passHostHeader bool
preservePath bool
responseHeaderTimeout time.Duration
}
// NewReverseProxy creates a new ReverseProxy.
func NewReverseProxy(targetURL *url.URL, proxyURL *url.URL, debug, passHostHeader bool, responseHeaderTimeout time.Duration, connPool *connPool) (*ReverseProxy, error) {
func NewReverseProxy(targetURL, proxyURL *url.URL, debug, passHostHeader, preservePath bool, responseHeaderTimeout time.Duration, connPool *connPool) (*ReverseProxy, error) {
var proxyAuth string
if proxyURL != nil && proxyURL.User != nil && targetURL.Scheme == "http" {
username := proxyURL.User.Username()
@ -136,6 +137,7 @@ func NewReverseProxy(targetURL *url.URL, proxyURL *url.URL, debug, passHostHeade
return &ReverseProxy{
debug: debug,
passHostHeader: passHostHeader,
preservePath: preservePath,
targetURL: targetURL,
proxyAuth: proxyAuth,
connPool: connPool,
@ -207,6 +209,11 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
u2.Path = u.Path
u2.RawPath = u.RawPath
if p.preservePath {
u2.Path, u2.RawPath = proxyhttputil.JoinURLPath(p.targetURL, u)
}
u2.RawQuery = strings.ReplaceAll(u.RawQuery, ";", "&")
outReq.SetHost(u2.Host)

View file

@ -230,7 +230,7 @@ func TestProxyFromEnvironment(t *testing.T) {
return u, nil
}
reverseProxy, err := builder.Build("foo", testhelpers.MustParseURL(backendURL), false)
reverseProxy, err := builder.Build("foo", testhelpers.MustParseURL(backendURL), false, false)
require.NoError(t, err)
reverseProxyServer := httptest.NewServer(reverseProxy)
@ -252,6 +252,32 @@ func TestProxyFromEnvironment(t *testing.T) {
}
}
func TestPreservePath(t *testing.T) {
var callCount int
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
callCount++
assert.Equal(t, "/base/foo/bar", req.URL.Path)
assert.Equal(t, "/base/foo%2Fbar", req.URL.RawPath)
}))
t.Cleanup(server.Close)
builder := NewProxyBuilder(&transportManagerMock{}, static.FastProxyConfig{})
serverURL, err := url.JoinPath(server.URL, "base")
require.NoError(t, err)
proxyHandler, err := builder.Build("", testhelpers.MustParseURL(serverURL), true, true)
require.NoError(t, err)
req := httptest.NewRequest(http.MethodGet, "/foo%2Fbar", http.NoBody)
res := httptest.NewRecorder()
proxyHandler.ServeHTTP(res, req)
assert.Equal(t, 1, callCount)
assert.Equal(t, http.StatusOK, res.Code)
}
func newCertificate(t *testing.T, domain string) *tls.Certificate {
t.Helper()

View file

@ -362,7 +362,7 @@ func TestWebSocketRequestWithHeadersInResponseWriter(t *testing.T) {
u := parseURI(t, srv.URL)
f, err := NewReverseProxy(u, nil, true, false, 0, newConnPool(1, 0, func() (net.Conn, error) {
f, err := NewReverseProxy(u, nil, true, false, false, 0, newConnPool(1, 0, func() (net.Conn, error) {
return net.Dial("tcp", u.Host)
}))
require.NoError(t, err)
@ -434,7 +434,7 @@ func TestWebSocketUpgradeFailed(t *testing.T) {
defer srv.Close()
u := parseURI(t, srv.URL)
f, err := NewReverseProxy(u, nil, true, false, 0, newConnPool(1, 0, func() (net.Conn, error) {
f, err := NewReverseProxy(u, nil, true, false, false, 0, newConnPool(1, 0, func() (net.Conn, error) {
return net.Dial("tcp", u.Host)
}))
require.NoError(t, err)
@ -676,7 +676,7 @@ func createProxyWithForwarder(t *testing.T, uri string, pool *connPool) *httptes
t.Helper()
u := parseURI(t, uri)
proxy, err := NewReverseProxy(u, nil, false, true, 0, pool)
proxy, err := NewReverseProxy(u, nil, false, true, false, 0, pool)
require.NoError(t, err)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {