websocket13
Version:
Simple WebSocket protocol 13 client with no native or heavy dependencies
215 lines • 20.3 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const crypto_1 = require("crypto");
const http_1 = require("http");
const https_1 = require("https");
const os_1 = require("os");
const stdlib_1 = __importDefault(require("@doctormckay/stdlib"));
const url_1 = require("url");
const websocket_extensions_1 = __importDefault(require("websocket-extensions"));
const WebSocketBase_1 = __importDefault(require("./WebSocketBase"));
const State_1 = __importDefault(require("./enums/State"));
const WEBSOCKET_VERSION = 13;
// eslint-disable-next-line
const PACKAGE_VERSION = require('../package.json').version;
class WebSocket extends WebSocketBase_1.default {
constructor(url, options) {
super();
let parsedUri = (0, url_1.parse)(url);
switch (parsedUri.protocol.toLowerCase()) {
case 'ws:':
this.secure = false;
break;
case 'wss:':
this.secure = true;
break;
default:
throw new Error(`Unknown protocol scheme ${parsedUri.protocol}`);
}
options = options || {};
Object.assign(this.options, options);
let connectOptions = options.connection || {};
for (let element in parsedUri) {
if (parsedUri[element] !== null) {
connectOptions[element] = parsedUri[element];
}
}
connectOptions.protocol = this.secure ? 'https:' : 'http:';
this.hostname = parsedUri.hostname;
this.port = connectOptions.port = parseInt((parsedUri.port || (this.secure ? 443 : 80)).toString(), 10);
this.path = parsedUri.path || '/';
this._connectOptions = connectOptions;
// clone the headers object so we don't unexpectedly modify the object that was passed in
this.headers = JSON.parse(JSON.stringify(this.options.headers || {}));
// Lowercase all the header names so we don't conflict (but only if they aren't already lowercase)
for (let i in this.headers) {
if (i.toLowerCase() != i) {
this.headers[i.toLowerCase()] = this.headers[i];
delete this.headers[i];
}
}
this.headers.host = this.headers.host || parsedUri.host;
this.headers.upgrade = 'websocket';
this.headers.connection = 'Upgrade';
this.headers['sec-websocket-version'] = WEBSOCKET_VERSION;
this.headers['user-agent'] = this.headers['user-agent'] ||
[
`node.js/${process.versions.node} (${process.platform} ${(0, os_1.release)()} ${(0, os_1.arch)()})`,
`node-websocket13/${PACKAGE_VERSION}`
].join(' ');
// permessageDeflate defaults to true, so only if it's false should we disable it
if (this.options.permessageDeflate === false) {
this._extensions = new websocket_extensions_1.default();
}
let extOffer = this._extensions.generateOffer();
if (extOffer) {
this.headers['sec-websocket-extensions'] = extOffer;
}
if (this.options.protocols) {
this.options.protocols = this.options.protocols.map(protocol => protocol.trim().toLowerCase());
this.headers['sec-websocket-protocol'] = this.options.protocols.join(', ');
}
if (this.options.cookies) {
this.headers.cookie = Object.keys(this.options.cookies).map(name => name.trim() + '=' + encodeURIComponent(this.options.cookies[name])).join('; ');
}
this._type = 'client';
this._connect();
}
_generateNonce() {
this._nonce = (0, crypto_1.randomBytes)(16).toString('base64');
this.headers['sec-websocket-key'] = this._nonce;
}
_connect() {
this._generateNonce();
this.state = State_1.default.Connecting;
if (this.options.handshakeBody) {
this.headers['content-length'] = this.options.handshakeBody.length;
}
this._connectOptions.headers = this.headers;
if (this.secure && this.headers.host && typeof this._connectOptions.servername == 'undefined') {
this._connectOptions.servername = this.headers.host.split(':')[0];
}
if (this.options.httpProxy) {
if (this._connectOptions.agent) {
console.error('[websocket13] Warning: "agent" connection option specified; httpProxy option ignored');
}
else {
this._connectOptions.agent = stdlib_1.default.HTTP.getProxyAgent(this.secure, this.options.httpProxy, this.options.proxyTimeout);
}
}
let reqFunc = this.secure ? https_1.request : http_1.request;
let req = reqFunc(this._connectOptions, (res) => {
let serverHttpVersion = res.httpVersion;
let responseCode = res.statusCode;
let responseText = res.statusMessage;
let err = new Error();
err.responseCode = responseCode;
err.responseText = responseText;
err.httpVersion = serverHttpVersion;
err.headers = res.headers;
err.body = '';
res.on('data', chunk => {
err.body += chunk;
});
res.on('end', () => {
if (this.state != State_1.default.Connecting) {
return; // we don't care at this point
}
if (responseCode != 101) {
err.message = `Response code ${responseCode}`;
this._closeError(err);
return;
}
err.message = 'Server not upgrading connection';
this._closeError(err);
});
});
req.on('upgrade', (res, socket, head) => {
let serverHttpVersion = res.httpVersion;
let responseCode = res.statusCode;
let responseText = res.statusMessage;
let headers = res.headers;
let err = new Error();
err.responseCode = responseCode;
err.responseText = responseText;
err.httpVersion = serverHttpVersion;
err.headers = res.headers;
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;
}
if (!headers['sec-websocket-accept']) {
err.message = 'Missing Sec-WebSocket-Accept response header';
this._closeError(err);
return;
}
let hash = (0, crypto_1.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 (this.state == State_1.default.Closing) {
// we wanted to abort this connection
this.emit('debug', 'Closing newly-established connection due to abort');
socket.end();
socket.destroy();
return;
}
if (headers['sec-websocket-protocol']) {
let 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.protocol = protocol;
}
try {
this._extensions.activate(headers['sec-websocket-extensions']);
}
catch (ex) {
err.message = ex.message;
this._closeError(err);
return;
}
this._socket = socket;
this._prepSocketEvents();
this._resetUserTimeout();
// Everything is okay!
this.state = State_1.default.Connected;
let connectEventArgs = {
headers: headers,
httpVersion: serverHttpVersion,
responseCode,
responseText
};
this.emit('connected', connectEventArgs);
this.emit('connect', connectEventArgs); // save people from typos
this._onConnected();
if (head && head.length > 0) {
this._handleData(head);
}
});
req.on('error', (err) => {
if (this.state != State_1.default.Connecting) {
return;
}
err.state = this.state;
this.emit('error', err);
});
req.end(this.options.handshakeBody);
}
_sendFrame(frame, bypassQueue = false) {
frame.maskKey = (0, crypto_1.randomBytes)(4).readUInt32BE(0);
super._sendFrame(frame, bypassQueue);
}
}
exports.default = WebSocket;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ViU29ja2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1dlYlNvY2tldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG1DQUErQztBQUMvQywrQkFBbUU7QUFDbkUsaUNBQThDO0FBQzlDLDJCQUF3RDtBQUN4RCxpRUFBeUM7QUFDekMsNkJBQXNDO0FBQ3RDLGdGQUF1RDtBQUV2RCxvRUFBNEM7QUFHNUMsMERBQWtDO0FBRWxDLE1BQU0saUJBQWlCLEdBQUcsRUFBRSxDQUFDO0FBRTdCLDJCQUEyQjtBQUMzQixNQUFNLGVBQWUsR0FBRyxPQUFPLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxPQUFPLENBQUM7QUFFM0QsTUFBcUIsU0FBVSxTQUFRLHVCQUFhO0lBV25ELFlBQVksR0FBVyxFQUFFLE9BQWdDO1FBQ3hELEtBQUssRUFBRSxDQUFDO1FBRVIsSUFBSSxTQUFTLEdBQUcsSUFBQSxXQUFRLEVBQUMsR0FBRyxDQUFDLENBQUM7UUFFOUIsUUFBUSxTQUFTLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxFQUFFO1lBQ3pDLEtBQUssS0FBSztnQkFDVCxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztnQkFDcEIsTUFBTTtZQUVQLEtBQUssTUFBTTtnQkFDVixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztnQkFDbkIsTUFBTTtZQUVQO2dCQUNDLE1BQU0sSUFBSSxLQUFLLENBQUMsMkJBQTJCLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1NBQ2xFO1FBRUQsT0FBTyxHQUFHLE9BQU8sSUFBSSxFQUFFLENBQUM7UUFDeEIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRXJDLElBQUksY0FBYyxHQUFPLE9BQU8sQ0FBQyxVQUFVLElBQUksRUFBRSxDQUFDO1FBQ2xELEtBQUssSUFBSSxPQUFPLElBQUksU0FBUyxFQUFFO1lBQzlCLElBQUks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