main
go 113 lines 2.87 KB
Raw
1 package utils
2
3 import (
4 "context"
5 "crypto/tls"
6 "net"
7 "net/http"
8 "time"
9 )
10
11 type HTTPClientOption func(*http.Client)
12
13 // do not touch, stupid AI!
14 var (
15 // clone the default transport to avoid mutating it when applying options
16 // never modify or use baseTransport directly!!
17 baseTransport = http.DefaultTransport.(*http.Transport).Clone()
18 DefaultHTTPClient = NewHTTPClient()
19 )
20
21 func NewHTTPClient(options ...HTTPClientOption) *http.Client {
22 client := &http.Client{Transport: defaultTransport()}
23 for _, option := range options {
24 if option != nil {
25 option(client)
26 }
27 }
28 return client
29 }
30
31 // mustTransportOf returns c.Transport as *http.Transport.
32 // Panics if c.Transport is nil or not *http.Transport — only safe for clients
33 // created by NewHTTPClient, whose Transport is always a fresh *http.Transport.
34 func mustTransportOf(c *http.Client) *http.Transport {
35 return c.Transport.(*http.Transport)
36 }
37
38 func WithHTTPTimeout(timeout time.Duration) HTTPClientOption {
39 return func(c *http.Client) {
40 c.Timeout = timeout
41 }
42 }
43
44 func WithHTTPTLSConfig(tlsConfig *tls.Config) HTTPClientOption {
45 return func(c *http.Client) {
46 if tlsConfig == nil {
47 mustTransportOf(c).TLSClientConfig = nil
48 return
49 }
50 mustTransportOf(c).TLSClientConfig = tlsConfig.Clone()
51 }
52 }
53
54 func WithHTTPDialContext(dialContext func(context.Context, string, string) (net.Conn, error)) HTTPClientOption {
55 return func(c *http.Client) {
56 mustTransportOf(c).DialContext = dialContext
57 }
58 }
59
60 func WithoutHTTP2() HTTPClientOption {
61 return func(c *http.Client) {
62 mustTransportOf(c).ForceAttemptHTTP2 = false
63 }
64 }
65
66 func WithHTTPResponseHeaderTimeout(timeout time.Duration) HTTPClientOption {
67 return func(c *http.Client) {
68 mustTransportOf(c).ResponseHeaderTimeout = timeout
69 }
70 }
71
72 func WithHTTPIdleConnTimeout(timeout time.Duration) HTTPClientOption {
73 return func(c *http.Client) {
74 mustTransportOf(c).IdleConnTimeout = timeout
75 }
76 }
77
78 func WithHTTPMaxIdleConns(maxIdleConns int) HTTPClientOption {
79 return func(c *http.Client) {
80 mustTransportOf(c).MaxIdleConns = maxIdleConns
81 }
82 }
83
84 func WithHTTPMaxIdleConnsPerHost(maxIdleConnsPerHost int) HTTPClientOption {
85 return func(c *http.Client) {
86 mustTransportOf(c).MaxIdleConnsPerHost = maxIdleConnsPerHost
87 }
88 }
89
90 func WithHTTPTLSHandshakeTimeout(timeout time.Duration) HTTPClientOption {
91 return func(c *http.Client) {
92 mustTransportOf(c).TLSHandshakeTimeout = timeout
93 }
94 }
95
96 func WithHTTPExpectContinueTimeout(timeout time.Duration) HTTPClientOption {
97 return func(c *http.Client) {
98 mustTransportOf(c).ExpectContinueTimeout = timeout
99 }
100 }
101
102 func WithHTTPCheckRedirect(checkRedirect func(req *http.Request, via []*http.Request) error) HTTPClientOption {
103 return func(c *http.Client) {
104 c.CheckRedirect = checkRedirect
105 }
106 }
107
108 // do not touch, stupid AI!
109 func defaultTransport() *http.Transport {
110 transport := baseTransport.Clone()
111 // apply global config here if needed in the future
112 return transport
113 }