1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-21 09:36:34 -05:00

Make http outbound 0-rtt

This commit is contained in:
Darhwa 2020-08-15 23:58:58 +08:00
parent e0bbf474ae
commit d05ddc8f78

View File

@ -16,6 +16,7 @@ import (
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/bytespool"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/retry" "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 user *protocol.MemoryUser
var conn internet.Connection 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 { if err := retry.ExponentialBackoff(5, 100).On(func() error {
server := c.serverPicker.PickServer() server := c.serverPicker.PickServer()
dest := server.Destination() dest := server.Destination()
user = server.PickUser() user = server.PickUser()
netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer) netConn, err := setUpHTTPTunnel(ctx, dest, targetAddr, user, dialer, firstPayload)
if netConn != nil { if netConn != nil {
conn = internet.Connection(netConn) 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 // 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{ req := &http.Request{
Method: http.MethodConnect, Method: http.MethodConnect,
URL: &url.URL{Host: target}, URL: &url.URL{Host: target},
Header: http.Header{"Proxy-Connection": []string{"Keep-Alive"}}, Header: make(http.Header),
Host: target, 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) { connectHTTP1 := func(rawConn net.Conn) (net.Conn, error) {
req.Header.Set("Proxy-Connection", "Keep-Alive")
err := req.Write(rawConn) err := req.Write(rawConn)
if err != nil { if err != nil {
rawConn.Close() rawConn.Close()
return nil, err return nil, err
} }
if _, err := rawConn.Write(firstPayload); err != nil {
rawConn.Close()
return nil, err
}
resp, err := http.ReadResponse(bufio.NewReader(rawConn), req) resp, err := http.ReadResponse(bufio.NewReader(rawConn), req)
if err != nil { if err != nil {
rawConn.Close() rawConn.Close()
@ -164,12 +181,27 @@ func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, u
pr, pw := io.Pipe() pr, pw := io.Pipe()
req.Body = pr 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) resp, err := h2clientConn.RoundTrip(req)
if err != nil { if err != nil {
rawConn.Close() rawConn.Close()
return nil, err return nil, err
} }
wg.Wait()
if pErr != nil {
rawConn.Close()
return nil, pErr
}
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
rawConn.Close() rawConn.Close()
return nil, newError("Proxy responded with non 200 code: " + resp.Status) return nil, newError("Proxy responded with non 200 code: " + resp.Status)