github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/transport/internet/httpupgrade/hub.go (about)

     1  package httpupgrade
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"github.com/v2fly/v2ray-core/v5/common"
    10  	"github.com/v2fly/v2ray-core/v5/common/net"
    11  	"github.com/v2fly/v2ray-core/v5/transport/internet"
    12  	"github.com/v2fly/v2ray-core/v5/transport/internet/transportcommon"
    13  )
    14  
    15  type server struct {
    16  	addConn        internet.ConnHandler
    17  	innnerListener net.Listener
    18  }
    19  
    20  func (s *server) Close() error {
    21  	return s.innnerListener.Close()
    22  }
    23  
    24  func (s *server) Addr() net.Addr {
    25  	return nil
    26  }
    27  
    28  func (s *server) Handle(conn net.Conn) (internet.Connection, error) {
    29  	connReader := bufio.NewReader(conn)
    30  	req, err := http.ReadRequest(connReader)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	connection := strings.ToLower(req.Header.Get("Connection"))
    35  	upgrade := strings.ToLower(req.Header.Get("Upgrade"))
    36  	if connection != "upgrade" || upgrade != "websocket" {
    37  		_ = conn.Close()
    38  		return nil, newError("unrecognized request")
    39  	}
    40  	resp := &http.Response{
    41  		Status:     "101 Switching Protocols",
    42  		StatusCode: 101,
    43  		Proto:      "HTTP/1.1",
    44  		ProtoMajor: 1,
    45  		ProtoMinor: 1,
    46  		Header:     http.Header{},
    47  	}
    48  	resp.Header.Set("Connection", "upgrade")
    49  	resp.Header.Set("Upgrade", "websocket")
    50  	err = resp.Write(conn)
    51  	if err != nil {
    52  		_ = conn.Close()
    53  		return nil, err
    54  	}
    55  	return internet.Connection(conn), nil
    56  }
    57  
    58  func (s *server) keepAccepting() {
    59  	for {
    60  		conn, err := s.innnerListener.Accept()
    61  		if err != nil {
    62  			return
    63  		}
    64  		handledConn, err := s.Handle(conn)
    65  		if err != nil {
    66  			newError("failed to handle request").Base(err).WriteToLog()
    67  			continue
    68  		}
    69  		s.addConn(handledConn)
    70  	}
    71  }
    72  
    73  func listenHTTPUpgrade(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, addConn internet.ConnHandler) (internet.Listener, error) {
    74  	transportConfiguration := streamSettings.ProtocolSettings.(*Config)
    75  	_ = transportConfiguration
    76  	serverInstance := &server{addConn: addConn}
    77  
    78  	listener, err := transportcommon.ListenWithSecuritySettings(ctx, address, port, streamSettings)
    79  	if err != nil {
    80  		return nil, newError("failed to listen on ", address, ":", port).Base(err)
    81  	}
    82  	serverInstance.innnerListener = listener
    83  	go serverInstance.keepAccepting()
    84  	return serverInstance, nil
    85  }
    86  
    87  func init() {
    88  	common.Must(internet.RegisterTransportListener(protocolName, listenHTTPUpgrade))
    89  }