Skip to content

Commit

Permalink
chore: better bufio.Reader warp
Browse files Browse the repository at this point in the history
  • Loading branch information
wwqgtxx committed Nov 2, 2023
1 parent 96220aa commit b0638cf
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 11 deletions.
10 changes: 10 additions & 0 deletions common/net/bufconn.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ func NewBufferedConn(c net.Conn) *BufferedConn {
return &BufferedConn{bufio.NewReader(c), NewExtendedConn(c), false}
}

func WarpConnWithBioReader(c net.Conn, br *bufio.Reader) net.Conn {
if br != nil && br.Buffered() > 0 {
if bc, ok := c.(*BufferedConn); ok && bc.r == br {
return bc
}
return &BufferedConn{br, NewExtendedConn(c), true}
}
return c
}

// Reader returns the internal bufio.Reader.
func (c *BufferedConn) Reader() *bufio.Reader {
return c.r
Expand Down
23 changes: 12 additions & 11 deletions transport/vmess/websocket.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package vmess

import (
"bufio"
"bytes"
"context"
"crypto/tls"
Expand Down Expand Up @@ -393,7 +392,11 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig,
return nil, fmt.Errorf("dial %s error: %w", uri.Host, err)
}

conn = newWebsocketConn(conn, reader, ws.StateClientSide)
// some bytes which could be written by the peer right after response and be caught by us during buffered read,
// so we need warp Conn with bio.Reader
conn = N.WarpConnWithBioReader(conn, reader)

conn = newWebsocketConn(conn, ws.StateClientSide)
// websocketConn can't correct handle ReadDeadline
// so call N.NewDeadlineConn to add a safe wrapper
return N.NewDeadlineConn(conn), nil
Expand All @@ -419,19 +422,13 @@ func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig)
return streamWebsocketConn(ctx, conn, c, nil)
}

func newWebsocketConn(conn net.Conn, br *bufio.Reader, state ws.State) *websocketConn {
func newWebsocketConn(conn net.Conn, state ws.State) *websocketConn {
controlHandler := wsutil.ControlFrameHandler(conn, state)
var reader io.Reader
if br != nil && br.Buffered() > 0 {
reader = br
} else {
reader = conn
}
return &websocketConn{
Conn: conn,
state: state,
reader: &wsutil.Reader{
Source: reader,
Source: conn,
State: state,
SkipHeaderCheck: true,
CheckUTF8: false,
Expand Down Expand Up @@ -463,7 +460,11 @@ func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Co
if err != nil {
return nil, err
}
conn := newWebsocketConn(wsConn, rw.Reader, ws.StateServerSide)

// gobwas/ws will flush rw.Writer, so we only need warp rw.Reader
wsConn = N.WarpConnWithBioReader(wsConn, rw.Reader)

conn := newWebsocketConn(wsConn, ws.StateServerSide)
if edBuf := decodeXray0rtt(r.Header); len(edBuf) > 0 {
return N.NewDeadlineConn(&websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}), nil
}
Expand Down

0 comments on commit b0638cf

Please sign in to comment.