mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-08 18:11:52 +00:00
LibWebSocket: Only call send() once on WebSocketImpl
The previous implementation would call send a half-dozen times when sending each frame of WebSocket data. This is excessive, especially since we need to allocate a new buffer for the payload in order to mask it anyway. Let's just allocate one buffer up front, and send all the completed data at the end of the method
This commit is contained in:
parent
c19ecf33d9
commit
ad985f3227
Notes:
github-actions[bot]
2025-02-20 22:06:19 +00:00
Author: https://github.com/ADKaster
Commit: ad985f3227
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3642
Reviewed-by: https://github.com/alimpfard ✅
1 changed files with 23 additions and 14 deletions
|
@ -534,8 +534,13 @@ void WebSocket::send_frame(WebSocket::OpCode op_code, ReadonlyBytes payload, boo
|
|||
{
|
||||
VERIFY(m_impl);
|
||||
VERIFY(m_state == WebSocket::InternalState::Open);
|
||||
|
||||
ByteBuffer buf = MUST(ByteBuffer::create_uninitialized(1 + 9 + 4 + payload.size()));
|
||||
size_t offset = 0;
|
||||
|
||||
u8 frame_head[1] = { (u8)((is_final ? 0x80 : 0x00) | ((u8)(op_code) & 0xf)) };
|
||||
m_impl->send(ReadonlyBytes(frame_head, 1));
|
||||
buf.overwrite(offset, frame_head, 1);
|
||||
offset += 1;
|
||||
// Section 5.1 : a client MUST mask all frames that it sends to the server
|
||||
bool has_mask = true;
|
||||
// FIXME: If the payload has a size > size_t max on a 32-bit platform, we could
|
||||
|
@ -555,7 +560,8 @@ void WebSocket::send_frame(WebSocket::OpCode op_code, ReadonlyBytes payload, boo
|
|||
(u8)((payload.size() >> 8) & 0xff),
|
||||
(u8)((payload.size() >> 0) & 0xff),
|
||||
};
|
||||
m_impl->send(ReadonlyBytes(payload_length, 9));
|
||||
buf.overwrite(offset, payload_length, 9);
|
||||
offset += 9;
|
||||
} else {
|
||||
u8 payload_length[9] = {
|
||||
(u8)((has_mask ? 0x80 : 0x00) | 127),
|
||||
|
@ -568,7 +574,8 @@ void WebSocket::send_frame(WebSocket::OpCode op_code, ReadonlyBytes payload, boo
|
|||
(u8)((payload.size() >> 8) & 0xff),
|
||||
(u8)((payload.size() >> 0) & 0xff),
|
||||
};
|
||||
m_impl->send(ReadonlyBytes(payload_length, 9));
|
||||
buf.overwrite(offset, payload_length, 9);
|
||||
offset += 9;
|
||||
}
|
||||
} else if (payload.size() >= 126) {
|
||||
// Send (the 'mask' flag + 126) + the 2-byte payload length
|
||||
|
@ -577,13 +584,15 @@ void WebSocket::send_frame(WebSocket::OpCode op_code, ReadonlyBytes payload, boo
|
|||
(u8)((payload.size() >> 8) & 0xff),
|
||||
(u8)((payload.size() >> 0) & 0xff),
|
||||
};
|
||||
m_impl->send(ReadonlyBytes(payload_length, 3));
|
||||
buf.overwrite(offset, payload_length, 3);
|
||||
offset += 3;
|
||||
} else {
|
||||
// Send the mask flag + the payload in a single byte
|
||||
u8 payload_length[1] = {
|
||||
(u8)((has_mask ? 0x80 : 0x00) | (u8)(payload.size() & 0x7f)),
|
||||
};
|
||||
m_impl->send(ReadonlyBytes(payload_length, 1));
|
||||
buf.overwrite(offset, payload_length, 1);
|
||||
offset += 1;
|
||||
}
|
||||
if (has_mask) {
|
||||
// Section 10.3 :
|
||||
|
@ -591,22 +600,22 @@ void WebSocket::send_frame(WebSocket::OpCode op_code, ReadonlyBytes payload, boo
|
|||
// > that cannot be predicted by end applications that provide data
|
||||
u8 masking_key[4];
|
||||
Crypto::fill_with_secure_random(masking_key);
|
||||
m_impl->send(ReadonlyBytes(masking_key, 4));
|
||||
buf.overwrite(offset, masking_key, 4);
|
||||
offset += 4;
|
||||
// don't try to send empty payload
|
||||
if (payload.size() == 0)
|
||||
return;
|
||||
// Mask the payload
|
||||
auto buffer_result = ByteBuffer::create_uninitialized(payload.size());
|
||||
if (!buffer_result.is_error()) {
|
||||
auto& masked_payload = buffer_result.value();
|
||||
for (size_t i = 0; i < payload.size(); ++i) {
|
||||
masked_payload[i] = payload[i] ^ (masking_key[i % 4]);
|
||||
}
|
||||
m_impl->send(masked_payload);
|
||||
auto masked_payload = buf.span().slice(offset, payload.size());
|
||||
for (size_t i = 0; i < payload.size(); ++i) {
|
||||
masked_payload[i] = payload[i] ^ (masking_key[i % 4]);
|
||||
}
|
||||
offset += payload.size();
|
||||
} else if (payload.size() > 0) {
|
||||
m_impl->send(payload);
|
||||
buf.overwrite(offset, payload.data(), payload.size());
|
||||
offset += payload.size();
|
||||
}
|
||||
m_impl->send(buf.span().slice(0, offset));
|
||||
}
|
||||
|
||||
void WebSocket::fatal_error(WebSocket::Error error)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue