|  | @@ -79,66 +79,28 @@ func parseHost(rawHost string, defaultPort v2net.Port) (v2net.Destination, error
 | 
											
												
													
														|  |  func (this *HttpProxyServer) handleConnection(conn *net.TCPConn) {
 |  |  func (this *HttpProxyServer) handleConnection(conn *net.TCPConn) {
 | 
											
												
													
														|  |  	defer conn.Close()
 |  |  	defer conn.Close()
 | 
											
												
													
														|  |  	reader := bufio.NewReader(conn)
 |  |  	reader := bufio.NewReader(conn)
 | 
											
												
													
														|  | -	for true {
 |  | 
 | 
											
												
													
														|  | -		request, err := http.ReadRequest(reader)
 |  | 
 | 
											
												
													
														|  | -		if err != nil {
 |  | 
 | 
											
												
													
														|  | -			break
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		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
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		dest, 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, dest, 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(dest, buffer, true)
 |  | 
 | 
											
												
													
														|  | -			ray := this.space.PacketDispatcher().DispatchToOutbound(packet)
 |  | 
 | 
											
												
													
														|  | -			go func() {
 |  | 
 | 
											
												
													
														|  | -				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)
 |  | 
 | 
											
												
													
														|  | -				conn.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)
 |  | 
 | 
											
												
													
														|  | -			conn.Write(buffer.Value)
 |  | 
 | 
											
												
													
														|  | -			buffer.Release()
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	request, err := http.ReadRequest(reader)
 | 
											
												
													
														|  | 
 |  | +	if err != nil {
 | 
											
												
													
														|  | 
 |  | +		return
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	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
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	dest, 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, dest, reader, conn)
 | 
											
												
													
														|  | 
 |  | +	} else {
 | 
											
												
													
														|  | 
 |  | +		this.handlePlainHTTP(request, dest, reader, conn)
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -166,18 +128,95 @@ func (this *HttpProxyServer) handleConnect(request *http.Request, destination v2
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  func (this *HttpProxyServer) transport(input io.Reader, output io.Writer, ray ray.InboundRay) {
 |  |  func (this *HttpProxyServer) transport(input io.Reader, output io.Writer, ray ray.InboundRay) {
 | 
											
												
													
														|  | -	var outputFinish sync.Mutex
 |  | 
 | 
											
												
													
														|  | -	outputFinish.Lock()
 |  | 
 | 
											
												
													
														|  | 
 |  | +	var wg sync.WaitGroup
 | 
											
												
													
														|  | 
 |  | +	wg.Add(2)
 | 
											
												
													
														|  | 
 |  | +	defer wg.Wait()
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	go func() {
 |  |  	go func() {
 | 
											
												
													
														|  |  		v2net.ReaderToChan(ray.InboundInput(), input)
 |  |  		v2net.ReaderToChan(ray.InboundInput(), input)
 | 
											
												
													
														|  |  		close(ray.InboundInput())
 |  |  		close(ray.InboundInput())
 | 
											
												
													
														|  | 
 |  | +		wg.Done()
 | 
											
												
													
														|  |  	}()
 |  |  	}()
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	go func() {
 |  |  	go func() {
 | 
											
												
													
														|  |  		v2net.ChanToWriter(output, ray.InboundOutput())
 |  |  		v2net.ChanToWriter(output, ray.InboundOutput())
 | 
											
												
													
														|  | -		outputFinish.Unlock()
 |  | 
 | 
											
												
													
														|  | 
 |  | +		wg.Done()
 | 
											
												
													
														|  |  	}()
 |  |  	}()
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -	outputFinish.Lock()
 |  | 
 | 
											
												
													
														|  | 
 |  | +func stripHopByHopHeaders(request *http.Request) {
 | 
											
												
													
														|  | 
 |  | +	// Strip hop-by-hop header basaed on RFC:
 | 
											
												
													
														|  | 
 |  | +	// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
 | 
											
												
													
														|  | 
 |  | +	// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	request.Header.Del("Proxy-Connection")
 | 
											
												
													
														|  | 
 |  | +	request.Header.Del("Proxy-Authenticate")
 | 
											
												
													
														|  | 
 |  | +	request.Header.Del("Proxy-Authorization")
 | 
											
												
													
														|  | 
 |  | +	request.Header.Del("TE")
 | 
											
												
													
														|  | 
 |  | +	request.Header.Del("Trailers")
 | 
											
												
													
														|  | 
 |  | +	request.Header.Del("Transfer-Encoding")
 | 
											
												
													
														|  | 
 |  | +	request.Header.Del("Upgrade")
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// TODO: support keep-alive
 | 
											
												
													
														|  | 
 |  | +	connections := request.Header.Get("Connection")
 | 
											
												
													
														|  | 
 |  | +	request.Header.Set("Connection", "close")
 | 
											
												
													
														|  | 
 |  | +	if len(connections) == 0 {
 | 
											
												
													
														|  | 
 |  | +		return
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	for _, h := range strings.Split(connections, ",") {
 | 
											
												
													
														|  | 
 |  | +		request.Header.Del(strings.TrimSpace(h))
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +func (this *HttpProxyServer) handlePlainHTTP(request *http.Request, dest v2net.Destination, reader *bufio.Reader, writer io.Writer) {
 | 
											
												
													
														|  | 
 |  | +	if len(request.URL.Host) <= 0 {
 | 
											
												
													
														|  | 
 |  | +		hdr := http.Header(make(map[string][]string))
 | 
											
												
													
														|  | 
 |  | +		hdr.Set("Connection", "close")
 | 
											
												
													
														|  | 
 |  | +		response := &http.Response{
 | 
											
												
													
														|  | 
 |  | +			Status:        "400 Bad Request",
 | 
											
												
													
														|  | 
 |  | +			StatusCode:    400,
 | 
											
												
													
														|  | 
 |  | +			Proto:         "HTTP/1.1",
 | 
											
												
													
														|  | 
 |  | +			ProtoMajor:    1,
 | 
											
												
													
														|  | 
 |  | +			ProtoMinor:    1,
 | 
											
												
													
														|  | 
 |  | +			Header:        hdr,
 | 
											
												
													
														|  | 
 |  | +			Body:          nil,
 | 
											
												
													
														|  | 
 |  | +			ContentLength: 0,
 | 
											
												
													
														|  | 
 |  | +			Close:         false,
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		buffer := alloc.NewSmallBuffer().Clear()
 | 
											
												
													
														|  | 
 |  | +		response.Write(buffer)
 | 
											
												
													
														|  | 
 |  | +		writer.Write(buffer.Value)
 | 
											
												
													
														|  | 
 |  | +		buffer.Release()
 | 
											
												
													
														|  | 
 |  | +		return
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	request.Host = request.URL.Host
 | 
											
												
													
														|  | 
 |  | +	stripHopByHopHeaders(request)
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	requestBuffer := alloc.NewBuffer().Clear()
 | 
											
												
													
														|  | 
 |  | +	request.Write(requestBuffer)
 | 
											
												
													
														|  | 
 |  | +	log.Info("Request to remote:\n%s", string(requestBuffer.Value))
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	packet := v2net.NewPacket(dest, requestBuffer, true)
 | 
											
												
													
														|  | 
 |  | +	ray := this.space.PacketDispatcher().DispatchToOutbound(packet)
 | 
											
												
													
														|  | 
 |  | +	defer close(ray.InboundInput())
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	var wg sync.WaitGroup
 | 
											
												
													
														|  | 
 |  | +	wg.Add(1)
 | 
											
												
													
														|  | 
 |  | +	go func() {
 | 
											
												
													
														|  | 
 |  | +		defer wg.Done()
 | 
											
												
													
														|  | 
 |  | +		responseReader := bufio.NewReader(NewChanReader(ray.InboundOutput()))
 | 
											
												
													
														|  | 
 |  | +		responseBuffer := alloc.NewBuffer()
 | 
											
												
													
														|  | 
 |  | +		defer responseBuffer.Release()
 | 
											
												
													
														|  | 
 |  | +		response, err := http.ReadResponse(responseReader, request)
 | 
											
												
													
														|  | 
 |  | +		if err != nil {
 | 
											
												
													
														|  | 
 |  | +			return
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		responseBuffer.Clear()
 | 
											
												
													
														|  | 
 |  | +		response.Write(responseBuffer)
 | 
											
												
													
														|  | 
 |  | +		writer.Write(responseBuffer.Value)
 | 
											
												
													
														|  | 
 |  | +		response.Body.Close()
 | 
											
												
													
														|  | 
 |  | +	}()
 | 
											
												
													
														|  | 
 |  | +	wg.Wait()
 | 
											
												
													
														|  |  }
 |  |  }
 |