mirror of
https://github.com/gospider007/requests.git
synced 2025-12-24 13:57:52 +08:00
1
This commit is contained in:
15
client.go
15
client.go
@@ -4,11 +4,12 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
|
||||
"gitee.com/baixudong/http2"
|
||||
"gitee.com/baixudong/ja3"
|
||||
utls "github.com/refraction-networking/utls"
|
||||
@@ -193,14 +194,11 @@ func NewClient(preCtx context.Context, options ...ClientOption) (*Client, error)
|
||||
// }
|
||||
// }
|
||||
var http0Transport *RoundTripper
|
||||
if option.Http0 {
|
||||
http0Transport = NewRoundTripper(dialClient)
|
||||
}
|
||||
if option.H2Ja3 || option.H2Ja3Spec.IsSet() {
|
||||
http2Upg = http2.NewUpg(transport, http2.UpgOption{
|
||||
http2Upg = http2.NewUpg(http2.UpgOption{
|
||||
H2Ja3Spec: option.H2Ja3Spec,
|
||||
DialTLSContext: dialClient.requestHttp2DialTlsContext,
|
||||
IdleConnTimeout: option.TLSHandshakeTimeout,
|
||||
IdleConnTimeout: option.IdleConnTimeout,
|
||||
TLSHandshakeTimeout: option.TLSHandshakeTimeout,
|
||||
ResponseHeaderTimeout: option.ResponseHeaderTimeout,
|
||||
TlsConfig: tlsConfig,
|
||||
@@ -211,6 +209,9 @@ func NewClient(preCtx context.Context, options ...ClientOption) (*Client, error)
|
||||
},
|
||||
}
|
||||
}
|
||||
if option.Http0 {
|
||||
http0Transport = NewRoundTripper(ctx, dialClient, http2Upg, option)
|
||||
}
|
||||
client := &http.Client{
|
||||
Jar: jar,
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
|
||||
@@ -2,9 +2,10 @@ package requests
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
_ "unsafe"
|
||||
|
||||
"net/http"
|
||||
|
||||
"gitee.com/baixudong/tools"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
3
dial.go
3
dial.go
@@ -7,12 +7,13 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"net/http"
|
||||
|
||||
"gitee.com/baixudong/ja3"
|
||||
"gitee.com/baixudong/tools"
|
||||
utls "github.com/refraction-networking/utls"
|
||||
|
||||
15
go.mod
15
go.mod
@@ -5,15 +5,17 @@ go 1.20
|
||||
require (
|
||||
gitee.com/baixudong/bar v0.0.0-20230726064206-c402a9061923
|
||||
gitee.com/baixudong/bs4 v0.0.0-20230726070247-16e869055fa3
|
||||
gitee.com/baixudong/http2 v0.0.0-20230726070349-0b364387f0f4
|
||||
gitee.com/baixudong/ja3 v0.0.0-20230726070357-f35eae6532ad
|
||||
gitee.com/baixudong/re v0.0.0-20230726070429-e1a623b3c133
|
||||
gitee.com/baixudong/tools v0.0.0-20230726070525-d80da902e36d
|
||||
gitee.com/baixudong/websocket v0.0.0-20230726070532-ab0f08baf667
|
||||
github.com/refraction-networking/utls v1.3.2
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/refraction-networking/utls v1.3.3
|
||||
github.com/tidwall/gjson v1.15.0
|
||||
golang.org/x/net v0.11.0
|
||||
)
|
||||
|
||||
require gitee.com/baixudong/http2 v0.0.0-20230726070349-0b364387f0f4
|
||||
|
||||
require (
|
||||
gitee.com/baixudong/blog v0.0.0-20230726070237-ee8a30e182ac // indirect
|
||||
gitee.com/baixudong/kinds v0.0.0-20230726070402-0bc6b1ebb086 // indirect
|
||||
@@ -25,7 +27,7 @@ require (
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/klauspost/compress v1.16.6 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
@@ -33,11 +35,10 @@ require (
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.9.0 // indirect
|
||||
golang.org/x/crypto v0.10.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
|
||||
golang.org/x/image v0.9.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/sys v0.8.0 // indirect
|
||||
golang.org/x/sys v0.9.0 // indirect
|
||||
golang.org/x/text v0.11.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
nhooyr.io/websocket v1.8.7 // indirect
|
||||
|
||||
24
go.sum
24
go.sum
@@ -63,8 +63,8 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
|
||||
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.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
|
||||
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
|
||||
github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk=
|
||||
github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
@@ -77,14 +77,14 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/refraction-networking/utls v1.3.2 h1:o+AkWB57mkcoW36ET7uJ002CpBWHu0KPxi6vzxvPnv8=
|
||||
github.com/refraction-networking/utls v1.3.2/go.mod h1:fmoaOww2bxzzEpIKOebIsnBvjQpqP7L2vcm/9KUfm/E=
|
||||
github.com/refraction-networking/utls v1.3.3 h1:f/TBLX7KBciRyFH3bwupp+CE4fzoYKCirhdRcC490sw=
|
||||
github.com/refraction-networking/utls v1.3.3/go.mod h1:DlecWW1LMlMJu+9qpzzQqdHDT/C2LAe03EdpLUz/RL8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.15.0 h1:5n/pM+v3r5ujuNl4YLZLsQ+UE5jlkLVm7jMzT5Mpolw=
|
||||
github.com/tidwall/gjson v1.15.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
@@ -103,8 +103,8 @@ go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
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.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
|
||||
@@ -117,8 +117,8 @@ golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
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=
|
||||
@@ -130,8 +130,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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=
|
||||
|
||||
@@ -2,6 +2,7 @@ package requests
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"net/http"
|
||||
|
||||
"gitee.com/baixudong/tools"
|
||||
|
||||
@@ -7,12 +7,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
_ "unsafe"
|
||||
|
||||
"net/http"
|
||||
|
||||
"gitee.com/baixudong/re"
|
||||
"gitee.com/baixudong/tools"
|
||||
"gitee.com/baixudong/websocket"
|
||||
|
||||
@@ -8,11 +8,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"net/http"
|
||||
|
||||
"gitee.com/baixudong/bar"
|
||||
"gitee.com/baixudong/bs4"
|
||||
"gitee.com/baixudong/tools"
|
||||
|
||||
296
roundTripper.go
296
roundTripper.go
@@ -2,118 +2,121 @@ package requests
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"container/list"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
"time"
|
||||
"sync/atomic"
|
||||
|
||||
"net/http"
|
||||
|
||||
h2ja3 "gitee.com/baixudong/http2"
|
||||
"golang.org/x/net/http2"
|
||||
|
||||
utls "github.com/refraction-networking/utls"
|
||||
)
|
||||
|
||||
type Connector struct {
|
||||
element *list.Element
|
||||
h2 bool
|
||||
r *bufio.Reader
|
||||
conn net.Conn
|
||||
type roundTripper interface {
|
||||
RoundTrip(*http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
type connecotr struct {
|
||||
conn net.Conn
|
||||
cnl context.CancelFunc
|
||||
ctx context.Context
|
||||
h2 bool
|
||||
r *bufio.Reader
|
||||
t2 *http2.Transport
|
||||
t22 *h2ja3.Upg
|
||||
|
||||
c2 roundTripper
|
||||
}
|
||||
|
||||
func (obj *connecotr) run() {
|
||||
defer obj.Close()
|
||||
con := make([]byte, 0)
|
||||
t := time.NewTimer(0)
|
||||
defer t.Stop()
|
||||
for {
|
||||
_, err := obj.conn.Read(con)
|
||||
if err != nil {
|
||||
return
|
||||
type reqTask struct {
|
||||
ctx context.Context //控制请求的生命周期
|
||||
cnl context.CancelFunc
|
||||
req *http.Request //发送的请求
|
||||
res *http.Response //接收的请求
|
||||
err error
|
||||
}
|
||||
|
||||
type connPool struct {
|
||||
ctx context.Context
|
||||
cnl context.CancelFunc
|
||||
key string
|
||||
total atomic.Int64
|
||||
tasks chan *reqTask
|
||||
rt *RoundTripper
|
||||
}
|
||||
|
||||
func (obj *connPool) rwMain(conn *connecotr) {
|
||||
defer func() {
|
||||
if obj.total.Load() == 0 {
|
||||
obj.rt.delConnPool(obj.key)
|
||||
}
|
||||
t.Reset(time.Second * 5)
|
||||
}()
|
||||
defer obj.total.Add(-1)
|
||||
if conn.h2 {
|
||||
obj.h2Main(conn)
|
||||
} else {
|
||||
obj.h1Main(conn)
|
||||
}
|
||||
}
|
||||
func (obj *connPool) h1Main(conn *connecotr) {
|
||||
for {
|
||||
select {
|
||||
case task := <-obj.tasks:
|
||||
http1Req(conn, task)
|
||||
case <-obj.ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
func (obj *connPool) h2Main(conn *connecotr) {
|
||||
for {
|
||||
select {
|
||||
case task := <-obj.tasks:
|
||||
http2Req(conn, task)
|
||||
case <-obj.ctx.Done():
|
||||
return
|
||||
case <-t.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *connecotr) Close() error {
|
||||
obj.cnl()
|
||||
return obj.conn.Close()
|
||||
}
|
||||
|
||||
func (obj *connecotr) Read(b []byte) (n int, err error) {
|
||||
obj.conn.SetDeadline(time.Now().Add(time.Second * 60 * 5))
|
||||
return obj.conn.Read(b)
|
||||
}
|
||||
func (obj *connecotr) Write(b []byte) (n int, err error) {
|
||||
obj.conn.SetDeadline(time.Now().Add(time.Second * 60 * 5))
|
||||
return obj.conn.Write(b)
|
||||
}
|
||||
|
||||
|
||||
type conns struct {
|
||||
conns *list.List
|
||||
connsLock sync.Mutex
|
||||
}
|
||||
type RoundTripper struct {
|
||||
conns map[string]*conns
|
||||
ctx context.Context
|
||||
cnl context.CancelFunc
|
||||
connPools map[string]*connPool
|
||||
connsLock sync.Mutex
|
||||
dialer *DialClient
|
||||
t2 *http2.Transport
|
||||
t22 *h2ja3.Upg
|
||||
}
|
||||
|
||||
func NewRoundTripper(dialClient *DialClient) *RoundTripper {
|
||||
func NewRoundTripper(preCtx context.Context, dialClient *DialClient, t22 *h2ja3.Upg, option ClientOption) *RoundTripper {
|
||||
if preCtx == nil {
|
||||
preCtx = context.TODO()
|
||||
}
|
||||
ctx, cnl := context.WithCancel(preCtx)
|
||||
t2 := http2.Transport{
|
||||
DialTLSContext: dialClient.requestHttp2DialTlsContext,
|
||||
TLSClientConfig: dialClient.TlsConfig(),
|
||||
ReadIdleTimeout: option.ResponseHeaderTimeout,
|
||||
PingTimeout: option.TLSHandshakeTimeout,
|
||||
WriteByteTimeout: option.IdleConnTimeout,
|
||||
}
|
||||
return &RoundTripper{
|
||||
conns: make(map[string]*conns),
|
||||
dialer: dialClient,
|
||||
t2: &t2,
|
||||
t22: t22,
|
||||
ctx: ctx,
|
||||
cnl: cnl,
|
||||
connPools: make(map[string]*connPool),
|
||||
dialer: dialClient,
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *Connector) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
err := req.Write(obj.conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n, err := obj.conn.Read(make([]byte, 0))
|
||||
log.Print("read end")
|
||||
log.Print(n, err)
|
||||
|
||||
resp, err := http.ReadResponse(bufio.NewReader(obj.conn), req)
|
||||
return resp, err
|
||||
}
|
||||
func (obj *conns) getConn() *Connector {
|
||||
obj.connsLock.Lock()
|
||||
defer obj.connsLock.Unlock()
|
||||
front := obj.conns.Front()
|
||||
if front == nil {
|
||||
return nil
|
||||
}
|
||||
conn := obj.conns.Remove(front).(*Connector)
|
||||
conn.element = nil
|
||||
return conn
|
||||
}
|
||||
func (obj *conns) putConn(conn *Connector) {
|
||||
obj.connsLock.Lock()
|
||||
defer obj.connsLock.Unlock()
|
||||
element := obj.conns.PushBack(conn)
|
||||
conn.element = element
|
||||
}
|
||||
func (obj *conns) newConn(req *http.Request) *Connector {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (obj *RoundTripper) getAddr(uurl *url.URL) string {
|
||||
func getAddr(uurl *url.URL) string {
|
||||
if uurl == nil {
|
||||
return ""
|
||||
}
|
||||
@@ -128,7 +131,7 @@ func (obj *RoundTripper) getAddr(uurl *url.URL) string {
|
||||
}
|
||||
return uurl.Host
|
||||
}
|
||||
func (obj *RoundTripper) getHost(req *http.Request) string {
|
||||
func getHost(req *http.Request) string {
|
||||
host := req.Host
|
||||
if host == "" {
|
||||
host = req.URL.Host
|
||||
@@ -144,20 +147,42 @@ func (obj *RoundTripper) getHost(req *http.Request) string {
|
||||
}
|
||||
return host
|
||||
}
|
||||
func (obj *RoundTripper) getKey(req *http.Request) string {
|
||||
func getKey(req *http.Request) string {
|
||||
ctxData := req.Context().Value(keyPrincipalID).(*reqCtxData)
|
||||
return fmt.Sprintf("%s@%s", obj.getAddr(ctxData.proxy), obj.getAddr(req.URL))
|
||||
return fmt.Sprintf("%s@%s", getAddr(ctxData.proxy), getAddr(req.URL))
|
||||
}
|
||||
func (obj *RoundTripper) getConn(key string) *Connector {
|
||||
|
||||
func (obj *RoundTripper) newConnPool(key string, conn *connecotr) *connPool {
|
||||
pool := new(connPool)
|
||||
pool.ctx, pool.cnl = context.WithCancel(obj.ctx)
|
||||
pool.total.Add(1)
|
||||
pool.tasks = make(chan *reqTask)
|
||||
pool.rt = obj
|
||||
pool.key = key
|
||||
go pool.rwMain(conn)
|
||||
return pool
|
||||
}
|
||||
func (obj *RoundTripper) delConnPool(key string) {
|
||||
obj.connsLock.Lock()
|
||||
defer obj.connsLock.Unlock()
|
||||
conns, ok := obj.conns[key]
|
||||
if ok {
|
||||
return conns.getConn()
|
||||
}
|
||||
return nil
|
||||
delete(obj.connPools, key)
|
||||
}
|
||||
func (obj *RoundTripper) newConn(req *http.Request) (connector *Connector, err error) {
|
||||
func (obj *RoundTripper) getConnPool(key string) *connPool {
|
||||
obj.connsLock.Lock()
|
||||
defer obj.connsLock.Unlock()
|
||||
return obj.connPools[key]
|
||||
}
|
||||
func (obj *RoundTripper) putConnPool(key string, conn *connecotr) {
|
||||
obj.connsLock.Lock()
|
||||
defer obj.connsLock.Unlock()
|
||||
pool, ok := obj.connPools[key]
|
||||
if ok {
|
||||
pool.rwMain(conn)
|
||||
} else {
|
||||
obj.connPools[key] = obj.newConnPool(key, conn)
|
||||
}
|
||||
}
|
||||
func (obj *RoundTripper) dial(key string, req *http.Request) (conn *connecotr, err error) {
|
||||
ctxData := req.Context().Value(keyPrincipalID).(*reqCtxData)
|
||||
if !ctxData.disProxy && ctxData.proxy == nil { //确定代理
|
||||
if ctxData.proxy, err = obj.dialer.GetProxy(req.Context(), req.URL); err != nil {
|
||||
@@ -165,8 +190,8 @@ func (obj *RoundTripper) newConn(req *http.Request) (connector *Connector, err e
|
||||
}
|
||||
}
|
||||
var netConn net.Conn
|
||||
host := obj.getHost(req)
|
||||
addr := obj.getAddr(req.URL)
|
||||
host := getHost(req)
|
||||
addr := getAddr(req.URL)
|
||||
if ctxData.proxy == nil {
|
||||
netConn, err = obj.dialer.DialContext(req.Context(), "tcp", addr)
|
||||
} else {
|
||||
@@ -175,7 +200,8 @@ func (obj *RoundTripper) newConn(req *http.Request) (connector *Connector, err e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
connector = new(Connector)
|
||||
conne := new(connecotr)
|
||||
var h2 bool
|
||||
if req.URL.Scheme == "https" {
|
||||
ctx, cnl := context.WithTimeout(req.Context(), obj.dialer.tlsHandshakeTimeout)
|
||||
defer cnl()
|
||||
@@ -186,28 +212,84 @@ func (obj *RoundTripper) newConn(req *http.Request) (connector *Connector, err e
|
||||
if tlsConn, ok := netConn.(interface {
|
||||
ConnectionState() utls.ConnectionState
|
||||
}); ok {
|
||||
connector.h2 = tlsConn.ConnectionState().NegotiatedProtocol == "h2"
|
||||
h2 = tlsConn.ConnectionState().NegotiatedProtocol == "h2"
|
||||
} else if tlsConn, ok := netConn.(interface {
|
||||
ConnectionState() tls.ConnectionState
|
||||
}); ok {
|
||||
connector.h2 = tlsConn.ConnectionState().NegotiatedProtocol == "h2"
|
||||
h2 = tlsConn.ConnectionState().NegotiatedProtocol == "h2"
|
||||
}
|
||||
}
|
||||
connector.conn = netConn
|
||||
return connector, nil
|
||||
conne.conn = netConn
|
||||
if h2 {
|
||||
conne.h2 = h2
|
||||
conne.t2 = obj.t2
|
||||
conne.t22 = obj.t22
|
||||
if conne.t22 != nil {
|
||||
if conne.c2, err = conne.t22.ClientConn(netConn); err != nil {
|
||||
return conne, err
|
||||
}
|
||||
} else {
|
||||
if conne.c2, err = conne.t2.NewClientConn(netConn); err != nil {
|
||||
return conne, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
conne.r = bufio.NewReader(netConn)
|
||||
}
|
||||
return conne, err
|
||||
}
|
||||
func (obj *RoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
||||
key := obj.getKey(req)
|
||||
conn := obj.getConn(key)
|
||||
if conn == nil {
|
||||
if conn, err = obj.newConn(req); err != nil {
|
||||
return nil, err
|
||||
func http1Req(conn *connecotr, task *reqTask) {
|
||||
log.Print("===============222")
|
||||
log.Print(task, conn)
|
||||
defer task.cnl()
|
||||
err := task.req.Write(conn.conn)
|
||||
log.Print("===============555", err)
|
||||
if err != nil {
|
||||
task.err = err
|
||||
} else {
|
||||
log.Print("===============666", conn.r)
|
||||
task.res, task.err = http.ReadResponse(conn.r, task.req)
|
||||
log.Print(task, err)
|
||||
}
|
||||
}
|
||||
func http2Req(conn *connecotr, task *reqTask) {
|
||||
log.Print("===============444")
|
||||
log.Print(conn)
|
||||
log.Print(task, conn)
|
||||
log.Print("===============3")
|
||||
defer task.cnl()
|
||||
task.res, task.err = conn.c2.RoundTrip(task.req)
|
||||
}
|
||||
func (obj *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
key := getKey(req)
|
||||
pool := obj.getConnPool(key)
|
||||
ctx, cnl := context.WithCancel(req.Context())
|
||||
defer cnl()
|
||||
task := &reqTask{
|
||||
ctx: ctx,
|
||||
cnl: cnl,
|
||||
req: req,
|
||||
}
|
||||
if pool != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case pool.tasks <- task:
|
||||
return task.res, task.err
|
||||
default:
|
||||
}
|
||||
}
|
||||
return conn.RoundTrip(req)
|
||||
|
||||
// // 2. 执行请求
|
||||
// // 3. 返回连接
|
||||
// obj.putConn(conn)
|
||||
// return resp, err
|
||||
conn, err := obj.dial(key, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !conn.h2 {
|
||||
http1Req(conn, task)
|
||||
} else {
|
||||
http2Req(conn, task)
|
||||
}
|
||||
if task.err == nil && task.res != nil {
|
||||
obj.putConnPool(key, conn)
|
||||
}
|
||||
return task.res, task.err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user