diff --git a/body.go b/body.go index 851e78a..74de514 100644 --- a/body.go +++ b/body.go @@ -287,8 +287,8 @@ func (obj *OrderData) parseForm(ctx context.Context, boundary string) (io.Reader stop := context.AfterFunc(ctx, func() { pw.CloseWithError(ctx.Err()) }) - defer stop() pw.CloseWithError(obj.formWriteMain(writer)) + stop() }() return pr, true, nil } diff --git a/dial.go b/dial.go index 9a35ba9..c9a66bd 100644 --- a/dial.go +++ b/dial.go @@ -95,7 +95,7 @@ func newDialer(dialOption *DialOption) dialer { dialer.dialer.SetMultipathTCP(true) return &dialer } -func (obj *Dialer) dialContext(ctx *Response, network string, addr Address, isProxy bool) (net.Conn, error) { +func (obj *Dialer) dialContext(ctx *Response, network string, addr Address) (net.Conn, error) { var err error if addr.Port == 0 { return nil, errors.New("port is nil") @@ -104,72 +104,49 @@ func (obj *Dialer) dialContext(ctx *Response, network string, addr Address, isPr addr.IP, err = obj.loadHost(ctx.Context(), addr.Host, ctx.option.DialOption) } if ctx.option != nil && ctx.option.Logger != nil { - if isProxy { - ctx.option.Logger(Log{ - Id: ctx.requestId, - Time: time.Now(), - Type: LogType_ProxyDNSLookup, - Msg: addr.Host, - }) - } else { - ctx.option.Logger(Log{ - Id: ctx.requestId, - Time: time.Now(), - Type: LogType_DNSLookup, - Msg: addr.Host, - }) - } + ctx.option.Logger(Log{ + Id: ctx.requestId, + Time: time.Now(), + Type: LogType_DNSLookup, + Msg: addr.Host, + }) } if err != nil { return nil, err } con, err := newDialer(ctx.option.DialOption).DialContext(ctx.Context(), network, addr.String()) if ctx.option != nil && ctx.option.Logger != nil { - if isProxy { - ctx.option.Logger(Log{ - Id: ctx.requestId, - Time: time.Now(), - Type: LogType_ProxyTCPConnect, - Msg: addr, - }) - } else { - ctx.option.Logger(Log{ - Id: ctx.requestId, - Time: time.Now(), - Type: LogType_TCPConnect, - Msg: addr, - }) - } + ctx.option.Logger(Log{ + Id: ctx.requestId, + Time: time.Now(), + Type: LogType_TCPConnect, + Msg: addr, + }) + } + if err != nil && con != nil { + con.Close() } return con, err } -func (obj *Dialer) DialContext(ctx *Response, network string, addr Address) (net.Conn, error) { - conn, err := obj.dialContext(ctx, network, addr, false) - if err != nil { - err = tools.WrapError(err, "DialContext error") - } - return conn, err -} -func (obj *Dialer) ProxyDialContext(ctx *Response, network string, addr Address) (net.Conn, error) { - conn, err := obj.dialContext(ctx, network, addr, true) - if err != nil { - err = tools.WrapError(err, "ProxyDialContext error") - } - return conn, err -} + func (obj *Dialer) DialProxyContext(ctx *Response, network string, proxyTlsConfig *tls.Config, proxyUrls ...Address) (net.PacketConn, net.Conn, error) { proxyLen := len(proxyUrls) - if proxyLen < 2 { + if proxyLen < 1 { return nil, nil, errors.New("proxyUrls is nil") } var conn net.Conn var err error + if proxyLen == 1 { + conn, err = obj.dialContext(ctx, network, proxyUrls[0]) + return nil, conn, err + } var packCon net.PacketConn for index := range proxyLen - 1 { oneProxy := proxyUrls[index] remoteUrl := proxyUrls[index+1] if index == 0 { - if conn, err = obj.dialProxyContext(ctx, network, oneProxy); err != nil { + _, conn, err = obj.DialProxyContext(ctx, network, nil, oneProxy) + if err != nil { break } } @@ -188,11 +165,13 @@ func (obj *Dialer) DialProxyContext(ctx *Response, network string, proxyTlsConfi } return packCon, conn, err } -func (obj *Dialer) dialProxyContext(ctx *Response, network string, proxyUrl Address) (net.Conn, error) { - return obj.ProxyDialContext(ctx, network, proxyUrl) -} -func (obj *Dialer) verifySSH(ctx *Response, conn net.Conn, proxyAddress Address, remoteAddress Address) (net.Conn, error) { +func (obj *Dialer) verifySSH(ctx *Response, conn net.Conn, proxyAddress Address, remoteAddress Address) (sshConn net.Conn, err error) { + defer func() { + if err != nil { + conn.Close() + } + }() if proxyAddress.User == "" || proxyAddress.Password == "" { return conn, errors.New("ssh proxy user or password is nil") } @@ -213,20 +192,20 @@ func (obj *Dialer) verifySSH(ctx *Response, conn net.Conn, proxyAddress Address, } func (obj *Dialer) verifyProxyToRemote(ctx *Response, conn net.Conn, proxyTlsConfig *tls.Config, proxyAddress Address, remoteAddress Address, isLast bool, forceHttp1 bool) (net.PacketConn, net.Conn, error) { var err error - var packCon net.PacketConn if proxyAddress.Scheme == "https" { if conn, err = obj.addTls(ctx.Context(), conn, proxyAddress.Host, proxyTlsConfig, forceHttp1); err != nil { - return packCon, conn, err + return nil, conn, err } if ctx.option.Logger != nil { ctx.option.Logger(Log{ Id: ctx.requestId, Time: time.Now(), - Type: LogType_ProxyTLSHandshake, + Type: LogType_TLSHandshake, Msg: proxyAddress.String(), }) } } + var packCon net.PacketConn done := make(chan struct{}) go func() { switch proxyAddress.Scheme { @@ -242,7 +221,6 @@ func (obj *Dialer) verifyProxyToRemote(ctx *Response, conn net.Conn, proxyTlsCon } case "ssh": conn, err = obj.verifySSH(ctx, conn, proxyAddress, remoteAddress) - // log.Print("verify ssh", remoteAddress.String(), err) case "socks5": if isLast && ctx.option.ForceHttp3 { packCon, err = obj.verifyUDPSocks5(ctx, conn, proxyAddress, remoteAddress) @@ -262,6 +240,7 @@ func (obj *Dialer) verifyProxyToRemote(ctx *Response, conn net.Conn, proxyTlsCon }() select { case <-ctx.Context().Done(): + conn.Close() return packCon, conn, context.Cause(ctx.Context()) case <-done: if err != nil { @@ -393,17 +372,24 @@ func (obj *Dialer) verifySocks5(ctx *Response, conn net.Conn, network string, pr } func (obj *Dialer) verifyTCPSocks5(ctx *Response, conn net.Conn, proxyAddr Address, remoteAddr Address) (err error) { _, err = obj.verifySocks5(ctx, conn, "tcp", proxyAddr, remoteAddr) + if err != nil { + conn.Close() + } return } func (obj *Dialer) verifyUDPSocks5(ctx *Response, conn net.Conn, proxyAddr Address, remoteAddr Address) (wrapConn net.PacketConn, err error) { remoteAddr.NetWork = "udp" proxyAddress, err := obj.verifySocks5(ctx, conn, "udp", proxyAddr, remoteAddr) if err != nil { + conn.Close() return } var listener net.ListenConfig wrapConn, err = listener.ListenPacket(ctx.Context(), "udp", ":0") if err != nil { + if wrapConn != nil { + wrapConn.Close() + } return } wrapConn = NewUDPConn(conn, wrapConn, &net.UDPAddr{IP: proxyAddress.IP, Port: proxyAddress.Port}, remoteAddr) @@ -487,15 +473,11 @@ func (obj *Dialer) addTls(ctx context.Context, conn net.Conn, host string, tlsCo func (obj *Dialer) addJa3Tls(ctx context.Context, conn net.Conn, host string, spec *ja3.Spec, tlsConfig *utls.Config, forceHttp1 bool) (*utls.UConn, error) { return specClient.Client(ctx, conn, spec, tlsConfig, gtls.GetServerName(host), forceHttp1) } -func (obj *Dialer) Socks5TcpProxy(ctx *Response, proxyAddr Address, remoteAddr Address) (conn net.Conn, err error) { - if conn, err = obj.DialContext(ctx, "tcp", proxyAddr); err != nil { - return +func (obj *Dialer) Socks5TcpProxy(ctx *Response, proxyAddr Address, remoteAddr Address) (net.Conn, error) { + _, conn, err := obj.DialProxyContext(ctx, "tcp", nil, proxyAddr) + if err != nil { + return conn, err } - defer func() { - if err != nil && conn != nil { - conn.Close() - } - }() didVerify := make(chan struct{}) go func() { defer close(didVerify) @@ -503,27 +485,19 @@ func (obj *Dialer) Socks5TcpProxy(ctx *Response, proxyAddr Address, remoteAddr A }() select { case <-ctx.Context().Done(): + conn.Close() return conn, context.Cause(ctx.Context()) case <-didVerify: - return + return conn, err } } -func (obj *Dialer) Socks5UdpProxy(ctx *Response, proxyAddress Address, remoteAddress Address) (udpConn net.PacketConn, err error) { - conn, err := obj.ProxyDialContext(ctx, "tcp", proxyAddress) +func (obj *Dialer) Socks5UdpProxy(ctx *Response, proxyAddress Address, remoteAddress Address) (net.PacketConn, error) { + _, conn, err := obj.DialProxyContext(ctx, "tcp", nil, proxyAddress) if err != nil { return nil, err } - defer func() { - if err != nil { - if conn != nil { - conn.Close() - } - if udpConn != nil { - udpConn.Close() - } - } - }() didVerify := make(chan struct{}) + var udpConn net.PacketConn go func() { defer close(didVerify) udpConn, err = obj.verifyUDPSocks5(ctx, conn, proxyAddress, remoteAddress) @@ -538,12 +512,18 @@ func (obj *Dialer) Socks5UdpProxy(ctx *Response, proxyAddress Address, remoteAdd }() select { case <-ctx.Context().Done(): + conn.Close() return udpConn, context.Cause(ctx.Context()) case <-didVerify: - return + return udpConn, err } } func (obj *Dialer) clientVerifyHttps(ctx context.Context, conn net.Conn, proxyAddress Address, remoteAddress Address) (err error) { + defer func() { + if err != nil { + conn.Close() + } + }() hdr := make(http.Header) if proxyAddress.User != "" && proxyAddress.Password != "" { hdr.Set("Proxy-Authorization", "Basic "+tools.Base64Encode(proxyAddress.User+":"+proxyAddress.Password)) diff --git a/go.mod b/go.mod index 85eb540..9579f6d 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/gospider007/bar v0.0.0-20250815030902-4f5b5d6312cf github.com/gospider007/bs4 v0.0.0-20250815030800-a352d3ad57ee github.com/gospider007/gson v0.0.0-20250815030832-fa016f03a353 - github.com/gospider007/gtls v0.0.0-20250818024401-0d7bcb040679 + github.com/gospider007/gtls v0.0.0-20250818100212-f466fa4cc860 github.com/gospider007/http1 v0.0.0-20250817122009-0b953c2c8efa github.com/gospider007/http2 v0.0.0-20250817122534-76043412544d github.com/gospider007/http3 v0.0.0-20250817123336-07d66db6dbb3 @@ -28,6 +28,7 @@ require ( ) require ( + github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/PuerkitoBio/goquery v1.10.3 // indirect github.com/STARRY-S/zip v0.2.3 // indirect github.com/andybalholm/brotli v1.2.0 // indirect @@ -61,7 +62,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nwaples/rardecode/v2 v2.1.1 // indirect - github.com/onsi/ginkgo/v2 v2.23.4 // indirect + github.com/onsi/ginkgo/v2 v2.24.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/quic-go/qpack v0.5.1 // indirect @@ -76,7 +77,7 @@ require ( github.com/zeebo/blake3 v0.2.4 // indirect go.mongodb.org/mongo-driver v1.17.4 // indirect go.uber.org/automaxprocs v1.6.0 // indirect - go.uber.org/mock v0.5.2 // indirect + go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect diff --git a/go.sum b/go.sum index 69971cb..572b2d2 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo= github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y= github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4= @@ -112,8 +114,8 @@ github.com/gospider007/bs4 v0.0.0-20250815030800-a352d3ad57ee h1:XKhfmuJ/lGYMN0n github.com/gospider007/bs4 v0.0.0-20250815030800-a352d3ad57ee/go.mod h1:AU9FRb74CELvy5vhGAP/4GDw5SgGxxIj7SI5X0AoPe0= github.com/gospider007/gson v0.0.0-20250815030832-fa016f03a353 h1:jrqXuLs1QzMZcl8mMoBLTaag6JaLY1eh/toCyDWC8GY= github.com/gospider007/gson v0.0.0-20250815030832-fa016f03a353/go.mod h1:nxA7Mekk0TdS1W+ycauVr8vW25mMXf9rxCGcGHNE28w= -github.com/gospider007/gtls v0.0.0-20250818024401-0d7bcb040679 h1:Rky2kfy1qNbmR88IMUEPjRahXza1Szi1NVGYwy40OI0= -github.com/gospider007/gtls v0.0.0-20250818024401-0d7bcb040679/go.mod h1:Np1+9Lmsm3g1LtDl3C8OOsMXfHRdOwyd7olW8YJMGLo= +github.com/gospider007/gtls v0.0.0-20250818100212-f466fa4cc860 h1:1+GNYHU9fFkIGk67Ssgc9xDdY8X1DbbCNek++XA6B/c= +github.com/gospider007/gtls v0.0.0-20250818100212-f466fa4cc860/go.mod h1:Np1+9Lmsm3g1LtDl3C8OOsMXfHRdOwyd7olW8YJMGLo= github.com/gospider007/http1 v0.0.0-20250817122009-0b953c2c8efa h1:SJPg55yHMzcrprjvBA2YBMYCmIRauhFtQGL6QVTManM= github.com/gospider007/http1 v0.0.0-20250817122009-0b953c2c8efa/go.mod h1:2KmewDOljCqfLfbSiIzuohAHvivZwj9pSd25pGEVvfE= github.com/gospider007/http2 v0.0.0-20250817122534-76043412544d h1:PShVXqSaKS0mOpkvYEyrSDRtUQokcBMDinKvLVs5w4M= @@ -175,8 +177,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/nwaples/rardecode/v2 v2.1.1 h1:OJaYalXdliBUXPmC8CZGQ7oZDxzX1/5mQmgn0/GASew= github.com/nwaples/rardecode/v2 v2.1.1/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= -github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= -github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= +github.com/onsi/ginkgo/v2 v2.24.0 h1:obZz8LAnHicNdbBqvG3ytAFx8fgza+i1IDpBVcHT2YE= +github.com/onsi/ginkgo/v2 v2.24.0/go.mod h1:ppTWQ1dh9KM/F1XgpeRqelR+zHVwV81DGRSDnFxK7Sk= github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= @@ -256,8 +258,8 @@ go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= diff --git a/option.go b/option.go index b3ad675..adf78bf 100644 --- a/option.go +++ b/option.go @@ -14,15 +14,14 @@ import ( type LogType string const ( - LogType_DNSLookup LogType = "DNSLookup" - LogType_TCPConnect LogType = "TCPConnect" - LogType_TLSHandshake LogType = "TLSHandshake" - LogType_ProxyDNSLookup LogType = "ProxyDNSLookup" - LogType_ProxyTCPConnect LogType = "ProxyTCPConnect" - LogType_ProxyTLSHandshake LogType = "ProxyTLSHandshake" + LogType_DNSLookup LogType = "DNSLookup" + LogType_TCPConnect LogType = "TCPConnect" + LogType_TLSHandshake LogType = "TLSHandshake" + LogType_ProxyConnectRemote LogType = "ProxyConnectRemote" - LogType_ResponseHeader LogType = "ResponseHeader" - LogType_ResponseBody LogType = "ResponseBody" + + LogType_ResponseHeader LogType = "ResponseHeader" + LogType_ResponseBody LogType = "ResponseBody" ) type Log struct { diff --git a/roundTripper.go b/roundTripper.go index c7a71aa..bbfd073 100644 --- a/roundTripper.go +++ b/roundTripper.go @@ -100,6 +100,9 @@ func (obj *roundTripper) http3Dial(ctx *Response, remtoeAddress Address, proxyAd } else { udpConn, err = net.ListenUDP("udp", nil) } + if err != nil && udpConn != nil { + udpConn.Close() + } return } func (obj *roundTripper) ghttp3Dial(ctx *Response, remoteAddress Address, proxyAddress ...Address) (conn http1.Conn, err error) { @@ -195,13 +198,9 @@ func (obj *roundTripper) dial(ctx *Response) (conn http1.Conn, err error) { arch = proxys[len(proxys)-1].Compression _, rawNetConn, err = obj.dialer.DialProxyContext(ctx, "tcp", ctx.option.TlsConfig.Clone(), append(proxys, remoteAddress)...) } else { - var remoteAddress Address - remoteAddress, err = GetAddressWithUrl(ctx.request.URL) - if err != nil { - return nil, err - } - rawNetConn, err = obj.dialer.DialContext(ctx, "tcp", remoteAddress) + _, rawNetConn, err = obj.dialer.DialProxyContext(ctx, "tcp", nil, remoteAddress) } + if err != nil { if rawNetConn != nil { rawNetConn.Close() @@ -211,30 +210,10 @@ func (obj *roundTripper) dial(ctx *Response) (conn http1.Conn, err error) { var h2 bool var rawConn net.Conn if ctx.request.URL.Scheme == "https" { - if ctx.option.TlsHandshakeTimeout > 0 { - tlsCtx, tlsCnl := context.WithTimeout(ctx.Context(), ctx.option.TlsHandshakeTimeout) - rawConn, h2, err = obj.dialAddTls(tlsCtx, ctx.option, ctx.request, rawNetConn) - tlsCnl() - } else { - rawConn, h2, err = obj.dialAddTls(ctx.Context(), ctx.option, ctx.request, rawNetConn) - } - if ctx.option.Logger != nil { - ctx.option.Logger(Log{ - Id: ctx.requestId, - Time: time.Now(), - Type: LogType_TLSHandshake, - Msg: fmt.Sprintf("host:%s, h2:%t", getHost(ctx.request), h2), - }) - } + rawConn, h2, err = obj.dialAddTlsWithResponse(ctx, rawNetConn) } else { rawConn = rawNetConn } - if err != nil { - if rawConn != nil { - rawConn.Close() - } - return nil, err - } if arch != "" { rawConn, err = NewCompressionConn(rawConn, arch) } @@ -258,6 +237,27 @@ func (obj *roundTripper) dialConnecotr(ctx *Response, rawCon net.Conn, h2 bool) } return } +func (obj *roundTripper) dialAddTlsWithResponse(ctx *Response, rawNetConn net.Conn) (tlsConn net.Conn, h2 bool, err error) { + if ctx.option.TlsHandshakeTimeout > 0 { + tlsCtx, tlsCnl := context.WithTimeout(ctx.Context(), ctx.option.TlsHandshakeTimeout) + tlsConn, h2, err = obj.dialAddTls(tlsCtx, ctx.option, ctx.request, rawNetConn) + tlsCnl() + } else { + tlsConn, h2, err = obj.dialAddTls(ctx.Context(), ctx.option, ctx.request, rawNetConn) + } + if ctx.option.Logger != nil { + ctx.option.Logger(Log{ + Id: ctx.requestId, + Time: time.Now(), + Type: LogType_TLSHandshake, + Msg: fmt.Sprintf("host:%s, h2:%t", getHost(ctx.request), h2), + }) + } + if err != nil && tlsConn != nil { + tlsConn.Close() + } + return tlsConn, h2, err +} func (obj *roundTripper) dialAddTls(ctx context.Context, option *RequestOption, req *http.Request, netConn net.Conn) (net.Conn, bool, error) { if option.gospiderSpec != nil && option.gospiderSpec.TLSSpec != nil { if tlsConn, err := obj.dialer.addJa3Tls(ctx, netConn, getHost(req), option.gospiderSpec.TLSSpec, option.UtlsConfig.Clone(), option.ForceHttp1); err != nil {