From b3ec97058eb07ce46d48b88a236d9eac8d0f9863 Mon Sep 17 00:00:00 2001 From: v2ray Date: Wed, 16 Dec 2015 15:52:40 +0100 Subject: [PATCH] refind http proxy --- proxy/http/http.go | 166 +++++++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 90 deletions(-) diff --git a/proxy/http/http.go b/proxy/http/http.go index 326bb4e5..13aa63a3 100644 --- a/proxy/http/http.go +++ b/proxy/http/http.go @@ -8,7 +8,6 @@ import ( "strconv" "strings" "sync" - "time" "github.com/v2ray/v2ray-core/app" "github.com/v2ray/v2ray-core/common/alloc" @@ -85,111 +84,98 @@ func (this *HttpProxyServer) handleConnection(conn *net.TCPConn) { if err != nil { break } - this.handleRequest(request, reader, conn) + log.Info("Request to Method [%s] Host [%s] with URL [%s]", request.Method, request.Host, request.URL.String()) + defaultPort := v2net.Port(80) + if strings.ToLower(request.URL.Scheme) == "https" { + defaultPort = v2net.Port(443) + } + host := request.Host + if len(host) == 0 { + host = request.URL.Host + } + address, err := parseHost(host, defaultPort) + if err != nil { + log.Warning("Malformed proxy host (%s): %v", host, err) + } + if strings.ToUpper(request.Method) == "CONNECT" { + this.handleConnect(request, address, reader, conn) + } else if len(request.URL.Host) > 0 { + request.Host = request.URL.Host + request.Header.Set("Connection", "keep-alive") + request.Header.Del("Proxy-Connection") + buffer := alloc.NewBuffer().Clear() + request.Write(buffer) + log.Info("Request to remote: %s", string(buffer.Value)) + packet := v2net.NewPacket(v2net.NewTCPDestination(address), buffer, true) + ray := this.space.PacketDispatcher().DispatchToOutbound(packet) + defer close(ray.InboundInput()) + + responseReader := bufio.NewReader(NewChanReader(ray.InboundOutput())) + response, err := http.ReadResponse(responseReader, request) + if err != nil { + return + } + + responseBuffer := alloc.NewBuffer().Clear() + response.Write(responseBuffer) + conn.Write(responseBuffer.Value) + responseBuffer.Release() + } else { + response := &http.Response{ + Status: "400 Bad Request", + StatusCode: 400, + 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) + buffer.Release() + } } } -func (this *HttpProxyServer) handleRequest(request *http.Request, reader io.Reader, writer io.Writer) { - log.Info("Request to Method [%s] Host [%s] with URL [%s]", request.Method, request.Host, request.URL.String()) - defaultPort := v2net.Port(80) - if strings.ToLower(request.URL.Scheme) == "https" { - defaultPort = v2net.Port(443) +func (this *HttpProxyServer) handleConnect(request *http.Request, address v2net.Address, reader io.Reader, writer io.Writer) { + 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, } - if strings.ToUpper(request.Method) == "CONNECT" { - address, err := parseHost(request.Host, defaultPort) - 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) - writer.Write(buffer.Value) + buffer := alloc.NewSmallBuffer().Clear() + response.Write(buffer) + writer.Write(buffer.Value) - packet := v2net.NewPacket(v2net.NewTCPDestination(address), nil, true) - ray := this.space.PacketDispatcher().DispatchToOutbound(packet) - this.transport(reader, writer, ray) - } else if len(request.URL.Host) > 0 { - address, err := parseHost(request.URL.Host, defaultPort) - if err != nil { - log.Warning("Malformed proxy host: %v", err) - return - } - request.Host = request.URL.Host - request.Header.Set("Connection", "keep-alive") - request.Header.Del("Proxy-Connection") - buffer := alloc.NewBuffer().Clear() - request.Write(buffer) - log.Info("Request to remote: %s", string(buffer.Value)) - packet := v2net.NewPacket(v2net.NewTCPDestination(address), buffer, true) - ray := this.space.PacketDispatcher().DispatchToOutbound(packet) - defer close(ray.InboundInput()) - - responseReader := bufio.NewReader(NewChanReader(ray.InboundOutput())) - response, err := http.ReadResponse(responseReader, request) - if err != nil { - return - } - - responseBuffer := alloc.NewBuffer().Clear() - defer responseBuffer.Release() - response.Write(responseBuffer) - writer.Write(responseBuffer.Value) - - } else { - response := &http.Response{ - Status: "400 Bad Request", - StatusCode: 400, - 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) - writer.Write(buffer.Value) - } + packet := v2net.NewPacket(v2net.NewTCPDestination(address), nil, true) + ray := this.space.PacketDispatcher().DispatchToOutbound(packet) + this.transport(reader, writer, ray) } func (this *HttpProxyServer) transport(input io.Reader, output io.Writer, ray ray.InboundRay) { - var inputFinish, outputFinish sync.Mutex + var outputFinish sync.Mutex outputFinish.Lock() - if input != nil { - inputFinish.Lock() - go func() { - v2net.ReaderToChan(ray.InboundInput(), input) - inputFinish.Unlock() - }() - } else { - // TODO: We can not close write so quickly, as some HTTP server will stop responding if so. - - } + go func() { + v2net.ReaderToChan(ray.InboundInput(), input) + close(ray.InboundInput()) + }() go func() { v2net.ChanToWriter(output, ray.InboundOutput()) outputFinish.Unlock() }() - inputFinish.Lock() - go func() { - <-time.After(10 * time.Second) - close(ray.InboundInput()) - }() outputFinish.Lock() }