瀏覽代碼

proxy/http: Avoid getting stuck when using server-first protocols

PR #99 reduces an extra RTT when setting up the CONNECT tunnel
via http proxy, however, server-first protocols (such as MySQL)
will be unusable as v2ray keeps to wait for the client request.
This commit solves the problem by limiting the maximum waiting
time to 50 ms.
lrh2000 4 年之前
父節點
當前提交
17d85263e2
共有 1 個文件被更改,包括 18 次插入8 次删除
  1. 18 8
      proxy/http/client.go

+ 18 - 8
proxy/http/client.go

@@ -8,6 +8,7 @@ import (
 	"net/http"
 	"net/url"
 	"sync"
+	"time"
 
 	"golang.org/x/net/http2"
 
@@ -79,14 +80,23 @@ 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)
+	var firstPayload []byte
+
+	if reader, ok := link.Reader.(buf.TimeoutReader); ok {
+		// 0-RTT optimization for HTTP/2: If the payload comes within 50 ms, it can be
+		// transmitted together. Note we should not get stuck here, as the payload may
+		// not exist (considering to access MySQL database via a HTTP proxy, where the
+		// server sends hello to the client first).
+		if mbuf, _ := reader.ReadMultiBufferTimeout(50 * time.Millisecond); mbuf != nil {
+			mlen := mbuf.Len()
+			firstPayload = bytespool.Alloc(mlen)
+			mbuf, _ = buf.SplitBytes(mbuf, firstPayload)
+			firstPayload = firstPayload[:mlen]
+
+			buf.ReleaseMulti(mbuf)
+			defer bytespool.Free(firstPayload)
+		}
+	}
 
 	if err := retry.ExponentialBackoff(5, 100).On(func() error {
 		server := c.serverPicker.PickServer()