File tree Expand file tree Collapse file tree 2 files changed +18
-15
lines changed Expand file tree Collapse file tree 2 files changed +18
-15
lines changed Original file line number Diff line number Diff line change @@ -496,25 +496,29 @@ func NewMaskingKey() MaskingKey {
496
496
return key
497
497
}
498
498
499
- // applyMask optimizes payload masking by working 8 bytes at a time .
499
+ // applyMask applies a [MaskingKey] to the payload in-place .
500
500
func applyMask (payload []byte , mask MaskingKey ) {
501
501
n := len (payload )
502
+ if n == 0 {
503
+ return
504
+ }
505
+
506
+ // duplicate 4 byte masking key to make uint64 mask that can be applied to
507
+ // the payload 8 bytes at a time in a single XOR.
508
+ mask64 := uint64 (mask [0 ]) | uint64 (mask [1 ])<< 8 | uint64 (mask [2 ])<< 16 | uint64 (mask [3 ])<< 24
509
+ mask64 |= mask64 << 32
510
+
511
+ // apply mask in-place 8 bytes at a time
502
512
chunks := n / 8
503
513
for i := range chunks {
504
- // create a slice of exactly 8 bytes that the compiler can verify and
505
- // eliminate bounds checks on the 8 xor operations per iteration
506
- chunk := payload [i * 8 : i * 8 + 8 ]
507
- chunk [0 ] ^= mask [0 ]
508
- chunk [1 ] ^= mask [1 ]
509
- chunk [2 ] ^= mask [2 ]
510
- chunk [3 ] ^= mask [3 ]
511
- chunk [4 ] ^= mask [0 ]
512
- chunk [5 ] ^= mask [1 ]
513
- chunk [6 ] ^= mask [2 ]
514
- chunk [7 ] ^= mask [3 ]
514
+ offset := i * 8
515
+ data := binary .LittleEndian .Uint64 (payload [offset : offset + 8 ])
516
+ data ^= mask64
517
+ binary .LittleEndian .PutUint64 (payload [offset :offset + 8 ], data )
515
518
}
519
+
516
520
remainder := payload [chunks * 8 :]
517
- for i := range len ( remainder ) {
521
+ for i := range remainder {
518
522
remainder [i ] ^= mask [i & 3 ] // i&3 == i%4, but faster
519
523
}
520
524
}
Original file line number Diff line number Diff line change @@ -230,13 +230,12 @@ func BenchmarkWriteFrame(b *testing.B) {
230
230
assert .NilError (b , websocket .WriteFrame (buf , mask , frame ))
231
231
expectedSize := len (buf .Bytes ())
232
232
b .SetBytes (int64 (expectedSize ))
233
- buf .Reset ()
234
233
b .ResetTimer ()
235
234
236
235
for i := 0 ; i < b .N ; i ++ {
237
236
buf .Reset ()
238
237
assert .NilError (b , websocket .WriteFrame (buf , mask , frame ))
239
- assert .Equal (b , len ( buf .Bytes () ), expectedSize , "payload length" )
238
+ assert .Equal (b , buf .Len ( ), expectedSize , "payload length" )
240
239
}
241
240
})
242
241
}
You can’t perform that action at this time.
0 commit comments