Comparing version 6.1.4 to 6.2.0
'use strict'; | ||
const { EMPTY_BUFFER } = require('./constants'); | ||
/** | ||
@@ -12,2 +14,5 @@ * Merges an array of buffers into a new buffer. | ||
function concat(list, totalLength) { | ||
if (list.length === 0) return EMPTY_BUFFER; | ||
if (list.length === 1) return list[0]; | ||
const target = Buffer.allocUnsafe(totalLength); | ||
@@ -56,2 +61,61 @@ var offset = 0; | ||
/** | ||
* Converts a buffer to an `ArrayBuffer`. | ||
* | ||
* @param {Buffer} buf The buffer to convert | ||
* @return {ArrayBuffer} Converted buffer | ||
* @public | ||
*/ | ||
function toArrayBuffer(buf) { | ||
if (buf.byteLength === buf.buffer.byteLength) { | ||
return buf.buffer; | ||
} | ||
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); | ||
} | ||
/** | ||
* Converts `data` to a `Buffer`. | ||
* | ||
* @param {*} data The data to convert | ||
* @return {Buffer} The buffer | ||
* @throws {TypeError} | ||
* @public | ||
*/ | ||
function toBuffer(data) { | ||
toBuffer.readOnly = true; | ||
if (Buffer.isBuffer(data)) return data; | ||
var buf; | ||
if (data instanceof ArrayBuffer) { | ||
buf = Buffer.from(data); | ||
} else if (ArrayBuffer.isView(data)) { | ||
buf = viewToBuffer(data); | ||
} else { | ||
buf = Buffer.from(data); | ||
toBuffer.readOnly = false; | ||
} | ||
return buf; | ||
} | ||
/** | ||
* Converts an `ArrayBuffer` view into a buffer. | ||
* | ||
* @param {(DataView|TypedArray)} view The view to convert | ||
* @return {Buffer} Converted view | ||
* @private | ||
*/ | ||
function viewToBuffer(view) { | ||
const buf = Buffer.from(view.buffer); | ||
if (view.byteLength !== view.buffer.byteLength) { | ||
return buf.slice(view.byteOffset, view.byteOffset + view.byteLength); | ||
} | ||
return buf; | ||
} | ||
try { | ||
@@ -62,2 +126,3 @@ const bufferUtil = require('bufferutil'); | ||
module.exports = { | ||
concat, | ||
mask(source, mask, output, offset, length) { | ||
@@ -67,10 +132,17 @@ if (length < 48) _mask(source, mask, output, offset, length); | ||
}, | ||
toArrayBuffer, | ||
toBuffer, | ||
unmask(buffer, mask) { | ||
if (buffer.length < 32) _unmask(buffer, mask); | ||
else bu.unmask(buffer, mask); | ||
}, | ||
concat | ||
} | ||
}; | ||
} catch (e) /* istanbul ignore next */ { | ||
module.exports = { concat, mask: _mask, unmask: _unmask }; | ||
module.exports = { | ||
concat, | ||
mask: _mask, | ||
toArrayBuffer, | ||
toBuffer, | ||
unmask: _unmask | ||
}; | ||
} |
'use strict'; | ||
const stream = require('stream'); | ||
const { Writable } = require('stream'); | ||
const PerMessageDeflate = require('./permessage-deflate'); | ||
const bufferUtil = require('./buffer-util'); | ||
const validation = require('./validation'); | ||
const constants = require('./constants'); | ||
const { | ||
BINARY_TYPES, | ||
EMPTY_BUFFER, | ||
kStatusCode, | ||
kWebSocket | ||
} = require('./constants'); | ||
const { concat, toArrayBuffer, unmask } = require('./buffer-util'); | ||
const { isValidStatusCode, isValidUTF8 } = require('./validation'); | ||
@@ -22,3 +27,3 @@ const GET_INFO = 0; | ||
*/ | ||
class Receiver extends stream.Writable { | ||
class Receiver extends Writable { | ||
/** | ||
@@ -34,4 +39,4 @@ * Creates a Receiver instance. | ||
this._binaryType = binaryType || constants.BINARY_TYPES[0]; | ||
this[constants.kWebSocket] = undefined; | ||
this._binaryType = binaryType || BINARY_TYPES[0]; | ||
this[kWebSocket] = undefined; | ||
this._extensions = extensions || {}; | ||
@@ -320,3 +325,3 @@ this._maxPayload = maxPayload | 0; | ||
getData(cb) { | ||
var data = constants.EMPTY_BUFFER; | ||
var data = EMPTY_BUFFER; | ||
@@ -330,3 +335,3 @@ if (this._payloadLength) { | ||
data = this.consume(this._payloadLength); | ||
if (this._masked) bufferUtil.unmask(data, this._mask); | ||
if (this._masked) unmask(data, this._mask); | ||
} | ||
@@ -405,5 +410,5 @@ | ||
if (this._binaryType === 'nodebuffer') { | ||
data = toBuffer(fragments, messageLength); | ||
data = concat(fragments, messageLength); | ||
} else if (this._binaryType === 'arraybuffer') { | ||
data = toArrayBuffer(toBuffer(fragments, messageLength)); | ||
data = toArrayBuffer(concat(fragments, messageLength)); | ||
} else { | ||
@@ -415,5 +420,5 @@ data = fragments; | ||
} else { | ||
const buf = toBuffer(fragments, messageLength); | ||
const buf = concat(fragments, messageLength); | ||
if (!validation.isValidUTF8(buf)) { | ||
if (!isValidUTF8(buf)) { | ||
this._loop = false; | ||
@@ -449,3 +454,3 @@ return error(Error, 'invalid UTF-8 sequence', true, 1007); | ||
if (!validation.isValidStatusCode(code)) { | ||
if (!isValidStatusCode(code)) { | ||
return error(RangeError, `invalid status code ${code}`, true, 1002); | ||
@@ -456,3 +461,3 @@ } | ||
if (!validation.isValidUTF8(buf)) { | ||
if (!isValidUTF8(buf)) { | ||
return error(Error, 'invalid UTF-8 sequence', true, 1007); | ||
@@ -493,32 +498,4 @@ } | ||
Error.captureStackTrace(err, error); | ||
err[constants.kStatusCode] = statusCode; | ||
err[kStatusCode] = statusCode; | ||
return err; | ||
} | ||
/** | ||
* Makes a buffer from a list of fragments. | ||
* | ||
* @param {Buffer[]} fragments The list of fragments composing the message | ||
* @param {Number} messageLength The length of the message | ||
* @return {Buffer} | ||
* @private | ||
*/ | ||
function toBuffer(fragments, messageLength) { | ||
if (fragments.length === 1) return fragments[0]; | ||
if (fragments.length > 1) return bufferUtil.concat(fragments, messageLength); | ||
return constants.EMPTY_BUFFER; | ||
} | ||
/** | ||
* Converts a buffer to an `ArrayBuffer`. | ||
* | ||
* @param {Buffer} buf The buffer to convert | ||
* @return {ArrayBuffer} Converted buffer | ||
*/ | ||
function toArrayBuffer(buf) { | ||
if (buf.byteLength === buf.buffer.byteLength) { | ||
return buf.buffer; | ||
} | ||
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); | ||
} |
'use strict'; | ||
const crypto = require('crypto'); | ||
const { randomBytes } = require('crypto'); | ||
const PerMessageDeflate = require('./permessage-deflate'); | ||
const bufferUtil = require('./buffer-util'); | ||
const validation = require('./validation'); | ||
const constants = require('./constants'); | ||
const { EMPTY_BUFFER } = require('./constants'); | ||
const { isValidStatusCode } = require('./validation'); | ||
const { mask: applyMask, toBuffer } = require('./buffer-util'); | ||
@@ -80,3 +80,3 @@ /** | ||
const mask = crypto.randomBytes(4); | ||
const mask = randomBytes(4); | ||
@@ -90,7 +90,7 @@ target[1] = payloadLength | 0x80; | ||
if (merge) { | ||
bufferUtil.mask(data, mask, target, offset, data.length); | ||
applyMask(data, mask, target, offset, data.length); | ||
return [target]; | ||
} | ||
bufferUtil.mask(data, mask, data, 0, data.length); | ||
applyMask(data, mask, data, 0, data.length); | ||
return [target, data]; | ||
@@ -112,7 +112,4 @@ } | ||
if (code === undefined) { | ||
buf = constants.EMPTY_BUFFER; | ||
} else if ( | ||
typeof code !== 'number' || | ||
!validation.isValidStatusCode(code) | ||
) { | ||
buf = EMPTY_BUFFER; | ||
} else if (typeof code !== 'number' || !isValidStatusCode(code)) { | ||
throw new TypeError('First argument must be a valid error code number'); | ||
@@ -165,19 +162,8 @@ } else if (data === undefined || data === '') { | ||
ping(data, mask, cb) { | ||
var readOnly = true; | ||
const buf = toBuffer(data); | ||
if (!Buffer.isBuffer(data)) { | ||
if (data instanceof ArrayBuffer) { | ||
data = Buffer.from(data); | ||
} else if (ArrayBuffer.isView(data)) { | ||
data = viewToBuffer(data); | ||
} else { | ||
data = Buffer.from(data); | ||
readOnly = false; | ||
} | ||
} | ||
if (this._deflating) { | ||
this.enqueue([this.doPing, data, mask, readOnly, cb]); | ||
this.enqueue([this.doPing, buf, mask, toBuffer.readOnly, cb]); | ||
} else { | ||
this.doPing(data, mask, readOnly, cb); | ||
this.doPing(buf, mask, toBuffer.readOnly, cb); | ||
} | ||
@@ -217,19 +203,8 @@ } | ||
pong(data, mask, cb) { | ||
var readOnly = true; | ||
const buf = toBuffer(data); | ||
if (!Buffer.isBuffer(data)) { | ||
if (data instanceof ArrayBuffer) { | ||
data = Buffer.from(data); | ||
} else if (ArrayBuffer.isView(data)) { | ||
data = viewToBuffer(data); | ||
} else { | ||
data = Buffer.from(data); | ||
readOnly = false; | ||
} | ||
} | ||
if (this._deflating) { | ||
this.enqueue([this.doPong, data, mask, readOnly, cb]); | ||
this.enqueue([this.doPong, buf, mask, toBuffer.readOnly, cb]); | ||
} else { | ||
this.doPong(data, mask, readOnly, cb); | ||
this.doPong(buf, mask, toBuffer.readOnly, cb); | ||
} | ||
@@ -273,23 +248,11 @@ } | ||
send(data, options, cb) { | ||
const buf = toBuffer(data); | ||
const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; | ||
var opcode = options.binary ? 2 : 1; | ||
var rsv1 = options.compress; | ||
var readOnly = true; | ||
if (!Buffer.isBuffer(data)) { | ||
if (data instanceof ArrayBuffer) { | ||
data = Buffer.from(data); | ||
} else if (ArrayBuffer.isView(data)) { | ||
data = viewToBuffer(data); | ||
} else { | ||
data = Buffer.from(data); | ||
readOnly = false; | ||
} | ||
} | ||
const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; | ||
if (this._firstFragment) { | ||
this._firstFragment = false; | ||
if (rsv1 && perMessageDeflate) { | ||
rsv1 = data.length >= perMessageDeflate._threshold; | ||
rsv1 = buf.length >= perMessageDeflate._threshold; | ||
} | ||
@@ -310,13 +273,13 @@ this._compress = rsv1; | ||
mask: options.mask, | ||
readOnly | ||
readOnly: toBuffer.readOnly | ||
}; | ||
if (this._deflating) { | ||
this.enqueue([this.dispatch, data, this._compress, opts, cb]); | ||
this.enqueue([this.dispatch, buf, this._compress, opts, cb]); | ||
} else { | ||
this.dispatch(data, this._compress, opts, cb); | ||
this.dispatch(buf, this._compress, opts, cb); | ||
} | ||
} else { | ||
this.sendFrame( | ||
Sender.frame(data, { | ||
Sender.frame(buf, { | ||
fin: options.fin, | ||
@@ -326,3 +289,3 @@ rsv1: false, | ||
mask: options.mask, | ||
readOnly | ||
readOnly: toBuffer.readOnly | ||
}), | ||
@@ -408,18 +371,1 @@ cb | ||
module.exports = Sender; | ||
/** | ||
* Converts an `ArrayBuffer` view into a buffer. | ||
* | ||
* @param {(DataView|TypedArray)} view The view to convert | ||
* @return {Buffer} Converted view | ||
* @private | ||
*/ | ||
function viewToBuffer(view) { | ||
const buf = Buffer.from(view.buffer); | ||
if (view.byteLength !== view.buffer.byteLength) { | ||
return buf.slice(view.byteOffset, view.byteOffset + view.byteLength); | ||
} | ||
return buf; | ||
} |
@@ -9,5 +9,7 @@ 'use strict'; | ||
const extension = require('./extension'); | ||
const constants = require('./constants'); | ||
const WebSocket = require('./websocket'); | ||
const { GUID } = require('./constants'); | ||
const keyRegex = /^[+/0-9A-Za-z]{22}==$/; | ||
/** | ||
@@ -180,2 +182,6 @@ * Class representing a WebSocket server. | ||
const key = | ||
req.headers['sec-websocket-key'] !== undefined | ||
? req.headers['sec-websocket-key'].trim() | ||
: false; | ||
const version = +req.headers['sec-websocket-version']; | ||
@@ -187,3 +193,4 @@ const extensions = {}; | ||
req.headers.upgrade.toLowerCase() !== 'websocket' || | ||
!req.headers['sec-websocket-key'] || | ||
!key || | ||
!keyRegex.test(key) || | ||
(version !== 8 && version !== 13) || | ||
@@ -231,3 +238,3 @@ !this.shouldHandle(req) | ||
this.completeUpgrade(extensions, req, socket, head, cb); | ||
this.completeUpgrade(key, extensions, req, socket, head, cb); | ||
}); | ||
@@ -240,3 +247,3 @@ return; | ||
this.completeUpgrade(extensions, req, socket, head, cb); | ||
this.completeUpgrade(key, extensions, req, socket, head, cb); | ||
} | ||
@@ -247,2 +254,3 @@ | ||
* | ||
* @param {String} key The value of the `Sec-WebSocket-Key` header | ||
* @param {Object} extensions The accepted extensions | ||
@@ -255,3 +263,3 @@ * @param {http.IncomingMessage} req The request object | ||
*/ | ||
completeUpgrade(extensions, req, socket, head, cb) { | ||
completeUpgrade(key, extensions, req, socket, head, cb) { | ||
// | ||
@@ -262,5 +270,5 @@ // Destroy the socket if the client has already sent a FIN packet. | ||
const key = crypto | ||
const digest = crypto | ||
.createHash('sha1') | ||
.update(req.headers['sec-websocket-key'] + constants.GUID, 'binary') | ||
.update(key + GUID) | ||
.digest('base64'); | ||
@@ -272,3 +280,3 @@ | ||
'Connection: Upgrade', | ||
`Sec-WebSocket-Accept: ${key}` | ||
`Sec-WebSocket-Accept: ${digest}` | ||
]; | ||
@@ -275,0 +283,0 @@ |
@@ -14,8 +14,14 @@ 'use strict'; | ||
const extension = require('./extension'); | ||
const constants = require('./constants'); | ||
const Receiver = require('./receiver'); | ||
const Sender = require('./sender'); | ||
const { | ||
BINARY_TYPES, | ||
EMPTY_BUFFER, | ||
GUID, | ||
kStatusCode, | ||
kWebSocket, | ||
NOOP | ||
} = require('./constants'); | ||
const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; | ||
const kWebSocket = constants.kWebSocket; | ||
const protocolVersions = [8, 13]; | ||
@@ -43,3 +49,3 @@ const closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly. | ||
this._binaryType = constants.BINARY_TYPES[0]; | ||
this._binaryType = BINARY_TYPES[0]; | ||
this._closeFrameReceived = false; | ||
@@ -51,3 +57,2 @@ this._closeFrameSent = false; | ||
this._extensions = {}; | ||
this._isServer = true; | ||
this._receiver = null; | ||
@@ -58,2 +63,5 @@ this._sender = null; | ||
if (address !== null) { | ||
this._isServer = false; | ||
this._redirects = 0; | ||
if (Array.isArray(protocols)) { | ||
@@ -66,3 +74,5 @@ protocols = protocols.join(', '); | ||
initAsClient.call(this, address, protocols, options); | ||
initAsClient(this, address, protocols, options); | ||
} else { | ||
this._isServer = true; | ||
} | ||
@@ -95,3 +105,3 @@ } | ||
set binaryType(type) { | ||
if (!constants.BINARY_TYPES.includes(type)) return; | ||
if (!BINARY_TYPES.includes(type)) return; | ||
@@ -274,3 +284,3 @@ this._binaryType = type; | ||
if (mask === undefined) mask = !this._isServer; | ||
this._sender.ping(data || constants.EMPTY_BUFFER, mask, cb); | ||
this._sender.ping(data || EMPTY_BUFFER, mask, cb); | ||
} | ||
@@ -307,3 +317,3 @@ | ||
if (mask === undefined) mask = !this._isServer; | ||
this._sender.pong(data || constants.EMPTY_BUFFER, mask, cb); | ||
this._sender.pong(data || EMPTY_BUFFER, mask, cb); | ||
} | ||
@@ -355,3 +365,3 @@ | ||
this._sender.send(data || constants.EMPTY_BUFFER, opts, cb); | ||
this._sender.send(data || EMPTY_BUFFER, opts, cb); | ||
} | ||
@@ -429,18 +439,27 @@ | ||
* | ||
* @param {WebSocket} websocket The client to initialize | ||
* @param {(String|url.Url|url.URL)} address The URL to which to connect | ||
* @param {String} protocols The subprotocols | ||
* @param {Object} options Connection options | ||
* @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate | ||
* @param {Number} options.handshakeTimeout Timeout in milliseconds for the handshake request | ||
* @param {Number} options.protocolVersion Value of the `Sec-WebSocket-Version` header | ||
* @param {String} options.origin Value of the `Origin` or `Sec-WebSocket-Origin` header | ||
* @param {(Boolean|Object)} options.perMessageDeflate Enable/disable | ||
* permessage-deflate | ||
* @param {Number} options.handshakeTimeout Timeout in milliseconds for the | ||
* handshake request | ||
* @param {Number} options.protocolVersion Value of the `Sec-WebSocket-Version` | ||
* header | ||
* @param {String} options.origin Value of the `Origin` or | ||
* `Sec-WebSocket-Origin` header | ||
* @param {Number} options.maxPayload The maximum allowed message size | ||
* @param {Boolean} options.followRedirects Whether or not to follow redirects | ||
* @param {Number} options.maxRedirects The maximum number of redirects allowed | ||
* @private | ||
*/ | ||
function initAsClient(address, protocols, options) { | ||
options = Object.assign( | ||
function initAsClient(websocket, address, protocols, options) { | ||
const opts = Object.assign( | ||
{ | ||
protocolVersion: protocolVersions[1], | ||
maxPayload: 100 * 1024 * 1024, | ||
perMessageDeflate: true, | ||
maxPayload: 100 * 1024 * 1024 | ||
followRedirects: false, | ||
maxRedirects: 10 | ||
}, | ||
@@ -462,5 +481,5 @@ options, | ||
if (!protocolVersions.includes(options.protocolVersion)) { | ||
if (!protocolVersions.includes(opts.protocolVersion)) { | ||
throw new RangeError( | ||
`Unsupported protocol version: ${options.protocolVersion} ` + | ||
`Unsupported protocol version: ${opts.protocolVersion} ` + | ||
`(supported versions: ${protocolVersions.join(', ')})` | ||
@@ -470,4 +489,2 @@ ); | ||
this._isServer = false; | ||
var parsedUrl; | ||
@@ -477,3 +494,3 @@ | ||
parsedUrl = address; | ||
this.url = address.href; | ||
websocket.url = address.href; | ||
} else { | ||
@@ -484,3 +501,3 @@ // | ||
parsedUrl = url.URL ? new url.URL(address) : url.parse(address); | ||
this.url = address; | ||
websocket.url = address; | ||
} | ||
@@ -491,3 +508,3 @@ | ||
if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) { | ||
throw new Error(`Invalid URL: ${this.url}`); | ||
throw new Error(`Invalid URL: ${websocket.url}`); | ||
} | ||
@@ -499,3 +516,3 @@ | ||
const key = crypto.randomBytes(16).toString('base64'); | ||
const httpObj = isSecure ? https : http; | ||
const get = isSecure ? https.get : http.get; | ||
const path = parsedUrl.search | ||
@@ -506,11 +523,11 @@ ? `${parsedUrl.pathname || '/'}${parsedUrl.search}` | ||
options.createConnection = isSecure ? tlsConnect : netConnect; | ||
options.defaultPort = options.defaultPort || defaultPort; | ||
options.port = parsedUrl.port || defaultPort; | ||
options.host = parsedUrl.hostname.startsWith('[') | ||
opts.createConnection = isSecure ? tlsConnect : netConnect; | ||
opts.defaultPort = opts.defaultPort || defaultPort; | ||
opts.port = parsedUrl.port || defaultPort; | ||
opts.host = parsedUrl.hostname.startsWith('[') | ||
? parsedUrl.hostname.slice(1, -1) | ||
: parsedUrl.hostname; | ||
options.headers = Object.assign( | ||
opts.headers = Object.assign( | ||
{ | ||
'Sec-WebSocket-Version': options.protocolVersion, | ||
'Sec-WebSocket-Version': opts.protocolVersion, | ||
'Sec-WebSocket-Key': key, | ||
@@ -520,14 +537,14 @@ Connection: 'Upgrade', | ||
}, | ||
options.headers | ||
opts.headers | ||
); | ||
options.path = path; | ||
options.timeout = options.handshakeTimeout; | ||
opts.path = path; | ||
opts.timeout = opts.handshakeTimeout; | ||
if (options.perMessageDeflate) { | ||
if (opts.perMessageDeflate) { | ||
perMessageDeflate = new PerMessageDeflate( | ||
options.perMessageDeflate !== true ? options.perMessageDeflate : {}, | ||
opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, | ||
false, | ||
options.maxPayload | ||
opts.maxPayload | ||
); | ||
options.headers['Sec-WebSocket-Extensions'] = extension.format({ | ||
opts.headers['Sec-WebSocket-Extensions'] = extension.format({ | ||
[PerMessageDeflate.extensionName]: perMessageDeflate.offer() | ||
@@ -537,15 +554,15 @@ }); | ||
if (protocols) { | ||
options.headers['Sec-WebSocket-Protocol'] = protocols; | ||
opts.headers['Sec-WebSocket-Protocol'] = protocols; | ||
} | ||
if (options.origin) { | ||
if (options.protocolVersion < 13) { | ||
options.headers['Sec-WebSocket-Origin'] = options.origin; | ||
if (opts.origin) { | ||
if (opts.protocolVersion < 13) { | ||
opts.headers['Sec-WebSocket-Origin'] = opts.origin; | ||
} else { | ||
options.headers.Origin = options.origin; | ||
opts.headers.Origin = opts.origin; | ||
} | ||
} | ||
if (parsedUrl.auth) { | ||
options.auth = parsedUrl.auth; | ||
opts.auth = parsedUrl.auth; | ||
} else if (parsedUrl.username || parsedUrl.password) { | ||
options.auth = `${parsedUrl.username}:${parsedUrl.password}`; | ||
opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; | ||
} | ||
@@ -556,11 +573,11 @@ | ||
options.socketPath = parts[0]; | ||
options.path = parts[1]; | ||
opts.socketPath = parts[0]; | ||
opts.path = parts[1]; | ||
} | ||
var req = (this._req = httpObj.get(options)); | ||
var req = (websocket._req = get(opts)); | ||
if (options.handshakeTimeout) { | ||
if (opts.timeout) { | ||
req.on('timeout', () => { | ||
abortHandshake(this, req, 'Opening handshake has timed out'); | ||
abortHandshake(websocket, req, 'Opening handshake has timed out'); | ||
}); | ||
@@ -570,18 +587,43 @@ } | ||
req.on('error', (err) => { | ||
if (this._req.aborted) return; | ||
if (websocket._req.aborted) return; | ||
req = this._req = null; | ||
this.readyState = WebSocket.CLOSING; | ||
this.emit('error', err); | ||
this.emitClose(); | ||
req = websocket._req = null; | ||
websocket.readyState = WebSocket.CLOSING; | ||
websocket.emit('error', err); | ||
websocket.emitClose(); | ||
}); | ||
req.on('response', (res) => { | ||
if (this.emit('unexpected-response', req, res)) return; | ||
const location = res.headers.location; | ||
const statusCode = res.statusCode; | ||
abortHandshake(this, req, `Unexpected server response: ${res.statusCode}`); | ||
if ( | ||
location && | ||
opts.followRedirects && | ||
statusCode >= 300 && | ||
statusCode < 400 | ||
) { | ||
if (++websocket._redirects > opts.maxRedirects) { | ||
abortHandshake(websocket, req, 'Maximum redirects exceeded'); | ||
return; | ||
} | ||
req.abort(); | ||
const addr = url.URL | ||
? new url.URL(location, address) | ||
: url.resolve(address, location); | ||
initAsClient(websocket, addr, protocols, options); | ||
} else if (!websocket.emit('unexpected-response', req, res)) { | ||
abortHandshake( | ||
websocket, | ||
req, | ||
`Unexpected server response: ${res.statusCode}` | ||
); | ||
} | ||
}); | ||
req.on('upgrade', (res, socket, head) => { | ||
this.emit('upgrade', res); | ||
websocket.emit('upgrade', res); | ||
@@ -592,13 +634,13 @@ // | ||
// | ||
if (this.readyState !== WebSocket.CONNECTING) return; | ||
if (websocket.readyState !== WebSocket.CONNECTING) return; | ||
req = this._req = null; | ||
req = websocket._req = null; | ||
const digest = crypto | ||
.createHash('sha1') | ||
.update(key + constants.GUID, 'binary') | ||
.update(key + GUID) | ||
.digest('base64'); | ||
if (res.headers['sec-websocket-accept'] !== digest) { | ||
abortHandshake(this, socket, 'Invalid Sec-WebSocket-Accept header'); | ||
abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header'); | ||
return; | ||
@@ -620,7 +662,7 @@ } | ||
if (protError) { | ||
abortHandshake(this, socket, protError); | ||
abortHandshake(websocket, socket, protError); | ||
return; | ||
} | ||
if (serverProt) this.protocol = serverProt; | ||
if (serverProt) websocket.protocol = serverProt; | ||
@@ -635,6 +677,12 @@ if (perMessageDeflate) { | ||
perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); | ||
this._extensions[PerMessageDeflate.extensionName] = perMessageDeflate; | ||
websocket._extensions[ | ||
PerMessageDeflate.extensionName | ||
] = perMessageDeflate; | ||
} | ||
} catch (err) { | ||
abortHandshake(this, socket, 'Invalid Sec-WebSocket-Extensions header'); | ||
abortHandshake( | ||
websocket, | ||
socket, | ||
'Invalid Sec-WebSocket-Extensions header' | ||
); | ||
return; | ||
@@ -644,3 +692,3 @@ } | ||
this.setSocket(socket, head, options.maxPayload); | ||
websocket.setSocket(socket, head, opts.maxPayload); | ||
}); | ||
@@ -748,3 +796,3 @@ } | ||
websocket.readyState = WebSocket.CLOSING; | ||
websocket._closeCode = err[constants.kStatusCode]; | ||
websocket._closeCode = err[kStatusCode]; | ||
websocket.emit('error', err); | ||
@@ -782,3 +830,3 @@ websocket._socket.destroy(); | ||
websocket.pong(data, !websocket._isServer, constants.NOOP); | ||
websocket.pong(data, !websocket._isServer, NOOP); | ||
websocket.emit('ping', data); | ||
@@ -873,3 +921,3 @@ } | ||
this.removeListener('error', socketOnError); | ||
this.on('error', constants.NOOP); | ||
this.on('error', NOOP); | ||
@@ -876,0 +924,0 @@ if (websocket) { |
{ | ||
"name": "ws", | ||
"version": "6.1.4", | ||
"version": "6.2.0", | ||
"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", | ||
@@ -28,3 +28,3 @@ "keywords": [ | ||
"integration": "npm run lint && mocha test/*.integration.js", | ||
"lint": "eslint . --ignore-path .gitignore && prettylint '**/*.{json,md}' --ignore-path .gitignore" | ||
"lint": "eslint --ignore-path .gitignore . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yml}\"" | ||
}, | ||
@@ -37,11 +37,11 @@ "dependencies": { | ||
"bufferutil": "~4.0.0", | ||
"eslint": "~5.14.0", | ||
"eslint-config-prettier": "~4.0.0", | ||
"coveralls": "~3.0.3", | ||
"eslint": "~5.15.0", | ||
"eslint-config-prettier": "~4.1.0", | ||
"eslint-plugin-prettier": "~3.0.0", | ||
"mocha": "~5.2.0", | ||
"mocha": "~6.0.0", | ||
"nyc": "~13.3.0", | ||
"prettier": "~1.16.1", | ||
"prettylint": "~1.0.0", | ||
"utf-8-validate": "~5.0.0" | ||
} | ||
} |
# ws: a Node.js WebSocket library | ||
[![Version npm](https://img.shields.io/npm/v/ws.svg)](https://www.npmjs.com/package/ws) | ||
[![Linux Build](https://img.shields.io/travis/websockets/ws/master.svg)](https://travis-ci.org/websockets/ws) | ||
[![Windows Build](https://ci.appveyor.com/api/projects/status/github/websockets/ws?branch=master&svg=true)](https://ci.appveyor.com/project/lpinca/ws) | ||
[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg)](https://coveralls.io/r/websockets/ws?branch=master) | ||
[![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws) | ||
[![Linux Build](https://img.shields.io/travis/websockets/ws/master.svg?logo=travis)](https://travis-ci.org/websockets/ws) | ||
[![Windows Build](https://img.shields.io/appveyor/ci/lpinca/ws/master.svg?logo=appveyor)](https://ci.appveyor.com/project/lpinca/ws) | ||
[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg)](https://coveralls.io/github/websockets/ws) | ||
@@ -8,0 +8,0 @@ ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
101597
2834