Skip to content

Commit

Permalink
websocket: add hasSentClosingHandshake utility fn
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak committed Feb 27, 2024
1 parent 5600aa1 commit f8d0d86
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 8 deletions.
4 changes: 2 additions & 2 deletions lib/web/websocket/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const {
kByteParser,
kReceivedClose
} = require('./symbols')
const { fireEvent, failWebsocketConnection } = require('./util')
const { fireEvent, failWebsocketConnection, hasSentClosingHandshake } = require('./util')
const { channels } = require('../../core/diagnostics')
const { CloseEvent } = require('./events')
const { makeRequest } = require('../fetch/request')
Expand Down Expand Up @@ -239,7 +239,7 @@ function onSocketClose () {
if (result) {
code = result.code ?? 1005
reason = result.reason
} else if (!ws[kSentClose]) {
} else if (!hasSentClosingHandshake(ws)) {
// If _The WebSocket
// Connection is Closed_ and no Close control frame was received by the
// endpoint (such as could occur if the underlying transport connection
Expand Down
4 changes: 2 additions & 2 deletions lib/web/websocket/receiver.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { Writable } = require('node:stream')
const { parserStates, opcodes, states, emptyBuffer } = require('./constants')
const { kReadyState, kSentClose, kResponse, kReceivedClose } = require('./symbols')
const { channels } = require('../../core/diagnostics')
const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived } = require('./util')
const { isValidStatusCode, failWebsocketConnection, websocketMessageReceived, hasSentClosingHandshake } = require('./util')
const { WebsocketFrameSend } = require('./frame')

// This code was influenced by ws released under the MIT license.
Expand Down Expand Up @@ -104,7 +104,7 @@ class ByteParser extends Writable {

this.#info.closeInfo = this.parseCloseBody(false, body)

if (!this.ws[kSentClose]) {
if (!hasSentClosingHandshake(this.ws)) {
// If an endpoint receives a Close frame and did not previously send a
// Close frame, the endpoint MUST send a Close frame in response. (When
// sending a Close frame in response, the endpoint typically echos the
Expand Down
14 changes: 13 additions & 1 deletion lib/web/websocket/util.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
'use strict'

const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = require('./symbols')
const { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL, kSentClose } = require('./symbols')
const { states, opcodes } = require('./constants')
const { MessageEvent, ErrorEvent } = require('./events')

/* globals Blob */

/**
* @param {import('./websocket').WebSocket} ws
* @returns {boolean}
*/
function isEstablished (ws) {
// If the server's response is validated as provided for above, it is
Expand All @@ -18,6 +19,7 @@ function isEstablished (ws) {

/**
* @param {import('./websocket').WebSocket} ws
* @returns {boolean}
*/
function isClosing (ws) {
// Upon either sending or receiving a Close control frame, it is said
Expand All @@ -28,6 +30,15 @@ function isClosing (ws) {

/**
* @param {import('./websocket').WebSocket} ws
* @returns {boolean}
*/
function hasSentClosingHandshake (ws) {
return ws[kSentClose] === true
}

/**
* @param {import('./websocket').WebSocket} ws
* @returns {boolean}
*/
function isClosed (ws) {
return ws[kReadyState] === states.CLOSED
Expand Down Expand Up @@ -193,6 +204,7 @@ module.exports = {
isEstablished,
isClosing,
isClosed,
hasSentClosingHandshake,
fireEvent,
isValidSubprotocol,
isValidStatusCode,
Expand Down
6 changes: 3 additions & 3 deletions lib/web/websocket/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const {
kSentClose,
kByteParser
} = require('./symbols')
const { isEstablished, isClosing, isValidSubprotocol, failWebsocketConnection, fireEvent } = require('./util')
const { isEstablished, isClosing, isValidSubprotocol, failWebsocketConnection, fireEvent, isClosed, hasSentClosingHandshake } = require('./util')
const { establishWebSocketConnection } = require('./connection')
const { WebsocketFrameSend } = require('./frame')
const { ByteParser } = require('./receiver')
Expand Down Expand Up @@ -184,7 +184,7 @@ class WebSocket extends EventTarget {
}

// 3. Run the first matching steps from the following list:
if (this[kReadyState] === WebSocket.CLOSING || this[kReadyState] === WebSocket.CLOSED) {
if (isClosing(this) || isClosed(this)) {
// If this's ready state is CLOSING (2) or CLOSED (3)
// Do nothing.
} else if (!isEstablished(this)) {
Expand All @@ -193,7 +193,7 @@ class WebSocket extends EventTarget {
// to CLOSING (2).
failWebsocketConnection(this, 'Connection was closed before it was established.')
this[kReadyState] = WebSocket.CLOSING
} else if (!isClosing(this)) {
} else if (!(hasSentClosingHandshake(this))) {
// If the WebSocket closing handshake has not yet been started
// Start the WebSocket closing handshake and set this's ready
// state to CLOSING (2).
Expand Down

0 comments on commit f8d0d86

Please sign in to comment.