mirror of
https://github.com/yusing/godoxy.git
synced 2025-06-09 13:02:33 +02:00
improved HTTP performance, especially when match_domains are used; api json string fix
This commit is contained in:
parent
46b4090629
commit
625bf4dfdc
4 changed files with 48 additions and 34 deletions
|
@ -2,6 +2,7 @@ package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/yusing/go-proxy/internal/logging"
|
"github.com/yusing/go-proxy/internal/logging"
|
||||||
|
@ -23,7 +24,7 @@ func RespondJSON(w http.ResponseWriter, r *http.Request, data any, code ...int)
|
||||||
|
|
||||||
switch data := data.(type) {
|
switch data := data.(type) {
|
||||||
case string:
|
case string:
|
||||||
j = []byte(`"` + data + `"`)
|
j = []byte(fmt.Sprintf("%q", data))
|
||||||
case []byte:
|
case []byte:
|
||||||
j = data
|
j = data
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -16,13 +16,12 @@ var (
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
DialContext: defaultDialer.DialContext,
|
DialContext: defaultDialer.DialContext,
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
MaxIdleConns: 100,
|
MaxIdleConnsPerHost: 100,
|
||||||
MaxIdleConnsPerHost: 10,
|
|
||||||
TLSHandshakeTimeout: 10 * time.Second,
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
ExpectContinueTimeout: 1 * time.Second,
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
}
|
}
|
||||||
DefaultTransportNoTLS = func() *http.Transport {
|
DefaultTransportNoTLS = func() *http.Transport {
|
||||||
var clone = DefaultTransport.Clone()
|
clone := DefaultTransport.Clone()
|
||||||
clone.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
clone.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
return clone
|
return clone
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -404,7 +404,7 @@ func (p *ReverseProxy) serveHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
rw.WriteHeader(res.StatusCode)
|
rw.WriteHeader(res.StatusCode)
|
||||||
|
|
||||||
err = U.Copy2(req.Context(), rw, res.Body)
|
_, err = io.Copy(rw, res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, context.Canceled) {
|
if !errors.Is(err, context.Canceled) {
|
||||||
p.errorHandler(rw, req, err, true)
|
p.errorHandler(rw, req, err, true)
|
||||||
|
|
|
@ -64,6 +64,11 @@ func SetFindMuxDomains(domains []string) {
|
||||||
if len(domains) == 0 {
|
if len(domains) == 0 {
|
||||||
findMuxFunc = findMuxAnyDomain
|
findMuxFunc = findMuxAnyDomain
|
||||||
} else {
|
} else {
|
||||||
|
for i, domain := range domains {
|
||||||
|
if !strings.HasPrefix(domain, ".") {
|
||||||
|
domains[i] = "." + domain
|
||||||
|
}
|
||||||
|
}
|
||||||
findMuxFunc = findMuxByDomains(domains)
|
findMuxFunc = findMuxByDomains(domains)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,11 +215,14 @@ func (r *HTTPRoute) addToLoadBalancer() {
|
||||||
|
|
||||||
func ProxyHandler(w http.ResponseWriter, r *http.Request) {
|
func ProxyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
mux, err := findMuxFunc(r.Host)
|
mux, err := findMuxFunc(r.Host)
|
||||||
|
if err == nil {
|
||||||
|
mux.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
// Why use StatusNotFound instead of StatusBadRequest or StatusBadGateway?
|
// Why use StatusNotFound instead of StatusBadRequest or StatusBadGateway?
|
||||||
// On nginx, when route for domain does not exist, it returns StatusBadGateway.
|
// On nginx, when route for domain does not exist, it returns StatusBadGateway.
|
||||||
// Then scraper / scanners will know the subdomain is invalid.
|
// Then scraper / scanners will know the subdomain is invalid.
|
||||||
// With StatusNotFound, they won't know whether it's the path, or the subdomain that is invalid.
|
// With StatusNotFound, they won't know whether it's the path, or the subdomain that is invalid.
|
||||||
if err != nil {
|
|
||||||
if !middleware.ServeStaticErrorPageFile(w, r) {
|
if !middleware.ServeStaticErrorPageFile(w, r) {
|
||||||
logger.Err(err).Str("method", r.Method).Str("url", r.URL.String()).Msg("request")
|
logger.Err(err).Str("method", r.Method).Str("url", r.URL.String()).Msg("request")
|
||||||
errorPage, ok := errorpage.GetErrorPageByStatus(http.StatusNotFound)
|
errorPage, ok := errorpage.GetErrorPageByStatus(http.StatusNotFound)
|
||||||
|
@ -228,22 +236,30 @@ func ProxyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusNotFound)
|
http.Error(w, err.Error(), http.StatusNotFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
mux.ServeHTTP(w, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func findMuxAnyDomain(host string) (http.Handler, 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 {
|
switch {
|
||||||
|
case n == 3:
|
||||||
|
host = hostSplit[0]
|
||||||
|
case n > 3:
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.Grow(2*n - 3)
|
||||||
|
builder.WriteString(hostSplit[0])
|
||||||
|
for _, part := range hostSplit[:n-2] {
|
||||||
|
builder.WriteRune('.')
|
||||||
|
builder.WriteString(part)
|
||||||
|
}
|
||||||
|
host = builder.String()
|
||||||
|
default:
|
||||||
return nil, errors.New("missing subdomain in url")
|
return nil, errors.New("missing subdomain in url")
|
||||||
}
|
}
|
||||||
sd := strings.Join(hostSplit[:n-2], ".")
|
if r, ok := httpRoutes.Load(host); ok {
|
||||||
if r, ok := httpRoutes.Load(sd); ok {
|
|
||||||
return r.handler, nil
|
return r.handler, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no such route: %s", sd)
|
return nil, fmt.Errorf("no such route: %s", host)
|
||||||
}
|
}
|
||||||
|
|
||||||
func findMuxByDomains(domains []string) func(host string) (http.Handler, error) {
|
func findMuxByDomains(domains []string) func(host string) (http.Handler, error) {
|
||||||
|
@ -251,20 +267,18 @@ func findMuxByDomains(domains []string) func(host string) (http.Handler, error)
|
||||||
var subdomain string
|
var subdomain string
|
||||||
|
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
if !strings.HasPrefix(domain, ".") {
|
if strings.HasSuffix(host, domain) {
|
||||||
domain = "." + domain
|
|
||||||
}
|
|
||||||
subdomain = strings.TrimSuffix(host, domain)
|
subdomain = strings.TrimSuffix(host, domain)
|
||||||
if len(subdomain) < len(host) {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(subdomain) == len(host) { // not matched
|
|
||||||
return nil, fmt.Errorf("%s does not match any base domain", host)
|
if subdomain != "" { // matched
|
||||||
}
|
|
||||||
if r, ok := httpRoutes.Load(subdomain); ok {
|
if r, ok := httpRoutes.Load(subdomain); ok {
|
||||||
return r.handler, nil
|
return r.handler, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no such route: %s", subdomain)
|
return nil, fmt.Errorf("no such route: %s", subdomain)
|
||||||
}
|
}
|
||||||
|
return nil, fmt.Errorf("%s does not match any base domain", host)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue