mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-29 12:16:16 +08:00
proxy: handle encoded path in URL
fix issue #1362 Signed-off-by: Tw <tw19881113@gmail.com>
This commit is contained in:
parent
91ff734327
commit
c37481cc7b
|
@ -273,11 +273,6 @@ func createUpstreamRequest(r *http.Request) *http.Request {
|
||||||
outreq.Body = nil
|
outreq.Body = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore URL Path if it has been modified
|
|
||||||
if outreq.URL.RawPath != "" {
|
|
||||||
outreq.URL.Opaque = outreq.URL.RawPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are modifying the same underlying map from req (shallow
|
// We are modifying the same underlying map from req (shallow
|
||||||
// copied above) so we only copy it if necessary.
|
// copied above) so we only copy it if necessary.
|
||||||
copiedHeaders := false
|
copiedHeaders := false
|
||||||
|
|
|
@ -949,6 +949,26 @@ func TestProxyDirectorURL(t *testing.T) {
|
||||||
expectURL: `https://localhost:2021/t/mypath`,
|
expectURL: `https://localhost:2021/t/mypath`,
|
||||||
without: "/test",
|
without: "/test",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
requestURL: `http://localhost:2020/%2C`,
|
||||||
|
targetURL: `https://localhost:2021/t/`,
|
||||||
|
expectURL: `https://localhost:2021/t/%2C`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requestURL: `http://localhost:2020/%2C/`,
|
||||||
|
targetURL: `https://localhost:2021/t/`,
|
||||||
|
expectURL: `https://localhost:2021/t/%2C/`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requestURL: `http://localhost:2020/test`,
|
||||||
|
targetURL: `https://localhost:2021/%2C`,
|
||||||
|
expectURL: `https://localhost:2021/%2C/test`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
requestURL: `http://localhost:2020/%2C`,
|
||||||
|
targetURL: `https://localhost:2021/%2C`,
|
||||||
|
expectURL: `https://localhost:2021/%2C/%2C`,
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
targetURL, err := url.Parse(c.targetURL)
|
targetURL, err := url.Parse(c.targetURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -18,7 +18,6 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -89,6 +88,18 @@ func socketDial(hostName string) func(network, addr string) (conn net.Conn, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func singleJoiningSlash(a, b string) string {
|
||||||
|
aslash := strings.HasSuffix(a, "/")
|
||||||
|
bslash := strings.HasPrefix(b, "/")
|
||||||
|
switch {
|
||||||
|
case aslash && bslash:
|
||||||
|
return a + b[1:]
|
||||||
|
case !aslash && !bslash && b != "":
|
||||||
|
return a + "/" + b
|
||||||
|
}
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
|
||||||
// NewSingleHostReverseProxy returns a new ReverseProxy that rewrites
|
// NewSingleHostReverseProxy returns a new ReverseProxy that rewrites
|
||||||
// URLs to the scheme, host, and base path provided in target. If the
|
// URLs to the scheme, host, and base path provided in target. If the
|
||||||
// target's path is "/base" and the incoming request was for "/dir",
|
// target's path is "/base" and the incoming request was for "/dir",
|
||||||
|
@ -119,12 +130,31 @@ func NewSingleHostReverseProxy(target *url.URL, without string, keepalive int) *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hadTrailingSlash := strings.HasSuffix(req.URL.Path, "/")
|
// prefer returns val if it isn't empty, otherwise def
|
||||||
req.URL.Path = path.Join(target.Path, req.URL.Path)
|
prefer := func(val, def string) string {
|
||||||
// path.Join will strip off the last /, so put it back if it was there.
|
if val != "" {
|
||||||
if hadTrailingSlash && !strings.HasSuffix(req.URL.Path, "/") {
|
return val
|
||||||
req.URL.Path = req.URL.Path + "/"
|
}
|
||||||
|
return def
|
||||||
}
|
}
|
||||||
|
// Make up the final URL by concatenating the request and target URL.
|
||||||
|
//
|
||||||
|
// If there is encoded part in request or target URL,
|
||||||
|
// the final URL should also be in encoded format.
|
||||||
|
// Here, we concatenate their encoded parts which are stored
|
||||||
|
// in URL.Opaque and URL.RawPath, if it is empty use
|
||||||
|
// URL.Path instead.
|
||||||
|
if req.URL.Opaque != "" || target.Opaque != "" {
|
||||||
|
req.URL.Opaque = singleJoiningSlash(
|
||||||
|
prefer(target.Opaque, target.Path),
|
||||||
|
prefer(req.URL.Opaque, req.URL.Path))
|
||||||
|
}
|
||||||
|
if req.URL.RawPath != "" || target.RawPath != "" {
|
||||||
|
req.URL.RawPath = singleJoiningSlash(
|
||||||
|
prefer(target.RawPath, target.Path),
|
||||||
|
prefer(req.URL.RawPath, req.URL.Path))
|
||||||
|
}
|
||||||
|
req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
|
||||||
|
|
||||||
// Trims the path of the socket from the URL path.
|
// Trims the path of the socket from the URL path.
|
||||||
// This is done because req.URL passed to your proxied service
|
// This is done because req.URL passed to your proxied service
|
||||||
|
@ -136,6 +166,12 @@ func NewSingleHostReverseProxy(target *url.URL, without string, keepalive int) *
|
||||||
// See comment on socketDial for the trim
|
// See comment on socketDial for the trim
|
||||||
socketPrefix := target.String()[len("unix://"):]
|
socketPrefix := target.String()[len("unix://"):]
|
||||||
req.URL.Path = strings.TrimPrefix(req.URL.Path, socketPrefix)
|
req.URL.Path = strings.TrimPrefix(req.URL.Path, socketPrefix)
|
||||||
|
if req.URL.Opaque != "" {
|
||||||
|
req.URL.Opaque = strings.TrimPrefix(req.URL.Opaque, socketPrefix)
|
||||||
|
}
|
||||||
|
if req.URL.RawPath != "" {
|
||||||
|
req.URL.RawPath = strings.TrimPrefix(req.URL.RawPath, socketPrefix)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetQuery == "" || req.URL.RawQuery == "" {
|
if targetQuery == "" || req.URL.RawQuery == "" {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user