Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
remove symbols
  • Loading branch information
KhafraDev committed Jul 7, 2024
commit b729538e6e96d11aa7e48482bcffb44821465f71
107 changes: 6 additions & 101 deletions lib/web/websocket/connection.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
'use strict'

const { uid, states, sentCloseFrameState } = require('./constants')
const {
kReadyState,
kSentClose,
kByteParser,
kReceivedClose,
kResponse
} = require('./symbols')
const { fireEvent, failWebsocketConnection, parseExtensions } = require('./util')
const { uid } = require('./constants')
const { failWebsocketConnection, parseExtensions } = require('./util')
const { channels } = require('../../core/diagnostics')
const { CloseEvent } = require('./events')
const { makeRequest } = require('../fetch/request')
const { fetching } = require('../fetch/index')
const { Headers, getHeadersList } = require('../fetch/headers')
Expand All @@ -29,11 +21,10 @@ try {
* @see https://websockets.spec.whatwg.org/#concept-websocket-establish
* @param {URL} url
* @param {string|string[]} protocols
* @param {import('./websocket').WebSocket} ws
* @param {import('./websocket').Handler} handler
* @param {Partial<import('../../types/websocket').WebSocketInit>} options
*/
function establishWebSocketConnection (url, protocols, client, ws, handler, options) {
function establishWebSocketConnection (url, protocols, client, handler, options) {
// 1. Let requestURL be a copy of url, with its scheme set to "http", if url’s
// scheme is "ws", and to "https" otherwise.
const requestURL = url
Expand Down Expand Up @@ -197,9 +188,9 @@ function establishWebSocketConnection (url, protocols, client, ws, handler, opti
}
}

response.socket.on('data', onSocketData)
response.socket.on('close', onSocketClose)
response.socket.on('error', onSocketError)
response.socket.on('data', handler.onSocketData)
response.socket.on('close', handler.onSocketClose)
response.socket.on('error', handler.onSocketError)

if (channels.open.hasSubscribers) {
channels.open.publish({
Expand All @@ -226,92 +217,6 @@ function closeWebSocketConnection (handler, code, reason, reasonByteLength) {
handler.onClose(code, reason, reasonByteLength)
}

/**
* @param {Buffer} chunk
*/
function onSocketData (chunk) {
if (!this.ws[kByteParser].write(chunk)) {
this.pause()
}
}

/**
* @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol
* @see https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.4
*/
function onSocketClose () {
const { ws } = this
const { [kResponse]: response } = ws

response.socket.off('data', onSocketData)
response.socket.off('close', onSocketClose)
response.socket.off('error', onSocketError)

// If the TCP connection was closed after the
// WebSocket closing handshake was completed, the WebSocket connection
// is said to have been closed _cleanly_.
const wasClean = ws[kSentClose] === sentCloseFrameState.SENT && ws[kReceivedClose]

let code = 1005
let reason = ''

const result = ws[kByteParser].closingInfo

if (result && !result.error) {
code = result.code ?? 1005
reason = result.reason
} else if (!ws[kReceivedClose]) {
// 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
// is lost), _The WebSocket Connection Close Code_ is considered to be
// 1006.
code = 1006
}

// 1. Change the ready state to CLOSED (3).
ws[kReadyState] = states.CLOSED

// 2. If the user agent was required to fail the WebSocket
// connection, or if the WebSocket connection was closed
// after being flagged as full, fire an event named error
// at the WebSocket object.
// TODO

// 3. Fire an event named close at the WebSocket object,
// using CloseEvent, with the wasClean attribute
// initialized to true if the connection closed cleanly
// and false otherwise, the code attribute initialized to
// the WebSocket connection close code, and the reason
// attribute initialized to the result of applying UTF-8
// decode without BOM to the WebSocket connection close
// reason.
// TODO: process.nextTick
fireEvent('close', ws, (type, init) => new CloseEvent(type, init), {
wasClean, code, reason
})

if (channels.close.hasSubscribers) {
channels.close.publish({
websocket: ws,
code,
reason
})
}
}

function onSocketError (error) {
const { ws } = this

ws[kReadyState] = states.CLOSING

if (channels.socketError.hasSubscribers) {
channels.socketError.publish(error)
}

this.destroy()
}

module.exports = {
establishWebSocketConnection,
closeWebSocketConnection
Expand Down
18 changes: 8 additions & 10 deletions lib/web/websocket/receiver.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
const { Writable } = require('node:stream')
const assert = require('node:assert')
const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require('./constants')
const { kReadyState, kSentClose, kResponse, kReceivedClose } = require('./symbols')
const { channels } = require('../../core/diagnostics')
const {
isValidStatusCode,
Expand Down Expand Up @@ -40,10 +39,9 @@ class ByteParser extends Writable {
/** @type {import('./websocket').Handler} */
#handler

constructor (ws, handler, extensions) {
constructor (handler, extensions) {
super()

this.ws = ws
this.#handler = handler
this.#extensions = extensions == null ? new Map() : extensions

Expand Down Expand Up @@ -357,7 +355,7 @@ class ByteParser extends Writable {
return false
}

if (this.ws[kSentClose] !== sentCloseFrameState.SENT) {
if (this.#handler.closeState !== sentCloseFrameState.SENT) {
// 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 All @@ -369,11 +367,11 @@ class ByteParser extends Writable {
}
const closeFrame = new WebsocketFrameSend(body)

this.ws[kResponse].socket.write(
this.#handler.socket.write(
closeFrame.createFrame(opcodes.CLOSE),
(err) => {
if (!err) {
this.ws[kSentClose] = sentCloseFrameState.SENT
this.#handler.closeState = sentCloseFrameState.SENT
}
}
)
Expand All @@ -382,8 +380,8 @@ class ByteParser extends Writable {
// Upon either sending or receiving a Close control frame, it is said
// that _The WebSocket Closing Handshake is Started_ and that the
// WebSocket connection is in the CLOSING state.
this.ws[kReadyState] = states.CLOSING
this.ws[kReceivedClose] = true
this.#handler.readyState = states.CLOSING
this.#handler.receivedClose = true

return false
} else if (opcode === opcodes.PING) {
Expand All @@ -392,10 +390,10 @@ class ByteParser extends Writable {
// A Pong frame sent in response to a Ping frame must have identical
// "Application data"

if (!this.ws[kReceivedClose]) {
if (!this.#handler.receivedClose) {
const frame = new WebsocketFrameSend(body)

this.ws[kResponse].socket.write(frame.createFrame(opcodes.PONG))
this.#handler.socket.write(frame.createFrame(opcodes.PONG))

if (channels.ping.hasSubscribers) {
channels.ping.publish({
Expand Down
9 changes: 0 additions & 9 deletions lib/web/websocket/symbols.js

This file was deleted.

25 changes: 12 additions & 13 deletions lib/web/websocket/util.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,47 @@
'use strict'

const { kReadyState } = require('./symbols')
const { states, opcodes } = require('./constants')
const { isUtf8 } = require('node:buffer')
const { collectASequenceOfCodePointsFast, removeHTTPWhitespace } = require('../fetch/data-url')

/**
* @param {import('./websocket').WebSocket} ws
* @param {number} readyState
* @returns {boolean}
*/
function isConnecting (ws) {
function isConnecting (readyState) {
// If the WebSocket connection is not yet established, and the connection
// is not yet closed, then the WebSocket connection is in the CONNECTING state.
return ws[kReadyState] === states.CONNECTING
return readyState === states.CONNECTING
}

/**
* @param {import('./websocket').WebSocket} ws
* @param {number} readyState
* @returns {boolean}
*/
function isEstablished (ws) {
function isEstablished (readyState) {
// If the server's response is validated as provided for above, it is
// said that _The WebSocket Connection is Established_ and that the
// WebSocket Connection is in the OPEN state.
return ws[kReadyState] === states.OPEN
return readyState === states.OPEN
}

/**
* @param {import('./websocket').WebSocket} ws
* @param {number} readyState
* @returns {boolean}
*/
function isClosing (ws) {
function isClosing (readyState) {
// Upon either sending or receiving a Close control frame, it is said
// that _The WebSocket Closing Handshake is Started_ and that the
// WebSocket connection is in the CLOSING state.
return ws[kReadyState] === states.CLOSING
return readyState === states.CLOSING
}

/**
* @param {import('./websocket').WebSocket} ws
* @param {number} readyState
* @returns {boolean}
*/
function isClosed (ws) {
return ws[kReadyState] === states.CLOSED
function isClosed (readyState) {
return readyState === states.CLOSED
}

/**
Expand Down
Loading