Quellcode durchsuchen

handle connect request in http proxy

v2ray vor 10 Jahren
Ursprung
Commit
d0a75ce9f3
1 geänderte Dateien mit 77 neuen und 24 gelöschten Zeilen
  1. 77 24
      proxy/http/http.go

+ 77 - 24
proxy/http/http.go

@@ -1,54 +1,107 @@
 package http
 
 import (
+	"bufio"
 	"net"
 	"net/http"
+	"strconv"
 	"strings"
 
 	"github.com/v2ray/v2ray-core/app"
-	_ "github.com/v2ray/v2ray-core/common/log"
+	"github.com/v2ray/v2ray-core/common/alloc"
+	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 )
 
 type HttpProxyServer struct {
-	accepting  bool
-	dispatcher app.PacketDispatcher
-	config     Config
+	accepting bool
+	space     app.Space
+	config    Config
 }
 
-func NewHttpProxyServer(dispatcher app.PacketDispatcher, config Config) *HttpProxyServer {
+func NewHttpProxyServer(space app.Space, config Config) *HttpProxyServer {
 	return &HttpProxyServer{
-		dispatcher: dispatcher,
-		config:     config,
+		space:  space,
+		config: config,
 	}
 }
 
 func (this *HttpProxyServer) Listen(port v2net.Port) error {
-	server := http.Server{
-		Addr:    ":" + port.String(),
-		Handler: this,
+	tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{
+		Port: int(port.Value()),
+		IP:   []byte{0, 0, 0, 0},
+	})
+	if err != nil {
+		return err
 	}
-	return server.ListenAndServe()
+	go this.accept(tcpListener)
+	return nil
 }
 
-func (this *HttpProxyServer) ServeHTTP(w http.ResponseWriter, request *http.Request) {
-	if strings.ToUpper(request.Method) == "CONNECT" {
-		host, port, err := net.SplitHostPort(request.URL.Host)
+func (this *HttpProxyServer) accept(listener *net.TCPListener) {
+	this.accepting = true
+	for this.accepting {
+		tcpConn, err := listener.AcceptTCP()
 		if err != nil {
-			if strings.Contains(err.(*net.AddrError).Err, "missing port") {
-				host = request.URL.Host
-				port = "80"
-			} else {
-				http.Error(w, "Bad Request", 400)
-				return
-			}
+			log.Error("Failed to accept HTTP connection: %v", err)
+			continue
 		}
-		_ = host + port
-	} else {
+		go this.handleConnection(tcpConn)
+	}
+}
 
+func parseHost(rawHost string) (v2net.Address, error) {
+	port := v2net.Port(80)
+	host, rawPort, err := net.SplitHostPort(rawHost)
+	if err != nil {
+		if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
+			host = rawHost
+			port = v2net.Port(80)
+		} else {
+			return nil, err
+		}
 	}
+	intPort, err := strconv.Atoi(rawPort)
+	if err != nil {
+		return nil, err
+	}
+	port = v2net.Port(intPort)
+	if ip := net.ParseIP(host); ip != nil {
+		return v2net.IPAddress(ip, port), nil
+	}
+	return v2net.DomainAddress(host, port), nil
 }
 
-func (this *HttpProxyServer) handleConnect(response http.ResponseWriter, request *http.Request) {
+func (this *HttpProxyServer) handleConnection(conn *net.TCPConn) {
+	httpReader := bufio.NewReader(conn)
+	request, err := http.ReadRequest(httpReader)
+	if err != nil {
+		log.Warning("Malformed HTTP request: %v", err)
+		return
+	}
+	if strings.ToUpper(request.Method) == "CONNECT" {
+		address, err := parseHost(request.Host)
+		if err != nil {
+			log.Warning("Malformed proxy host: %v", err)
+			return
+		}
+		response := &http.Response{
+			Status:        "200 OK",
+			StatusCode:    200,
+			Proto:         "HTTP/1.1",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			Header:        http.Header(make(map[string][]string)),
+			Body:          nil,
+			ContentLength: 0,
+			Close:         false,
+		}
+
+		buffer := alloc.NewSmallBuffer().Clear()
+		response.Write(buffer)
+		conn.Write(buffer.Value)
 
+		packet := v2net.NewPacket(v2net.NewTCPDestination(address), nil, true)
+		this.space.PacketDispatcher().DispatchToOutbound(packet)
+	}
 }