spray/internal/ihttp/client.go

177 lines
4.3 KiB
Go
Raw Normal View History

package ihttp
import (
"crypto/tls"
"fmt"
2024-02-07 01:29:05 +08:00
"github.com/chainreactors/logs"
"github.com/valyala/fasthttp"
2024-02-07 01:29:05 +08:00
"github.com/valyala/fasthttp/fasthttpproxy"
"golang.org/x/net/proxy"
"net"
"net/http"
2024-02-07 01:29:05 +08:00
"net/url"
"strings"
"time"
)
var (
DefaultMaxBodySize int64 = 1024 * 100 // 100k
)
func CheckBodySize(size int64) bool {
if DefaultMaxBodySize == -1 {
return true
}
if DefaultMaxBodySize == 0 {
return false
}
return size < DefaultMaxBodySize
}
const (
2023-01-10 00:57:55 +08:00
Auto = iota
FAST
STANDARD
)
2024-02-07 01:29:05 +08:00
func NewClient(config *ClientConfig) *Client {
2024-03-03 01:59:56 +08:00
var client *Client
2024-02-07 01:29:05 +08:00
if config.Type == FAST {
2024-03-03 01:59:56 +08:00
client = &Client{
fastClient: &fasthttp.Client{
TLSConfig: &tls.Config{
Renegotiation: tls.RenegotiateOnceAsClient,
InsecureSkipVerify: true,
},
2024-02-07 01:29:05 +08:00
Dial: customDialFunc(config.ProxyAddr, config.Timeout),
MaxConnsPerHost: config.Thread * 3 / 2,
MaxIdleConnDuration: config.Timeout,
//MaxConnWaitTimeout: time.Duration(timeout) * time.Second,
2024-09-23 14:59:05 +08:00
ReadTimeout: config.Timeout,
WriteTimeout: config.Timeout,
ReadBufferSize: 16384, // 16k
MaxResponseBodySize: int(DefaultMaxBodySize),
NoDefaultUserAgentHeader: true,
DisablePathNormalizing: true,
DisableHeaderNamesNormalizing: true,
},
ClientConfig: config,
}
} else {
2024-03-03 01:59:56 +08:00
client = &Client{
standardClient: &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
2024-08-21 15:57:41 +08:00
Renegotiation: tls.RenegotiateNever,
InsecureSkipVerify: true,
},
2024-05-30 23:33:57 +08:00
TLSHandshakeTimeout: config.Timeout,
MaxConnsPerHost: config.Thread * 3 / 2,
IdleConnTimeout: config.Timeout,
ReadBufferSize: 16384, // 16k
},
2024-02-07 01:29:05 +08:00
Timeout: config.Timeout,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
},
ClientConfig: config,
}
2024-03-03 01:59:56 +08:00
if config.ProxyAddr != "" {
client.standardClient.Transport.(*http.Transport).Proxy = func(_ *http.Request) (*url.URL, error) {
return url.Parse(config.ProxyAddr)
}
}
}
2024-03-03 01:59:56 +08:00
return client
}
2024-02-07 01:29:05 +08:00
type ClientConfig struct {
Type int
Timeout time.Duration
Thread int
ProxyAddr string
}
type Client struct {
fastClient *fasthttp.Client
standardClient *http.Client
*ClientConfig
}
func (c *Client) TransToCheck() {
if c.fastClient != nil {
c.fastClient.MaxConnsPerHost = -1 // disable keepalive
} else if c.standardClient != nil {
c.standardClient.Transport.(*http.Transport).DisableKeepAlives = true // disable keepalive
}
}
func (c *Client) FastDo(req *fasthttp.Request) (*fasthttp.Response, error) {
resp := fasthttp.AcquireResponse()
err := c.fastClient.DoTimeout(req, resp, c.Timeout)
2022-12-02 15:21:17 +08:00
return resp, err
}
func (c *Client) StandardDo(req *http.Request) (*http.Response, error) {
return c.standardClient.Do(req)
}
func (c *Client) Do(req *Request) (*Response, error) {
if c.fastClient != nil {
resp, err := c.FastDo(req.FastRequest)
2022-10-27 23:40:15 +08:00
return &Response{FastResponse: resp, ClientType: FAST}, err
} else if c.standardClient != nil {
resp, err := c.StandardDo(req.StandardRequest)
2022-10-27 23:40:15 +08:00
return &Response{StandardResponse: resp, ClientType: STANDARD}, err
} else {
return nil, fmt.Errorf("not found client")
}
}
2024-02-07 01:29:05 +08:00
func customDialFunc(proxyAddr string, timeout time.Duration) fasthttp.DialFunc {
2024-02-07 01:54:31 +08:00
if proxyAddr == "" {
return func(addr string) (net.Conn, error) {
return fasthttp.DialTimeout(addr, timeout)
}
}
2024-02-07 01:29:05 +08:00
u, err := url.Parse(proxyAddr)
if err != nil {
logs.Log.Error(err.Error())
return nil
}
if strings.ToLower(u.Scheme) == "socks5" {
return func(addr string) (net.Conn, error) {
2024-06-06 18:21:26 +08:00
var auth *proxy.Auth
username := u.User.Username()
password, ok := u.User.Password()
if ok {
auth = &proxy.Auth{
User: username,
Password: password,
}
}
dialer, err := proxy.SOCKS5("tcp", u.Host, auth, proxy.Direct)
2024-02-07 01:29:05 +08:00
if err != nil {
return nil, err
}
// Set up a connection with a timeout
conn, err := dialer.Dial("tcp", addr)
if err != nil {
return nil, err
}
// Set deadlines for the connection
deadline := time.Now().Add(timeout)
if err := conn.SetDeadline(deadline); err != nil {
conn.Close()
return nil, err
}
return conn, nil
}
} else {
return fasthttpproxy.FasthttpHTTPDialerTimeout(u.Host, timeout)
2024-02-07 01:29:05 +08:00
}
}