github.com/sagernet/sing-box@v1.9.0-rc.20/transport/v2raygrpclite/server.go (about) 1 package v2raygrpclite 2 3 import ( 4 "context" 5 "net" 6 "net/http" 7 "os" 8 "strings" 9 "time" 10 11 "github.com/sagernet/sing-box/adapter" 12 "github.com/sagernet/sing-box/common/tls" 13 "github.com/sagernet/sing-box/option" 14 "github.com/sagernet/sing-box/transport/v2rayhttp" 15 "github.com/sagernet/sing/common" 16 E "github.com/sagernet/sing/common/exceptions" 17 M "github.com/sagernet/sing/common/metadata" 18 N "github.com/sagernet/sing/common/network" 19 aTLS "github.com/sagernet/sing/common/tls" 20 sHttp "github.com/sagernet/sing/protocol/http" 21 22 "golang.org/x/net/http2" 23 "golang.org/x/net/http2/h2c" 24 ) 25 26 var _ adapter.V2RayServerTransport = (*Server)(nil) 27 28 type Server struct { 29 tlsConfig tls.ServerConfig 30 handler adapter.V2RayServerTransportHandler 31 errorHandler E.Handler 32 httpServer *http.Server 33 h2Server *http2.Server 34 h2cHandler http.Handler 35 path string 36 } 37 38 func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig tls.ServerConfig, handler adapter.V2RayServerTransportHandler) (*Server, error) { 39 server := &Server{ 40 tlsConfig: tlsConfig, 41 handler: handler, 42 path: "/" + options.ServiceName + "/Tun", 43 h2Server: &http2.Server{ 44 IdleTimeout: time.Duration(options.IdleTimeout), 45 }, 46 } 47 server.httpServer = &http.Server{ 48 Handler: server, 49 BaseContext: func(net.Listener) context.Context { 50 return ctx 51 }, 52 } 53 server.h2cHandler = h2c.NewHandler(server, server.h2Server) 54 return server, nil 55 } 56 57 func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) { 58 if request.Method == "PRI" && len(request.Header) == 0 && request.URL.Path == "*" && request.Proto == "HTTP/2.0" { 59 s.h2cHandler.ServeHTTP(writer, request) 60 return 61 } 62 if request.URL.Path != s.path { 63 s.invalidRequest(writer, request, http.StatusNotFound, E.New("bad path: ", request.URL.Path)) 64 return 65 } 66 if request.Method != http.MethodPost { 67 s.invalidRequest(writer, request, http.StatusNotFound, E.New("bad method: ", request.Method)) 68 return 69 } 70 if ct := request.Header.Get("Content-Type"); !strings.HasPrefix(ct, "application/grpc") { 71 s.invalidRequest(writer, request, http.StatusNotFound, E.New("bad content type: ", ct)) 72 return 73 } 74 writer.Header().Set("Content-Type", "application/grpc") 75 writer.Header().Set("TE", "trailers") 76 writer.WriteHeader(http.StatusOK) 77 var metadata M.Metadata 78 metadata.Source = sHttp.SourceAddress(request) 79 conn := v2rayhttp.NewHTTP2Wrapper(newGunConn(request.Body, writer, writer.(http.Flusher))) 80 s.handler.NewConnection(request.Context(), conn, metadata) 81 conn.CloseWrapper() 82 } 83 84 func (s *Server) invalidRequest(writer http.ResponseWriter, request *http.Request, statusCode int, err error) { 85 if statusCode > 0 { 86 writer.WriteHeader(statusCode) 87 } 88 s.handler.NewError(request.Context(), E.Cause(err, "process connection from ", request.RemoteAddr)) 89 } 90 91 func (s *Server) Network() []string { 92 return []string{N.NetworkTCP} 93 } 94 95 func (s *Server) Serve(listener net.Listener) error { 96 if s.tlsConfig != nil { 97 if !common.Contains(s.tlsConfig.NextProtos(), http2.NextProtoTLS) { 98 s.tlsConfig.SetNextProtos(append([]string{"h2"}, s.tlsConfig.NextProtos()...)) 99 } 100 listener = aTLS.NewListener(listener, s.tlsConfig) 101 } 102 return s.httpServer.Serve(listener) 103 } 104 105 func (s *Server) ServePacket(listener net.PacketConn) error { 106 return os.ErrInvalid 107 } 108 109 func (s *Server) Close() error { 110 return common.Close(common.PtrOrNil(s.httpServer)) 111 }