func (this *Server) handlePlainHTTP(request *http.Request, session *proxy.SessionInfo, reader *bufio.Reader, writer io.Writer) { if len(request.URL.Host) <= 0 { response := this.GenerateResponse(400, "Bad Request") response.Write(writer) return } request.Host = request.URL.Host StripHopByHopHeaders(request) ray := this.packetDispatcher.DispatchToOutbound(session) defer ray.InboundInput().Close() defer ray.InboundOutput().Release() var finish sync.WaitGroup finish.Add(1) go func() { defer finish.Done() requestWriter := v2io.NewBufferedWriter(v2io.NewChainWriter(ray.InboundInput())) err := request.Write(requestWriter) if err != nil { log.Warning("HTTP: Failed to write request: ", err) return } requestWriter.Flush() }() finish.Add(1) go func() { defer finish.Done() responseReader := bufio.NewReader(v2io.NewChanReader(ray.InboundOutput())) response, err := http.ReadResponse(responseReader, request) if err != nil { log.Warning("HTTP: Failed to read response: ", err) response = this.GenerateResponse(503, "Service Unavailable") } responseWriter := v2io.NewBufferedWriter(writer) err = response.Write(responseWriter) if err != nil { log.Warning("HTTP: Failed to write response: ", err) return } responseWriter.Flush() }() finish.Wait() }
func (v *VMessInboundHandler) Process(ctx context.Context, network net.Network, connection internet.Connection) error { connReader := net.NewTimeOutReader(8, connection) reader := bufio.NewReader(connReader) session := encoding.NewServerSession(v.clients) request, err := session.DecodeRequestHeader(reader) if err != nil { if errors.Cause(err) != io.EOF { log.Access(connection.RemoteAddr(), "", log.AccessRejected, err) log.Info("VMess|Inbound: Invalid request from ", connection.RemoteAddr(), ": ", err) } connection.SetReusable(false) return err } log.Access(connection.RemoteAddr(), request.Destination(), log.AccessAccepted, "") log.Info("VMess|Inbound: Received request for ", request.Destination()) connection.SetReusable(request.Option.Has(protocol.RequestOptionConnectionReuse)) ctx = proxy.ContextWithDestination(ctx, request.Destination()) ctx = protocol.ContextWithUser(ctx, request.User) ray := v.packetDispatcher.DispatchToOutbound(ctx) input := ray.InboundInput() output := ray.InboundOutput() userSettings := request.User.GetSettings() connReader.SetTimeOut(userSettings.PayloadReadTimeout) reader.SetBuffered(false) requestDone := signal.ExecuteAsync(func() error { return transferRequest(session, request, reader, input) }) writer := bufio.NewWriter(connection) response := &protocol.ResponseHeader{ Command: v.generateCommand(ctx, request), } if connection.Reusable() { response.Option.Set(protocol.ResponseOptionConnectionReuse) } responseDone := signal.ExecuteAsync(func() error { return transferResponse(session, request, response, output, writer) }) if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil { log.Info("VMess|Inbound: Connection ending with ", err) connection.SetReusable(false) input.CloseError() output.CloseError() return err } if err := writer.Flush(); err != nil { log.Info("VMess|Inbound: Failed to flush remain data: ", err) connection.SetReusable(false) return err } return nil }