mirror of
https://github.com/yusing/godoxy.git
synced 2025-07-13 09:24:02 +02:00
fixing sub path_mode
This commit is contained in:
parent
2f439233ed
commit
bee415e22c
12 changed files with 121 additions and 48 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
compose.yml
|
compose.yml
|
||||||
go-proxy.yml
|
go-proxy.yml
|
||||||
bin/go-proxy.bak
|
bin/go-proxy.bak
|
||||||
logs/
|
logs/
|
||||||
|
log/
|
4
Makefile
4
Makefile
|
@ -13,14 +13,14 @@ quick-restart: # quick restart without restarting the container
|
||||||
docker cp bin/go-proxy go-proxy:/app/go-proxy
|
docker cp bin/go-proxy go-proxy:/app/go-proxy
|
||||||
docker cp templates/* go-proxy:/app/templates
|
docker cp templates/* go-proxy:/app/templates
|
||||||
docker cp entrypoint.sh go-proxy:/app/entrypoint.sh
|
docker cp entrypoint.sh go-proxy:/app/entrypoint.sh
|
||||||
docker exec -d go-proxy bash -c "/app/entrypoint.sh restart"
|
docker exec -d go-proxy bash /app/entrypoint.sh restart
|
||||||
|
|
||||||
restart:
|
restart:
|
||||||
docker kill go-proxy
|
docker kill go-proxy
|
||||||
docker compose up -d go-proxy
|
docker compose up -d go-proxy
|
||||||
|
|
||||||
logs:
|
logs:
|
||||||
docker logs -f go-proxy
|
tail -f log/go-proxy.log
|
||||||
|
|
||||||
get:
|
get:
|
||||||
go get -d -u ./src/go-proxy
|
go get -d -u ./src/go-proxy
|
||||||
|
|
|
@ -25,7 +25,7 @@ In the examples domain `x.y.z` is used, replace them with your domain
|
||||||
- subdomain matching **(domain name doesn't matter)**
|
- subdomain matching **(domain name doesn't matter)**
|
||||||
- path matching
|
- path matching
|
||||||
- HTTP proxy
|
- HTTP proxy
|
||||||
- TCP/UDP Proxy (experimental, unable to release port on hot-reload)
|
- TCP/UDP Proxy
|
||||||
- HTTP round robin load balance support (same subdomain and path across containers replicas)
|
- HTTP round robin load balance support (same subdomain and path across containers replicas)
|
||||||
- Auto hot-reload when container start / die / stop.
|
- Auto hot-reload when container start / die / stop.
|
||||||
- Simple panel to see all reverse proxies and health (visit port [panel port] of go-proxy `https://*.y.z:[panel port]`)
|
- Simple panel to see all reverse proxies and health (visit port [panel port] of go-proxy `https://*.y.z:[panel port]`)
|
||||||
|
@ -97,7 +97,8 @@ However, there are some labels you can manipulate with:
|
||||||
- forward: path remain unchanged
|
- forward: path remain unchanged
|
||||||
1. apps.y.z/webdav -> webdav:80/webdav
|
1. apps.y.z/webdav -> webdav:80/webdav
|
||||||
2. apps.y.z./webdav/path/to/file -> webdav:80/webdav/path/to/file
|
2. apps.y.z./webdav/path/to/file -> webdav:80/webdav/path/to/file
|
||||||
- sub: remove path prefix from both URL and HTML attributes (`src`, `href` and `action`)
|
- sub: (experimental) remove path prefix from URL and also append path to HTML link attributes (`src`, `href` and `action`) and Javascript `fetch(url)` by response body substitution
|
||||||
|
e.g. apps.y.z/app1 -> webdav:80, `href="/path/to/file"` -> `href="/app1/path/to/file"`
|
||||||
|
|
||||||
- `proxy.<alias>.load_balance`: enable load balance
|
- `proxy.<alias>.load_balance`: enable load balance
|
||||||
- allowed: `1`, `true`
|
- allowed: `1`, `true`
|
||||||
|
|
BIN
bin/go-proxy
BIN
bin/go-proxy
Binary file not shown.
|
@ -19,7 +19,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- /path/to/cert.pem:/certs/cert.crt:ro
|
- /path/to/cert.pem:/certs/cert.crt:ro
|
||||||
- /path/to/privkey.pem:/certs/priv.key:ro
|
- /path/to/privkey.pem:/certs/priv.key:ro
|
||||||
- ./go-proxy/logs:/app/log # path to logs
|
- ./log:/app/log # path to logs
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- host.docker.internal:host-gateway # required if you have containers in `host` network_mode
|
- host.docker.internal:host-gateway # required if you have containers in `host` network_mode
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
if [ "$1" == "restart" ]; then
|
if [ "$1" == "restart" ]; then
|
||||||
|
echo "restarting"
|
||||||
killall go-proxy
|
killall go-proxy
|
||||||
fi
|
fi
|
||||||
|
if [ -z "$VERBOSITY" ]; then
|
||||||
|
VERBOSITY=1
|
||||||
|
fi
|
||||||
|
echo "starting with verbosity $VERBOSITY" > log/go-proxy.log
|
||||||
if [ "$DEBUG" == "1" ]; then
|
if [ "$DEBUG" == "1" ]; then
|
||||||
/app/go-proxy -v=$VERBOSITY -log_dir=log --stderrthreshold=0 &
|
/app/go-proxy -v=$VERBOSITY -log_dir=log --stderrthreshold=0 2>> log/go-proxy.log &
|
||||||
if [ "$1" != "restart" ]; then
|
tail -f /dev/null
|
||||||
tail -f /dev/null
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
/app/go-proxy -v=$VERBOSITY -log_dir=log --stderrthreshold=0 &
|
/app/go-proxy -v=$VERBOSITY -log_dir=log --stderrthreshold=0
|
||||||
fi
|
fi
|
8
go.sum
8
go.sum
|
@ -74,16 +74,12 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
|
||||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
|
||||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -94,8 +90,6 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -108,8 +102,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
|
||||||
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
|
||||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||||
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
|
@ -46,7 +46,7 @@ const (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProxyPathMode_Forward = "forward"
|
ProxyPathMode_Forward = "forward"
|
||||||
ProxyPathMode_Sub = "sub" // TODO: implement
|
ProxyPathMode_Sub = "sub"
|
||||||
ProxyPathMode_RemovedPath = ""
|
ProxyPathMode_RemovedPath = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -65,20 +65,31 @@ func NewHTTPRoute(config *ProxyConfig) (*HTTPRoute, error) {
|
||||||
initRewrite(pr)
|
initRewrite(pr)
|
||||||
// disable compression
|
// disable compression
|
||||||
pr.Out.Header.Set("Accept-Encoding", "identity")
|
pr.Out.Header.Set("Accept-Encoding", "identity")
|
||||||
|
// remove path prefix
|
||||||
pr.Out.URL.Path = strings.TrimPrefix(pr.Out.URL.Path, config.Path)
|
pr.Out.URL.Path = strings.TrimPrefix(pr.Out.URL.Path, config.Path)
|
||||||
}
|
}
|
||||||
route.Proxy.ModifyResponse = func(r *http.Response) error {
|
route.Proxy.ModifyResponse = func(r *http.Response) error {
|
||||||
contentType, ok := r.Header["Content-Type"]
|
contentType, ok := r.Header["Content-Type"]
|
||||||
if !ok || len(contentType) == 0 {
|
if !ok || len(contentType) == 0 {
|
||||||
glog.Infof("unknown content type for %s", r.Request.URL.String())
|
if glog.V(3) {
|
||||||
|
glog.Infof("[Path sub] unknown content type for %s", r.Request.URL.String())
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !strings.HasPrefix(contentType[0], "text/html") {
|
// disable cache
|
||||||
return nil
|
r.Header.Set("Cache-Control", "no-store")
|
||||||
|
|
||||||
|
var err error = nil
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(contentType[0], "text/html"):
|
||||||
|
err = utils.respHTMLSubPath(r, config.Path)
|
||||||
|
case strings.HasPrefix(contentType[0], "application/javascript"):
|
||||||
|
err = utils.respJSSubPath(r, config.Path)
|
||||||
|
default:
|
||||||
|
glog.V(4).Infof("[Path sub] unknown content type(s): %s", contentType)
|
||||||
}
|
}
|
||||||
err := utils.respRemovePath(r, config.Path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("failed to remove path prefix %s: %v", config.Path, err)
|
err = fmt.Errorf("[Path sub] failed to remove path prefix %s: %v", config.Path, err)
|
||||||
r.Status = err.Error()
|
r.Status = err.Error()
|
||||||
r.StatusCode = http.StatusInternalServerError
|
r.StatusCode = http.StatusInternalServerError
|
||||||
}
|
}
|
||||||
|
@ -96,7 +107,7 @@ func NewHTTPRoute(config *ProxyConfig) (*HTTPRoute, error) {
|
||||||
rewrite(pr)
|
rewrite(pr)
|
||||||
r := pr.In
|
r := pr.In
|
||||||
glog.Infof("[Request] %s %s%s", r.Method, r.Host, r.URL.Path)
|
glog.Infof("[Request] %s %s%s", r.Method, r.Host, r.URL.Path)
|
||||||
glog.V(4).InfoDepthf(1, "Headers: %v", r.Header)
|
glog.V(5).InfoDepthf(1, "Headers: %v", r.Header)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
route.Proxy.Rewrite = rewrite
|
route.Proxy.Rewrite = rewrite
|
||||||
|
@ -141,7 +152,6 @@ func httpProxyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
r.URL.Path,
|
r.URL.Path,
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
glog.Error(err)
|
|
||||||
http.Error(w, err.Error(), http.StatusNotFound)
|
http.Error(w, err.Error(), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
@ -51,6 +52,12 @@ func main() {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for range time.Tick(100 * time.Millisecond) {
|
||||||
|
glog.Flush()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc("/", httpProxyHandler)
|
mux.HandleFunc("/", httpProxyHandler)
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,14 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
xhtml "golang.org/x/net/html"
|
xhtml "golang.org/x/net/html"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -79,7 +83,7 @@ func (*Utils) healthCheckHttp(targetUrl string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Utils) healthCheckStream(scheme string, host string) error {
|
func (*Utils) healthCheckStream(scheme, host string) error {
|
||||||
conn, err := net.DialTimeout(scheme, host, 5*time.Second)
|
conn, err := net.DialTimeout(scheme, host, 5*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -93,25 +97,49 @@ func (*Utils) snakeToCamel(s string) string {
|
||||||
return strings.ReplaceAll(toHyphenCamel, "-", "")
|
return strings.ReplaceAll(toHyphenCamel, "-", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func htmlNodesSubPath(node *xhtml.Node, path string) {
|
func tryAppendPathPrefixImpl(pOrig, pAppend string) string {
|
||||||
if node.Type == xhtml.ElementNode {
|
switch {
|
||||||
for _, attr := range node.Attr {
|
case strings.Contains(pOrig, "://"):
|
||||||
switch attr.Key {
|
return pOrig
|
||||||
case "src": // img, script, etc.
|
case pOrig == "", pOrig == "#", pOrig == "/":
|
||||||
case "href": // link
|
return pAppend
|
||||||
case "action": // form
|
case filepath.IsLocal(pOrig) && !strings.HasPrefix(pOrig, pAppend):
|
||||||
if strings.HasPrefix(attr.Val, path) {
|
return path.Join(pAppend, pOrig)
|
||||||
attr.Val = strings.Replace(attr.Val, path, "", 1)
|
default:
|
||||||
}
|
return pOrig
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for c := node.FirstChild; c != nil; c = c.NextSibling {
|
|
||||||
htmlNodesSubPath(c, path)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*Utils) respRemovePath(r *http.Response, path string) error {
|
var tryAppendPathPrefix func(string, string) string
|
||||||
|
var _ = func() int {
|
||||||
|
if glog.V(4) {
|
||||||
|
tryAppendPathPrefix = func(s1, s2 string) string {
|
||||||
|
replaced := tryAppendPathPrefixImpl(s1, s2)
|
||||||
|
glog.Infof("[Path sub] %s -> %s", s1, replaced)
|
||||||
|
return replaced
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tryAppendPathPrefix = tryAppendPathPrefixImpl
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}()
|
||||||
|
|
||||||
|
func htmlNodesSubPath(n *xhtml.Node, p string) {
|
||||||
|
if n.Type == xhtml.ElementNode {
|
||||||
|
for i, attr := range n.Attr {
|
||||||
|
switch attr.Key {
|
||||||
|
case "src", "href", "action": // img, script, link, form etc.
|
||||||
|
n.Attr[i].Val = tryAppendPathPrefix(attr.Val, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||||
|
htmlNodesSubPath(c, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Utils) respHTMLSubPath(r *http.Response, p string) error {
|
||||||
// remove all path prefix from relative path in script, img, a, ...
|
// remove all path prefix from relative path in script, img, a, ...
|
||||||
doc, err := xhtml.Parse(r.Body)
|
doc, err := xhtml.Parse(r.Body)
|
||||||
|
|
||||||
|
@ -119,11 +147,14 @@ func (*Utils) respRemovePath(r *http.Response, path string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlNodesSubPath(doc, path)
|
if p[0] == '/' {
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
htmlNodesSubPath(doc, p)
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err = xhtml.Render(&buf, doc)
|
err = xhtml.Render(&buf, doc)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -132,3 +163,29 @@ func (*Utils) respRemovePath(r *http.Response, path string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*Utils) respJSSubPath(r *http.Response, p string) error {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
_, err := buf.ReadFrom(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if p[0] == '/' {
|
||||||
|
p = p[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
js := buf.String()
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`fetch\(["'].+["']\)`)
|
||||||
|
replace := func(match string) string {
|
||||||
|
match = match[7 : len(match)-2]
|
||||||
|
replaced := tryAppendPathPrefix(match, p)
|
||||||
|
return fmt.Sprintf(`fetch(%q)`, replaced)
|
||||||
|
}
|
||||||
|
js = re.ReplaceAllStringFunc(js, replace)
|
||||||
|
|
||||||
|
r.Body = io.NopCloser(strings.NewReader(js))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -72,8 +72,8 @@
|
||||||
function updateHealthStatus() {
|
function updateHealthStatus() {
|
||||||
let rows = document.querySelectorAll('tbody tr');
|
let rows = document.querySelectorAll('tbody tr');
|
||||||
rows.forEach(row => {
|
rows.forEach(row => {
|
||||||
let url = row.cells[2].textContent;
|
let url = row.cells[3].textContent;
|
||||||
let cell = row.cells[3]; // Health column cell
|
let cell = row.cells[4]; // Health column cell
|
||||||
checkHealth(url, cell);
|
checkHealth(url, cell);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th>Alias</th>
|
<th>Alias</th>
|
||||||
<th>Path</th>
|
<th>Path</th>
|
||||||
|
<th>Path Mode</th>
|
||||||
<th>URL</th>
|
<th>URL</th>
|
||||||
<th>Health</th>
|
<th>Health</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -111,6 +112,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{$alias}}</td>
|
<td>{{$alias}}</td>
|
||||||
<td>{{$path}}</td>
|
<td>{{$path}}</td>
|
||||||
|
<td>{{$route.PathMode}}</td>
|
||||||
<td>{{$route.Url.String}}</td>
|
<td>{{$route.Url.String}}</td>
|
||||||
<td class="align-middle">
|
<td class="align-middle">
|
||||||
<div class="health-circle"></div>
|
<div class="health-circle"></div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue