client.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package v2rayhttpupgrade
  2. import (
  3. std_bufio "bufio"
  4. "context"
  5. "net"
  6. "net/http"
  7. "net/url"
  8. "strings"
  9. "github.com/sagernet/sing-box/adapter"
  10. "github.com/sagernet/sing-box/common/tls"
  11. "github.com/sagernet/sing-box/option"
  12. "github.com/sagernet/sing/common/buf"
  13. "github.com/sagernet/sing/common/bufio"
  14. E "github.com/sagernet/sing/common/exceptions"
  15. M "github.com/sagernet/sing/common/metadata"
  16. N "github.com/sagernet/sing/common/network"
  17. sHTTP "github.com/sagernet/sing/protocol/http"
  18. )
  19. var _ adapter.V2RayClientTransport = (*Client)(nil)
  20. type Client struct {
  21. dialer N.Dialer
  22. tlsConfig tls.Config
  23. serverAddr M.Socksaddr
  24. requestURL url.URL
  25. headers http.Header
  26. host string
  27. }
  28. func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayHTTPUpgradeOptions, tlsConfig tls.Config) (*Client, error) {
  29. if tlsConfig != nil {
  30. if len(tlsConfig.NextProtos()) == 0 {
  31. tlsConfig.SetNextProtos([]string{"http/1.1"})
  32. }
  33. }
  34. var host string
  35. if options.Host != "" {
  36. host = options.Host
  37. } else if tlsConfig != nil && tlsConfig.ServerName() != "" {
  38. host = tlsConfig.ServerName()
  39. } else {
  40. host = serverAddr.String()
  41. }
  42. var requestURL url.URL
  43. if tlsConfig == nil {
  44. requestURL.Scheme = "http"
  45. } else {
  46. requestURL.Scheme = "https"
  47. }
  48. requestURL.Host = serverAddr.String()
  49. requestURL.Path = options.Path
  50. err := sHTTP.URLSetPath(&requestURL, options.Path)
  51. if err != nil {
  52. return nil, E.Cause(err, "parse path")
  53. }
  54. if !strings.HasPrefix(requestURL.Path, "/") {
  55. requestURL.Path = "/" + requestURL.Path
  56. }
  57. headers := make(http.Header)
  58. for key, value := range options.Headers {
  59. headers[key] = value
  60. }
  61. return &Client{
  62. dialer: dialer,
  63. tlsConfig: tlsConfig,
  64. serverAddr: serverAddr,
  65. requestURL: requestURL,
  66. headers: headers,
  67. host: host,
  68. }, nil
  69. }
  70. func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
  71. conn, err := c.dialer.DialContext(ctx, N.NetworkTCP, c.serverAddr)
  72. if err != nil {
  73. return nil, err
  74. }
  75. if c.tlsConfig != nil {
  76. conn, err = tls.ClientHandshake(ctx, conn, c.tlsConfig)
  77. if err != nil {
  78. return nil, err
  79. }
  80. }
  81. request := &http.Request{
  82. Method: http.MethodGet,
  83. URL: &c.requestURL,
  84. Header: c.headers.Clone(),
  85. Host: c.host,
  86. }
  87. request.Header.Set("Connection", "Upgrade")
  88. request.Header.Set("Upgrade", "websocket")
  89. err = request.Write(conn)
  90. if err != nil {
  91. return nil, err
  92. }
  93. bufReader := std_bufio.NewReader(conn)
  94. response, err := http.ReadResponse(bufReader, request)
  95. if err != nil {
  96. return nil, err
  97. }
  98. if response.StatusCode != 101 ||
  99. !strings.EqualFold(response.Header.Get("Connection"), "upgrade") ||
  100. !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") {
  101. return nil, E.New("v2ray-http-upgrade: unexpected status: ", response.Status)
  102. }
  103. if bufReader.Buffered() > 0 {
  104. buffer := buf.NewSize(bufReader.Buffered())
  105. _, err = buffer.ReadFullFrom(bufReader, buffer.Len())
  106. if err != nil {
  107. return nil, err
  108. }
  109. conn = bufio.NewCachedConn(conn, buffer)
  110. }
  111. return conn, nil
  112. }
  113. func (c *Client) Close() error {
  114. return nil
  115. }