github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/transport/internet/request/roundtripper/httprt/httprt.go (about) 1 package httprt 2 3 //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen 4 5 import ( 6 "bytes" 7 "context" 8 "encoding/base64" 9 "io" 10 gonet "net" 11 "net/http" 12 "time" 13 14 "github.com/v2fly/v2ray-core/v5/transport/internet/transportcommon" 15 16 "github.com/v2fly/v2ray-core/v5/common" 17 "github.com/v2fly/v2ray-core/v5/common/net" 18 "github.com/v2fly/v2ray-core/v5/transport/internet/request" 19 ) 20 21 func newHTTPRoundTripperClient(ctx context.Context, config *ClientConfig) request.RoundTripperClient { 22 _ = ctx 23 return &httpTripperClient{config: config} 24 } 25 26 type httpTripperClient struct { 27 httpRTT http.RoundTripper 28 config *ClientConfig 29 assembly request.TransportClientAssembly 30 } 31 32 type unimplementedBackDrop struct{} 33 34 func (u unimplementedBackDrop) RoundTrip(r *http.Request) (*http.Response, error) { 35 return nil, newError("unimplemented") 36 } 37 38 func (h *httpTripperClient) OnTransportClientAssemblyReady(assembly request.TransportClientAssembly) { 39 h.assembly = assembly 40 } 41 42 func (h *httpTripperClient) RoundTrip(ctx context.Context, req request.Request, opts ...request.RoundTripperOption) (resp request.Response, err error) { 43 if h.httpRTT == nil { 44 h.httpRTT = transportcommon.NewALPNAwareHTTPRoundTripper(ctx, func(ctx context.Context, addr string) (gonet.Conn, error) { 45 return h.assembly.AutoImplDialer().Dial(ctx) 46 }, unimplementedBackDrop{}) 47 } 48 49 connectionTagStr := base64.RawURLEncoding.EncodeToString(req.ConnectionTag) 50 51 httpRequest, err := http.NewRequest("POST", h.config.Http.UrlPrefix+h.config.Http.Path, bytes.NewReader(req.Data)) 52 if err != nil { 53 return 54 } 55 56 httpRequest.Header.Set("X-Session-ID", connectionTagStr) 57 58 httpResp, err := h.httpRTT.RoundTrip(httpRequest) 59 if err != nil { 60 return 61 } 62 defer httpResp.Body.Close() 63 result, err := io.ReadAll(httpResp.Body) 64 if err != nil { 65 return 66 } 67 return request.Response{Data: result}, err 68 } 69 70 func newHTTPRoundTripperServer(ctx context.Context, config *ServerConfig) request.RoundTripperServer { 71 return &httpTripperServer{ctx: ctx, config: config} 72 } 73 74 type httpTripperServer struct { 75 ctx context.Context 76 listener net.Listener 77 assembly request.TransportServerAssembly 78 79 config *ServerConfig 80 } 81 82 func (h *httpTripperServer) OnTransportServerAssemblyReady(assembly request.TransportServerAssembly) { 83 h.assembly = assembly 84 } 85 86 func (h *httpTripperServer) ServeHTTP(writer http.ResponseWriter, r *http.Request) { 87 h.onRequest(writer, r) 88 } 89 90 func (h *httpTripperServer) onRequest(resp http.ResponseWriter, req *http.Request) { 91 tail := req.Header.Get("X-Session-ID") 92 data := []byte(tail) 93 if !h.config.NoDecodingSessionTag { 94 decodedData, err := base64.RawURLEncoding.DecodeString(tail) 95 if err != nil { 96 newError("unable to decode tag").Base(err).AtInfo().WriteToLog() 97 return 98 } 99 data = decodedData 100 } 101 body, err := io.ReadAll(req.Body) 102 req.Body.Close() 103 if err != nil { 104 newError("unable to read body").Base(err).AtInfo().WriteToLog() 105 } 106 recvResp, err := h.assembly.TripperReceiver().OnRoundTrip(h.ctx, request.Request{Data: body, ConnectionTag: data}) 107 if err != nil { 108 newError("unable to process roundtrip").Base(err).AtInfo().WriteToLog() 109 } 110 _, err = io.Copy(resp, bytes.NewReader(recvResp.Data)) 111 if err != nil { 112 newError("unable to send response").Base(err).AtInfo().WriteToLog() 113 } 114 } 115 116 func (h *httpTripperServer) Start() error { 117 listener, err := h.assembly.AutoImplListener().Listen(h.ctx) 118 if err != nil { 119 return newError("unable to create a listener for http tripper server").Base(err) 120 } 121 h.listener = listener 122 go func() { 123 httpServer := http.Server{ 124 ReadHeaderTimeout: 15 * time.Second, 125 ReadTimeout: 15 * time.Second, 126 WriteTimeout: 10 * time.Second, 127 IdleTimeout: 30 * time.Second, 128 } 129 httpServer.Handler = h 130 err := httpServer.Serve(h.listener) 131 if err != nil { 132 newError("unable to serve listener for http tripper server").Base(err).WriteToLog() 133 } 134 }() 135 return nil 136 } 137 138 func (h *httpTripperServer) Close() error { 139 return h.listener.Close() 140 } 141 142 func init() { 143 common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 144 clientConfig, ok := config.(*ClientConfig) 145 if !ok { 146 return nil, newError("not a ClientConfig") 147 } 148 return newHTTPRoundTripperClient(ctx, clientConfig), nil 149 })) 150 common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { 151 serverConfig, ok := config.(*ServerConfig) 152 if !ok { 153 return nil, newError("not a ServerConfig") 154 } 155 return newHTTPRoundTripperServer(ctx, serverConfig), nil 156 })) 157 }