Conversation
|
Review requested:
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #66335 +/- ##
==========================================
- Coverage 90.37% 90.37% -0.01%
==========================================
Files 792 792
Lines 275324 275447 +123
Branches 52764 52797 +33
==========================================
+ Hits 248828 248933 +105
- Misses 16918 16920 +2
- Partials 9578 9594 +16
🚀 New features to boost your workflow:
|
|
First off: I like it! (LGTM) Question: unmask is just |
|
I kept it as a separate function to keep the API shape the same as bufferutil. Happy to coalesce but would like to see what @lpinca thinks |
|
The discussion about whether to add this feature to the Node.js core dates back to 2015 (#1010 (comment), #1010 (comment), #1202) and I think it would be a valuable addition. Every WebSocket implementation would benefit from this just like I don't have a strong option about Some tests are hard to follow. |
|
I think there's value in matching the current API so that there's just less for someone migrating from |
03fe080 to
ae2229e
Compare
Add buffer.mask(source, mask, output[, offset[, length]]) and buffer.unmask(buffer, mask), which XOR data with a repeating 4-byte key. This is the masking that WebSocket clients apply to every frame they send (RFC 6455, Section 5.3), and that servers undo on every frame they receive. Userland WebSocket implementations do this either with a byte-by-byte JS loop (undici, and ws without optional dependencies) or with the bufferutil native addon. bufferutil is installed for only about 3% of ws downloads and has no linux-arm64 prebuild, so almost all users run the JS loop. The signature matches bufferutil, so existing users can switch with a feature check, as ws did for buffer.isUtf8(). The implementation uses a V8 fast API call and processes 8-byte words, which the compiler vectorizes. It handles overlapping source and output views, and treats every view type as raw bytes. It is about 20x faster than the JS loop at 1 KiB and 40x faster at 64 KiB, and faster than bufferutil at every size from 32 bytes up. Signed-off-by: James M Snell <jasnell@gmail.com>
ae2229e to
dc5a1d7
Compare
Add buffer.mask(source, mask, output[, offset[, length]]) and buffer.unmask(buffer, mask), which XOR data with a repeating 4-byte key. This is the masking that WebSocket clients apply to every frame they send (RFC 6455, Section 5.3), and that servers undo on every frame they receive.
undiciandws(without optional dependencies) both need mask and unmask. Thebufferutilnative addon makes it faster but it's an optional dependency that appears to only be installed withwsabout 3% of the time. So almost all users run the JS loop.Since we're shipping
undiciandWebSocketnow, it's worth making this faster.I put this on
bufferbecause it's an operation on a buffer but it's likely only useful forWebSocket, so we could just as easily expose it viahttp. I have no particular preference.For inputs < 24, the JS loop is still faster because we hit the floor of the C++ binding, even with fast apis. There's not much we can do about that. At larger sizes the perf boost is significant.