http.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. package libbox
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/sha256"
  6. "crypto/tls"
  7. "crypto/x509"
  8. "encoding/hex"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "math/rand"
  13. "net"
  14. "net/http"
  15. "net/url"
  16. "os"
  17. "strconv"
  18. "sync"
  19. C "github.com/sagernet/sing-box/constant"
  20. "github.com/sagernet/sing/common"
  21. "github.com/sagernet/sing/common/bufio"
  22. E "github.com/sagernet/sing/common/exceptions"
  23. M "github.com/sagernet/sing/common/metadata"
  24. "github.com/sagernet/sing/protocol/socks"
  25. "github.com/sagernet/sing/protocol/socks/socks5"
  26. )
  27. type HTTPClient interface {
  28. RestrictedTLS()
  29. ModernTLS()
  30. PinnedTLS12()
  31. PinnedSHA256(sumHex string)
  32. TrySocks5(port int32)
  33. KeepAlive()
  34. NewRequest() HTTPRequest
  35. Close()
  36. }
  37. type HTTPRequest interface {
  38. SetURL(link string) error
  39. SetMethod(method string)
  40. SetHeader(key string, value string)
  41. SetContent(content []byte)
  42. SetContentString(content string)
  43. RandomUserAgent()
  44. SetUserAgent(userAgent string)
  45. Execute() (HTTPResponse, error)
  46. }
  47. type HTTPResponse interface {
  48. GetContent() (*StringBox, error)
  49. WriteTo(path string) error
  50. WriteToWithProgress(path string, handler HTTPResponseWriteToProgressHandler) error
  51. }
  52. type HTTPResponseWriteToProgressHandler interface {
  53. Update(progress int64, total int64)
  54. }
  55. var (
  56. _ HTTPClient = (*httpClient)(nil)
  57. _ HTTPRequest = (*httpRequest)(nil)
  58. _ HTTPResponse = (*httpResponse)(nil)
  59. )
  60. type httpClient struct {
  61. tls tls.Config
  62. client http.Client
  63. transport http.Transport
  64. }
  65. func NewHTTPClient() HTTPClient {
  66. client := new(httpClient)
  67. client.client.Transport = &client.transport
  68. client.transport.ForceAttemptHTTP2 = true
  69. client.transport.TLSHandshakeTimeout = C.TCPTimeout
  70. client.transport.TLSClientConfig = &client.tls
  71. client.transport.DisableKeepAlives = true
  72. return client
  73. }
  74. func (c *httpClient) ModernTLS() {
  75. c.setTLSVersion(tls.VersionTLS12, 0, func(suite *tls.CipherSuite) bool { return true })
  76. }
  77. func (c *httpClient) RestrictedTLS() {
  78. c.setTLSVersion(tls.VersionTLS13, 0, func(suite *tls.CipherSuite) bool {
  79. return common.Contains(suite.SupportedVersions, uint16(tls.VersionTLS13))
  80. })
  81. }
  82. func (c *httpClient) setTLSVersion(minVersion, maxVersion uint16, filter func(*tls.CipherSuite) bool) {
  83. c.tls.MinVersion = minVersion
  84. if maxVersion != 0 {
  85. c.tls.MaxVersion = maxVersion
  86. }
  87. c.tls.CipherSuites = common.Map(common.Filter(tls.CipherSuites(), filter), func(it *tls.CipherSuite) uint16 {
  88. return it.ID
  89. })
  90. }
  91. func (c *httpClient) PinnedTLS12() {
  92. c.setTLSVersion(tls.VersionTLS12, tls.VersionTLS12, func(suite *tls.CipherSuite) bool { return true })
  93. }
  94. func (c *httpClient) PinnedSHA256(sumHex string) {
  95. c.tls.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
  96. for _, rawCert := range rawCerts {
  97. certSum := sha256.Sum256(rawCert)
  98. if sumHex == hex.EncodeToString(certSum[:]) {
  99. return nil
  100. }
  101. }
  102. return E.New("pinned sha256 sum mismatch")
  103. }
  104. }
  105. func (c *httpClient) TrySocks5(port int32) {
  106. dialer := new(net.Dialer)
  107. c.transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
  108. for {
  109. socksConn, err := dialer.DialContext(ctx, "tcp", "127.0.0.1:"+strconv.Itoa(int(port)))
  110. if err != nil {
  111. break
  112. }
  113. _, err = socks.ClientHandshake5(socksConn, socks5.CommandConnect, M.ParseSocksaddr(addr), "", "")
  114. if err != nil {
  115. break
  116. }
  117. //nolint:staticcheck
  118. return socksConn, err
  119. }
  120. return dialer.DialContext(ctx, network, addr)
  121. }
  122. }
  123. func (c *httpClient) KeepAlive() {
  124. c.transport.DisableKeepAlives = false
  125. }
  126. func (c *httpClient) NewRequest() HTTPRequest {
  127. req := &httpRequest{httpClient: c}
  128. req.request = http.Request{
  129. Method: "GET",
  130. Header: http.Header{},
  131. }
  132. return req
  133. }
  134. func (c *httpClient) Close() {
  135. c.transport.CloseIdleConnections()
  136. }
  137. type httpRequest struct {
  138. *httpClient
  139. request http.Request
  140. }
  141. func (r *httpRequest) SetURL(link string) (err error) {
  142. r.request.URL, err = url.Parse(link)
  143. if err != nil {
  144. return
  145. }
  146. if r.request.URL.User != nil {
  147. user := r.request.URL.User.Username()
  148. password, _ := r.request.URL.User.Password()
  149. r.request.SetBasicAuth(user, password)
  150. }
  151. return
  152. }
  153. func (r *httpRequest) SetMethod(method string) {
  154. r.request.Method = method
  155. }
  156. func (r *httpRequest) SetHeader(key string, value string) {
  157. r.request.Header.Set(key, value)
  158. }
  159. func (r *httpRequest) RandomUserAgent() {
  160. r.request.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", rand.Int()%54, rand.Int()%2))
  161. }
  162. func (r *httpRequest) SetUserAgent(userAgent string) {
  163. r.request.Header.Set("User-Agent", userAgent)
  164. }
  165. func (r *httpRequest) SetContent(content []byte) {
  166. r.request.Body = io.NopCloser(bytes.NewReader(content))
  167. r.request.ContentLength = int64(len(content))
  168. }
  169. func (r *httpRequest) SetContentString(content string) {
  170. r.SetContent([]byte(content))
  171. }
  172. func (r *httpRequest) Execute() (HTTPResponse, error) {
  173. response, err := r.client.Do(&r.request)
  174. if err != nil {
  175. return nil, err
  176. }
  177. httpResp := &httpResponse{Response: response}
  178. if response.StatusCode != http.StatusOK {
  179. return nil, errors.New(httpResp.errorString())
  180. }
  181. return httpResp, nil
  182. }
  183. type httpResponse struct {
  184. *http.Response
  185. getContentOnce sync.Once
  186. content []byte
  187. contentError error
  188. }
  189. func (h *httpResponse) errorString() string {
  190. content, err := h.GetContent()
  191. if err != nil {
  192. return fmt.Sprint("HTTP ", h.Status)
  193. }
  194. return fmt.Sprint("HTTP ", h.Status, ": ", content)
  195. }
  196. func (h *httpResponse) GetContent() (*StringBox, error) {
  197. h.getContentOnce.Do(func() {
  198. defer h.Body.Close()
  199. h.content, h.contentError = io.ReadAll(h.Body)
  200. })
  201. if h.contentError != nil {
  202. return nil, h.contentError
  203. }
  204. return wrapString(string(h.content)), nil
  205. }
  206. func (h *httpResponse) WriteTo(path string) error {
  207. defer h.Body.Close()
  208. file, err := os.Create(path)
  209. if err != nil {
  210. return err
  211. }
  212. defer file.Close()
  213. return common.Error(bufio.Copy(file, h.Body))
  214. }
  215. func (h *httpResponse) WriteToWithProgress(path string, handler HTTPResponseWriteToProgressHandler) error {
  216. defer h.Body.Close()
  217. file, err := os.Create(path)
  218. if err != nil {
  219. return err
  220. }
  221. defer file.Close()
  222. return common.Error(bufio.Copy(&progressWriter{
  223. writer: file,
  224. handler: handler,
  225. total: h.ContentLength,
  226. }, h.Body))
  227. }
  228. type progressWriter struct {
  229. writer io.Writer
  230. handler HTTPResponseWriteToProgressHandler
  231. total int64
  232. written int64
  233. }
  234. func (w *progressWriter) Write(p []byte) (int, error) {
  235. n, err := w.writer.Write(p)
  236. w.written += int64(n)
  237. w.handler.Update(w.written, w.total)
  238. return n, err
  239. }