undici 7.11.0 → 7.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -924,17 +924,6 @@ function sameOrigin (A, B) {
924
924
  return false
925
925
  }
926
926
 
927
- function createDeferredPromise () {
928
- let res
929
- let rej
930
- const promise = new Promise((resolve, reject) => {
931
- res = resolve
932
- rej = reject
933
- })
934
-
935
- return { promise, resolve: res, reject: rej }
936
- }
937
-
938
927
  function isAborted (fetchParams) {
939
928
  return fetchParams.controller.state === 'aborted'
940
929
  }
@@ -1177,6 +1166,11 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
1177
1166
  }
1178
1167
 
1179
1168
  /**
1169
+ * @param {import('./body').ExtractBodyResult} body
1170
+ * @param {(bytes: Uint8Array) => void} processBody
1171
+ * @param {(error: Error) => void} processBodyError
1172
+ * @returns {void}
1173
+ *
1180
1174
  * @see https://fetch.spec.whatwg.org/#body-fully-read
1181
1175
  */
1182
1176
  function fullyReadBody (body, processBody, processBodyError) {
@@ -1191,20 +1185,17 @@ function fullyReadBody (body, processBody, processBodyError) {
1191
1185
  // with taskDestination.
1192
1186
  const errorSteps = processBodyError
1193
1187
 
1188
+ try {
1194
1189
  // 4. Let reader be the result of getting a reader for body’s stream.
1195
1190
  // If that threw an exception, then run errorSteps with that
1196
1191
  // exception and return.
1197
- let reader
1192
+ const reader = body.stream.getReader()
1198
1193
 
1199
- try {
1200
- reader = body.stream.getReader()
1194
+ // 5. Read all bytes from reader, given successSteps and errorSteps.
1195
+ readAllBytes(reader, successSteps, errorSteps)
1201
1196
  } catch (e) {
1202
1197
  errorSteps(e)
1203
- return
1204
1198
  }
1205
-
1206
- // 5. Read all bytes from reader, given successSteps and errorSteps.
1207
- readAllBytes(reader, successSteps, errorSteps)
1208
1199
  }
1209
1200
 
1210
1201
  /**
@@ -1241,15 +1232,16 @@ function isomorphicEncode (input) {
1241
1232
  /**
1242
1233
  * @see https://streams.spec.whatwg.org/#readablestreamdefaultreader-read-all-bytes
1243
1234
  * @see https://streams.spec.whatwg.org/#read-loop
1244
- * @param {ReadableStreamDefaultReader} reader
1235
+ * @param {ReadableStream<Uint8Array<ArrayBuffer>>} reader
1245
1236
  * @param {(bytes: Uint8Array) => void} successSteps
1246
1237
  * @param {(error: Error) => void} failureSteps
1238
+ * @returns {Promise<void>}
1247
1239
  */
1248
1240
  async function readAllBytes (reader, successSteps, failureSteps) {
1249
- const bytes = []
1250
- let byteLength = 0
1251
-
1252
1241
  try {
1242
+ const bytes = []
1243
+ let byteLength = 0
1244
+
1253
1245
  do {
1254
1246
  const { done, value: chunk } = await reader.read()
1255
1247
 
@@ -1324,10 +1316,17 @@ function urlIsHttpHttpsScheme (url) {
1324
1316
  return protocol === 'http:' || protocol === 'https:'
1325
1317
  }
1326
1318
 
1319
+ /**
1320
+ * @typedef {Object} RangeHeaderValue
1321
+ * @property {number|null} rangeStartValue
1322
+ * @property {number|null} rangeEndValue
1323
+ */
1324
+
1327
1325
  /**
1328
1326
  * @see https://fetch.spec.whatwg.org/#simple-range-header-value
1329
1327
  * @param {string} value
1330
1328
  * @param {boolean} allowWhitespace
1329
+ * @return {RangeHeaderValue|'failure'}
1331
1330
  */
1332
1331
  function simpleRangeHeaderValue (value, allowWhitespace) {
1333
1332
  // 1. Let data be the isomorphic decoding of value.
@@ -1732,7 +1731,6 @@ module.exports = {
1732
1731
  isAborted,
1733
1732
  isCancelled,
1734
1733
  isValidEncodedURL,
1735
- createDeferredPromise,
1736
1734
  ReadableStreamFrom,
1737
1735
  tryUpgradeRequestToAPotentiallyTrustworthyURL,
1738
1736
  clampAndCoarsenConnectionTimingInfo,
@@ -2,7 +2,6 @@
2
2
 
3
3
  const { uid, states, sentCloseFrameState, emptyBuffer, opcodes } = require('./constants')
4
4
  const { parseExtensions, isClosed, isClosing, isEstablished, validateCloseCodeAndReason } = require('./util')
5
- const { channels } = require('../../core/diagnostics')
6
5
  const { makeRequest } = require('../fetch/request')
7
6
  const { fetching } = require('../fetch/index')
8
7
  const { Headers, getHeadersList } = require('../fetch/headers')
@@ -200,14 +199,6 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
200
199
  response.socket.on('close', handler.onSocketClose)
201
200
  response.socket.on('error', handler.onSocketError)
202
201
 
203
- if (channels.open.hasSubscribers) {
204
- channels.open.publish({
205
- address: response.socket.address(),
206
- protocol: secProtocol,
207
- extensions: secExtension
208
- })
209
- }
210
-
211
202
  handler.wasEverConnected = true
212
203
  handler.onConnectionEstablished(response, extensions)
213
204
  }
@@ -3,7 +3,6 @@
3
3
  const { Writable } = require('node:stream')
4
4
  const assert = require('node:assert')
5
5
  const { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require('./constants')
6
- const { channels } = require('../../core/diagnostics')
7
6
  const {
8
7
  isValidStatusCode,
9
8
  isValidOpcode,
@@ -423,22 +422,13 @@ class ByteParser extends Writable {
423
422
 
424
423
  this.#handler.socket.write(frame.createFrame(opcodes.PONG))
425
424
 
426
- if (channels.ping.hasSubscribers) {
427
- channels.ping.publish({
428
- payload: body
429
- })
430
- }
425
+ this.#handler.onPing(body)
431
426
  }
432
427
  } else if (opcode === opcodes.PONG) {
433
428
  // A Pong frame MAY be sent unsolicited. This serves as a
434
429
  // unidirectional heartbeat. A response to an unsolicited Pong frame is
435
430
  // not expected.
436
-
437
- if (channels.pong.hasSubscribers) {
438
- channels.pong.publish({
439
- payload: body
440
- })
441
- }
431
+ this.#handler.onPong(body)
442
432
  }
443
433
 
444
434
  return true
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const { createDeferredPromise, environmentSettingsObject } = require('../../fetch/util')
3
+ const { createDeferredPromise } = require('../../../util/promise')
4
+ const { environmentSettingsObject } = require('../../fetch/util')
4
5
  const { states, opcodes, sentCloseFrameState } = require('../constants')
5
6
  const { webidl } = require('../../webidl')
6
7
  const { getURLRecord, isValidSubprotocol, isEstablished, utf8Decode } = require('../util')
@@ -21,11 +22,11 @@ class WebSocketStream {
21
22
  #url
22
23
 
23
24
  // Each WebSocketStream object has an associated opened promise , which is a promise.
24
- /** @type {ReturnType<typeof createDeferredPromise>} */
25
+ /** @type {import('../../../util/promise').DeferredPromise} */
25
26
  #openedPromise
26
27
 
27
28
  // Each WebSocketStream object has an associated closed promise , which is a promise.
28
- /** @type {ReturnType<typeof createDeferredPromise>} */
29
+ /** @type {import('../../../util/promise').DeferredPromise} */
29
30
  #closedPromise
30
31
 
31
32
  // Each WebSocketStream object has an associated readable stream , which is a ReadableStream .
@@ -64,6 +65,8 @@ class WebSocketStream {
64
65
  this.#handler.socket.destroy()
65
66
  },
66
67
  onSocketClose: () => this.#onSocketClose(),
68
+ onPing: () => {},
69
+ onPong: () => {},
67
70
 
68
71
  readyState: states.CONNECTING,
69
72
  socket: null,
@@ -388,7 +391,7 @@ class WebSocketStream {
388
391
  // 6. If the connection was closed cleanly ,
389
392
  if (wasClean) {
390
393
  // 6.1. Close stream ’s readable stream .
391
- this.#readableStream.cancel().catch(() => {})
394
+ this.#readableStreamController.close()
392
395
 
393
396
  // 6.2. Error stream ’s writable stream with an " InvalidStateError " DOMException indicating that a closed WebSocketStream cannot be written to.
394
397
  if (!this.#writableStream.locked) {
@@ -8,6 +8,7 @@ const {
8
8
  isConnecting,
9
9
  isEstablished,
10
10
  isClosing,
11
+ isClosed,
11
12
  isValidSubprotocol,
12
13
  fireEvent,
13
14
  utf8Decode,
@@ -21,6 +22,7 @@ const { getGlobalDispatcher } = require('../../global')
21
22
  const { types } = require('node:util')
22
23
  const { ErrorEvent, CloseEvent, createFastMessageEvent } = require('./events')
23
24
  const { SendQueue } = require('./sender')
25
+ const { WebsocketFrameSend } = require('./frame')
24
26
  const { channels } = require('../../core/diagnostics')
25
27
 
26
28
  /**
@@ -33,6 +35,8 @@ const { channels } = require('../../core/diagnostics')
33
35
  * @property {(chunk: Buffer) => void} onSocketData
34
36
  * @property {(err: Error) => void} onSocketError
35
37
  * @property {() => void} onSocketClose
38
+ * @property {(body: Buffer) => void} onPing
39
+ * @property {(body: Buffer) => void} onPong
36
40
  *
37
41
  * @property {number} readyState
38
42
  * @property {import('stream').Duplex} socket
@@ -79,6 +83,22 @@ class WebSocket extends EventTarget {
79
83
  this.#handler.socket.destroy()
80
84
  },
81
85
  onSocketClose: () => this.#onSocketClose(),
86
+ onPing: (body) => {
87
+ if (channels.ping.hasSubscribers) {
88
+ channels.ping.publish({
89
+ payload: body,
90
+ websocket: this
91
+ })
92
+ }
93
+ },
94
+ onPong: (body) => {
95
+ if (channels.pong.hasSubscribers) {
96
+ channels.pong.publish({
97
+ payload: body,
98
+ websocket: this
99
+ })
100
+ }
101
+ },
82
102
 
83
103
  readyState: states.CONNECTING,
84
104
  socket: null,
@@ -460,6 +480,15 @@ class WebSocket extends EventTarget {
460
480
 
461
481
  // 4. Fire an event named open at the WebSocket object.
462
482
  fireEvent('open', this)
483
+
484
+ if (channels.open.hasSubscribers) {
485
+ channels.open.publish({
486
+ address: response.socket.address(),
487
+ protocol: this.#protocol,
488
+ extensions: this.#extensions,
489
+ websocket: this
490
+ })
491
+ }
463
492
  }
464
493
 
465
494
  #onFail (code, reason, cause) {
@@ -586,8 +615,34 @@ class WebSocket extends EventTarget {
586
615
  })
587
616
  }
588
617
  }
618
+
619
+ /**
620
+ * @param {WebSocket} ws
621
+ * @param {Buffer|undefined} buffer
622
+ */
623
+ static ping (ws, buffer) {
624
+ if (Buffer.isBuffer(buffer)) {
625
+ if (buffer.length > 125) {
626
+ throw new TypeError('A PING frame cannot have a body larger than 125 bytes.')
627
+ }
628
+ } else if (buffer !== undefined) {
629
+ throw new TypeError('Expected buffer payload')
630
+ }
631
+
632
+ // An endpoint MAY send a Ping frame any time after the connection is
633
+ // established and before the connection is closed.
634
+ const readyState = ws.#handler.readyState
635
+
636
+ if (isEstablished(readyState) && !isClosing(readyState) && !isClosed(readyState)) {
637
+ const frame = new WebsocketFrameSend(buffer)
638
+ ws.#handler.socket.write(frame.createFrame(opcodes.PING))
639
+ }
640
+ }
589
641
  }
590
642
 
643
+ const { ping } = WebSocket
644
+ Reflect.deleteProperty(WebSocket, 'ping')
645
+
591
646
  // https://websockets.spec.whatwg.org/#dom-websocket-connecting
592
647
  WebSocket.CONNECTING = WebSocket.prototype.CONNECTING = states.CONNECTING
593
648
  // https://websockets.spec.whatwg.org/#dom-websocket-open
@@ -682,5 +737,6 @@ webidl.converters.WebSocketSendData = function (V) {
682
737
  }
683
738
 
684
739
  module.exports = {
685
- WebSocket
740
+ WebSocket,
741
+ ping
686
742
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "7.11.0",
3
+ "version": "7.12.0",
4
4
  "description": "An HTTP/1.1 client, written from scratch for Node.js",
5
5
  "homepage": "https://undici.nodejs.org",
6
6
  "bugs": {
@@ -91,7 +91,7 @@
91
91
  "test:tdd:node-test": "borp -p \"test/node-test/**/*.js\" -w",
92
92
  "test:typescript": "tsd && tsc test/imports/undici-import.ts --typeRoots ./types --noEmit && tsc ./types/*.d.ts --noEmit --typeRoots ./types",
93
93
  "test:webidl": "borp -p \"test/webidl/*.js\"",
94
- "test:websocket": "borp -p \"test/websocket/*.js\"",
94
+ "test:websocket": "borp -p \"test/websocket/**/*.js\"",
95
95
  "test:websocket:autobahn": "node test/autobahn/client.js",
96
96
  "test:websocket:autobahn:report": "node test/autobahn/report.js",
97
97
  "test:wpt": "node test/wpt/start-fetch.mjs && node test/wpt/start-mimesniff.mjs && node test/wpt/start-xhr.mjs && node test/wpt/start-websockets.mjs && node test/wpt/start-cacheStorage.mjs && node test/wpt/start-eventsource.mjs",
package/types/webidl.d.ts CHANGED
@@ -182,6 +182,16 @@ interface WebidlConverters {
182
182
 
183
183
  ['record<ByteString, ByteString>']: RecordConverter<string, string>
184
184
 
185
+ /**
186
+ * @see https://fetch.spec.whatwg.org/#requestinfo
187
+ */
188
+ RequestInfo (V: unknown): undici.Request | string
189
+
190
+ /**
191
+ * @see https://fetch.spec.whatwg.org/#requestinit
192
+ */
193
+ RequestInit (V: unknown): undici.RequestInit
194
+
185
195
  [Key: string]: (...args: any[]) => unknown
186
196
  }
187
197
 
@@ -182,3 +182,5 @@ export declare const WebSocketError: {
182
182
  prototype: WebSocketError
183
183
  new (type: string, init?: WebSocketCloseInfo): WebSocketError
184
184
  }
185
+
186
+ export declare const ping: (ws: WebSocket, body?: Buffer) => void
@@ -1,5 +0,0 @@
1
- 'use strict'
2
-
3
- module.exports = function () {
4
- return { WeakRef, FinalizationRegistry }
5
- }