mirror of
https://github.com/gospider007/requests.git
synced 2025-12-24 13:57:52 +08:00
optimize code
This commit is contained in:
26
body.go
26
body.go
@@ -43,9 +43,6 @@ func (obj *orderMap) Del(key string) {
|
||||
obj.order = tools.DelSliceVals(obj.order, key)
|
||||
}
|
||||
func (obj *orderMap) parseHeaders() (map[string][]string, []string) {
|
||||
if len(obj.order) == 0 || len(obj.data) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
head := make(http.Header)
|
||||
for kk, vv := range obj.data {
|
||||
if vvs, ok := vv.([]string); ok {
|
||||
@@ -186,10 +183,7 @@ func paramsWrite(buf *bytes.Buffer, key string, val any) {
|
||||
buf.WriteByte('=')
|
||||
buf.WriteString(url.QueryEscape(fmt.Sprint(val)))
|
||||
}
|
||||
func (obj *orderMap) parseParams() string {
|
||||
if len(obj.order) == 0 || len(obj.data) == 0 {
|
||||
return ""
|
||||
}
|
||||
func (obj *orderMap) parseParams() *bytes.Buffer {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
for _, k := range obj.order {
|
||||
if vals, ok := obj.data[k].([]any); ok {
|
||||
@@ -200,25 +194,15 @@ func (obj *orderMap) parseParams() string {
|
||||
paramsWrite(buf, k, obj.data[k])
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
return buf
|
||||
}
|
||||
func (obj *orderMap) parseData() *bytes.Reader {
|
||||
if len(obj.order) == 0 || len(obj.data) == 0 {
|
||||
val := obj.parseParams().Bytes()
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
tempVal := url.Values{}
|
||||
for kk, vv := range obj.data {
|
||||
if vvs, ok := vv.([]any); ok {
|
||||
for _, vv := range vvs {
|
||||
tempVal.Add(kk, fmt.Sprint(vv))
|
||||
}
|
||||
} else {
|
||||
tempVal.Add(kk, fmt.Sprint(vv))
|
||||
}
|
||||
}
|
||||
return bytes.NewReader(tools.StringToBytes(tempVal.Encode()))
|
||||
return bytes.NewReader(val)
|
||||
}
|
||||
|
||||
func (obj *orderMap) MarshalJSON() ([]byte, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := buf.WriteByte('{')
|
||||
|
||||
121
client.go
121
client.go
@@ -3,136 +3,65 @@ package requests
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"net/http"
|
||||
|
||||
"github.com/gospider007/gtls"
|
||||
"github.com/gospider007/ja3"
|
||||
)
|
||||
|
||||
// Connection Management
|
||||
type Client struct {
|
||||
forceHttp1 bool
|
||||
orderHeaders []string
|
||||
|
||||
jar *Jar
|
||||
maxRedirect int
|
||||
disDecode bool
|
||||
disUnZip bool
|
||||
disAlive bool
|
||||
|
||||
maxRetries int
|
||||
|
||||
requestCallBack func(context.Context, *http.Request, *http.Response) error
|
||||
|
||||
optionCallBack func(context.Context, *Client, *RequestOption) error
|
||||
resultCallBack func(ctx context.Context, client *Client, response *Response) error
|
||||
errCallBack func(context.Context, *Client, *Response, error) error
|
||||
|
||||
timeout time.Duration
|
||||
responseHeaderTimeout time.Duration
|
||||
tlsHandshakeTimeout time.Duration
|
||||
|
||||
headers any
|
||||
bar bool
|
||||
|
||||
disCookie bool
|
||||
option ClientOption
|
||||
client *http.Client
|
||||
proxy *url.URL
|
||||
|
||||
ctx context.Context
|
||||
cnl context.CancelFunc
|
||||
transport *RoundTripper
|
||||
|
||||
ja3Spec ja3.Ja3Spec
|
||||
h2Ja3Spec ja3.H2Ja3Spec
|
||||
|
||||
addrType gtls.AddrType
|
||||
transport *roundTripper
|
||||
}
|
||||
|
||||
var defaultClient, _ = NewClient(nil)
|
||||
|
||||
func checkRedirect(req *http.Request, via []*http.Request) error {
|
||||
ctxData := GetReqCtxData(req.Context())
|
||||
if ctxData.maxRedirect == 0 || ctxData.maxRedirect >= len(via) {
|
||||
return nil
|
||||
}
|
||||
return http.ErrUseLastResponse
|
||||
}
|
||||
|
||||
// New Connection Management
|
||||
func NewClient(preCtx context.Context, options ...ClientOption) (*Client, error) {
|
||||
if preCtx == nil {
|
||||
preCtx = context.TODO()
|
||||
}
|
||||
ctx, cnl := context.WithCancel(preCtx)
|
||||
var option ClientOption
|
||||
|
||||
if len(options) > 0 {
|
||||
option = options[0]
|
||||
}
|
||||
transport := newRoundTripper(ctx, roundTripperOption{
|
||||
DialTimeout: option.DialTimeout,
|
||||
KeepAlive: option.KeepAlive,
|
||||
|
||||
LocalAddr: option.LocalAddr,
|
||||
AddrType: option.AddrType,
|
||||
GetAddrType: option.GetAddrType,
|
||||
Dns: option.Dns,
|
||||
GetProxy: option.GetProxy,
|
||||
})
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
ctxData := GetReqCtxData(req.Context())
|
||||
if ctxData.maxRedirect == 0 || ctxData.maxRedirect >= len(via) {
|
||||
return nil
|
||||
}
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
result := &Client{
|
||||
ctx: ctx,
|
||||
cnl: cnl,
|
||||
client: client,
|
||||
transport: transport,
|
||||
forceHttp1: option.ForceHttp1,
|
||||
requestCallBack: option.RequestCallBack,
|
||||
orderHeaders: option.OrderHeaders,
|
||||
disCookie: option.DisCookie,
|
||||
maxRedirect: option.MaxRedirect,
|
||||
disDecode: option.DisDecode,
|
||||
disUnZip: option.DisUnZip,
|
||||
disAlive: option.DisAlive,
|
||||
maxRetries: option.MaxRetries,
|
||||
optionCallBack: option.OptionCallBack,
|
||||
resultCallBack: option.ResultCallBack,
|
||||
errCallBack: option.ErrCallBack,
|
||||
timeout: option.Timeout,
|
||||
responseHeaderTimeout: option.ResponseHeaderTimeout,
|
||||
tlsHandshakeTimeout: option.TlsHandshakeTimeout,
|
||||
headers: option.Headers,
|
||||
bar: option.Bar,
|
||||
addrType: option.AddrType,
|
||||
}
|
||||
result := new(Client)
|
||||
result.ctx, result.cnl = context.WithCancel(preCtx)
|
||||
result.transport = newRoundTripper(result.ctx, option)
|
||||
result.client = &http.Client{Transport: result.transport, CheckRedirect: checkRedirect}
|
||||
result.option = option
|
||||
//cookiesjar
|
||||
if !option.DisCookie {
|
||||
if option.Jar != nil {
|
||||
result.jar = option.Jar
|
||||
} else {
|
||||
result.jar = NewJar()
|
||||
if !result.option.DisCookie {
|
||||
if result.option.Jar == nil {
|
||||
result.option.Jar = NewJar()
|
||||
}
|
||||
result.client.Jar = result.jar.jar
|
||||
result.client.Jar = result.option.Jar.jar
|
||||
}
|
||||
var err error
|
||||
if option.Proxy != "" {
|
||||
result.proxy, err = gtls.VerifyProxy(option.Proxy)
|
||||
if result.option.Proxy != "" {
|
||||
_, err = gtls.VerifyProxy(result.option.Proxy)
|
||||
}
|
||||
if option.Ja3Spec.IsSet() {
|
||||
result.ja3Spec = option.Ja3Spec
|
||||
} else if option.Ja3 {
|
||||
result.ja3Spec = ja3.DefaultJa3Spec()
|
||||
}
|
||||
result.h2Ja3Spec = option.H2Ja3Spec
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Modifying the client's proxy
|
||||
func (obj *Client) SetProxy(proxyUrl string) (err error) {
|
||||
obj.proxy, err = gtls.VerifyProxy(proxyUrl)
|
||||
_, err = gtls.VerifyProxy(proxyUrl)
|
||||
if err == nil {
|
||||
obj.option.Proxy = proxyUrl
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
48
conn.go
48
conn.go
@@ -17,33 +17,30 @@ import (
|
||||
|
||||
type connecotr struct {
|
||||
key connKey
|
||||
err error
|
||||
deleteCtx context.Context //force close
|
||||
deleteCnl context.CancelFunc
|
||||
deleteCnl context.CancelCauseFunc
|
||||
|
||||
closeCtx context.Context //safe close
|
||||
closeCnl context.CancelFunc
|
||||
closeCnl context.CancelCauseFunc
|
||||
|
||||
bodyCtx context.Context //body close
|
||||
bodyCnl context.CancelFunc
|
||||
bodyCnl context.CancelCauseFunc
|
||||
|
||||
rawConn net.Conn
|
||||
h2 bool
|
||||
r *bufio.Reader
|
||||
w *bufio.Writer
|
||||
h2RawConn *http2.ClientConn
|
||||
rc chan []byte
|
||||
rn chan int
|
||||
pr *pipCon
|
||||
isPool bool
|
||||
}
|
||||
|
||||
func (obj *connecotr) withCancel(deleteCtx context.Context, closeCtx context.Context) {
|
||||
obj.deleteCtx, obj.deleteCnl = context.WithCancel(deleteCtx)
|
||||
obj.closeCtx, obj.closeCnl = context.WithCancel(closeCtx)
|
||||
obj.deleteCtx, obj.deleteCnl = context.WithCancelCause(deleteCtx)
|
||||
obj.closeCtx, obj.closeCnl = context.WithCancelCause(closeCtx)
|
||||
}
|
||||
func (obj *connecotr) Close() error {
|
||||
obj.deleteCnl()
|
||||
obj.deleteCnl(errors.New("connecotr close"))
|
||||
if obj.h2RawConn != nil {
|
||||
obj.h2RawConn.Close()
|
||||
}
|
||||
@@ -56,11 +53,13 @@ func (obj *connecotr) read() (err error) {
|
||||
var pw *pipCon
|
||||
obj.pr, pw = pipe(obj.deleteCtx)
|
||||
defer func() {
|
||||
obj.pr.cnl(err)
|
||||
pw.cnl(err)
|
||||
obj.pr.cnl(err)
|
||||
obj.Close()
|
||||
}()
|
||||
_, err = io.Copy(pw, obj.rawConn)
|
||||
if _, err = io.Copy(pw, obj.rawConn); err == nil {
|
||||
err = io.EOF
|
||||
}
|
||||
return
|
||||
}
|
||||
func (obj *connecotr) Read(b []byte) (i int, err error) {
|
||||
@@ -72,21 +71,6 @@ func (obj *connecotr) Read(b []byte) (i int, err error) {
|
||||
func (obj *connecotr) Write(b []byte) (int, error) {
|
||||
return obj.rawConn.Write(b)
|
||||
}
|
||||
func (obj *connecotr) LocalAddr() net.Addr {
|
||||
return obj.rawConn.LocalAddr()
|
||||
}
|
||||
func (obj *connecotr) RemoteAddr() net.Addr {
|
||||
return obj.rawConn.RemoteAddr()
|
||||
}
|
||||
func (obj *connecotr) SetDeadline(t time.Time) error {
|
||||
return obj.rawConn.SetDeadline(t)
|
||||
}
|
||||
func (obj *connecotr) SetReadDeadline(t time.Time) error {
|
||||
return obj.rawConn.SetReadDeadline(t)
|
||||
}
|
||||
func (obj *connecotr) SetWriteDeadline(t time.Time) error {
|
||||
return obj.rawConn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (obj *connecotr) h2Closed() bool {
|
||||
state := obj.h2RawConn.State()
|
||||
@@ -94,7 +78,7 @@ func (obj *connecotr) h2Closed() bool {
|
||||
}
|
||||
func (obj *connecotr) wrapBody(task *reqTask) {
|
||||
body := new(readWriteCloser)
|
||||
obj.bodyCtx, obj.bodyCnl = context.WithCancel(obj.deleteCtx)
|
||||
obj.bodyCtx, obj.bodyCnl = context.WithCancelCause(obj.deleteCtx)
|
||||
body.body = task.res.Body
|
||||
body.conn = obj
|
||||
task.res.Body = body
|
||||
@@ -191,13 +175,13 @@ func (obj *connecotr) taskMain(task *reqTask, afterTime *time.Timer) (*http.Resp
|
||||
|
||||
type connPool struct {
|
||||
deleteCtx context.Context
|
||||
deleteCnl context.CancelFunc
|
||||
deleteCnl context.CancelCauseFunc
|
||||
closeCtx context.Context
|
||||
closeCnl context.CancelFunc
|
||||
closeCnl context.CancelCauseFunc
|
||||
key connKey
|
||||
total atomic.Int64
|
||||
tasks chan *reqTask
|
||||
rt *RoundTripper
|
||||
rt *roundTripper
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
@@ -252,10 +236,10 @@ func (obj *connPool) rwMain(conn *connecotr) {
|
||||
}
|
||||
}
|
||||
func (obj *connPool) forceClose() {
|
||||
obj.deleteCnl()
|
||||
obj.deleteCnl(errors.New("connPool forceClose"))
|
||||
obj.close()
|
||||
}
|
||||
func (obj *connPool) close() {
|
||||
obj.closeCnl()
|
||||
obj.closeCnl(errors.New("connPool close"))
|
||||
obj.rt.delConnPool(obj.key)
|
||||
}
|
||||
|
||||
12
go.mod
12
go.mod
@@ -12,10 +12,10 @@ require (
|
||||
github.com/gospider007/net v0.0.0-20231028084010-313c148cf0a1
|
||||
github.com/gospider007/re v0.0.0-20231024115818-adfd03636256
|
||||
github.com/gospider007/tools v0.0.0-20231122021245-1cafbac3ef46
|
||||
github.com/gospider007/websocket v0.0.0-20231124124758-1491f1b57db1
|
||||
github.com/gospider007/websocket v0.0.0-20231128065110-6296f87425c4
|
||||
github.com/refraction-networking/utls v1.5.4
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
||||
golang.org/x/net v0.18.0
|
||||
golang.org/x/exp v0.0.0-20231127185646-65229373498e
|
||||
golang.org/x/net v0.19.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -42,11 +42,11 @@ require (
|
||||
go.mongodb.org/mongo-driver v1.13.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/crypto v0.15.0 // indirect
|
||||
golang.org/x/crypto v0.16.0 // indirect
|
||||
golang.org/x/image v0.14.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.15.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
nhooyr.io/websocket v1.8.10 // indirect
|
||||
)
|
||||
|
||||
36
go.sum
36
go.sum
@@ -25,16 +25,10 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ=
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/gospider007/bar v0.0.0-20231024075629-3f50832a4cbf h1:ow0/zY4+dwhS6xMDEc/m0woLJ0XDO5Q5cttcprJ4hRs=
|
||||
github.com/gospider007/bar v0.0.0-20231024075629-3f50832a4cbf/go.mod h1:KC7Tt189vS0u4KB6ThC5ShzTRvDsU54KM6wvmJBvqfg=
|
||||
github.com/gospider007/bar v0.0.0-20231121084140-33c7b6797626 h1:zDK4PcXQmAX37JdGUp45gFDMolnBGzWVXgemm5ekG1Y=
|
||||
github.com/gospider007/bar v0.0.0-20231121084140-33c7b6797626/go.mod h1:aYPgmG9340i9x9VQZhf34/XtIj7PHDTq0wSO+7zU/8s=
|
||||
github.com/gospider007/blog v0.0.0-20231024075658-5da1a801a2c8 h1:rcbzO343eHoZ1yJygef05WYxCjPgqo03OMwG4Ql6ckE=
|
||||
github.com/gospider007/blog v0.0.0-20231024075658-5da1a801a2c8/go.mod h1:CCJ+hvQ0kxL+qB/Wfr1xt7xspsG4XiczhnAPVxG2m3M=
|
||||
github.com/gospider007/blog v0.0.0-20231121084103-59a004dafccf h1:1laTsuH/wl5pZ5QlHzacX09QzvwQw0DFENoRMpGBK8Y=
|
||||
github.com/gospider007/blog v0.0.0-20231121084103-59a004dafccf/go.mod h1:CCJ+hvQ0kxL+qB/Wfr1xt7xspsG4XiczhnAPVxG2m3M=
|
||||
github.com/gospider007/bs4 v0.0.0-20231119141556-162d71807dcc h1:cYnsCLDMRfuWV3AoK4d2R1CTXdmQpOYm42ms8PhcBFI=
|
||||
github.com/gospider007/bs4 v0.0.0-20231119141556-162d71807dcc/go.mod h1:oFH47TbYECc3Mbd+6W3UmJWZoOvj/8ZwXimE8iIedRI=
|
||||
github.com/gospider007/bs4 v0.0.0-20231123090151-001db0b91941 h1:Aik3aBqnpujF5LA+JyIm3LNxivobnqAOPr+VVlTbqds=
|
||||
github.com/gospider007/bs4 v0.0.0-20231123090151-001db0b91941/go.mod h1:bbSbFlcbgzxvmjVGp8rZq/BX975acPgGbuICISi1usI=
|
||||
github.com/gospider007/gson v0.0.0-20231119141525-66095080057d h1:K9IbMHY2dZfi1ddJWL7a+KkZe6apIYaXN1cD8lDRH5I=
|
||||
@@ -49,16 +43,10 @@ github.com/gospider007/net v0.0.0-20231028084010-313c148cf0a1 h1:tYOQEvELrV+USjK
|
||||
github.com/gospider007/net v0.0.0-20231028084010-313c148cf0a1/go.mod h1:3ggAwYdh0NB0OvtiX0l5AfHdBjgsIt9MGsXCQ3iCzQc=
|
||||
github.com/gospider007/re v0.0.0-20231024115818-adfd03636256 h1:Z6kHRANoWB+/4rDzq51vBts0rIXilDrF8pdRNmbMJi4=
|
||||
github.com/gospider007/re v0.0.0-20231024115818-adfd03636256/go.mod h1:X58uk0/F3mVskuQOZng0ZKJiAt3ETn0wxuLN//rVZrE=
|
||||
github.com/gospider007/tools v0.0.0-20231120122411-d631cc2fc371 h1:wF5pm7gilDuDKg4rmhmz4S+/Y3EEVgvZdwgywnhbyKA=
|
||||
github.com/gospider007/tools v0.0.0-20231120122411-d631cc2fc371/go.mod h1:myK4kDqDx4TlplDVnfYMI7Xi5VUbFZ3fxwAh2Cwm7ks=
|
||||
github.com/gospider007/tools v0.0.0-20231122021245-1cafbac3ef46 h1:vskdS8WLAveNSDHsAAdwiD+LBLMHq3AND1nGnVydwfM=
|
||||
github.com/gospider007/tools v0.0.0-20231122021245-1cafbac3ef46/go.mod h1:myK4kDqDx4TlplDVnfYMI7Xi5VUbFZ3fxwAh2Cwm7ks=
|
||||
github.com/gospider007/websocket v0.0.0-20231114095858-b8bc9b2033d3 h1:HpiNfOZ9Tjo4hhP1+jmlgqykngykles3ypXa2BUuxRc=
|
||||
github.com/gospider007/websocket v0.0.0-20231114095858-b8bc9b2033d3/go.mod h1:jINjCM6qIRiqn2Di1bat4Ie5gY66ae7LYT8YK4fAejY=
|
||||
github.com/gospider007/websocket v0.0.0-20231124122326-78d52f163d6c h1:AVquutD7Mbb9gcq7/ciRC/Vt2StSiBuUagJviG8+vkg=
|
||||
github.com/gospider007/websocket v0.0.0-20231124122326-78d52f163d6c/go.mod h1:TquIvV/QrLmSufnwdc+54DAbUd39HsNgpFcoQYthVU8=
|
||||
github.com/gospider007/websocket v0.0.0-20231124124758-1491f1b57db1 h1:/7C93+nXTXAsg87hUH5n4trT99uaTUPglQ8wMxKA5gQ=
|
||||
github.com/gospider007/websocket v0.0.0-20231124124758-1491f1b57db1/go.mod h1:TquIvV/QrLmSufnwdc+54DAbUd39HsNgpFcoQYthVU8=
|
||||
github.com/gospider007/websocket v0.0.0-20231128065110-6296f87425c4 h1:h+74nkhhTDN2tiaDjHwR4CjqBTHgh+t1pqE2IAWHN3k=
|
||||
github.com/gospider007/websocket v0.0.0-20231128065110-6296f87425c4/go.mod h1:OncvZIlq9TzwD/tQS/BYY/RKBqbW4+gGY3Ere1K7s24=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
@@ -122,10 +110,10 @@ go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No=
|
||||
golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
|
||||
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
@@ -140,8 +128,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -155,8 +143,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
@@ -174,8 +162,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
||||
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
|
||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
||||
8
jar.go
8
jar.go
@@ -24,19 +24,19 @@ func NewJar() *Jar {
|
||||
|
||||
// get cookies
|
||||
func (obj *Client) GetCookies(href string) (Cookies, error) {
|
||||
return obj.jar.GetCookies(href)
|
||||
return obj.option.Jar.GetCookies(href)
|
||||
}
|
||||
|
||||
// set cookies
|
||||
func (obj *Client) SetCookies(href string, cookies ...any) error {
|
||||
return obj.jar.SetCookies(href, cookies...)
|
||||
return obj.option.Jar.SetCookies(href, cookies...)
|
||||
}
|
||||
|
||||
// clear cookies
|
||||
func (obj *Client) ClearCookies() {
|
||||
if obj.client.Jar != nil {
|
||||
obj.jar.ClearCookies()
|
||||
obj.client.Jar = obj.jar.jar
|
||||
obj.option.Jar.ClearCookies()
|
||||
obj.client.Jar = obj.option.Jar.jar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
59
option.go
59
option.go
@@ -158,92 +158,95 @@ func (obj *RequestOption) initParams() (string, error) {
|
||||
if err != nil {
|
||||
return obj.Url.String(), err
|
||||
}
|
||||
query := dataMap.parseParams()
|
||||
query := dataMap.parseParams().String()
|
||||
if query == "" {
|
||||
return obj.Url.String(), nil
|
||||
}
|
||||
pu := cloneUrl(obj.Url)
|
||||
puValues := pu.Query()
|
||||
pu.RawQuery = puValues.Encode() + "&" + query
|
||||
pquery := pu.Query().Encode()
|
||||
if pquery == "" {
|
||||
pu.RawQuery = query
|
||||
} else {
|
||||
pu.RawQuery = pquery + "&" + query
|
||||
}
|
||||
return pu.String(), nil
|
||||
}
|
||||
func (obj *Client) newRequestOption(option RequestOption) RequestOption {
|
||||
if !option.DisProxy {
|
||||
if option.Proxy == "" && obj.proxy != nil {
|
||||
option.Proxy = obj.proxy.String()
|
||||
if option.Proxy == "" && obj.option.Proxy != "" {
|
||||
option.Proxy = obj.option.Proxy
|
||||
}
|
||||
} else {
|
||||
option.Proxy = ""
|
||||
}
|
||||
|
||||
if option.MaxRetries < 0 {
|
||||
option.MaxRetries = 0
|
||||
} else if option.MaxRetries == 0 {
|
||||
option.MaxRetries = obj.maxRetries
|
||||
option.MaxRetries = obj.option.MaxRetries
|
||||
}
|
||||
if option.Headers == nil {
|
||||
option.Headers = obj.headers
|
||||
option.Headers = obj.option.Headers
|
||||
}
|
||||
if !option.Bar {
|
||||
option.Bar = obj.bar
|
||||
option.Bar = obj.option.Bar
|
||||
}
|
||||
if option.MaxRedirect == 0 {
|
||||
option.MaxRedirect = obj.maxRedirect
|
||||
option.MaxRedirect = obj.option.MaxRedirect
|
||||
}
|
||||
if option.Timeout == 0 {
|
||||
option.Timeout = obj.timeout
|
||||
option.Timeout = obj.option.Timeout
|
||||
}
|
||||
if option.ResponseHeaderTimeout == 0 {
|
||||
option.ResponseHeaderTimeout = obj.responseHeaderTimeout
|
||||
option.ResponseHeaderTimeout = obj.option.ResponseHeaderTimeout
|
||||
}
|
||||
if option.AddrType == 0 {
|
||||
option.AddrType = obj.addrType
|
||||
option.AddrType = obj.option.AddrType
|
||||
}
|
||||
if option.TlsHandshakeTimeout == 0 {
|
||||
option.TlsHandshakeTimeout = obj.tlsHandshakeTimeout
|
||||
option.TlsHandshakeTimeout = obj.option.TlsHandshakeTimeout
|
||||
}
|
||||
if !option.DisCookie {
|
||||
option.DisCookie = obj.disCookie
|
||||
option.DisCookie = obj.option.DisCookie
|
||||
}
|
||||
if !option.DisDecode {
|
||||
option.DisDecode = obj.disDecode
|
||||
option.DisDecode = obj.option.DisDecode
|
||||
}
|
||||
if !option.DisUnZip {
|
||||
option.DisUnZip = obj.disUnZip
|
||||
option.DisUnZip = obj.option.DisUnZip
|
||||
}
|
||||
|
||||
if !option.ForceHttp1 {
|
||||
option.ForceHttp1 = obj.forceHttp1
|
||||
option.ForceHttp1 = obj.option.ForceHttp1
|
||||
}
|
||||
|
||||
if !option.DisAlive {
|
||||
option.DisAlive = obj.disAlive
|
||||
option.DisAlive = obj.option.DisAlive
|
||||
}
|
||||
if option.OrderHeaders == nil {
|
||||
option.OrderHeaders = obj.orderHeaders
|
||||
option.OrderHeaders = obj.option.OrderHeaders
|
||||
}
|
||||
|
||||
if !option.Ja3Spec.IsSet() {
|
||||
if obj.ja3Spec.IsSet() {
|
||||
option.Ja3Spec = obj.ja3Spec
|
||||
} else if option.Ja3 {
|
||||
if obj.option.Ja3Spec.IsSet() {
|
||||
option.Ja3Spec = obj.option.Ja3Spec
|
||||
} else if option.Ja3 || obj.option.Ja3 {
|
||||
option.Ja3Spec = ja3.DefaultJa3Spec()
|
||||
}
|
||||
}
|
||||
if !option.H2Ja3Spec.IsSet() {
|
||||
option.H2Ja3Spec = obj.h2Ja3Spec
|
||||
option.H2Ja3Spec = obj.option.H2Ja3Spec
|
||||
}
|
||||
if option.OptionCallBack == nil {
|
||||
option.OptionCallBack = obj.optionCallBack
|
||||
option.OptionCallBack = obj.option.OptionCallBack
|
||||
}
|
||||
if option.ResultCallBack == nil {
|
||||
option.ResultCallBack = obj.resultCallBack
|
||||
option.ResultCallBack = obj.option.ResultCallBack
|
||||
}
|
||||
if option.ErrCallBack == nil {
|
||||
option.ErrCallBack = obj.errCallBack
|
||||
option.ErrCallBack = obj.option.ErrCallBack
|
||||
}
|
||||
if option.RequestCallBack == nil {
|
||||
option.RequestCallBack = obj.requestCallBack
|
||||
option.RequestCallBack = obj.option.RequestCallBack
|
||||
}
|
||||
return option
|
||||
}
|
||||
|
||||
@@ -432,7 +432,7 @@ func (obj *Client) request(ctx context.Context, option *RequestOption) (response
|
||||
response.disUnzip = response.response.Uncompressed
|
||||
}
|
||||
if response.response.StatusCode == 101 {
|
||||
response.webSocket, err = websocket.NewClientConn(response.response, response.ForceCloseConn)
|
||||
response.webSocket, err = websocket.NewClientConn(response.rawConn.Conn(), response.response.Header, response.ForceCloseConn)
|
||||
if ctxData.debug {
|
||||
debugPrint(ctxData.requestId, "new websocket client, err: ", err)
|
||||
}
|
||||
|
||||
55
response.go
55
response.go
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/gospider007/bar"
|
||||
"github.com/gospider007/bs4"
|
||||
"github.com/gospider007/gson"
|
||||
"github.com/gospider007/re"
|
||||
"github.com/gospider007/tools"
|
||||
"github.com/gospider007/websocket"
|
||||
)
|
||||
@@ -61,21 +62,35 @@ func (obj *Sse) Recv() (Event, error) {
|
||||
if err != nil || readStr == "\n" {
|
||||
return event, err
|
||||
}
|
||||
if strings.HasPrefix(readStr, "data: ") {
|
||||
event.Data += readStr[6 : len(readStr)-1]
|
||||
} else if strings.HasPrefix(readStr, "event: ") {
|
||||
event.Event = readStr[7 : len(readStr)-1]
|
||||
} else if strings.HasPrefix(readStr, "id: ") {
|
||||
event.Id = readStr[4 : len(readStr)-1]
|
||||
} else if strings.HasPrefix(readStr, "retry: ") {
|
||||
if event.Retry, err = strconv.Atoi(readStr[7 : len(readStr)-1]); err != nil {
|
||||
reResult := re.Search(`data:\s?(.*)`, readStr)
|
||||
if reResult != nil {
|
||||
event.Data += reResult.Group(1)
|
||||
continue
|
||||
}
|
||||
reResult = re.Search(`event:\s?(.*)`, readStr)
|
||||
|
||||
if reResult != nil {
|
||||
event.Event = reResult.Group(1)
|
||||
continue
|
||||
}
|
||||
reResult = re.Search(`id:\s?(.*)`, readStr)
|
||||
if reResult != nil {
|
||||
event.Id = reResult.Group(1)
|
||||
continue
|
||||
}
|
||||
reResult = re.Search(`retry:\s?(.*)`, readStr)
|
||||
if reResult != nil {
|
||||
if event.Retry, err = strconv.Atoi(reResult.Group(1)); err != nil {
|
||||
return event, err
|
||||
}
|
||||
} else if strings.HasPrefix(readStr, ": ") {
|
||||
event.Comment = readStr[2 : len(readStr)-1]
|
||||
} else {
|
||||
return event, errors.New("content parse error:" + readStr)
|
||||
continue
|
||||
}
|
||||
reResult = re.Search(`:\s?(.*)`, readStr)
|
||||
if reResult != nil {
|
||||
event.Comment = reResult.Group(1)
|
||||
continue
|
||||
}
|
||||
return event, errors.New("content parse error:" + readStr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,22 +356,6 @@ func (obj *Response) InPool() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// conn ja3
|
||||
func (obj *Response) Ja3() string {
|
||||
if obj.rawConn != nil {
|
||||
return obj.rawConn.Ja3()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// conn h2ja3
|
||||
func (obj *Response) H2Ja3() string {
|
||||
if obj.rawConn != nil {
|
||||
return obj.rawConn.H2Ja3()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// safe close conn
|
||||
func (obj *Response) CloseConn() {
|
||||
if obj.rawConn != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"sync"
|
||||
@@ -50,8 +51,6 @@ func (obj *reqTask) inPool() bool {
|
||||
type connKey struct {
|
||||
proxy string
|
||||
addr string
|
||||
ja3 string
|
||||
h2Ja3 string
|
||||
}
|
||||
|
||||
func getKey(ctxData *reqCtxData, req *http.Request) connKey {
|
||||
@@ -60,14 +59,12 @@ func getKey(ctxData *reqCtxData, req *http.Request) connKey {
|
||||
proxy = ctxData.proxy.String()
|
||||
}
|
||||
return connKey{
|
||||
h2Ja3: ctxData.h2Ja3Spec.Fp(),
|
||||
ja3: ctxData.ja3Spec.String(),
|
||||
proxy: proxy,
|
||||
addr: getAddr(req.URL),
|
||||
}
|
||||
}
|
||||
|
||||
type RoundTripper struct {
|
||||
type roundTripper struct {
|
||||
ctx context.Context
|
||||
cnl context.CancelFunc
|
||||
connPools sync.Map
|
||||
@@ -87,7 +84,7 @@ type roundTripperOption struct {
|
||||
GetProxy func(ctx context.Context, url *url.URL) (string, error)
|
||||
}
|
||||
|
||||
func newRoundTripper(preCtx context.Context, option roundTripperOption) *RoundTripper {
|
||||
func newRoundTripper(preCtx context.Context, option ClientOption) *roundTripper {
|
||||
if preCtx == nil {
|
||||
preCtx = context.TODO()
|
||||
}
|
||||
@@ -113,7 +110,7 @@ func newRoundTripper(preCtx context.Context, option roundTripperOption) *RoundTr
|
||||
OmitEmptyPsk: true,
|
||||
PreferSkipResumptionOnNilExtension: true,
|
||||
}
|
||||
return &RoundTripper{
|
||||
return &roundTripper{
|
||||
tlsConfig: tlsConfig,
|
||||
utlsConfig: utlsConfig,
|
||||
ctx: ctx,
|
||||
@@ -122,28 +119,28 @@ func newRoundTripper(preCtx context.Context, option roundTripperOption) *RoundTr
|
||||
proxy: option.GetProxy,
|
||||
}
|
||||
}
|
||||
func (obj *RoundTripper) newConnPool(conn *connecotr, key connKey) *connPool {
|
||||
func (obj *roundTripper) newConnPool(conn *connecotr, key connKey) *connPool {
|
||||
pool := new(connPool)
|
||||
pool.key = key
|
||||
pool.deleteCtx, pool.deleteCnl = context.WithCancel(obj.ctx)
|
||||
pool.closeCtx, pool.closeCnl = context.WithCancel(pool.deleteCtx)
|
||||
pool.deleteCtx, pool.deleteCnl = context.WithCancelCause(obj.ctx)
|
||||
pool.closeCtx, pool.closeCnl = context.WithCancelCause(pool.deleteCtx)
|
||||
pool.tasks = make(chan *reqTask)
|
||||
pool.rt = obj
|
||||
pool.total.Add(1)
|
||||
go pool.rwMain(conn)
|
||||
return pool
|
||||
}
|
||||
func (obj *RoundTripper) getConnPool(key connKey) *connPool {
|
||||
func (obj *roundTripper) getConnPool(key connKey) *connPool {
|
||||
val, ok := obj.connPools.Load(key)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return val.(*connPool)
|
||||
}
|
||||
func (obj *RoundTripper) delConnPool(key connKey) {
|
||||
func (obj *roundTripper) delConnPool(key connKey) {
|
||||
obj.connPools.Delete(key)
|
||||
}
|
||||
func (obj *RoundTripper) putConnPool(key connKey, conn *connecotr) {
|
||||
func (obj *roundTripper) putConnPool(key connKey, conn *connecotr) {
|
||||
conn.isPool = true
|
||||
if !conn.h2 {
|
||||
go conn.read()
|
||||
@@ -162,13 +159,13 @@ func (obj *RoundTripper) putConnPool(key connKey, conn *connecotr) {
|
||||
obj.connPools.Store(key, obj.newConnPool(conn, key))
|
||||
}
|
||||
}
|
||||
func (obj *RoundTripper) tlsConfigClone() *tls.Config {
|
||||
func (obj *roundTripper) tlsConfigClone() *tls.Config {
|
||||
return obj.tlsConfig.Clone()
|
||||
}
|
||||
func (obj *RoundTripper) utlsConfigClone() *utls.Config {
|
||||
func (obj *roundTripper) utlsConfigClone() *utls.Config {
|
||||
return obj.utlsConfig.Clone()
|
||||
}
|
||||
func (obj *RoundTripper) dial(ctxData *reqCtxData, key *connKey, req *http.Request) (conn *connecotr, err error) {
|
||||
func (obj *roundTripper) dial(ctxData *reqCtxData, key *connKey, req *http.Request) (conn *connecotr, err error) {
|
||||
proxy := ctxData.proxy
|
||||
if !ctxData.disProxy && proxy == nil {
|
||||
if proxy, err = obj.getProxy(req.Context(), req.URL); err != nil {
|
||||
@@ -189,8 +186,6 @@ func (obj *RoundTripper) dial(ctxData *reqCtxData, key *connKey, req *http.Reque
|
||||
return conn, err
|
||||
}
|
||||
conne := new(connecotr)
|
||||
conne.rn = make(chan int)
|
||||
conne.rc = make(chan []byte)
|
||||
conne.withCancel(obj.ctx, obj.ctx)
|
||||
if req.URL.Scheme == "https" {
|
||||
ctx, cnl := context.WithTimeout(req.Context(), ctxData.tlsHandshakeTimeout)
|
||||
@@ -218,7 +213,7 @@ func (obj *RoundTripper) dial(ctxData *reqCtxData, key *connKey, req *http.Reque
|
||||
conne.rawConn = netConn
|
||||
if conne.h2 {
|
||||
if conne.h2RawConn, err = http2.NewClientConn(func() {
|
||||
conne.closeCnl()
|
||||
conne.closeCnl(errors.New("http2 client close"))
|
||||
}, netConn, ctxData.h2Ja3Spec); err != nil {
|
||||
return conne, err
|
||||
}
|
||||
@@ -228,10 +223,10 @@ func (obj *RoundTripper) dial(ctxData *reqCtxData, key *connKey, req *http.Reque
|
||||
}
|
||||
return conne, err
|
||||
}
|
||||
func (obj *RoundTripper) setGetProxy(getProxy func(ctx context.Context, url *url.URL) (string, error)) {
|
||||
func (obj *roundTripper) setGetProxy(getProxy func(ctx context.Context, url *url.URL) (string, error)) {
|
||||
obj.proxy = getProxy
|
||||
}
|
||||
func (obj *RoundTripper) getProxy(ctx context.Context, proxyUrl *url.URL) (*url.URL, error) {
|
||||
func (obj *roundTripper) getProxy(ctx context.Context, proxyUrl *url.URL) (*url.URL, error) {
|
||||
if obj.proxy == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -242,7 +237,7 @@ func (obj *RoundTripper) getProxy(ctx context.Context, proxyUrl *url.URL) (*url.
|
||||
return gtls.VerifyProxy(proxy)
|
||||
}
|
||||
|
||||
func (obj *RoundTripper) poolRoundTrip(task *reqTask, key connKey) (bool, error) {
|
||||
func (obj *roundTripper) poolRoundTrip(task *reqTask, key connKey) (bool, error) {
|
||||
if task.debug {
|
||||
debugPrint(task.requestId, "poolRoundTrip start")
|
||||
}
|
||||
@@ -290,7 +285,7 @@ func (obj *RoundTripper) poolRoundTrip(task *reqTask, key connKey) (bool, error)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (obj *RoundTripper) closeConns() {
|
||||
func (obj *roundTripper) closeConns() {
|
||||
obj.connPools.Range(func(key, value any) bool {
|
||||
pool := value.(*connPool)
|
||||
pool.close()
|
||||
@@ -299,7 +294,7 @@ func (obj *RoundTripper) closeConns() {
|
||||
})
|
||||
}
|
||||
|
||||
func (obj *RoundTripper) forceCloseConns() {
|
||||
func (obj *roundTripper) forceCloseConns() {
|
||||
obj.connPools.Range(func(key, value any) bool {
|
||||
pool := value.(*connPool)
|
||||
pool.forceClose()
|
||||
@@ -307,7 +302,7 @@ func (obj *RoundTripper) forceCloseConns() {
|
||||
return true
|
||||
})
|
||||
}
|
||||
func (obj *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
func (obj *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
ctxData := GetReqCtxData(req.Context())
|
||||
if ctxData.requestCallBack != nil {
|
||||
if err := ctxData.requestCallBack(req.Context(), req, nil); err != nil {
|
||||
|
||||
14
rw.go
14
rw.go
@@ -1,8 +1,8 @@
|
||||
package requests
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
type readWriteCloser struct {
|
||||
@@ -10,7 +10,7 @@ type readWriteCloser struct {
|
||||
conn *connecotr
|
||||
}
|
||||
|
||||
func (obj *readWriteCloser) Conn() net.Conn {
|
||||
func (obj *readWriteCloser) Conn() *connecotr {
|
||||
return obj.conn
|
||||
}
|
||||
func (obj *readWriteCloser) Read(p []byte) (n int, err error) {
|
||||
@@ -21,7 +21,7 @@ func (obj *readWriteCloser) Close() (err error) {
|
||||
if !obj.InPool() {
|
||||
obj.ForceCloseConn()
|
||||
} else {
|
||||
obj.conn.bodyCnl()
|
||||
obj.conn.bodyCnl(errors.New("readWriteCloser close"))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -31,16 +31,10 @@ func (obj *readWriteCloser) InPool() bool {
|
||||
func (obj *readWriteCloser) Proxy() string {
|
||||
return obj.conn.key.proxy
|
||||
}
|
||||
func (obj *readWriteCloser) Ja3() string {
|
||||
return obj.conn.key.ja3
|
||||
}
|
||||
func (obj *readWriteCloser) H2Ja3() string {
|
||||
return obj.conn.key.h2Ja3
|
||||
}
|
||||
|
||||
// safe close conn
|
||||
func (obj *readWriteCloser) CloseConn() {
|
||||
obj.conn.closeCnl()
|
||||
obj.conn.closeCnl(errors.New("readWriterCloser close conn"))
|
||||
}
|
||||
|
||||
// force close conn
|
||||
|
||||
@@ -1,14 +1,52 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gospider007/gson"
|
||||
"github.com/gospider007/requests"
|
||||
)
|
||||
|
||||
func TestSse(t *testing.T) {
|
||||
response, err := requests.Get(nil, "https://sse.dev/test") // Send WebSocket request
|
||||
// Start the server
|
||||
go func() {
|
||||
err := http.ListenAndServe(":3333", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
w.Header().Set("Connection", "keep-alive")
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
// SSE event format
|
||||
event := "message"
|
||||
data := "testing"
|
||||
// Start SSE loop
|
||||
for i := 0; i < 3; i++ {
|
||||
// Send SSE event
|
||||
_, err := w.Write([]byte("event: " + event + "\n"))
|
||||
if err != nil {
|
||||
log.Println("Error writing SSE event:", err)
|
||||
return
|
||||
}
|
||||
_, err = w.Write([]byte("data: " + data + "\n\n"))
|
||||
if err != nil {
|
||||
log.Println("Error writing SSE data:", err)
|
||||
return
|
||||
}
|
||||
// Flush the response writer
|
||||
if f, ok := w.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
// Delay before sending the next event
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}()
|
||||
response, err := requests.Get(nil, "http://127.0.0.1:3333/events") // Send WebSocket request
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -17,16 +55,15 @@ func TestSse(t *testing.T) {
|
||||
if sseCli == nil {
|
||||
t.Error("not is sseCli")
|
||||
}
|
||||
for maxNum := 0; maxNum < 3; maxNum++ {
|
||||
for {
|
||||
data, err := sseCli.Recv()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
if err != io.EOF {
|
||||
t.Error(err)
|
||||
}
|
||||
break
|
||||
}
|
||||
jsonData, err := gson.Decode(data.Data)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if !jsonData.Get("testing").Bool() {
|
||||
if data.Data != "testing" {
|
||||
t.Error("testing")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user