Comparing version 8.6.0 to 8.7.0
@@ -233,19 +233,34 @@ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^net|tls|https$" }] */ | ||
const key = | ||
req.headers['sec-websocket-key'] !== undefined | ||
? req.headers['sec-websocket-key'] | ||
: false; | ||
const key = req.headers['sec-websocket-key']; | ||
const version = +req.headers['sec-websocket-version']; | ||
if ( | ||
req.method !== 'GET' || | ||
req.headers.upgrade.toLowerCase() !== 'websocket' || | ||
!key || | ||
!keyRegex.test(key) || | ||
(version !== 8 && version !== 13) || | ||
!this.shouldHandle(req) | ||
) { | ||
return abortHandshake(socket, 400); | ||
if (req.method !== 'GET') { | ||
const message = 'Invalid HTTP method'; | ||
abortHandshakeOrEmitwsClientError(this, req, socket, 405, message); | ||
return; | ||
} | ||
if (req.headers.upgrade.toLowerCase() !== 'websocket') { | ||
const message = 'Invalid Upgrade header'; | ||
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); | ||
return; | ||
} | ||
if (!key || !keyRegex.test(key)) { | ||
const message = 'Missing or invalid Sec-WebSocket-Key header'; | ||
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); | ||
return; | ||
} | ||
if (version !== 8 && version !== 13) { | ||
const message = 'Missing or invalid Sec-WebSocket-Version header'; | ||
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); | ||
return; | ||
} | ||
if (!this.shouldHandle(req)) { | ||
abortHandshake(socket, 400); | ||
return; | ||
} | ||
const secWebSocketProtocol = req.headers['sec-websocket-protocol']; | ||
@@ -258,3 +273,5 @@ let protocols = new Set(); | ||
} catch (err) { | ||
return abortHandshake(socket, 400); | ||
const message = 'Invalid Sec-WebSocket-Protocol header'; | ||
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); | ||
return; | ||
} | ||
@@ -284,3 +301,6 @@ } | ||
} catch (err) { | ||
return abortHandshake(socket, 400); | ||
const message = | ||
'Invalid or unacceptable Sec-WebSocket-Extensions header'; | ||
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); | ||
return; | ||
} | ||
@@ -452,3 +472,3 @@ } | ||
/** | ||
* Handle premature socket errors. | ||
* Handle socket errors. | ||
* | ||
@@ -471,23 +491,50 @@ * @private | ||
function abortHandshake(socket, code, message, headers) { | ||
if (socket.writable) { | ||
message = message || http.STATUS_CODES[code]; | ||
headers = { | ||
Connection: 'close', | ||
'Content-Type': 'text/html', | ||
'Content-Length': Buffer.byteLength(message), | ||
...headers | ||
}; | ||
// | ||
// The socket is writable unless the user destroyed or ended it before calling | ||
// `server.handleUpgrade()` or in the `verifyClient` function, which is a user | ||
// error. Handling this does not make much sense as the worst that can happen | ||
// is that some of the data written by the user might be discarded due to the | ||
// call to `socket.end()` below, which triggers an `'error'` event that in | ||
// turn causes the socket to be destroyed. | ||
// | ||
message = message || http.STATUS_CODES[code]; | ||
headers = { | ||
Connection: 'close', | ||
'Content-Type': 'text/html', | ||
'Content-Length': Buffer.byteLength(message), | ||
...headers | ||
}; | ||
socket.write( | ||
`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` + | ||
Object.keys(headers) | ||
.map((h) => `${h}: ${headers[h]}`) | ||
.join('\r\n') + | ||
'\r\n\r\n' + | ||
message | ||
); | ||
} | ||
socket.once('finish', socket.destroy); | ||
socket.removeListener('error', socketOnError); | ||
socket.destroy(); | ||
socket.end( | ||
`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` + | ||
Object.keys(headers) | ||
.map((h) => `${h}: ${headers[h]}`) | ||
.join('\r\n') + | ||
'\r\n\r\n' + | ||
message | ||
); | ||
} | ||
/** | ||
* Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least | ||
* one listener for it, otherwise call `abortHandshake()`. | ||
* | ||
* @param {WebSocketServer} server The WebSocket server | ||
* @param {http.IncomingMessage} req The request object | ||
* @param {(net.Socket|tls.Socket)} socket The socket of the upgrade request | ||
* @param {Number} code The HTTP response status code | ||
* @param {String} message The HTTP response body | ||
* @private | ||
*/ | ||
function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) { | ||
if (server.listenerCount('wsClientError')) { | ||
const err = new Error(message); | ||
Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError); | ||
server.emit('wsClientError', err, socket, req); | ||
} else { | ||
abortHandshake(socket, code, message); | ||
} | ||
} |
@@ -774,2 +774,3 @@ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Readable$" }] */ | ||
if (websocket._redirects === 0) { | ||
websocket._originalSecure = isSecure; | ||
websocket._originalHost = parsedUrl.host; | ||
@@ -790,14 +791,17 @@ | ||
} | ||
} else if ( | ||
websocket.listenerCount('redirect') === 0 && | ||
parsedUrl.host !== websocket._originalHost | ||
) { | ||
// | ||
// Match curl 7.77.0 behavior and drop the following headers. These | ||
// headers are also dropped when following a redirect to a subdomain. | ||
// | ||
delete opts.headers.authorization; | ||
delete opts.headers.cookie; | ||
delete opts.headers.host; | ||
opts.auth = undefined; | ||
} else if (websocket.listenerCount('redirect') === 0) { | ||
const isSameHost = parsedUrl.host === websocket._originalHost; | ||
if (!isSameHost || (websocket._originalSecure && !isSecure)) { | ||
// | ||
// Match curl 7.77.0 behavior and drop the following headers. These | ||
// headers are also dropped when following a redirect to a subdomain. | ||
// | ||
delete opts.headers.authorization; | ||
delete opts.headers.cookie; | ||
if (!isSameHost) delete opts.headers.host; | ||
opts.auth = undefined; | ||
} | ||
} | ||
@@ -894,2 +898,7 @@ | ||
if (res.headers.upgrade.toLowerCase() !== 'websocket') { | ||
abortHandshake(websocket, socket, 'Invalid Upgrade header'); | ||
return; | ||
} | ||
const digest = createHash('sha1') | ||
@@ -896,0 +905,0 @@ .update(key + GUID) |
{ | ||
"name": "ws", | ||
"version": "8.6.0", | ||
"version": "8.7.0", | ||
"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
133810
3889