mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-20 12:42:34 +02:00
improved homepage support, memory leak partial fix
This commit is contained in:
parent
4f09dbf044
commit
de6c1be51b
7 changed files with 42 additions and 32 deletions
|
@ -16,6 +16,7 @@ var (
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
DialContext: defaultDialer.DialContext,
|
DialContext: defaultDialer.DialContext,
|
||||||
MaxIdleConnsPerHost: 1000,
|
MaxIdleConnsPerHost: 1000,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
}
|
}
|
||||||
DefaultTransportNoTLS = func() *http.Transport {
|
DefaultTransportNoTLS = func() *http.Transport {
|
||||||
var clone = DefaultTransport.Clone()
|
var clone = DefaultTransport.Clone()
|
||||||
|
|
|
@ -71,17 +71,11 @@ func (cfg *Config) HomepageConfig() H.HomePageConfig {
|
||||||
if item.Category == "" {
|
if item.Category == "" {
|
||||||
item.Category = "Docker"
|
item.Category = "Docker"
|
||||||
}
|
}
|
||||||
if item.Icon == "" {
|
|
||||||
item.Icon = "🐳"
|
|
||||||
}
|
|
||||||
item.SourceType = string(PR.ProviderTypeDocker)
|
item.SourceType = string(PR.ProviderTypeDocker)
|
||||||
} else if p.GetType() == PR.ProviderTypeFile {
|
} else if p.GetType() == PR.ProviderTypeFile {
|
||||||
if item.Category == "" {
|
if item.Category == "" {
|
||||||
item.Category = "Others"
|
item.Category = "Others"
|
||||||
}
|
}
|
||||||
if item.Icon == "" {
|
|
||||||
item.Icon = "🔗"
|
|
||||||
}
|
|
||||||
item.SourceType = string(PR.ProviderTypeFile)
|
item.SourceType = string(PR.ProviderTypeFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +84,7 @@ func (cfg *Config) HomepageConfig() H.HomePageConfig {
|
||||||
item.URL = fmt.Sprintf("%s://%s.%s:%s", proto, strings.ToLower(alias), domains[0], port)
|
item.URL = fmt.Sprintf("%s://%s.%s:%s", proto, strings.ToLower(alias), domains[0], port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
item.AltURL = r.URL().String()
|
||||||
|
|
||||||
hpCfg.Add(&item)
|
hpCfg.Add(&item)
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,13 +8,14 @@ type (
|
||||||
Show bool `yaml:"show" json:"show"`
|
Show bool `yaml:"show" json:"show"`
|
||||||
Name string `yaml:"name" json:"name"`
|
Name string `yaml:"name" json:"name"`
|
||||||
Icon string `yaml:"icon" json:"icon"`
|
Icon string `yaml:"icon" json:"icon"`
|
||||||
URL string `yaml:"url" json:"url"` // URL or unicodes
|
URL string `yaml:"url" json:"url"` // alias + domain
|
||||||
Category string `yaml:"category" json:"category"`
|
Category string `yaml:"category" json:"category"`
|
||||||
Description string `yaml:"description" json:"description"`
|
Description string `yaml:"description" json:"description"`
|
||||||
WidgetConfig map[string]any `yaml:",flow" json:"widget_config"`
|
WidgetConfig map[string]any `yaml:",flow" json:"widget_config"`
|
||||||
|
|
||||||
SourceType string `yaml:"-" json:"source_type"`
|
SourceType string `yaml:"-" json:"source_type"`
|
||||||
Initialized bool `yaml:"-" json:"-"`
|
Initialized bool `yaml:"-" json:"-"`
|
||||||
|
AltURL string `yaml:"-" json:"alt_url"` // original proxy target
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ import (
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/http/httpguts"
|
"golang.org/x/net/http/httpguts"
|
||||||
|
|
||||||
|
U "github.com/yusing/go-proxy/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A ProxyRequest contains a request to be rewritten by a [ReverseProxy].
|
// A ProxyRequest contains a request to be rewritten by a [ReverseProxy].
|
||||||
|
@ -418,9 +420,11 @@ func (p *ReverseProxy) serveHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
rw.WriteHeader(res.StatusCode)
|
rw.WriteHeader(res.StatusCode)
|
||||||
|
|
||||||
_, err = io.Copy(rw, res.Body)
|
err = U.Copy2(req.Context(), rw, res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.errorHandler(rw, req, err, true)
|
if !errors.Is(err, context.Canceled) {
|
||||||
|
p.errorHandler(rw, req, err, true)
|
||||||
|
}
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -525,17 +529,9 @@ func (p *ReverseProxy) handleUpgradeResponse(rw http.ResponseWriter, req *http.R
|
||||||
p.errorHandler(rw, req, fmt.Errorf("response flush: %s", err), true)
|
p.errorHandler(rw, req, fmt.Errorf("response flush: %s", err), true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
errc := make(chan error, 1)
|
|
||||||
|
|
||||||
go func() {
|
bdp := U.NewBidirectionalPipe(req.Context(), conn, backConn)
|
||||||
_, err := io.Copy(conn, backConn)
|
bdp.Start()
|
||||||
errc <- err
|
|
||||||
}()
|
|
||||||
go func() {
|
|
||||||
_, err := io.Copy(backConn, conn)
|
|
||||||
errc <- err
|
|
||||||
}()
|
|
||||||
<-errc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsPrint(s string) bool {
|
func IsPrint(s string) bool {
|
||||||
|
|
|
@ -27,7 +27,7 @@ type (
|
||||||
PathPatterns PT.PathPatterns `json:"path_patterns"`
|
PathPatterns PT.PathPatterns `json:"path_patterns"`
|
||||||
|
|
||||||
entry *P.ReverseProxyEntry
|
entry *P.ReverseProxyEntry
|
||||||
mux *http.ServeMux
|
mux http.Handler
|
||||||
handler *ReverseProxy
|
handler *ReverseProxy
|
||||||
|
|
||||||
regIdleWatcher func() E.NestedError
|
regIdleWatcher func() E.NestedError
|
||||||
|
@ -36,16 +36,24 @@ type (
|
||||||
|
|
||||||
URL url.URL
|
URL url.URL
|
||||||
SubdomainKey = PT.Alias
|
SubdomainKey = PT.Alias
|
||||||
|
|
||||||
|
ReverseProxyHandler struct {
|
||||||
|
*ReverseProxy
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
findMuxFunc = findMuxAnyDomain
|
findMuxFunc = findMuxAnyDomain
|
||||||
|
|
||||||
httpRoutes = F.NewMapOf[SubdomainKey, *HTTPRoute]()
|
httpRoutes = F.NewMapOf[string, *HTTPRoute]()
|
||||||
httpRoutesMu sync.Mutex
|
httpRoutesMu sync.Mutex
|
||||||
globalMux = http.NewServeMux() // TODO: support regex subdomain matching
|
globalMux = http.NewServeMux() // TODO: support regex subdomain matching
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (rp ReverseProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
rp.ReverseProxy.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
func SetFindMuxDomains(domains []string) {
|
func SetFindMuxDomains(domains []string) {
|
||||||
if len(domains) == 0 {
|
if len(domains) == 0 {
|
||||||
findMuxFunc = findMuxAnyDomain
|
findMuxFunc = findMuxAnyDomain
|
||||||
|
@ -134,12 +142,17 @@ func (r *HTTPRoute) Start() E.NestedError {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
r.mux = http.NewServeMux()
|
if len(r.PathPatterns) == 1 && r.PathPatterns[0] == "/" {
|
||||||
for _, p := range r.PathPatterns {
|
r.mux = ReverseProxyHandler{r.handler}
|
||||||
r.mux.HandleFunc(string(p), r.handler.ServeHTTP)
|
} else {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
for _, p := range r.PathPatterns {
|
||||||
|
mux.HandleFunc(string(p), r.handler.ServeHTTP)
|
||||||
|
}
|
||||||
|
r.mux = mux
|
||||||
}
|
}
|
||||||
|
|
||||||
httpRoutes.Store(r.Alias, r)
|
httpRoutes.Store(string(r.Alias), r)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +170,7 @@ func (r *HTTPRoute) Stop() E.NestedError {
|
||||||
}
|
}
|
||||||
|
|
||||||
r.mux = nil
|
r.mux = nil
|
||||||
httpRoutes.Delete(r.Alias)
|
httpRoutes.Delete(string(r.Alias))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,21 +207,21 @@ func ProxyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
mux.ServeHTTP(w, r)
|
mux.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func findMuxAnyDomain(host string) (*http.ServeMux, error) {
|
func findMuxAnyDomain(host string) (http.Handler, error) {
|
||||||
hostSplit := strings.Split(host, ".")
|
hostSplit := strings.Split(host, ".")
|
||||||
n := len(hostSplit)
|
n := len(hostSplit)
|
||||||
if n <= 2 {
|
if n <= 2 {
|
||||||
return nil, fmt.Errorf("missing subdomain in url")
|
return nil, fmt.Errorf("missing subdomain in url")
|
||||||
}
|
}
|
||||||
sd := strings.Join(hostSplit[:n-2], ".")
|
sd := strings.Join(hostSplit[:n-2], ".")
|
||||||
if r, ok := httpRoutes.Load(PT.Alias(sd)); ok {
|
if r, ok := httpRoutes.Load(sd); ok {
|
||||||
return r.mux, nil
|
return r.mux, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no such route: %s", sd)
|
return nil, fmt.Errorf("no such route: %s", sd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func findMuxByDomains(domains []string) func(host string) (*http.ServeMux, error) {
|
func findMuxByDomains(domains []string) func(host string) (http.Handler, error) {
|
||||||
return func(host string) (*http.ServeMux, error) {
|
return func(host string) (http.Handler, error) {
|
||||||
var subdomain string
|
var subdomain string
|
||||||
|
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
|
@ -223,7 +236,7 @@ func findMuxByDomains(domains []string) func(host string) (*http.ServeMux, error
|
||||||
if len(subdomain) == len(host) { // not matched
|
if len(subdomain) == len(host) { // not matched
|
||||||
return nil, fmt.Errorf("%s does not match any base domain", host)
|
return nil, fmt.Errorf("%s does not match any base domain", host)
|
||||||
}
|
}
|
||||||
if r, ok := httpRoutes.Load(PT.Alias(subdomain)); ok {
|
if r, ok := httpRoutes.Load(subdomain); ok {
|
||||||
return r.mux, nil
|
return r.mux, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no such route: %s", subdomain)
|
return nil, fmt.Errorf("no such route: %s", subdomain)
|
||||||
|
|
|
@ -74,7 +74,7 @@ func (rt *route) Type() RouteType {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *route) URL() *url.URL {
|
func (rt *route) URL() *url.URL {
|
||||||
url, _ := url.Parse(fmt.Sprintf("%s://%s", rt.entry.Scheme, rt.entry.Host))
|
url, _ := url.Parse(fmt.Sprintf("%s://%s:%s", rt.entry.Scheme, rt.entry.Host, rt.entry.Port))
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,10 @@ func Copy(dst *ContextWriter, src *ContextReader) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Copy2(ctx context.Context, dst io.Writer, src io.Reader) error {
|
||||||
|
return Copy(&ContextWriter{ctx: ctx, Writer: dst}, &ContextReader{ctx: ctx, Reader: src})
|
||||||
|
}
|
||||||
|
|
||||||
func LoadJson[T any](path string, pointer *T) E.NestedError {
|
func LoadJson[T any](path string, pointer *T) E.NestedError {
|
||||||
data, err := E.Check(os.ReadFile(path))
|
data, err := E.Check(os.ReadFile(path))
|
||||||
if err.HasError() {
|
if err.HasError() {
|
||||||
|
|
Loading…
Add table
Reference in a new issue