mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-20 00:03:53 +01:00
Merge branch 'main' into dev
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||
@@ -43,10 +44,22 @@ func ProxyHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
r.URL.Scheme = ""
|
||||
r.URL.Host = ""
|
||||
r.URL.Path = r.URL.Path[agent.HTTPProxyURLPrefixLen:] // strip the {API_BASE}/proxy/http prefix
|
||||
r.RequestURI = r.URL.String()
|
||||
// Strip the {API_BASE}/proxy/http prefix while preserving URL escaping.
|
||||
//
|
||||
// NOTE: `r.URL.Path` is decoded. If we rewrite it without keeping `RawPath`
|
||||
// in sync, Go may re-escape the path (e.g. turning "%5B" into "%255B"),
|
||||
// which breaks urls with percent-encoded characters, like Next.js static chunk URLs.
|
||||
prefix := agent.APIEndpointBase + agent.EndpointProxyHTTP
|
||||
r.URL.Path = strings.TrimPrefix(r.URL.Path, prefix)
|
||||
if r.URL.RawPath != "" {
|
||||
if after, ok := strings.CutPrefix(r.URL.RawPath, prefix); ok {
|
||||
r.URL.RawPath = after
|
||||
} else {
|
||||
// RawPath is no longer a valid encoding for Path; force Go to re-derive it.
|
||||
r.URL.RawPath = ""
|
||||
}
|
||||
}
|
||||
r.RequestURI = ""
|
||||
|
||||
rp := &httputil.ReverseProxy{
|
||||
Director: func(r *http.Request) {
|
||||
|
||||
@@ -4555,6 +4555,11 @@
|
||||
"x-nullable": false,
|
||||
"x-omitempty": false
|
||||
},
|
||||
"is_excluded": {
|
||||
"type": "boolean",
|
||||
"x-nullable": false,
|
||||
"x-omitempty": false
|
||||
},
|
||||
"statuses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -1056,6 +1056,8 @@ definitions:
|
||||
type: number
|
||||
is_docker:
|
||||
type: boolean
|
||||
is_excluded:
|
||||
type: boolean
|
||||
statuses:
|
||||
items:
|
||||
$ref: '#/definitions/RouteStatus'
|
||||
|
||||
@@ -146,11 +146,18 @@ func findRouteAnyDomain(host string) types.HTTPRoute {
|
||||
if r, ok := routes.HTTP.Get(host); ok {
|
||||
return r
|
||||
}
|
||||
// try striping the trailing :port from the host
|
||||
if before, _, ok := strings.Cut(host, ":"); ok {
|
||||
if r, ok := routes.HTTP.Get(before); ok {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func findRouteByDomains(domains []string) func(host string) types.HTTPRoute {
|
||||
return func(host string) types.HTTPRoute {
|
||||
host, _, _ = strings.Cut(host, ":") // strip the trailing :port
|
||||
for _, domain := range domains {
|
||||
if target, ok := strings.CutSuffix(host, domain); ok {
|
||||
if r, ok := routes.HTTP.Get(target); ok {
|
||||
|
||||
@@ -128,3 +128,47 @@ func TestFindRouteByDomainsExactMatch(t *testing.T) {
|
||||
|
||||
run(t, tests, testsNoMatch)
|
||||
}
|
||||
|
||||
func TestFindRouteWithPort(t *testing.T) {
|
||||
t.Run("AnyDomain", func(t *testing.T) {
|
||||
addRoute("app1")
|
||||
addRoute("app2.com")
|
||||
|
||||
tests := []string{
|
||||
"app1:8080",
|
||||
"app1.domain.com:8080",
|
||||
"app2.com:8080",
|
||||
}
|
||||
testsNoMatch := []string{
|
||||
"app11",
|
||||
"app2.co",
|
||||
"app2.co:8080",
|
||||
}
|
||||
run(t, tests, testsNoMatch)
|
||||
})
|
||||
|
||||
t.Run("ByDomains", func(t *testing.T) {
|
||||
ep.SetFindRouteDomains([]string{
|
||||
".domain.com",
|
||||
})
|
||||
addRoute("app1")
|
||||
addRoute("app2")
|
||||
addRoute("app3.domain.com")
|
||||
|
||||
tests := []string{
|
||||
"app1.domain.com:8080",
|
||||
"app2:8080", // exact match fallback
|
||||
"app3.domain.com:8080",
|
||||
}
|
||||
testsNoMatch := []string{
|
||||
"app11",
|
||||
"app1.domain.co",
|
||||
"app1.domain.co:8080",
|
||||
"app2.co",
|
||||
"app2.co:8080",
|
||||
"app3.domain.co",
|
||||
"app3.domain.co:8080",
|
||||
}
|
||||
run(t, tests, testsNoMatch)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/yusing/ds/ordered"
|
||||
"github.com/yusing/godoxy/internal/homepage/widgets"
|
||||
"github.com/yusing/godoxy/internal/serialization"
|
||||
strutils "github.com/yusing/goutils/strings"
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -146,13 +147,13 @@ func (c *Category) sortByClicks() {
|
||||
return 1
|
||||
}
|
||||
// fallback to alphabetical
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
return strings.Compare(strutils.Title(a.Name), strutils.Title(b.Name))
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Category) sortByAlphabetical() {
|
||||
slices.SortStableFunc(c.Items, func(a, b *Item) int {
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
return strings.Compare(strutils.Title(a.Name), strutils.Title(b.Name))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ type (
|
||||
Idle float32 `json:"idle"`
|
||||
AvgLatency float32 `json:"avg_latency"`
|
||||
IsDocker bool `json:"is_docker"`
|
||||
IsExcluded bool `json:"is_excluded"`
|
||||
CurrentStatus types.HealthStatus `json:"current_status" swaggertype:"string" enums:"healthy,unhealthy,unknown,napping,starting"`
|
||||
Statuses []Status `json:"statuses"`
|
||||
} // @name RouteUptimeAggregate
|
||||
@@ -156,6 +157,7 @@ func (rs RouteStatuses) aggregate(limit int, offset int) Aggregated {
|
||||
CurrentStatus: status,
|
||||
Statuses: statuses,
|
||||
IsDocker: r != nil && r.IsDocker(),
|
||||
IsExcluded: r == nil || r.ShouldExclude(),
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user