From d05ddc8f78dabc66efce2dc2ead520d28b4ab710 Mon Sep 17 00:00:00 2001 From: Darhwa <65339668+darhwa@users.noreply.github.com> Date: Sat, 15 Aug 2020 23:58:58 +0800 Subject: [PATCH] Make http outbound 0-rtt --- proxy/http/client.go | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/proxy/http/client.go b/proxy/http/client.go index 120a5299..31c40283 100644 --- a/proxy/http/client.go +++ b/proxy/http/client.go @@ -16,6 +16,7 @@ import ( "v2ray.com/core" "v2ray.com/core/common" "v2ray.com/core/common/buf" + "v2ray.com/core/common/bytespool" "v2ray.com/core/common/net" "v2ray.com/core/common/protocol" "v2ray.com/core/common/retry" @@ -80,12 +81,21 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter var user *protocol.MemoryUser var conn internet.Connection + mbuf, _ := link.Reader.ReadMultiBuffer() + len := mbuf.Len() + firstPayload := bytespool.Alloc(len) + mbuf, _ = buf.SplitBytes(mbuf, firstPayload) + firstPayload = firstPayload[:len] + + buf.ReleaseMulti(mbuf) + defer bytespool.Free(firstPayload) + if err := retry.ExponentialBackoff(5, 100).On(func() error { server := c.serverPicker.PickServer() dest := server.Destination() user = server.PickUser() - netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer) + netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer, firstPayload) if netConn != nil { conn = internet.Connection(netConn) } @@ -126,11 +136,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter } // setUpHTTPTunnel will create a socket tunnel via HTTP CONNECT method -func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, user *protocol.MemoryUser, dialer internet.Dialer) (net.Conn, error) { +func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, user *protocol.MemoryUser, dialer internet.Dialer, firstPayload []byte) (net.Conn, error) { req := &http.Request{ Method: http.MethodConnect, URL: &url.URL{Host: target}, - Header: http.Header{"Proxy-Connection": []string{"Keep-Alive"}}, + Header: make(http.Header), Host: target, } @@ -141,12 +151,19 @@ func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, u } connectHTTP1 := func(rawConn net.Conn) (net.Conn, error) { + req.Header.Set("Proxy-Connection", "Keep-Alive") + err := req.Write(rawConn) if err != nil { rawConn.Close() return nil, err } + if _, err := rawConn.Write(firstPayload); err != nil { + rawConn.Close() + return nil, err + } + resp, err := http.ReadResponse(bufio.NewReader(rawConn), req) if err != nil { rawConn.Close() @@ -164,12 +181,27 @@ func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, u pr, pw := io.Pipe() req.Body = pr + var pErr error + var wg sync.WaitGroup + wg.Add(1) + + go func() { + _, pErr = pw.Write(firstPayload) + wg.Done() + }() + resp, err := h2clientConn.RoundTrip(req) if err != nil { rawConn.Close() return nil, err } + wg.Wait() + if pErr != nil { + rawConn.Close() + return nil, pErr + } + if resp.StatusCode != http.StatusOK { rawConn.Close() return nil, newError("Proxy responded with non 200 code: " + resp.Status)