Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

websocket13

Package Overview
Dependencies
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

websocket13 - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

.idea/libraries/websocket13_node_modules.xml

161

lib/base.js
var WS13 = require('./index.js');
var StreamedFrame = require('./streamedframe.js');
var StreamedOutgoingMessage = require('./StreamedOutgoingMessage.js');
var StreamedIncomingMessage = require('./StreamedIncomingMessage.js');

@@ -15,5 +16,12 @@ var Crypto = require('crypto');

this.options = {
"pingInterval": 10000,
"pingTimeout": 10000,
"pingFailures": 3
};
this._data = {};
this._outgoingFrames = []; // holds frame objects which we haven't sent yet
this._dataBuffer = new Buffer(0); // holds raw TCP data that we haven't processed yet
this._frameData = null; // holds the current frame for which we're still receiving payload data
this._incomingStream = null; // StreamedIncomingMessage object for the current message

@@ -76,3 +84,3 @@ this.on('connected', () => {

WebSocketBase.prototype.createMessageStream = function(type) {
var frame = new StreamedFrame(this, type);
var frame = new StreamedOutgoingMessage(this, type);
this._outgoingFrames.push(frame);

@@ -82,2 +90,45 @@ return frame;

WebSocketBase.prototype.data = function(key, value) {
var val = this._data[key];
if (typeof value === 'undefined') {
return val;
}
this._data[key] = value;
return val;
};
WebSocketBase.prototype._prepSocketEvents = function() {
this.remoteAddress = this._socket.remoteAddress;
this._socket.on('data', (data) => {
if ([WS13.State.Connected, WS13.State.Closing, WS13.State.ClosingError].indexOf(this.state) != -1) {
this._handleData(data);
}
});
this._socket.on('close', () => {
if (this.state == WS13.State.ClosingError) {
this.state = WS13.State.Closing;
return;
}
if (this.state == WS13.State.Closed) {
this.emit('debug', "Socket closed after successful websocket closure.");
return;
}
var state = this.state;
this.state = WS13.State.Closed;
this.emit('disconnected', WS13.StatusCode.AbnormalTermination, "Socket closed", state == WS13.State.Closing);
});
this._socket.on('error', (err) => {
err.state = this.state;
this.state = WS13.State.ClosingError;
this.emit('error', err);
});
};
WebSocketBase.prototype._queuePing = function() {

@@ -187,2 +238,9 @@ clearTimeout(this._pingTimer);

// We don't have any extensions, so all the RSV bits must be 0 or else we have to bail
if (frame.RSV1 || frame.RSV2 || frame.RSV3) {
var bit = (frame.RSV1 ? 'RSV1' : (frame.RSV2 ? 'RSV2' : 'RSV3'));
this._terminateError(WS13.StatusCode.ProtocolError, "Unexpected reserved bit " + bit + "set");
return;
}
this.emit('debug', "Got frame " + frame.opcode.toString(16).toUpperCase() + ", " + (frame.FIN ? "FIN, " : "") +

@@ -192,4 +250,3 @@ (frame.maskKey ? "MASK, " : "") + "payload " + frame.payload.length + " bytes");

if (
this.state != WS13.State.Connected &&
!(
this.state != WS13.State.Connected && !(
(this.state == WS13.State.ClosingError || this.state == WS13.State.Closing) &&

@@ -203,8 +260,14 @@ frame.opcode == WS13.FrameType.Control.Close

// Unmask if applicable
if (frame.maskKey !== null && frame.payload && frame.payload.length > 0) {
frame.payload = maskOrUnmask(frame.payload, frame.maskKey);
}
var payload;
// Is this a control frame?
// Is this a control frame? They need to be handled before anything else as they can be interjected between
// fragmented message frames.
if (frame.opcode & (1 << 3)) {
if (!frame.FIN) {
this._terminateError(new Error("Got a fragmented control frame " + frame.opcode.toString(16)));
this._terminateError(WS13.StatusCode.ProtocolError, "Got a fragmented control frame " + frame.opcode.toString(16));
return;

@@ -214,10 +277,6 @@ }

if (frame.payload.length > 125) {
this._terminateError(new Error("Got a control frame " + frame.opcode.toString(16) + " with invalid payload length " + frame.payload.length));
this._terminateError(WS13.StatusCode.ProtocolError, "Got a control frame " + frame.opcode.toString(16) + " with invalid payload length " + frame.payload.length);
return;
}
if (frame.maskKey !== null && frame.payload && frame.payload.length > 0) {
frame.payload = maskOrUnmask(frame.payload, frame.maskKey);
}
switch (frame.opcode) {

@@ -273,18 +332,43 @@ case WS13.FrameType.Control.Close:

// Sanity checks
if (!this._incomingStream && frame.opcode == WS13.FrameType.Continuation) {
this._terminateError(WS13.StatusCode.ProtocolError, "Received continuation frame without initial frame.");
return;
} else if (this._incomingStream && frame.opcode != WS13.FrameType.Continuation) {
this._terminateError(WS13.StatusCode.ProtocolError, "Received new message without finishing a fragmented one.");
return;
}
// Is this the first frame of a fragmented message?
if (!frame.FIN && !this._incomingStream) {
this.emit('debug', "Got first frame of fragmented message.");
var dispatch = this.listenerCount('streamedMessage') >= 1;
this._incomingStream = new StreamedIncomingMessage(frame, dispatch);
if (dispatch) {
this.emit('streamedMessage', frame.opcode, this._incomingStream);
}
this._incomingStream.on('end', data => {
if (!dispatch) {
var frame = this._incomingStream.frameHeader;
frame.payload = data;
frame.payloadLength = frame.payload.length;
this._dispatchDataFrame(frame);
}
});
return;
}
if (frame.opcode == WS13.FrameType.Continuation) {
this.emit('debug', "Got continuation frame");
var fin = frame.FIN;
payload = frame.payload;
this._incomingStream._frame(frame);
frame = this._frameData;
if (frame.FIN) {
this._incomingStream = null;
}
frame.FIN = fin;
frame.payload = Buffer.concat([frame.payload, payload]);
}
if (!frame.FIN) {
// There is more to come
// TODO: Expose a Stream interface for these
this.emit('debug', "Got non-FIN frame");
this._frameData = frame;
return;

@@ -295,7 +379,6 @@ }

// At this time we support no extensions so don't worry about extension data.
this._dispatchDataFrame(frame);
};
if (frame.maskKey !== null && frame.payload && frame.payload.length > 0) {
frame.payload = maskOrUnmask(frame.payload, frame.maskKey);
}
WebSocketBase.prototype._dispatchDataFrame = function(frame) {
switch (frame.opcode) {

@@ -325,3 +408,5 @@ case WS13.FrameType.Data.Text:

WebSocketBase.prototype._sendFrame = function(frame, bypassQueue) {
if (this.state != WS13.State.Connected) {
var isControl = !!(frame.opcode & (1 << 3));
if (this.state != WS13.State.Connected && !(this.state == WS13.State.Closing && isControl)) {
throw new Error("Cannot send data while not connected.");

@@ -334,3 +419,3 @@ }

if (frame.opcode & (1 << 3)) {
if (isControl) {
bypassQueue = true; // we can send control messages whenever

@@ -412,5 +497,5 @@ }

if (frame instanceof StreamedFrame) {
if (frame instanceof StreamedOutgoingMessage) {
if (!frame.started) {
this.emit('debug', "Starting StreamedFrame");
this.emit('debug', "Starting StreamedOutgoingMessage");
frame._start();

@@ -433,2 +518,6 @@ }

WebSocketBase.prototype._sendControl = function(opcode, payload) {
if (this.state == WS13.State.Closed || !this._socket) {
return;
}
this._sendFrame({

@@ -448,4 +537,8 @@ "opcode": opcode,

this.state = WS13.State.Closed;
this._socket.end();
this._socket.destroy();
if (this._socket) {
this._socket.end();
this._socket.destroy();
}
this.emit('error', err);

@@ -452,0 +545,0 @@ };

@@ -5,7 +5,6 @@ var WS13 = require('./index.js');

var parseUrl = require('url').parse;
var Net = require('net');
var TLS = require('tls');
var Http = require('http');
var Https = require('https');
var Crypto = require('crypto');
const HTTP_VERSION = 1.1;
const WEBSOCKET_VERSION = 13;

@@ -34,8 +33,2 @@

this.options = {
"pingInterval": 10000,
"pingTimeout": 10000,
"pingFailures": 3
};
options = options || {};

@@ -48,4 +41,13 @@ for (var option in options) {

this._connectOptions = options.connection || {};
for (var element in uri) {
if (uri.hasOwnProperty(element) && uri[element] !== null) {
this._connectOptions[element] = uri[element];
}
}
this._connectOptions.protocol = this.secure ? "https:" : "http:";
this.hostname = uri.hostname;
this.port = parseInt(uri.port || (this.secure ? 443 : 80), 10);
this.port = this._connectOptions.port = parseInt(uri.port || (this.secure ? 443 : 80), 10);
this.path = uri.path || '/';

@@ -72,3 +74,5 @@

// TODO: Cookies
if (this.options.cookies) {
this.headers.cookie = Object.keys(this.options.cookies).map(name => name.trim() + '=' + encodeURIComponent(this.options.cookies[name])).join('; ');
}

@@ -88,163 +92,125 @@ this._connect();

var connectOptions = this.options.connection || {};
connectOptions.port = this.port;
connectOptions.host = this.hostname;
this._socket = Net.connect(connectOptions);
var event = 'connect';
if (this.secure) {
connectOptions.socket = this._socket;
this._socket = TLS.connect(connectOptions);
event = 'secureConnect';
if (this.options.handshakeBody) {
this.headers['content-length'] = this.options.handshakeBody.length;
}
this._socket.on(event, () => {
// Time to send the handshake
this._socket.write("GET " + this.path + " HTTP/" + HTTP_VERSION + "\r\n");
this._connectOptions.headers = this.headers;
this._connectOptions.agent = false;
// Send headers
for (var name in this.headers) {
if (this.headers.hasOwnProperty(name)) {
this._socket.write(name + ": " + this.headers[name] + "\r\n");
}
}
var req = (this.secure ? Https : Http).request(this._connectOptions, (res) => {
var serverHttpVersion = res.httpVersion;
var responseCode = res.statusCode;
var responseText = res.statusMessage;
this._socket.write("\r\n");
});
var err = new Error();
err.responseCode = responseCode;
err.responseText = responseText;
err.httpVersion = serverHttpVersion;
err.headers = res.headers;
var handshakeBuffer = '';
err.body = '';
this._socket.on('data', (data) => {
switch (this.state) {
case WS13.State.Connecting:
handshakeBuffer += data.toString('ascii');
var pos = handshakeBuffer.indexOf("\r\n\r\n");
if (pos != -1) {
// Anything after these characters is actual websocket data
this._handleData(new Buffer(handshakeBuffer.slice(pos + 4), 'ascii'));
handshakeBuffer = handshakeBuffer.substring(0, pos);
res.on('data', chunk => {
err.body += chunk;
});
// Now we have our full headers
var lines = handshakeBuffer.split("\r\n");
var match = lines[0].match(/^HTTP\/(\d+\.\d+) (\d+) (.+)$/);
if (!match) {
this._closeError(new Error("Malformed handshake response"));
return;
}
res.on('end', () => {
if (this.state != WS13.State.Connecting) {
return; // we don't care at this point
}
var serverHttpVersion = match[1];
var responseCode = parseInt(match[2], 10);
var responseText = match[3];
if (responseCode != 101) {
err.message = "Response code " + responseCode;
this._closeError(err);
return;
}
var err = new Error();
err.responseCode = responseCode;
err.responseText = responseText;
err.httpVersion = serverHttpVersion;
err.message = "Server not upgrading connection";
this._closeError(err);
});
});
if (responseCode != 101) {
err.message = "Response code " + responseCode;
this._closeError(err);
return;
}
req.on('upgrade', (res, socket, head) => {
var serverHttpVersion = res.httpVersion;
var responseCode = res.statusCode;
var responseText = res.statusMessage;
var headers = res.headers;
// Parse out our headers
var headers = {};
lines.slice(1).forEach(line => {
match = line.match(/^([^:]+): ?(.+)$/);
if (!match) {
// Malformed response header, let's just ignore it
return;
}
var err = new Error();
err.responseCode = responseCode;
err.responseText = responseText;
err.httpVersion = serverHttpVersion;
err.headers = res.headers;
headers[match[1].toLowerCase()] = match[2].trim();
});
if (!headers.upgrade || !headers.connection || !headers.upgrade.match(/websocket/i) || !headers.connection.match(/upgrade/i)) {
err.message = "Invalid server upgrade response";
this._closeError(err);
return;
}
err.headers = headers;
if (!headers['sec-websocket-accept']) {
err.message = "Missing Sec-WebSocket-Accept response header";
this._closeError(err);
return;
}
if (!headers.upgrade || !headers.connection || !headers.upgrade.match(/websocket/i) || !headers.connection.match(/upgrade/i)) {
err.message = "Server not upgrading connection";
this._closeError(err);
return;
}
var hash = Crypto.createHash('sha1').update(this._nonce + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest('base64');
if (headers['sec-websocket-accept'] != hash) {
err.message = "Mismatching Sec-WebSocket-Accept header";
err.expected = hash;
err.actual = headers['sec-websocket-accept'];
this._closeError(err);
return;
}
if (!headers['sec-websocket-accept']) {
err.message = "Missing Sec-WebSocket-Accept response header";
this._closeError(err);
return;
}
if (headers['sec-websocket-extensions']) {
var extensions = headers['sec-websocket-extensions'].split(',').map(item => item.trim().toLowerCase());
var unsupported = extensions.filter(extension => this.extensions.indexOf(extension) == -1);
if (unsupported.length > 0) {
err.message = "Server is using unsupported extension" + (unsupported.length > 1 ? "s" : "") + unsupported.join(', ');
this._closeError(err);
return;
}
var hash = Crypto.createHash('sha1').update(this._nonce + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest('base64');
if (headers['sec-websocket-accept'] != hash) {
err.message = "Mismatching Sec-WebSocket-Accept header";
err.expected = hash;
err.actual = headers['sec-websocket-accept'];
this._closeError(err);
return;
}
this.extensions = extensions;
}
if (headers['sec-websocket-extensions']) {
var extensions = headers['sec-websocket-extensions'].split(',').map(item => item.trim().toLowerCase());
var unsupported = extensions.filter(extension => this.extensions.indexOf(extension) == -1);
if (unsupported.length > 0) {
err.message = "Server is using unsupported extension" + (unsupported.length > 1 ? "s" : "") + unsupported.join(', ');
this._closeError(err);
return;
}
if (headers['sec-websocket-protocol']) {
var protocol = headers['sec-websocket-protocol'].toLowerCase();
if (this.options.protocols.indexOf(protocol) == -1) {
err.message = "Server is using unsupported protocol " + protocol;
this._closeError(err);
return;
}
this.extensions = extensions;
}
this.protocol = protocol;
}
if (headers['sec-websocket-protocol']) {
var protocol = headers['sec-websocket-protocol'].toLowerCase();
if (this.options.protocols.indexOf(protocol) == -1) {
err.message = "Server is using unsupported protocol " + protocol;
this._closeError(err);
return;
}
this._socket = socket;
this._prepSocketEvents();
this.protocol = protocol;
}
// Everything is okay!
this.state = WS13.State.Connected;
this.emit('connected', {
"headers": headers,
"httpVersion": serverHttpVersion,
"responseCode": responseCode,
"responseText": responseText
});
// Everything is okay!
this.state = WS13.State.Connected;
this.emit('connected', {
"headers": headers,
"httpVersion": serverHttpVersion,
"responseCode": responseCode,
"responseText": responseText
});
}
break;
case WS13.State.Connected:
case WS13.State.Closing:
case WS13.State.ClosingError:
this._handleData(data);
break;
if (head && head.length > 0) {
this._handleData(head);
}
});
this._socket.on('close', () => {
if (this.state == WS13.State.ClosingError) {
this.state = WS13.State.Closing;
req.on('error', (err) => {
if (this.state != WS13.State.Connecting) {
return;
}
if (this.state == WS13.State.Closed) {
this.emit('debug', "Socket closed after successful websocket closure.");
return;
}
var state = this.state;
this.state = WS13.State.Closed;
this.emit('disconnected', WS13.StatusCode.AbnormalTermination, "Socket closed", state == WS13.State.Closing);
});
this._socket.on('error', (err) => {
err.state = this.state;
this.state = WS13.State.ClosingError;
this.emit('error', err);
});
req.end(this.options.handshakeBody);
};

@@ -251,0 +217,0 @@

@@ -41,1 +41,2 @@ exports.State = {

require('./client.js');
require('./server.js');
{
"name": "websocket13",
"version": "1.0.0",
"version": "1.1.0",
"description": "Simple WebSocket protocol 13 client with no native or heavy dependencies",

@@ -5,0 +5,0 @@ "author": "Alexander Corn <mckay@doctormckay.com>",

# WebSockets for Node.js
[![npm version](https://img.shields.io/npm/v/websocket13.svg)](https://www.npmjs.com/package/websocket13)
[![npm downloads](https://img.shields.io/npm/dm/websocket13.svg)](https://npmjs.com/package/websocket13)
[![dependencies](https://img.shields.io/david/DoctorMcKay/node-websocket13.svg)](https://david-dm.org/DoctorMcKay/node-websocket13)
[![license](https://img.shields.io/npm/l/websocket13.svg)](https://github.com/DoctorMcKay/node-websocket13/blob/master/LICENSE)
[![paypal](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=N36YVAT42CZ4G&item_name=node%2dwebsocket13&currency_code=USD)

@@ -7,313 +12,10 @@ This is a pure-JavaScript implementation of [WebSockets version 13](https://tools.ietf.org/html/rfc6455).

# Installation and Example
**Requires node.js v4.0.0 or later.**
Install it from npm:
# Documentation
$ npm install websocket13
Please see the [GitHub wiki](https://github.com/DoctorMcKay/node-websocket13/wiki) for documentation.
Exports a `WS13` namespace, which contains a few object-enums and the `WebSocket` object.
```js
var WS13 = require('websocket13');
var socket = new WebSocket('wss://echo.websocket.org', {
"pingInterval": 10000, // default
"pingTimeout": 10000, // default
"pingFailures": 3 // default
"headers": {
"Origin": "http://example.com"
},
"protocols": ["some_subprotocol", "some_other_subprotocol"],
"connection": {
"servername": "echo.websocket.org", // for SNI
"rejectUnauthorized": false // to not reject self-signed or otherwise invalid certificates
}
});
socket.on('connected', function(info) {
console.log("Successfully connected to echo server with HTTP version %s, HTTP status code %d, and HTTP status text %s. Headers follow.",
info.httpVersion, info.responseCode, info.responseText);
console.log(info.headers);
socket.send("This is a string message.");
var buffer = new Buffer(8);
buffer.writeUInt32BE(1337, 0);
buffer.writeUInt32BE(8675309, 4);
socket.send(buffer);
setTimeout(() => {
socket.disconnect(WS13.StatusCode.NormalClosure, "Bye bye!");
}, 5000);
});
socket.on('message', function(type, data) {
switch (type) {
case WS13.FrameType.Data.Text:
console.log("Received text: %s", data);
break;
case WS13.FrameType.Data.Binary:
console.log("Received binary data containing two integers: %d and %d.",
data.readUInt32BE(0), data.readUInt32BE(4));
break;
}
});
socket.on('disconnected', function(code, reason, initiatedByUs) {
console.log("Disconnected from echo server with code %d and reason string '%s'. Disconnection %s initiated by us.",
code, reason, initiatedByUs ? "was" : "was NOT");
});
socket.on('error', function(err) {
console.log("Fatal error: %s", err.message);
});
```
# Features
- Very lightweight. Only one dependency (directly; two dependencies counting nested dependencies).
- No native dependencies
- Easy-to-use API
- Supports the latest version of the WebSocket protocol
- TLS support
- Supports WebSocket subprotocols
- Able to automatically send ping requests to the server at a customizable interval, and tear down the connection when the server stops responding
- Supports both UTF-8 and binary data
- Transparent framing removes the need to buffer the TCP connection yourself
- `Stream` interface to which data can be written or piped, and appear on the other side as a single message
# Enums
There are a few enums (implemented as objects) available from the root namespace object that is returned by `websocket13`.
These are:
```js
WS13.State = {
"Closed": 0,
"Connecting": 1,
"Connected": 2,
"Closing": 3,
"ClosingError": 4
};
WS13.FrameType = {
"Continuation": 0x0,
"Data": {
"Text": 0x1,
"Binary": 0x2
},
"Control": {
"Close": 0x8,
"Ping": 0x9,
"Pong": 0xA
}
};
WS13.StatusCode = {
"NormalClosure": 1000, /** Graceful disconnection */
"EndpointGoingAway": 1001, /** Closing connection because either the server or the client is going down (e.g. browser navigating away) */
"ProtocolError": 1002, /** Either side is terminating the connection due to a protocol error */
"UnacceptableDataType": 1003, /** Terminating because either side received data that it can't accept or process */
"Reserved1": 1004, /** Reserved. Do not use. */
"NoStatusCode": 1005, /** MUST NOT be sent over the wire. Used internally when no status code was sent. */
"AbnormalTermination": 1006, /** MUST NOT be sent over the wire. Used internally when the connection is closed without sending/receiving a Close frame. */
"InconsistentData": 1007, /** Terminating because either side received data that wasn't consistent with the expected type */
"PolicyViolation": 1008, /** Generic. Terminating because either side received a message that violated its policy */
"MessageTooBig": 1009, /** Terminating because either side received a message that is too big to process */
"MissingExtension": 1010, /** Client is terminating because the server didn't negotiate one or more extensions that we require */
"UnexpectedCondition": 1011, /** Server is terminating because it encountered an unexpected condition that prevented it from fulfilling the request */
"TLSFailed": 1015 /** MUST NOT be sent over the wire. Used internally when TLS handshake fails. */
};
```
# Constructor
To construct a new WebSocket client, use this signature:
WebSocket(uri[, options])
`uri` should be a string containing the URI to which you want to connect. The protocol must be either `ws://` for
insecure, or `wss://` for secure. For example: `wss://echo.websocket.org:443/?query=string`.
`options` should be an object containing zero or more of the properties in the following section. You can omit it if
you don't wish to pass any options.
The WebSocket will immediately attempt to connect after being constructed. If you want to reconnect after being
disconnected, you should construct a new one.
# Options
### pingInterval
Defaults to `10000`. The time in milliseconds between `Ping` requests that we send to the server automatically.
### pingTimeout
Defaults to `10000`. The time in milliseconds that we will wait for a `Pong` in reply to a `Ping` request (controlled
by the `pingInterval` option).
### pingFailures
Defaults to `3`. After this many `Ping` requests timeout, the WebSocket will be closed and `error` will be emitted
with `message` equaling `Ping timeout`.
### headers
An object containing any HTTP headers which will be added to the connection handshake. The following headers are
reserved for internal use and will be ignored:
- Host
- Upgrade
- Connection
- Sec-WebSocket-Version
- Sec-WebSocket-Protocol
- Sec-WebSocket-Key
### protocols
An array of strings containing acceptable subprotocols. These will be sent to the server in the connection handshake
and if any are acceptable, the server will choose one. The chosen subprotocol will be assigned to the `protocol`
property in the [`connected`](#connected) event.
### connection
An object which will be passed to [`net.connect`](https://nodejs.org/api/net.html#net_net_connect_options_connectlistener)
(and [`tls.connect`](https://nodejs.org/api/tls.html#tls_tls_connect_options_callback) if secure) as `options`. Here you
can bind to a specific local interface, configure TLS options, and more.
# Properties
### options
**Read-only.** The options object which you provided to the constructor.
### hostname
The hostname or IP address of the server to which we're connected.
### port
The port to which we're connected on the server.
### path
The request path of the handshake.
### headers
An object containing the HTTP headers we sent in the handshake.
### state
A value from the `WS13.State` enum representing our current connection state.
### extensions
An array containing the WebSocket extensions which are currently in use. Currently, none are supported so this will be
empty.
### protocol
The subprotocol chosen by the server, if any. `null` if none.
# Methods
### disconnect([code][, reason])
- `code` - A value from the `WS13.StatusCode` enum describing why we're disconnecting. Defaults to `NormalClosure`.
- `reason` - An optional string explaining why we're disconnecting. Does not need to be human-readable. Defaults to empty.
Begins our side of the disconnection process. [`disconnected`](#disconnected) will be emitted when fully disconnected.
You cannot send any more data after calling `disconnect()`.
### send(data)
- `data` - Either a `string` or `Buffer` containing the data you want to send
Sends either UTF-8 string or binary data to the server. If `data` is a `string`, it must be valid UTF-8. Otherwise, it
must be a `Buffer` containing the binary data you wish to send. Since the WebSocket protocol has transparent framing,
unlike plain TCP, the data will be received in one whole message. Therefore, one `send()` call maps to exactly one
received message on the other side.
The message will be queued and sent after every message before it is sent. If you have an ongoing
[`StreamedFrame`](#streamedframe), it will be delayed until after the entire stream is sent.
### createMessageStream(type)
- `type` - A value from the `WS13.FrameType.Data` enum representing what kind of data is to be sent
Creates and returns a new [`StreamedFrame`](#streamedframe) object. See the [`StreamedFrame` documentation](#streamedframe)
for more information.
# Events
### connected
- `details` - An object containing details about your connection
- `httpVersion` - The HTTP version used by the server
- `responseCode` - The HTTP response code sent by the server (always `101`)
- `responseText` - The HTTP response text sent by the server (usually `Switching Protocols`)
- `headers` - An object containing the HTTP headers received from the server
Emitted when we successfully establish a WebSocket connection to the server. At this point, the [`state`](#state)
property will equal `WS13.State.Connected`, the [`extensions`](#extensions) array will be populated with any extensions
that are in use, and the [`protocol`](#protocol) property will be defined with the subprotocol selected by the server,
if any. You can now safely send and receive data.
### disconnected
- `code` - A value from the `WS13.StatusCode` enum
- `reason` - A string (possibly empty) which may or may not be human-readable describing why you disconnceted
- `initiatedByUs` - `true` if we initiated this disconnection, or `false` if the server condition did
Emitted when we're disconnected from the server. Not emitted if we're disconnected due to an error; see [`error`](#error)
in that case.
### error
- `err` - An `Error` object
Emitted when a fatal error causes our connection to fail (while connecting) or be disconnected (while connected). Under
certain conditions, `err` may contain zero or more of these properties:
- `responseCode` - The HTTP status code we received if the error occurred during the handshake
- `responseText` - The HTTP status text we received if the error occurred during the handshake
- `httpVersion` - The HTTP version employed by the server if the error occurred during the handshake
- `headers` - An object containing the HTTP headers we received from the server if the error occurred during the handshake
- `expected` - A string containing the `Sec-WebSocket-Accept` value we expected to receive, if the error occurred because we didn't
- `actual` - A string containing the actual `Sec-WebSocket-Accept` value we received, if the error occurred because it didn't match what we expected
- `state` - The connection state at the time of error. Always present.
- `code` - A value from the `WS13.StatusCode` enum, if the error occurred after the WebSocket connection was established
### message
- `type` - A value from the `WS13.FrameType.Data` enum describing what type of data we received
- `data` - The data we received
Emitted when we receive a complete message from the server. If `type` is `Text`, then `data` is a UTF-8 string.
If `type` is `Binary`, then `data` is a `Buffer`.
# StreamedFrame
Messages are sent over WebSockets in *frames*. Usually, a frame contains one complete message. However, the WebSocket
protocol also allows messages to be split up across multiple frames. This is useful when the entire data isn't available
at the time of sending, and you'd like to stream it to the other side. In this case, call
[`createMessageStream`](#createmessagestreamtype), which returns a `StreamedFrame` object.
`StreamedFrame` implements the [`Writable`](https://nodejs.org/api/stream.html#stream_class_stream_writable) interface.
To send a chunk of data to the server, just call `frame.write(chunk)`. When you're done, call `frame.end()`.
Because this implements the `Writable` interface, you can `pipe()` a `ReadableStream` into it. One use-case would be to
pipe a download or a file on the disk into a WebSocket.
One frame can contain only one type of data. This data type is set in the `createMessageStream` method, and is fixed
for the lifetime of the `StreamedFrame`. Therefore, if your data type is `Text`, you must only call `write()` with
UTF-8 strings. If it's `Binary`, you must only call `write()` with `Buffer` objects. If you call `write()` with the
wrong data type, the `StreamedFrame` will emit an `error`.
You *can* call `send()` or create new `StreamedFrame`s while you have one ongoing, but they will be queued and cannot
be sent to the server until the currently-active `StreamedFrame` is ended. Be sure to call `end()` when you're done
writing data to it.
# Planned Features
- `StreamedFrame` support for incoming multi-frame messages. Currently they're just buffered internally and `message` is emitted when all frames are received.
- Server support
- Support for cookies in handshake
- [Per-message compression](https://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-28)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc