This commit is contained in:
gospider
2025-06-10 14:11:15 +08:00
parent 6cdf796956
commit 8883fd2cac
10 changed files with 251 additions and 91 deletions

View File

@@ -1,6 +1,7 @@
package requests
import (
"compress/flate"
"errors"
"io"
"net"
@@ -8,7 +9,6 @@ import (
"time"
"github.com/klauspost/compress/zstd"
"github.com/mholt/archives"
)
type CompressionConn struct {
@@ -17,17 +17,97 @@ type CompressionConn struct {
r io.ReadCloser
f interface{ Flush() error }
}
type Compression interface {
OpenReader(r io.Reader) (io.ReadCloser, error)
OpenWriter(w io.Writer) (io.WriteCloser, error)
}
type compression struct {
openReader func(r io.Reader) (io.ReadCloser, error)
openWriter func(w io.Writer) (io.WriteCloser, error)
}
func NewCompressionConn(decode string, conn net.Conn) (net.Conn, error) {
var r io.ReadCloser
var w io.WriteCloser
var err error
func (obj compression) OpenReader(r io.Reader) (io.ReadCloser, error) {
return obj.openReader(r)
}
func (obj compression) OpenWriter(w io.Writer) (io.WriteCloser, error) {
return obj.openWriter(w)
}
type CompressionLevel int
const (
CompressionLevelFast CompressionLevel = 1
CompressionLevelBest CompressionLevel = 2
)
func NewCompression(decode string, leval CompressionLevel) (Compression, error) {
var arch Compression
switch strings.ToLower(decode) {
case "zstd":
r, w, err = newZstdConn(conn)
options := []zstd.EOption{}
options2 := []zstd.DOption{}
switch leval {
case CompressionLevelFast:
options = append(options, zstd.WithEncoderLevel(zstd.SpeedFastest), zstd.WithZeroFrames(true), zstd.WithLowerEncoderMem(true))
options2 = append(options2, zstd.WithDecoderLowmem(true))
case CompressionLevelBest:
options = append(options, zstd.WithEncoderLevel(zstd.SpeedBetterCompression))
default:
options = append(options, zstd.WithEncoderLevel(zstd.SpeedDefault), zstd.WithZeroFrames(true), zstd.WithLowerEncoderMem(true))
options2 = append(options2, zstd.WithDecoderLowmem(true))
}
arch = compression{
openReader: func(r io.Reader) (io.ReadCloser, error) {
decoder, err := zstd.NewReader(r, options2...)
if err != nil {
return nil, err
}
return decoder.IOReadCloser(), nil
},
openWriter: func(w io.Writer) (io.WriteCloser, error) {
encoder, err := zstd.NewWriter(w, options...)
if err != nil {
return nil, err
}
return encoder, nil
},
}
case "flate":
arch = compression{
openReader: func(r io.Reader) (io.ReadCloser, error) {
buf := make([]byte, 1)
n, err := r.Read(buf)
if err != nil {
return nil, err
}
if n != 1 || buf[0] != 92 {
return nil, errors.New("invalid response")
}
return flate.NewReader(r), nil
},
openWriter: func(w io.Writer) (io.WriteCloser, error) {
n, err := w.Write([]byte{92})
if err != nil {
return nil, err
}
if n != 1 {
return nil, errors.New("invalid response")
}
return flate.NewWriter(w, flate.BestCompression)
},
}
default:
return nil, errors.New("unsupported compression type")
}
return arch, nil
}
func NewCompressionConn(conn net.Conn, arch Compression) (net.Conn, error) {
w, err := arch.OpenWriter(conn)
if err != nil {
return nil, err
}
r, err := arch.OpenReader(conn)
if err != nil {
return nil, err
}
@@ -38,35 +118,6 @@ func NewCompressionConn(decode string, conn net.Conn) (net.Conn, error) {
return ccon, nil
}
func newZstdConn(conn net.Conn) (io.ReadCloser, io.WriteCloser, error) {
r, err := archives.Zstd{
EncoderOptions: []zstd.EOption{
zstd.WithEncoderLevel(zstd.SpeedFastest),
zstd.WithWindowSize(zstd.MinWindowSize), // 1MB 窗口,减少内存
zstd.WithEncoderConcurrency(1), // 单线程,减少内存
},
DecoderOptions: []zstd.DOption{
zstd.WithDecodeBuffersBelow(zstd.MinWindowSize),
},
}.OpenReader(conn)
if err != nil {
return nil, nil, err
}
w, err := archives.Zstd{
EncoderOptions: []zstd.EOption{
zstd.WithEncoderLevel(zstd.SpeedFastest),
zstd.WithWindowSize(zstd.MinWindowSize), // 1MB 窗口,减少内存
zstd.WithEncoderConcurrency(1), // 单线程,减少内存
},
DecoderOptions: []zstd.DOption{
zstd.WithDecodeBuffersBelow(zstd.MinWindowSize),
},
}.OpenWriter(conn)
if err != nil {
return nil, nil, err
}
return r, w, nil
}
func (obj *CompressionConn) Read(b []byte) (n int, err error) {
return obj.r.Read(b)
}

37
conn.go
View File

@@ -200,3 +200,40 @@ func (obj *connPool) close(err error) {
obj.connPools.del(obj.connKey)
obj.forceCnl(tools.WrapError(err, "connPool close"))
}
func newSSHConn(sshCon net.Conn, rawCon net.Conn) *sshConn {
return &sshConn{sshCon: sshCon, rawCon: rawCon}
}
type sshConn struct {
sshCon net.Conn
rawCon net.Conn
}
func (obj *sshConn) Read(b []byte) (n int, err error) {
return obj.sshCon.Read(b)
}
func (obj *sshConn) Write(b []byte) (n int, err error) {
return obj.sshCon.Write(b)
}
func (obj *sshConn) Close() error {
return obj.sshCon.Close()
}
func (obj *sshConn) LocalAddr() net.Addr {
return obj.sshCon.LocalAddr()
}
func (obj *sshConn) RemoteAddr() net.Addr {
return obj.sshCon.RemoteAddr()
}
func (obj *sshConn) SetDeadline(deadline time.Time) error {
return obj.rawCon.SetDeadline(deadline)
}
func (obj *sshConn) SetReadDeadline(deadline time.Time) error {
return obj.rawCon.SetReadDeadline(deadline)
}
func (obj *sshConn) SetWriteDeadline(deadline time.Time) error {
return obj.rawCon.SetWriteDeadline(deadline)
}

27
dial.go
View File

@@ -17,6 +17,7 @@ import (
"github.com/gospider007/ja3"
"github.com/gospider007/tools"
utls "github.com/refraction-networking/utls"
"golang.org/x/crypto/ssh"
)
type msgClient struct {
@@ -135,9 +136,6 @@ func (obj *Dialer) dialContext(ctx *Response, network string, addr Address, isPr
})
}
}
if err == nil && addr.Compression != "" {
return NewCompressionConn(addr.Compression, con)
}
return con, err
}
func (obj *Dialer) DialContext(ctx *Response, network string, addr Address) (net.Conn, error) {
@@ -177,6 +175,26 @@ func (obj *Dialer) DialProxyContext(ctx *Response, network string, proxyTlsConfi
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) {
if proxyAddress.User == "" || proxyAddress.Password == "" {
return conn, errors.New("ssh proxy user or password is nil")
}
config := &ssh.ClientConfig{
User: proxyAddress.User,
Auth: []ssh.AuthMethod{ssh.Password(proxyAddress.Password)},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
c, chans, reqs, err := ssh.NewClientConn(conn, proxyAddress.String(), config)
if err != nil {
return conn, err
}
sshC, err := ssh.NewClient(c, chans, reqs).DialContext(ctx.Context(), "tcp", remoteAddress.String())
if err != nil {
return conn, err
}
return newSSHConn(sshC, conn), nil
}
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
@@ -206,6 +224,9 @@ func (obj *Dialer) verifyProxyToRemote(ctx *Response, conn net.Conn, proxyTlsCon
Msg: remoteAddress.String(),
})
}
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)

26
go.mod
View File

@@ -6,20 +6,20 @@ require (
github.com/gospider007/bar v0.0.0-20250217074946-47896d8de2ba
github.com/gospider007/bs4 v0.0.0-20250413121342-fed910fb00c9
github.com/gospider007/gson v0.0.0-20250530002642-aee7c1b761df
github.com/gospider007/gtls v0.0.0-20250427082859-097a9e35c601
github.com/gospider007/gtls v0.0.0-20250610060422-446e017b9858
github.com/gospider007/http2 v0.0.0-20250427082905-4aed0707e580
github.com/gospider007/http3 v0.0.0-20250416085920-b642f3f91f47
github.com/gospider007/ja3 v0.0.0-20250427082442-f7dc5fb959e6
github.com/gospider007/re v0.0.0-20250217075352-bcb79f285d6c
github.com/gospider007/tools v0.0.0-20250529114105-be4d4dbf36a2
github.com/gospider007/tools v0.0.0-20250610060552-2e45eaa25022
github.com/gospider007/websocket v0.0.0-20250429035144-b1cf6819063a
github.com/klauspost/compress v1.18.0
github.com/mholt/archives v0.1.2
github.com/quic-go/quic-go v0.52.0
github.com/refraction-networking/uquic v0.0.6
github.com/refraction-networking/utls v1.7.3
github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301
golang.org/x/net v0.40.0
golang.org/x/crypto v0.39.0
golang.org/x/net v0.41.0
gopkg.in/errgo.v2 v2.1.0
)
@@ -43,7 +43,7 @@ require (
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e // indirect
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect
github.com/gospider007/blog v0.0.0-20250302134054-8afc12c2a9a7 // indirect
github.com/gospider007/kinds v0.0.0-20250217075226-10f199f7215d // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
@@ -53,6 +53,7 @@ require (
github.com/kr/pretty v0.3.1 // indirect
github.com/libdns/libdns v1.1.0 // indirect
github.com/mholt/acmez/v3 v3.1.2 // indirect
github.com/mholt/archives v0.1.2 // indirect
github.com/miekg/dns v1.1.66 // indirect
github.com/minio/minlz v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -72,21 +73,20 @@ require (
github.com/txthinking/runnergroup v0.0.0-20250224021307-5864ffeb65ae // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/zeebo/blake3 v0.2.4 // indirect
go.mongodb.org/mongo-driver v1.17.3 // 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/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
go.uber.org/zap/exp v0.3.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b // indirect
golang.org/x/image v0.27.0 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect
golang.org/x/image v0.28.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.33.0 // indirect
golang.org/x/tools v0.34.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
)

50
go.sum
View File

@@ -97,8 +97,8 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e h1:FJta/0WsADCe1r9vQjdHbd3KuiLPu7Y9WlyLGwMUNyE=
github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a h1://KbezygeMJZCSHH+HgUZiTeSoiuFspbMg1ge+eFj18=
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@@ -110,8 +110,8 @@ github.com/gospider007/bs4 v0.0.0-20250413121342-fed910fb00c9 h1:V/Fuzox1GNZzlZC
github.com/gospider007/bs4 v0.0.0-20250413121342-fed910fb00c9/go.mod h1:KBnaNWpVupRQbPZ6jz2jhX/hnRK1w30RKJvl3Micjws=
github.com/gospider007/gson v0.0.0-20250530002642-aee7c1b761df h1:Xi1Sm1caw39tXUVZAuVAVSdJ9x7h0Y1bPOw3sxxkzsM=
github.com/gospider007/gson v0.0.0-20250530002642-aee7c1b761df/go.mod h1:+O/+tzjrqz67RehAyJaRApESHo1Z9fuxBeQmQ8GMELw=
github.com/gospider007/gtls v0.0.0-20250427082859-097a9e35c601 h1:0r67F8bARNcUwMpSVCgp5u92sP01kWgZLRliRFKmgMM=
github.com/gospider007/gtls v0.0.0-20250427082859-097a9e35c601/go.mod h1:UzfvBwe5Jtz1nKzlGSH4q8VP/9XfcsmMFDahR3PgCkM=
github.com/gospider007/gtls v0.0.0-20250610060422-446e017b9858 h1:Tb+T5YfysjR7Mp22AgrJhMPF28KBgjWkbKj2zi8AyBU=
github.com/gospider007/gtls v0.0.0-20250610060422-446e017b9858/go.mod h1:SxhMpxq4EYHlUre2EdQ4dKKGZyvj7+1PYZ2LQ9RO0y4=
github.com/gospider007/http2 v0.0.0-20250427082905-4aed0707e580 h1:JLZeCin6giqOV3sAy7BGqFkc+qHvO389O/aTT5JJc1k=
github.com/gospider007/http2 v0.0.0-20250427082905-4aed0707e580/go.mod h1:WH7RqG9ecX15uAhzZDr5cbTaTPZST3ST0X4okNDSR5I=
github.com/gospider007/http3 v0.0.0-20250416085920-b642f3f91f47 h1:dpV6hkUeMbZrCZSaR99u6TNXry9M3FSga+9CmjZ5Zmo=
@@ -122,8 +122,8 @@ github.com/gospider007/kinds v0.0.0-20250217075226-10f199f7215d h1:+Fih572EdNmYC
github.com/gospider007/kinds v0.0.0-20250217075226-10f199f7215d/go.mod h1:3u6J+nbdWhCNJGiQjq/hKSukn2k6ebjd98rd2+fzKNo=
github.com/gospider007/re v0.0.0-20250217075352-bcb79f285d6c h1:8/Cf+c2680tkWJ+ueZ9RLLK5R5R8nhE8pNBUPHjkvkM=
github.com/gospider007/re v0.0.0-20250217075352-bcb79f285d6c/go.mod h1:dd8aDIUG1vDPP5r+vHBtiUK0Zn6uk3SsWt1ZvmCCHLs=
github.com/gospider007/tools v0.0.0-20250529114105-be4d4dbf36a2 h1:w5KTBR3sR3o/MCQjLLTgDIWQF3pZwkN3P65viwxv0BE=
github.com/gospider007/tools v0.0.0-20250529114105-be4d4dbf36a2/go.mod h1:gGaFJtYG/UPq+HVYhhVGhSOmF6NZMRayw3FflTOb27g=
github.com/gospider007/tools v0.0.0-20250610060552-2e45eaa25022 h1:IPoXe0+GyHjiIPn0Qy7nElpJ81awXUWrCoNholizqV4=
github.com/gospider007/tools v0.0.0-20250610060552-2e45eaa25022/go.mod h1:x7fyDzsG7lPJO6Q3D6DIzdUA+J9RAQoyOdmcP1XQF1k=
github.com/gospider007/websocket v0.0.0-20250429035144-b1cf6819063a h1:DJMk+oALIJg3ArN5/DIPrQagWQL1Qi/c3DlXT9l1dGo=
github.com/gospider007/websocket v0.0.0-20250429035144-b1cf6819063a/go.mod h1:0yVYF7b5kRayyUzAVgg6h1x+eZujKoSaA4n2krG5F7g=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -242,8 +242,8 @@ github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -271,8 +271,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -281,12 +281,12 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b h1:QoALfVG9rhQ/M7vYDScfPdWjGL9dlsVVM5VGh7aKoAA=
golang.org/x/exp v0.0.0-20250531010427-b6e5de432a8b/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4=
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -309,8 +309,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -334,8 +334,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -353,8 +353,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -391,6 +391,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -404,8 +406,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
@@ -439,8 +441,8 @@ golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@@ -82,16 +82,15 @@ func (obj *clientConn) send(req *http.Request, orderHeaders []interface {
defer func() {
obj.readWriteCtx.readCnl(readErr)
}()
noBody := res.Body == nil || (res.ContentLength == -1 && len(res.TransferEncoding) == 0)
if !noBody {
if res.Body != nil {
_, readErr = io.Copy(pw, rawBody)
}
pw.CloseWithError(readErr)
if readErr != nil && readErr != io.EOF && readErr != io.ErrUnexpectedEOF {
err = tools.WrapError(readErr, "failed to read response body")
} else {
readErr = nil
}
pw.CloseWithError(readErr)
if readErr != nil {
obj.CloseWithError(readErr)
} else {

View File

@@ -146,6 +146,7 @@ func (obj *roundTripper) ghttp3Dial(ctx *Response, remoteAddress Address, proxyA
if err != nil {
return nil, err
}
conn = obj.newConnecotr()
conn.Conn, err = http3.NewClient(netConn, func() {
conn.forceCnl(errors.New("http3 client close"))
@@ -160,7 +161,11 @@ func (obj *roundTripper) ghttp3Dial(ctx *Response, remoteAddress Address, proxyA
return
}
func (obj *roundTripper) uhttp3Dial(ctx *Response, spec uquic.QUICSpec, remoteAddress Address, proxyAddress ...Address) (conn *connecotr, err error) {
func (obj *roundTripper) uhttp3Dial(ctx *Response, remoteAddress Address, proxyAddress ...Address) (conn *connecotr, err error) {
spec, err := ja3.CreateUSpec(ctx.option.USpec)
if err != nil {
return nil, err
}
udpConn, err := obj.http3Dial(ctx, remoteAddress, proxyAddress...)
if err != nil {
return nil, err
@@ -201,6 +206,36 @@ func (obj *roundTripper) uhttp3Dial(ctx *Response, spec uquic.QUICSpec, remoteAd
return
}
// func (obj *roundTripper) thttp3Dial(ctx *Response, remoteAddress Address, proxyAddress ...Address) (conn *connecotr, err error) {
// // var rawNetConn net.Conn
// // if len(proxys) > 0 {
// // comp := proxys[len(proxys)-1]
// // if comp.Compression != "" {
// // arch, err = NewCompression(comp.Compression, CompressionLevelBest)
// // if err != nil {
// // return nil, err
// // }
// // }
// // _, 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)
// // }
// // defer func() {
// // if err != nil && rawNetConn != nil {
// // rawNetConn.Close()
// // }
// // }()
// // if err != nil {
// // return nil, err
// // }
// }
func (obj *roundTripper) dial(ctx *Response) (conn *connecotr, err error) {
proxys, err := obj.initProxys(ctx)
if err != nil {
@@ -212,18 +247,21 @@ func (obj *roundTripper) dial(ctx *Response) (conn *connecotr, err error) {
}
if ctx.option.ForceHttp3 {
if ctx.option.USpec != nil {
spec, err := ja3.CreateUSpec(ctx.option.USpec)
return obj.uhttp3Dial(ctx, remoteAddress, proxys...)
} else {
return obj.ghttp3Dial(ctx, remoteAddress, proxys...)
}
}
var rawNetConn net.Conn
var arch Compression
if len(proxys) > 0 {
comp := proxys[len(proxys)-1]
if comp.Compression != "" {
arch, err = NewCompression(comp.Compression, CompressionLevelBest)
if err != nil {
return nil, err
}
if spec.ClientHelloSpec != nil {
return obj.uhttp3Dial(ctx, spec, remoteAddress, proxys...)
}
}
return obj.ghttp3Dial(ctx, remoteAddress, proxys...)
}
var rawNetConn net.Conn
if len(proxys) > 0 {
_, rawNetConn, err = obj.dialer.DialProxyContext(ctx, "tcp", ctx.option.TlsConfig.Clone(), append(proxys, remoteAddress)...)
} else {
var remoteAddress Address
@@ -260,6 +298,12 @@ func (obj *roundTripper) dial(ctx *Response) (conn *connecotr, err error) {
} else {
conne.c = rawNetConn
}
if arch != nil {
conne.c, err = NewCompressionConn(conne.c, arch)
if err != nil {
return nil, err
}
}
err = obj.dialConnecotr(ctx, conne, h2)
if err != nil {
return nil, err

4
rw.go
View File

@@ -3,7 +3,6 @@ package requests
import (
"errors"
"io"
"log"
)
type wrapBody struct {
@@ -33,9 +32,6 @@ func (obj *wrapBody) Close() error {
// safe close conn
func (obj *wrapBody) CloseConn() {
log.Print("111")
obj.conn.forceCnl(errors.New("readWriterCloser close conn"))
log.Print("222")
obj.conn.CloseWithError(errConnectionForceClosed)
log.Print("333")
}

View File

@@ -85,6 +85,12 @@ func (a Address) String() string {
func (a Address) Network() string {
return a.NetWork
}
func (a Address) IsZero() bool {
if a.Port == 0 && a.Host == "" && len(a.IP) == 0 && a.NetWork == "" {
return true
}
return false
}
type UDPConn struct {
ctx context.Context

View File

@@ -54,6 +54,8 @@ func GetAddressWithUrl(uurl *url.URL) (addr Address, err error) {
addr.Port = 80
case "https":
addr.Port = 443
case "ssh":
addr.Port = 22
case "socks5":
addr.Port = 1080
}
@@ -93,6 +95,8 @@ func GetAddressWithReq(req *http.Request) (addr Address, err error) {
addr.Port = 80
case "https":
addr.Port = 443
case "ssh":
addr.Port = 22
case "socks5":
addr.Port = 1080
// default: