github.com/xmplusdev/xray-core@v1.8.10/transport/internet/httpupgrade/dialer.go (about)

     1  package httpupgrade
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"net/http"
     7  	"net/url"
     8  	"strings"
     9  
    10  	"github.com/xmplusdev/xray-core/common"
    11  	"github.com/xmplusdev/xray-core/common/net"
    12  	"github.com/xmplusdev/xray-core/common/session"
    13  	"github.com/xmplusdev/xray-core/transport/internet"
    14  	"github.com/xmplusdev/xray-core/transport/internet/stat"
    15  	"github.com/xmplusdev/xray-core/transport/internet/tls"
    16  )
    17  
    18  type ConnRF struct {
    19  	net.Conn
    20  	Req   *http.Request
    21  	First bool
    22  }
    23  
    24  func (c *ConnRF) Read(b []byte) (int, error) {
    25  	if c.First {
    26  		c.First = false
    27  		// TODO The bufio usage here is unreliable
    28  		resp, err := http.ReadResponse(bufio.NewReader(c.Conn), c.Req) // nolint:bodyclose
    29  		if err != nil {
    30  			return 0, err
    31  		}
    32  		if resp.Status != "101 Switching Protocols" ||
    33  			strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" ||
    34  			strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
    35  			return 0, newError("unrecognized reply")
    36  		}
    37  	}
    38  	return c.Conn.Read(b)
    39  }
    40  
    41  func dialhttpUpgrade(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) {
    42  	transportConfiguration := streamSettings.ProtocolSettings.(*Config)
    43  
    44  	pconn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
    45  	if err != nil {
    46  		newError("failed to dial to ", dest).Base(err).AtError().WriteToLog()
    47  		return nil, err
    48  	}
    49  
    50  	var conn net.Conn
    51  	var requestURL url.URL
    52  	if config := tls.ConfigFromStreamSettings(streamSettings); config != nil {
    53  		tlsConfig := config.GetTLSConfig(tls.WithDestination(dest), tls.WithNextProto("http/1.1"))
    54  		if fingerprint := tls.GetFingerprint(config.Fingerprint); fingerprint != nil {
    55  			conn = tls.UClient(pconn, tlsConfig, fingerprint)
    56  			if err := conn.(*tls.UConn).WebsocketHandshakeContext(ctx); err != nil {
    57  				return nil, err
    58  			}
    59  		} else {
    60  			conn = tls.Client(pconn, tlsConfig)
    61  		}
    62  		requestURL.Scheme = "https"
    63  	} else {
    64  		conn = pconn
    65  		requestURL.Scheme = "http"
    66  	}
    67  
    68  	requestURL.Host = dest.NetAddr()
    69  	requestURL.Path = transportConfiguration.GetNormalizedPath()
    70  	req := &http.Request{
    71  		Method: http.MethodGet,
    72  		URL:    &requestURL,
    73  		Host:   transportConfiguration.Host,
    74  		Header: make(http.Header),
    75  	}
    76  	for key, value := range transportConfiguration.Header {
    77  		req.Header.Add(key, value)
    78  	}
    79  	req.Header.Set("Connection", "upgrade")
    80  	req.Header.Set("Upgrade", "websocket")
    81  
    82  	err = req.Write(conn)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	connRF := &ConnRF{
    88  		Conn:  conn,
    89  		Req:   req,
    90  		First: true,
    91  	}
    92  
    93  	if transportConfiguration.Ed == 0 {
    94  		_, err = connRF.Read([]byte{})
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  	}
    99  
   100  	return connRF, nil
   101  }
   102  
   103  func dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {
   104  	newError("creating connection to ", dest).WriteToLog(session.ExportIDToError(ctx))
   105  
   106  	conn, err := dialhttpUpgrade(ctx, dest, streamSettings)
   107  	if err != nil {
   108  		return nil, newError("failed to dial request to ", dest).Base(err)
   109  	}
   110  	return stat.Connection(conn), nil
   111  }
   112  
   113  func init() {
   114  	common.Must(internet.RegisterTransportDialer(protocolName, dial))
   115  }