* @see https://whatpr.org/websockets/48.html#close-the-websocket * @param {import('./websocket').Handler} object * @param {number} [code=null] * @param {string} [reason='']
(object, code, reason, validate = false)
| 225 | * @param {string} [reason=''] |
| 226 | */ |
| 227 | function closeWebSocketConnection (object, code, reason, validate = false) { |
| 228 | // 1. If code was not supplied, let code be null. |
| 229 | code ??= null |
| 230 | |
| 231 | // 2. If reason was not supplied, let reason be the empty string. |
| 232 | reason ??= '' |
| 233 | |
| 234 | // 3. Validate close code and reason with code and reason. |
| 235 | if (validate) validateCloseCodeAndReason(code, reason) |
| 236 | |
| 237 | // 4. Run the first matching steps from the following list: |
| 238 | // - If object’s ready state is CLOSING (2) or CLOSED (3) |
| 239 | // - If the WebSocket connection is not yet established [WSP] |
| 240 | // - If the WebSocket closing handshake has not yet been started [WSP] |
| 241 | // - Otherwise |
| 242 | if (isClosed(object.readyState) || isClosing(object.readyState)) { |
| 243 | // Do nothing. |
| 244 | } else if (!isEstablished(object.readyState)) { |
| 245 | // Fail the WebSocket connection and set object’s ready state to CLOSING (2). [WSP] |
| 246 | failWebsocketConnection(object) |
| 247 | object.readyState = states.CLOSING |
| 248 | } else if (!object.closeState.has(sentCloseFrameState.SENT) && !object.closeState.has(sentCloseFrameState.RECEIVED)) { |
| 249 | // Upon either sending or receiving a Close control frame, it is said |
| 250 | // that _The WebSocket Closing Handshake is Started_ and that the |
| 251 | // WebSocket connection is in the CLOSING state. |
| 252 | |
| 253 | const frame = new WebsocketFrameSend() |
| 254 | |
| 255 | // If neither code nor reason is present, the WebSocket Close |
| 256 | // message must not have a body. |
| 257 | |
| 258 | // If code is present, then the status code to use in the |
| 259 | // WebSocket Close message must be the integer given by code. |
| 260 | // If code is null and reason is the empty string, the WebSocket Close frame must not have a body. |
| 261 | // If reason is non-empty but code is null, then set code to 1000 ("Normal Closure"). |
| 262 | if (reason.length !== 0 && code === null) { |
| 263 | code = 1000 |
| 264 | } |
| 265 | |
| 266 | // If code is set, then the status code to use in the WebSocket Close frame must be the integer given by code. |
| 267 | assert(code === null || Number.isInteger(code)) |
| 268 | |
| 269 | if (code === null && reason.length === 0) { |
| 270 | frame.frameData = emptyBuffer |
| 271 | } else if (code !== null && reason === null) { |
| 272 | frame.frameData = Buffer.allocUnsafe(2) |
| 273 | frame.frameData.writeUInt16BE(code, 0) |
| 274 | } else if (code !== null && reason !== null) { |
| 275 | // If reason is also present, then reasonBytes must be |
| 276 | // provided in the Close message after the status code. |
| 277 | frame.frameData = Buffer.allocUnsafe(2 + Buffer.byteLength(reason)) |
| 278 | frame.frameData.writeUInt16BE(code, 0) |
| 279 | // the body MAY contain UTF-8-encoded data with value /reason/ |
| 280 | frame.frameData.write(reason, 2, 'utf-8') |
| 281 | } else { |
| 282 | frame.frameData = emptyBuffer |
| 283 | } |
| 284 |
no test coverage detected
searching dependent graphs…