helpers.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package httpclient
  2. import (
  3. "context"
  4. stdTLS "crypto/tls"
  5. "io"
  6. "net"
  7. "net/http"
  8. "strings"
  9. "github.com/sagernet/sing-box/common/tls"
  10. E "github.com/sagernet/sing/common/exceptions"
  11. M "github.com/sagernet/sing/common/metadata"
  12. N "github.com/sagernet/sing/common/network"
  13. "golang.org/x/net/idna"
  14. )
  15. func dialTLS(ctx context.Context, rawDialer N.Dialer, baseTLSConfig tls.Config, destination M.Socksaddr, nextProtos []string, expectProto string) (net.Conn, error) {
  16. if baseTLSConfig == nil {
  17. return nil, E.New("TLS transport unavailable")
  18. }
  19. tlsConfig := baseTLSConfig.Clone()
  20. if tlsConfig.ServerName() == "" && destination.IsValid() {
  21. tlsConfig.SetServerName(destination.AddrString())
  22. }
  23. tlsConfig.SetNextProtos(nextProtos)
  24. conn, err := rawDialer.DialContext(ctx, N.NetworkTCP, destination)
  25. if err != nil {
  26. return nil, err
  27. }
  28. tlsConn, err := tls.ClientHandshake(ctx, conn, tlsConfig)
  29. if err != nil {
  30. conn.Close()
  31. return nil, err
  32. }
  33. if expectProto != "" && tlsConn.ConnectionState().NegotiatedProtocol != expectProto {
  34. tlsConn.Close()
  35. return nil, errHTTP2Fallback
  36. }
  37. return tlsConn, nil
  38. }
  39. func applyHeaders(request *http.Request, headers http.Header, host string) {
  40. for header, values := range headers {
  41. request.Header[header] = append([]string(nil), values...)
  42. }
  43. if host != "" {
  44. request.Host = host
  45. }
  46. }
  47. func requestRequiresHTTP1(request *http.Request) bool {
  48. return strings.Contains(strings.ToLower(request.Header.Get("Connection")), "upgrade") &&
  49. strings.EqualFold(request.Header.Get("Upgrade"), "websocket")
  50. }
  51. func requestReplayable(request *http.Request) bool {
  52. return request.Body == nil || request.Body == http.NoBody || request.GetBody != nil
  53. }
  54. func cloneRequestForRetry(request *http.Request) *http.Request {
  55. cloned := request.Clone(request.Context())
  56. if request.Body != nil && request.Body != http.NoBody && request.GetBody != nil {
  57. cloned.Body = mustGetBody(request)
  58. }
  59. return cloned
  60. }
  61. func mustGetBody(request *http.Request) io.ReadCloser {
  62. body, err := request.GetBody()
  63. if err != nil {
  64. panic(err)
  65. }
  66. return body
  67. }
  68. func requestAuthority(request *http.Request) string {
  69. if request == nil || request.URL == nil || request.URL.Host == "" {
  70. return ""
  71. }
  72. host, port, err := net.SplitHostPort(request.URL.Host)
  73. if err != nil {
  74. host = request.URL.Host
  75. port = ""
  76. }
  77. if port == "" {
  78. if request.URL.Scheme == "http" {
  79. port = "80"
  80. } else {
  81. port = "443"
  82. }
  83. }
  84. if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
  85. return host + ":" + port
  86. }
  87. ascii, idnaErr := idna.Lookup.ToASCII(host)
  88. if idnaErr == nil {
  89. host = ascii
  90. } else {
  91. host = strings.ToLower(host)
  92. }
  93. return net.JoinHostPort(host, port)
  94. }
  95. func buildSTDTLSConfig(baseTLSConfig tls.Config, destination M.Socksaddr, nextProtos []string) (*stdTLS.Config, error) {
  96. if baseTLSConfig == nil {
  97. return nil, nil
  98. }
  99. tlsConfig := baseTLSConfig.Clone()
  100. if tlsConfig.ServerName() == "" && destination.IsValid() {
  101. tlsConfig.SetServerName(destination.AddrString())
  102. }
  103. tlsConfig.SetNextProtos(nextProtos)
  104. return tlsConfig.STDConfig()
  105. }