From 9a56c8fba3483ddf752581f9ab1e30f50959b60d Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Thu, 10 Oct 2024 16:52:01 +0800 Subject: [PATCH] add keepalive option for http handler --- handler/http/handler.go | 32 ++++-- handler/http/metadata.go | 5 +- metadata/util/util.go | 225 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+), 11 deletions(-) create mode 100644 metadata/util/util.go diff --git a/handler/http/handler.go b/handler/http/handler.go index 35704378..f2a83f44 100644 --- a/handler/http/handler.go +++ b/handler/http/handler.go @@ -338,31 +338,39 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt conn.SetReadDeadline(time.Time{}) } + dial := func(ctx context.Context, network, address string) (net.Conn, error) { + return cc, nil + } + dialTLS := func(ctx context.Context, network, address string, cfg *tls.Config) (net.Conn, error) { + return cc, nil + } sniffer := &sniffing.Sniffer{ Recorder: h.recorder.Recorder, RecorderOptions: h.recorder.Options, - RecorderObject: ro, Certificate: h.md.certificate, PrivateKey: h.md.privateKey, NegotiatedProtocol: h.md.alpn, CertPool: h.certPool, MitmBypass: h.md.mitmBypass, ReadTimeout: h.md.readTimeout, - Log: log, - Dial: func(ctx context.Context, network, address string) (net.Conn, error) { - return cc, nil - }, - DialTLS: func(ctx context.Context, network, address string, cfg *tls.Config) (net.Conn, error) { - return cc, nil - }, } conn = xnet.NewReadWriteConn(br, rw, conn) switch proto { case sniffing.ProtoHTTP: - return sniffer.HandleHTTP(ctx, conn) + return sniffer.HandleHTTP(ctx, conn, + sniffing.WithDial(dial), + sniffing.WithDialTLS(dialTLS), + sniffing.WithRecorderObject(ro), + sniffing.WithLog(log), + ) case sniffing.ProtoTLS: - return sniffer.HandleTLS(ctx, conn) + return sniffer.HandleTLS(ctx, conn, + sniffing.WithDial(dial), + sniffing.WithDialTLS(dialTLS), + sniffing.WithRecorderObject(ro), + sniffing.WithLog(log), + ) } } @@ -450,6 +458,10 @@ func (h *httpHandler) proxyRoundTrip(ctx context.Context, rw io.ReadWriter, cc n } } + if !h.md.keepalive { + req.Header.Set("Connection", "close") + } + req.Header.Del("Proxy-Authorization") req.Header.Del("Proxy-Connection") req.Header.Del("Gost-Target") diff --git a/handler/http/metadata.go b/handler/http/metadata.go index 50ed5478..13579117 100644 --- a/handler/http/metadata.go +++ b/handler/http/metadata.go @@ -10,7 +10,7 @@ import ( "github.com/go-gost/core/bypass" mdata "github.com/go-gost/core/metadata" - mdutil "github.com/go-gost/core/metadata/util" + mdutil "github.com/go-gost/x/metadata/util" "github.com/go-gost/x/registry" ) @@ -21,6 +21,7 @@ const ( type metadata struct { readTimeout time.Duration + keepalive bool probeResistance *probeResistance enableUDP bool header http.Header @@ -52,6 +53,8 @@ func (h *httpHandler) parseMetadata(md mdata.Metadata) error { h.md.header = hd } + h.md.keepalive = mdutil.GetBool(md, "http.keepalive", "keepalive") + if pr := mdutil.GetString(md, "probeResist", "probe_resist"); pr != "" { if ss := strings.SplitN(pr, ":", 2); len(ss) == 2 { h.md.probeResistance = &probeResistance{ diff --git a/metadata/util/util.go b/metadata/util/util.go new file mode 100644 index 00000000..5fa13c0f --- /dev/null +++ b/metadata/util/util.go @@ -0,0 +1,225 @@ +package util + +import ( + "fmt" + "strconv" + "time" + + "github.com/go-gost/core/metadata" +) + +func IsExists(md metadata.Metadata, keys ...string) bool { + for _, key := range keys { + if md.IsExists(key) { + return true + } + } + return false +} + +func GetBool(md metadata.Metadata, keys ...string) (v bool) { + if md == nil { + return + } + + for _, key := range keys { + if !md.IsExists(key) { + continue + } + switch vv := md.Get(key).(type) { + case bool: + v = vv + case int: + v = vv != 0 + case string: + v, _ = strconv.ParseBool(vv) + } + break + } + + return +} + +func GetInt(md metadata.Metadata, keys ...string) (v int) { + if md == nil { + return + } + + for _, key := range keys { + if !md.IsExists(key) { + continue + } + switch vv := md.Get(key).(type) { + case bool: + if vv { + v = 1 + } + case int: + v = vv + case string: + v, _ = strconv.Atoi(vv) + } + break + } + + return +} + +func GetFloat(md metadata.Metadata, keys ...string) (v float64) { + if md == nil { + return + } + + for _, key := range keys { + if !md.IsExists(key) { + continue + } + + switch vv := md.Get(key).(type) { + case float64: + v = vv + case int: + v = float64(vv) + case string: + v, _ = strconv.ParseFloat(vv, 64) + } + break + } + return +} + +func GetDuration(md metadata.Metadata, keys ...string) (v time.Duration) { + if md == nil { + return + } + + for _, key := range keys { + if !md.IsExists(key) { + continue + } + + switch vv := md.Get(key).(type) { + case int: + v = time.Duration(vv) * time.Second + case string: + v, _ = time.ParseDuration(vv) + if v == 0 { + n, _ := strconv.Atoi(vv) + v = time.Duration(n) * time.Second + } + } + break + } + return +} + +func GetString(md metadata.Metadata, keys ...string) (v string) { + if md == nil { + return + } + + for _, key := range keys { + if !md.IsExists(key) { + continue + } + + switch vv := md.Get(key).(type) { + case string: + v = vv + case int: + v = strconv.FormatInt(int64(vv), 10) + case int64: + v = strconv.FormatInt(vv, 10) + case uint: + v = strconv.FormatUint(uint64(vv), 10) + case uint64: + v = strconv.FormatUint(uint64(vv), 10) + case bool: + v = strconv.FormatBool(vv) + case float32: + v = strconv.FormatFloat(float64(vv), 'f', -1, 32) + case float64: + v = strconv.FormatFloat(float64(vv), 'f', -1, 64) + } + break + } + + return +} + +func GetStrings(md metadata.Metadata, keys ...string) (ss []string) { + if md == nil { + return + } + + for _, key := range keys { + if !md.IsExists(key) { + continue + } + + switch v := md.Get(key).(type) { + case []string: + ss = v + case []any: + for _, vv := range v { + if s, ok := vv.(string); ok { + ss = append(ss, s) + } + } + } + break + } + return +} + +func GetStringMap(md metadata.Metadata, keys ...string) (m map[string]any) { + if md == nil { + return + } + + for _, key := range keys { + if !md.IsExists(key) { + continue + } + + switch vv := md.Get(key).(type) { + case map[string]any: + m = vv + case map[any]any: + m = make(map[string]any) + for k, v := range vv { + m[fmt.Sprintf("%v", k)] = v + } + } + break + } + return +} + +func GetStringMapString(md metadata.Metadata, keys ...string) (m map[string]string) { + if md == nil { + return + } + + for _, key := range keys { + if !md.IsExists(key) { + continue + } + + switch vv := md.Get(key).(type) { + case map[string]any: + m = make(map[string]string) + for k, v := range vv { + m[k] = fmt.Sprintf("%v", v) + } + case map[any]any: + m = make(map[string]string) + for k, v := range vv { + m[fmt.Sprintf("%v", k)] = fmt.Sprintf("%v", v) + } + } + break + } + + return +}