
Security News
Socket Releases Free Certified Patches for Critical vm2 Sandbox Escape
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.
ws-low-level
Advanced tools
ws-low-level provides low-level functions to create a WebSocket server in Node.JS. It is promise-based and easy to get started with -- just use the example below.
The library is flexible and low-level enough to make your own customizations like:
request.url)Here is a complete example of a Node.JS WebSocket server using ws-low-level. For example, create a file named
websocket-server.js, place this code in the file, and run node websocket-server.js.
// websocket-server.js
import http from 'http';
import {
sendHandshake,
getMessagesFactory,
sendFactory,
prepareWebsocketFrame,
prepareCloseFramePayload
} from 'ws-low-level';
const httpServer = http.createServer(
function (
request /* <http.IncomingMessage> */,
response /* <http.ServerResponse> */
) {
// Handle HTTP messages by verbs like GET and POST (not part of ws-low-level)
}
);
httpServer.on('upgrade', function (
request /* <http.IncomingMessage> */,
socket /* <stream.Duplex> */ ,
head /* <Buffer> websocket header */
) {
console.log('upgrade');
const send =
sendFactory(socket);
const getMessages =
getMessagesFactory(
socket,
{
maxInMemoryStoreSize: 2147483648 // 2 GB
}
);
(async () => {
for await (
const {
payload /* <Promise> <Uint8Array> */,
opcode /* Integer <Number> from 0 to 15 */,
rsv1 /* Integer <Number> from 0 to 1 */,
rsv2 /* Integer <Number> from 0 to 1 */,
rsv3 /* Integer <Number> from 0 to 1 */,
mask /* Integer <Number> from 0 to 1 */
} of getMessages()
) {
if (
payload.length
&&
mask === 0
) {
// No masking from client, close the connection with a status code
send(
prepareWebsocketFrame(
prepareCloseFramePayload({
code: 1002,
reason: 'Websocket payload from client was not masked.'
}),
{
opcode: 0x8 /* Close */
}
)
);
}
switch (opcode) {
case 0x1:
// Text
const decoder =
new TextDecoder("utf-8");
console.log(
`received message ${decoder.decode(payload)}`
);
break;
case 0x2:
// Binary
console.log(
`received message with payload length ${payload.length}`
);
break;
case 0x9:
// Ping, respond with Pong
send(
prepareWebsocketFrame(
payload,
{
opcode: 0xA /* Pong */
}
)
);
break;
case 0xA:
// Pong
console.log("Pong");
break;
case 0x8:
// Close
console.log("Connection closed.");
break;
default:
console.log(
`received message with opcode ${opcode} payload length ${payload.length}`
);
}
}
})();
const headers =
[] /* Optional <Array> of well-formed header strings */;
sendHandshake(
request,
socket,
headers
);
// Send Ping
send(
prepareWebsocketFrame(
new Uint8Array(0),
{
opcode: 0x9 /* Ping */
}
)
);
const encoder =
new TextEncoder('utf-8');
// Send UTF-8 encoded message
send(
prepareWebsocketFrame(
new Uint8Array(
encoder.encode("Hello from the WebSocket server.")
),
{
isUtf8: true
}
)
);
});
httpServer.listen(3000);
Here is example html (place in an .html file like index.html) that would connect to the example server:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ws-low-level example webpage</title>
</head>
<body>
<script>
let ws = new WebSocket("ws://localhost:3000/");
ws.onopen = function() {
ws.send("Hello from the WebSocket");
}
</script>
</body>
</html>
The library exports the following functions. They can be imported and used in your Node webserver (see the example above).
function sendHandshake (
request /* <http.IncomingMessage> */,
socket /* <stream.Duplex> */,
headers /* <Array> of well-formatted http header strings */
) {
// ...
}
Send the handshake to establish the WebSocket connection. Pass the request and socket from http.on('upgrade'), and
optionally pass an array of header strings, for example to include a sec-websocket-extension or
sec-websocket-protocol.
function getMessagesFactory (
socket /* <stream.Duplex> */,
/* Optional options object */
{
/* Optional <Integer> of max in-memory message store size, in bytes. This is not enforced
* on small messages, which do not necessarily make use of the in-memory store class
*/
maxInMemoryStoreSize
} = {}
) {
// ...
}
Returns an async generator getMessages. Pass the socket object from http.on('upgrade'). The factory should only be
called once per endpoint/route.
function sendFactory (
socket /* <stream.Duplex> */
) {
//...
}
Returns a function send that accepts a frame. (Prepare a frame with the function prepareWebsocketFrame from
ws-low-level, below). Pass the socket object from http.on('upgrade'). The factory can be called multiple times to make multiple send functions.
function prepareWebsocketFrame (
payload /* <Uint8Array> */,
/* Optional options object */
{
isUtf8 = false /* <Boolean> */,
/* For advanced usage */
opcode /* Integer <Number> between 0 and 15 */,
fin = 1 /* Integer <Number> between 0 and 1 */,
rsv1 = 0 /* Integer <Number> between 0 and 1 */,
rsv2 = 0 /* Integer <Number> between 0 and 1 */,
rsv3 = 0 /* Integer <Number> between 0 and 1 */
} = {}
) {
//...
}
Make a WebSocket frame to prepare it for sending. Provide the payload, which is by default encoded as a binary frame
(opcode 2). Optionally provide an options object { isUtf8: true } to designate that the payload is encoded as UTF-8
text (opcode 1). Other opcodes can be optionally provided by providing an opcode in the options object. The fin bit
(for fragmenting messages) and the rsv1, rsv2 and rsv3 bits (for extensions) can also be set.
function prepareCloseFramePayload (
{
code /* Integer <Number> from 1000 to 65536 */,
reason = '' /* optional UTF-8 <String> */,
/* for advanced usage */
extensionData = new Uint8Array(0) /* optional <Uint8Array> */
} = {}
) {
// ...
}
Prepare the payload of a close frame. Provide a code and optionally a reason. Optionally provide extension data.
extended_payload_length.Copyright (c) 2024 Jon Lachlan.
GNU Public License v.3
FAQs
A Promise-based, low-level WebSocket server library
The npm package ws-low-level receives a total of 8 weekly downloads. As such, ws-low-level popularity was classified as not popular.
We found that ws-low-level demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A critical vm2 sandbox escape can allow untrusted JavaScript to break isolation and execute commands on the host Node.js process.

Research
Five malicious NuGet packages impersonate Chinese .NET libraries to deploy a stealer targeting browser credentials, crypto wallets, SSH keys, and local files.

Security News
pnpm 11 turns on a 1-day Minimum Release Age and blocks exotic subdeps by default, adding safeguards against fast-moving supply chain attacks.