Skip to content

Commit ee1f3c6

Browse files
committed
Reuse write and read header buffers
Next is reusing the header structures.
1 parent df60edf commit ee1f3c6

File tree

3 files changed

+26
-15
lines changed

3 files changed

+26
-15
lines changed

header.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,19 @@ type header struct {
3131
maskKey [4]byte
3232
}
3333

34+
func makeWriteHeaderBuf() []byte {
35+
return make([]byte, maxHeaderSize)
36+
}
37+
3438
// bytes returns the bytes of the header.
3539
// See https://tools.ietf.org/html/rfc6455#section-5.2
36-
func marshalHeader(h header) []byte {
37-
b := make([]byte, 2, maxHeaderSize)
40+
func writeHeader(b []byte, h header) []byte {
41+
if b == nil {
42+
b = makeWriteHeaderBuf()
43+
}
44+
45+
b = b[:2]
46+
b[0] = 0
3847

3948
if h.fin {
4049
b[0] |= 1 << 7
@@ -75,16 +84,17 @@ func marshalHeader(h header) []byte {
7584
return b
7685
}
7786

78-
func makeHeaderBuf() []byte {
87+
func makeReadHeaderBuf() []byte {
7988
return make([]byte, maxHeaderSize-2)
8089
}
8190

8291
// readHeader reads a header from the reader.
8392
// See https://tools.ietf.org/html/rfc6455#section-5.2
8493
func readHeader(b []byte, r io.Reader) (header, error) {
8594
if b == nil {
86-
b = makeHeaderBuf()
95+
b = makeReadHeaderBuf()
8796
}
97+
8898
// We read the first two bytes first so that we know
8999
// exactly how long the header is.
90100
b = b[:2]

header_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func TestHeader(t *testing.T) {
2424
t.Run("readNegativeLength", func(t *testing.T) {
2525
t.Parallel()
2626

27-
b := marshalHeader(header{
27+
b := writeHeader(nil, header{
2828
payloadLength: 1<<16 + 1,
2929
})
3030

@@ -90,7 +90,7 @@ func TestHeader(t *testing.T) {
9090
}
9191

9292
func testHeader(t *testing.T, h header) {
93-
b := marshalHeader(h)
93+
b := writeHeader(nil, h)
9494
r := bytes.NewReader(b)
9595
h2, err := readHeader(nil, r)
9696
if err != nil {

websocket.go

+10-9
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,21 @@ type Conn struct {
4545
// writeFrameLock is acquired to write a single frame.
4646
// Effectively meaning whoever holds it gets to write to bw.
4747
writeFrameLock chan struct{}
48+
writeHeaderBuf []byte
4849

4950
// Used to ensure the previous reader is read till EOF before allowing
5051
// a new one.
5152
previousReader *messageReader
5253
// readFrameLock is acquired to read from bw.
53-
readFrameLock chan struct{}
54+
readFrameLock chan struct{}
55+
readHeaderBuf []byte
56+
controlPayloadBuf []byte
5457

5558
setReadTimeout chan context.Context
5659
setWriteTimeout chan context.Context
5760

5861
activePingsMu sync.Mutex
5962
activePings map[string]chan<- struct{}
60-
61-
headerBuf []byte
62-
controlPayloadBuf []byte
6363
}
6464

6565
func (c *Conn) init() {
@@ -77,7 +77,8 @@ func (c *Conn) init() {
7777

7878
c.activePings = make(map[string]chan<- struct{})
7979

80-
c.headerBuf = makeHeaderBuf()
80+
c.writeHeaderBuf = makeWriteHeaderBuf()
81+
c.readHeaderBuf = makeReadHeaderBuf()
8182
c.controlPayloadBuf = make([]byte, maxControlFramePayload)
8283

8384
runtime.SetFinalizer(c, func(c *Conn) {
@@ -215,7 +216,7 @@ func (c *Conn) readFrameHeader(ctx context.Context) (header, error) {
215216
case c.setReadTimeout <- ctx:
216217
}
217218

218-
h, err := readHeader(c.headerBuf, c.br)
219+
h, err := readHeader(c.readHeaderBuf, c.br)
219220
if err != nil {
220221
select {
221222
case <-c.closed:
@@ -628,7 +629,7 @@ func (c *Conn) writeFrame(ctx context.Context, fin bool, opcode opcode, p []byte
628629
}
629630
}
630631

631-
b2 := marshalHeader(h)
632+
headerBytes := writeHeader(c.writeHeaderBuf, h)
632633

633634
err := c.acquireLock(ctx, c.writeFrameLock)
634635
if err != nil {
@@ -651,7 +652,7 @@ func (c *Conn) writeFrame(ctx context.Context, fin bool, opcode opcode, p []byte
651652
default:
652653
}
653654

654-
err = xerrors.Errorf("failed to write frame: %w", err)
655+
err = xerrors.Errorf("failed to write %v frame: %w", h.opcode, err)
655656
// We need to release the lock first before closing the connection to ensure
656657
// the lock can be acquired inside close to ensure no one can access c.bw.
657658
c.releaseLock(c.writeFrameLock)
@@ -660,7 +661,7 @@ func (c *Conn) writeFrame(ctx context.Context, fin bool, opcode opcode, p []byte
660661
return err
661662
}
662663

663-
_, err = c.bw.Write(b2)
664+
_, err = c.bw.Write(headerBytes)
664665
if err != nil {
665666
return 0, writeErr(err)
666667
}

0 commit comments

Comments
 (0)