Skip to content

Commit b258b4f

Browse files
committed
Use bufio.Writer returned from hijack in upgrade
Reuse the buffer backing the bufio.Writer returned from hijack if that buffer is large enough to be generally useful and Upgrader.WriteBufferSize == 0. Update the logic for reusing bufio.Reader returned from hijack to match the logic for bufio.Reader: The buffer backing the reader must be sufficiently large to be generally useful and Upgrader.ReadBufferSize == 0. Improve the documentation for ReadBufferSize and WriterBufferSize in Dialer and Upgrader.
1 parent 4873052 commit b258b4f

File tree

4 files changed

+67
-22
lines changed

4 files changed

+67
-22
lines changed

client.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,9 @@ type Dialer struct {
6666
// HandshakeTimeout specifies the duration for the handshake to complete.
6767
HandshakeTimeout time.Duration
6868

69-
// Input and output buffer sizes. If the buffer size is zero, then a
70-
// default value of 4096 is used.
69+
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
70+
// size is zero, then a useful default size is used. The I/O buffer sizes
71+
// do not limit the size of the messages that can be sent or received.
7172
ReadBufferSize, WriteBufferSize int
7273

7374
// Subprotocols specifies the client's requested subprotocols.

conn.go

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -268,33 +268,58 @@ func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int)
268268
return newConnBRW(conn, isServer, readBufferSize, writeBufferSize, nil)
269269
}
270270

271+
type writeHook struct {
272+
p []byte
273+
}
274+
275+
func (wh *writeHook) Write(p []byte) (int, error) {
276+
wh.p = p
277+
return len(p), nil
278+
}
279+
271280
func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int, brw *bufio.ReadWriter) *Conn {
272281
mu := make(chan bool, 1)
273282
mu <- true
274283

275-
if readBufferSize == 0 {
276-
readBufferSize = defaultReadBufferSize
277-
}
278-
if readBufferSize < maxControlFramePayloadSize {
279-
readBufferSize = maxControlFramePayloadSize
280-
}
281-
282-
// Reuse the supplied brw.Reader if brw.Reader's buf is the requested size.
283284
var br *bufio.Reader
284-
if brw != nil && brw.Reader != nil {
285-
// This code assumes that peek on a reset reader returns
285+
if readBufferSize == 0 && brw != nil && brw.Reader != nil {
286+
// Reuse the supplied bufio.Reader if the buffer has a useful size.
287+
// This code assumes that peek on a reader returns
286288
// bufio.Reader.buf[:0].
287289
brw.Reader.Reset(conn)
288-
if p, err := brw.Reader.Peek(0); err == nil && cap(p) == readBufferSize {
290+
if p, err := brw.Reader.Peek(0); err == nil && cap(p) >= 256 {
289291
br = brw.Reader
290292
}
291293
}
292294
if br == nil {
295+
if readBufferSize == 0 {
296+
readBufferSize = defaultReadBufferSize
297+
}
298+
if readBufferSize < maxControlFramePayloadSize {
299+
readBufferSize = maxControlFramePayloadSize
300+
}
293301
br = bufio.NewReaderSize(conn, readBufferSize)
294302
}
295303

296-
if writeBufferSize == 0 {
297-
writeBufferSize = defaultWriteBufferSize
304+
var writeBuf []byte
305+
if writeBufferSize == 0 && brw != nil && brw.Writer != nil {
306+
// Use the bufio.Writer's buffer if the buffer has a useful size. This
307+
// code assumes that bufio.Writer.buf[:1] is passed to the
308+
// bufio.Writer's underlying writer.
309+
var wh writeHook
310+
brw.Writer.Reset(&wh)
311+
brw.Writer.WriteByte(0)
312+
brw.Flush()
313+
if cap(wh.p) >= maxFrameHeaderSize+256 {
314+
writeBuf = wh.p[:cap(wh.p)]
315+
}
316+
}
317+
318+
if writeBuf == nil {
319+
if writeBufferSize == 0 {
320+
writeBufferSize = defaultWriteBufferSize
321+
}
322+
writeBuf = make([]byte, writeBufferSize+maxFrameHeaderSize)
298323
}
299324

300325
c := &Conn{
@@ -303,7 +328,7 @@ func newConnBRW(conn net.Conn, isServer bool, readBufferSize, writeBufferSize in
303328
conn: conn,
304329
mu: mu,
305330
readFinal: true,
306-
writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize),
331+
writeBuf: writeBuf,
307332
enableWriteCompression: true,
308333
compressionLevel: defaultCompressionLevel,
309334
}

conn_test.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -464,16 +464,34 @@ func TestFailedConnectionReadPanic(t *testing.T) {
464464
t.Fatal("should not get here")
465465
}
466466

467-
func TestBufioReaderReuse(t *testing.T) {
468-
brw := bufio.NewReadWriter(bufio.NewReader(nil), nil)
467+
func TestBufioReuse(t *testing.T) {
468+
brw := bufio.NewReadWriter(bufio.NewReader(nil), bufio.NewWriter(nil))
469469
c := newConnBRW(nil, false, 0, 0, brw)
470+
470471
if c.br != brw.Reader {
471472
t.Error("connection did not reuse bufio.Reader")
472473
}
473474

474-
brw = bufio.NewReadWriter(bufio.NewReaderSize(nil, 1234), nil) // size must not equal bufio.defaultBufSize
475+
var wh writeHook
476+
brw.Writer.Reset(&wh)
477+
brw.WriteByte(0)
478+
brw.Flush()
479+
if &c.writeBuf[0] != &wh.p[0] {
480+
t.Error("connection did not reuse bufio.Writer")
481+
}
482+
483+
brw = bufio.NewReadWriter(bufio.NewReaderSize(nil, 0), bufio.NewWriterSize(nil, 0))
475484
c = newConnBRW(nil, false, 0, 0, brw)
485+
476486
if c.br == brw.Reader {
477-
t.Error("connection reuse bufio.Reader with wrong size")
487+
t.Error("connection used bufio.Reader with small size")
478488
}
489+
490+
brw.Writer.Reset(&wh)
491+
brw.WriteByte(0)
492+
brw.Flush()
493+
if &c.writeBuf[0] != &wh.p[0] {
494+
t.Error("connection used bufio.Writer with small size")
495+
}
496+
479497
}

server.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ type Upgrader struct {
2828
HandshakeTimeout time.Duration
2929

3030
// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
31-
// size is zero, then a default value of 4096 is used. The I/O buffer sizes
32-
// do not limit the size of the messages that can be sent or received.
31+
// size is zero, then buffers allocated by the HTTP server are used. The
32+
// I/O buffer sizes do not limit the size of the messages that can be sent
33+
// or received.
3334
ReadBufferSize, WriteBufferSize int
3435

3536
// Subprotocols specifies the server's supported protocols in order of

0 commit comments

Comments
 (0)