undici 7.15.0 → 7.17.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.
- package/README.md +48 -2
- package/docs/docs/api/Agent.md +1 -0
- package/docs/docs/api/Client.md +1 -0
- package/docs/docs/api/DiagnosticsChannel.md +57 -0
- package/docs/docs/api/Dispatcher.md +86 -0
- package/docs/docs/api/Errors.md +0 -1
- package/docs/docs/api/RoundRobinPool.md +145 -0
- package/docs/docs/api/WebSocket.md +21 -0
- package/docs/docs/best-practices/crawling.md +58 -0
- package/index-fetch.js +2 -2
- package/index.js +8 -9
- package/lib/api/api-request.js +22 -8
- package/lib/api/api-upgrade.js +2 -1
- package/lib/api/readable.js +7 -5
- package/lib/core/connect.js +4 -1
- package/lib/core/diagnostics.js +28 -1
- package/lib/core/errors.js +217 -13
- package/lib/core/request.js +5 -1
- package/lib/core/symbols.js +3 -0
- package/lib/core/util.js +61 -41
- package/lib/dispatcher/agent.js +19 -7
- package/lib/dispatcher/balanced-pool.js +10 -0
- package/lib/dispatcher/client-h1.js +18 -23
- package/lib/dispatcher/client-h2.js +166 -26
- package/lib/dispatcher/client.js +64 -59
- package/lib/dispatcher/dispatcher-base.js +20 -16
- package/lib/dispatcher/env-http-proxy-agent.js +12 -16
- package/lib/dispatcher/fixed-queue.js +15 -39
- package/lib/dispatcher/h2c-client.js +7 -78
- package/lib/dispatcher/pool-base.js +60 -43
- package/lib/dispatcher/pool.js +2 -2
- package/lib/dispatcher/proxy-agent.js +27 -11
- package/lib/dispatcher/round-robin-pool.js +137 -0
- package/lib/encoding/index.js +33 -0
- package/lib/global.js +19 -1
- package/lib/handler/cache-handler.js +84 -27
- package/lib/handler/deduplication-handler.js +216 -0
- package/lib/handler/retry-handler.js +0 -2
- package/lib/interceptor/cache.js +94 -15
- package/lib/interceptor/decompress.js +2 -1
- package/lib/interceptor/deduplicate.js +109 -0
- package/lib/interceptor/dns.js +55 -13
- package/lib/mock/mock-agent.js +4 -4
- package/lib/mock/mock-errors.js +10 -0
- package/lib/mock/mock-utils.js +13 -12
- package/lib/mock/snapshot-agent.js +11 -5
- package/lib/mock/snapshot-recorder.js +12 -4
- package/lib/mock/snapshot-utils.js +4 -4
- package/lib/util/cache.js +29 -1
- package/lib/util/date.js +534 -140
- package/lib/util/runtime-features.js +124 -0
- package/lib/web/cookies/index.js +1 -1
- package/lib/web/cookies/parse.js +1 -1
- package/lib/web/eventsource/eventsource-stream.js +2 -2
- package/lib/web/eventsource/eventsource.js +34 -29
- package/lib/web/eventsource/util.js +1 -9
- package/lib/web/fetch/body.js +45 -61
- package/lib/web/fetch/data-url.js +12 -160
- package/lib/web/fetch/formdata-parser.js +204 -127
- package/lib/web/fetch/index.js +21 -19
- package/lib/web/fetch/request.js +6 -0
- package/lib/web/fetch/response.js +4 -7
- package/lib/web/fetch/util.js +10 -79
- package/lib/web/infra/index.js +229 -0
- package/lib/web/subresource-integrity/subresource-integrity.js +6 -5
- package/lib/web/webidl/index.js +207 -44
- package/lib/web/websocket/connection.js +33 -22
- package/lib/web/websocket/events.js +1 -1
- package/lib/web/websocket/frame.js +9 -15
- package/lib/web/websocket/stream/websocketerror.js +22 -1
- package/lib/web/websocket/stream/websocketstream.js +17 -8
- package/lib/web/websocket/util.js +2 -1
- package/lib/web/websocket/websocket.js +32 -42
- package/package.json +9 -7
- package/types/agent.d.ts +2 -1
- package/types/api.d.ts +2 -2
- package/types/balanced-pool.d.ts +2 -1
- package/types/cache-interceptor.d.ts +1 -0
- package/types/client.d.ts +1 -1
- package/types/connector.d.ts +2 -2
- package/types/diagnostics-channel.d.ts +2 -2
- package/types/dispatcher.d.ts +12 -12
- package/types/errors.d.ts +5 -15
- package/types/fetch.d.ts +4 -4
- package/types/formdata.d.ts +1 -1
- package/types/h2c-client.d.ts +1 -1
- package/types/index.d.ts +9 -1
- package/types/interceptors.d.ts +36 -2
- package/types/pool.d.ts +1 -1
- package/types/readable.d.ts +2 -2
- package/types/round-robin-pool.d.ts +41 -0
- package/types/webidl.d.ts +82 -21
- package/types/websocket.d.ts +9 -9
package/lib/web/webidl/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { types, inspect } = require('node:util')
|
|
4
|
-
const {
|
|
4
|
+
const { runtimeFeatures } = require('../../util/runtime-features')
|
|
5
5
|
|
|
6
6
|
const UNDEFINED = 1
|
|
7
7
|
const BOOLEAN = 2
|
|
@@ -157,10 +157,12 @@ webidl.util.TypeValueToString = function (o) {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
webidl.util.markAsUncloneable = markAsUncloneable
|
|
160
|
+
webidl.util.markAsUncloneable = runtimeFeatures.has('markAsUncloneable')
|
|
161
|
+
? require('node:worker_threads').markAsUncloneable
|
|
162
|
+
: () => {}
|
|
161
163
|
|
|
162
164
|
// https://webidl.spec.whatwg.org/#abstract-opdef-converttoint
|
|
163
|
-
webidl.util.ConvertToInt = function (V, bitLength, signedness,
|
|
165
|
+
webidl.util.ConvertToInt = function (V, bitLength, signedness, flags) {
|
|
164
166
|
let upperBound
|
|
165
167
|
let lowerBound
|
|
166
168
|
|
|
@@ -204,7 +206,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts) {
|
|
|
204
206
|
|
|
205
207
|
// 6. If the conversion is to an IDL type associated
|
|
206
208
|
// with the [EnforceRange] extended attribute, then:
|
|
207
|
-
if (
|
|
209
|
+
if (webidl.util.HasFlag(flags, webidl.attributes.EnforceRange)) {
|
|
208
210
|
// 1. If x is NaN, +∞, or −∞, then throw a TypeError.
|
|
209
211
|
if (
|
|
210
212
|
Number.isNaN(x) ||
|
|
@@ -236,7 +238,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts) {
|
|
|
236
238
|
// 7. If x is not NaN and the conversion is to an IDL
|
|
237
239
|
// type associated with the [Clamp] extended
|
|
238
240
|
// attribute, then:
|
|
239
|
-
if (!Number.isNaN(x) &&
|
|
241
|
+
if (!Number.isNaN(x) && webidl.util.HasFlag(flags, webidl.attributes.Clamp)) {
|
|
240
242
|
// 1. Set x to min(max(x, lowerBound), upperBound).
|
|
241
243
|
x = Math.min(Math.max(x, lowerBound), upperBound)
|
|
242
244
|
|
|
@@ -310,6 +312,25 @@ webidl.util.Stringify = function (V) {
|
|
|
310
312
|
}
|
|
311
313
|
}
|
|
312
314
|
|
|
315
|
+
webidl.util.IsResizableArrayBuffer = function (V) {
|
|
316
|
+
if (types.isArrayBuffer(V)) {
|
|
317
|
+
return V.resizable
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (types.isSharedArrayBuffer(V)) {
|
|
321
|
+
return V.growable
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
throw webidl.errors.exception({
|
|
325
|
+
header: 'IsResizableArrayBuffer',
|
|
326
|
+
message: `"${webidl.util.Stringify(V)}" is not an array buffer.`
|
|
327
|
+
})
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
webidl.util.HasFlag = function (flags, attributes) {
|
|
331
|
+
return typeof flags === 'number' && (flags & attributes) === attributes
|
|
332
|
+
}
|
|
333
|
+
|
|
313
334
|
// https://webidl.spec.whatwg.org/#es-sequence
|
|
314
335
|
webidl.sequenceConverter = function (converter) {
|
|
315
336
|
return (V, prefix, argument, Iterable) => {
|
|
@@ -514,13 +535,20 @@ webidl.is.URL = webidl.util.MakeTypeAssertion(URL)
|
|
|
514
535
|
webidl.is.AbortSignal = webidl.util.MakeTypeAssertion(AbortSignal)
|
|
515
536
|
webidl.is.MessagePort = webidl.util.MakeTypeAssertion(MessagePort)
|
|
516
537
|
|
|
538
|
+
webidl.is.BufferSource = function (V) {
|
|
539
|
+
return types.isArrayBuffer(V) || (
|
|
540
|
+
ArrayBuffer.isView(V) &&
|
|
541
|
+
types.isArrayBuffer(V.buffer)
|
|
542
|
+
)
|
|
543
|
+
}
|
|
544
|
+
|
|
517
545
|
// https://webidl.spec.whatwg.org/#es-DOMString
|
|
518
|
-
webidl.converters.DOMString = function (V, prefix, argument,
|
|
546
|
+
webidl.converters.DOMString = function (V, prefix, argument, flags) {
|
|
519
547
|
// 1. If V is null and the conversion is to an IDL type
|
|
520
548
|
// associated with the [LegacyNullToEmptyString]
|
|
521
549
|
// extended attribute, then return the DOMString value
|
|
522
550
|
// that represents the empty string.
|
|
523
|
-
if (V === null &&
|
|
551
|
+
if (V === null && webidl.util.HasFlag(flags, webidl.attributes.LegacyNullToEmptyString)) {
|
|
524
552
|
return ''
|
|
525
553
|
}
|
|
526
554
|
|
|
@@ -599,7 +627,7 @@ webidl.converters.any = function (V) {
|
|
|
599
627
|
// https://webidl.spec.whatwg.org/#es-long-long
|
|
600
628
|
webidl.converters['long long'] = function (V, prefix, argument) {
|
|
601
629
|
// 1. Let x be ? ConvertToInt(V, 64, "signed").
|
|
602
|
-
const x = webidl.util.ConvertToInt(V, 64, 'signed',
|
|
630
|
+
const x = webidl.util.ConvertToInt(V, 64, 'signed', 0, prefix, argument)
|
|
603
631
|
|
|
604
632
|
// 2. Return the IDL long long value that represents
|
|
605
633
|
// the same numeric value as x.
|
|
@@ -609,7 +637,7 @@ webidl.converters['long long'] = function (V, prefix, argument) {
|
|
|
609
637
|
// https://webidl.spec.whatwg.org/#es-unsigned-long-long
|
|
610
638
|
webidl.converters['unsigned long long'] = function (V, prefix, argument) {
|
|
611
639
|
// 1. Let x be ? ConvertToInt(V, 64, "unsigned").
|
|
612
|
-
const x = webidl.util.ConvertToInt(V, 64, 'unsigned',
|
|
640
|
+
const x = webidl.util.ConvertToInt(V, 64, 'unsigned', 0, prefix, argument)
|
|
613
641
|
|
|
614
642
|
// 2. Return the IDL unsigned long long value that
|
|
615
643
|
// represents the same numeric value as x.
|
|
@@ -619,7 +647,7 @@ webidl.converters['unsigned long long'] = function (V, prefix, argument) {
|
|
|
619
647
|
// https://webidl.spec.whatwg.org/#es-unsigned-long
|
|
620
648
|
webidl.converters['unsigned long'] = function (V, prefix, argument) {
|
|
621
649
|
// 1. Let x be ? ConvertToInt(V, 32, "unsigned").
|
|
622
|
-
const x = webidl.util.ConvertToInt(V, 32, 'unsigned',
|
|
650
|
+
const x = webidl.util.ConvertToInt(V, 32, 'unsigned', 0, prefix, argument)
|
|
623
651
|
|
|
624
652
|
// 2. Return the IDL unsigned long value that
|
|
625
653
|
// represents the same numeric value as x.
|
|
@@ -627,9 +655,9 @@ webidl.converters['unsigned long'] = function (V, prefix, argument) {
|
|
|
627
655
|
}
|
|
628
656
|
|
|
629
657
|
// https://webidl.spec.whatwg.org/#es-unsigned-short
|
|
630
|
-
webidl.converters['unsigned short'] = function (V, prefix, argument,
|
|
658
|
+
webidl.converters['unsigned short'] = function (V, prefix, argument, flags) {
|
|
631
659
|
// 1. Let x be ? ConvertToInt(V, 16, "unsigned").
|
|
632
|
-
const x = webidl.util.ConvertToInt(V, 16, 'unsigned',
|
|
660
|
+
const x = webidl.util.ConvertToInt(V, 16, 'unsigned', flags, prefix, argument)
|
|
633
661
|
|
|
634
662
|
// 2. Return the IDL unsigned short value that represents
|
|
635
663
|
// the same numeric value as x.
|
|
@@ -637,15 +665,16 @@ webidl.converters['unsigned short'] = function (V, prefix, argument, opts) {
|
|
|
637
665
|
}
|
|
638
666
|
|
|
639
667
|
// https://webidl.spec.whatwg.org/#idl-ArrayBuffer
|
|
640
|
-
webidl.converters.ArrayBuffer = function (V, prefix, argument,
|
|
641
|
-
// 1. If
|
|
668
|
+
webidl.converters.ArrayBuffer = function (V, prefix, argument, flags) {
|
|
669
|
+
// 1. If V is not an Object, or V does not have an
|
|
642
670
|
// [[ArrayBufferData]] internal slot, then throw a
|
|
643
671
|
// TypeError.
|
|
672
|
+
// 2. If IsSharedArrayBuffer(V) is true, then throw a
|
|
673
|
+
// TypeError.
|
|
644
674
|
// see: https://tc39.es/ecma262/#sec-properties-of-the-arraybuffer-instances
|
|
645
|
-
// see: https://tc39.es/ecma262/#sec-properties-of-the-sharedarraybuffer-instances
|
|
646
675
|
if (
|
|
647
676
|
webidl.util.Type(V) !== OBJECT ||
|
|
648
|
-
!types.
|
|
677
|
+
!types.isArrayBuffer(V)
|
|
649
678
|
) {
|
|
650
679
|
throw webidl.errors.conversionFailed({
|
|
651
680
|
prefix,
|
|
@@ -654,14 +683,38 @@ webidl.converters.ArrayBuffer = function (V, prefix, argument, opts) {
|
|
|
654
683
|
})
|
|
655
684
|
}
|
|
656
685
|
|
|
657
|
-
//
|
|
658
|
-
// with the [
|
|
659
|
-
//
|
|
686
|
+
// 3. If the conversion is not to an IDL type associated
|
|
687
|
+
// with the [AllowResizable] extended attribute, and
|
|
688
|
+
// IsResizableArrayBuffer(V) is true, then throw a
|
|
660
689
|
// TypeError.
|
|
661
|
-
if (
|
|
690
|
+
if (!webidl.util.HasFlag(flags, webidl.attributes.AllowResizable) && webidl.util.IsResizableArrayBuffer(V)) {
|
|
662
691
|
throw webidl.errors.exception({
|
|
663
|
-
header:
|
|
664
|
-
message:
|
|
692
|
+
header: prefix,
|
|
693
|
+
message: `${argument} cannot be a resizable ArrayBuffer.`
|
|
694
|
+
})
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// 4. Return the IDL ArrayBuffer value that is a
|
|
698
|
+
// reference to the same object as V.
|
|
699
|
+
return V
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// https://webidl.spec.whatwg.org/#idl-SharedArrayBuffer
|
|
703
|
+
webidl.converters.SharedArrayBuffer = function (V, prefix, argument, flags) {
|
|
704
|
+
// 1. If V is not an Object, or V does not have an
|
|
705
|
+
// [[ArrayBufferData]] internal slot, then throw a
|
|
706
|
+
// TypeError.
|
|
707
|
+
// 2. If IsSharedArrayBuffer(V) is false, then throw a
|
|
708
|
+
// TypeError.
|
|
709
|
+
// see: https://tc39.es/ecma262/#sec-properties-of-the-sharedarraybuffer-instances
|
|
710
|
+
if (
|
|
711
|
+
webidl.util.Type(V) !== OBJECT ||
|
|
712
|
+
!types.isSharedArrayBuffer(V)
|
|
713
|
+
) {
|
|
714
|
+
throw webidl.errors.conversionFailed({
|
|
715
|
+
prefix,
|
|
716
|
+
argument: `${argument} ("${webidl.util.Stringify(V)}")`,
|
|
717
|
+
types: ['SharedArrayBuffer']
|
|
665
718
|
})
|
|
666
719
|
}
|
|
667
720
|
|
|
@@ -669,19 +722,20 @@ webidl.converters.ArrayBuffer = function (V, prefix, argument, opts) {
|
|
|
669
722
|
// with the [AllowResizable] extended attribute, and
|
|
670
723
|
// IsResizableArrayBuffer(V) is true, then throw a
|
|
671
724
|
// TypeError.
|
|
672
|
-
if (
|
|
725
|
+
if (!webidl.util.HasFlag(flags, webidl.attributes.AllowResizable) && webidl.util.IsResizableArrayBuffer(V)) {
|
|
673
726
|
throw webidl.errors.exception({
|
|
674
|
-
header:
|
|
675
|
-
message:
|
|
727
|
+
header: prefix,
|
|
728
|
+
message: `${argument} cannot be a resizable SharedArrayBuffer.`
|
|
676
729
|
})
|
|
677
730
|
}
|
|
678
731
|
|
|
679
|
-
// 4. Return the IDL
|
|
732
|
+
// 4. Return the IDL SharedArrayBuffer value that is a
|
|
680
733
|
// reference to the same object as V.
|
|
681
734
|
return V
|
|
682
735
|
}
|
|
683
736
|
|
|
684
|
-
webidl.
|
|
737
|
+
// https://webidl.spec.whatwg.org/#dfn-typed-array-type
|
|
738
|
+
webidl.converters.TypedArray = function (V, T, prefix, argument, flags) {
|
|
685
739
|
// 1. Let T be the IDL type V is being converted to.
|
|
686
740
|
|
|
687
741
|
// 2. If Type(V) is not Object, or V does not have a
|
|
@@ -694,7 +748,7 @@ webidl.converters.TypedArray = function (V, T, prefix, name, opts) {
|
|
|
694
748
|
) {
|
|
695
749
|
throw webidl.errors.conversionFailed({
|
|
696
750
|
prefix,
|
|
697
|
-
argument: `${
|
|
751
|
+
argument: `${argument} ("${webidl.util.Stringify(V)}")`,
|
|
698
752
|
types: [T.name]
|
|
699
753
|
})
|
|
700
754
|
}
|
|
@@ -703,10 +757,10 @@ webidl.converters.TypedArray = function (V, T, prefix, name, opts) {
|
|
|
703
757
|
// with the [AllowShared] extended attribute, and
|
|
704
758
|
// IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is
|
|
705
759
|
// true, then throw a TypeError.
|
|
706
|
-
if (
|
|
760
|
+
if (!webidl.util.HasFlag(flags, webidl.attributes.AllowShared) && types.isSharedArrayBuffer(V.buffer)) {
|
|
707
761
|
throw webidl.errors.exception({
|
|
708
|
-
header:
|
|
709
|
-
message:
|
|
762
|
+
header: prefix,
|
|
763
|
+
message: `${argument} cannot be a view on a shared array buffer.`
|
|
710
764
|
})
|
|
711
765
|
}
|
|
712
766
|
|
|
@@ -714,10 +768,10 @@ webidl.converters.TypedArray = function (V, T, prefix, name, opts) {
|
|
|
714
768
|
// with the [AllowResizable] extended attribute, and
|
|
715
769
|
// IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is
|
|
716
770
|
// true, then throw a TypeError.
|
|
717
|
-
if (
|
|
771
|
+
if (!webidl.util.HasFlag(flags, webidl.attributes.AllowResizable) && webidl.util.IsResizableArrayBuffer(V.buffer)) {
|
|
718
772
|
throw webidl.errors.exception({
|
|
719
|
-
header:
|
|
720
|
-
message:
|
|
773
|
+
header: prefix,
|
|
774
|
+
message: `${argument} cannot be a view on a resizable array buffer.`
|
|
721
775
|
})
|
|
722
776
|
}
|
|
723
777
|
|
|
@@ -726,13 +780,15 @@ webidl.converters.TypedArray = function (V, T, prefix, name, opts) {
|
|
|
726
780
|
return V
|
|
727
781
|
}
|
|
728
782
|
|
|
729
|
-
webidl.
|
|
783
|
+
// https://webidl.spec.whatwg.org/#idl-DataView
|
|
784
|
+
webidl.converters.DataView = function (V, prefix, argument, flags) {
|
|
730
785
|
// 1. If Type(V) is not Object, or V does not have a
|
|
731
786
|
// [[DataView]] internal slot, then throw a TypeError.
|
|
732
787
|
if (webidl.util.Type(V) !== OBJECT || !types.isDataView(V)) {
|
|
733
|
-
throw webidl.errors.
|
|
734
|
-
|
|
735
|
-
|
|
788
|
+
throw webidl.errors.conversionFailed({
|
|
789
|
+
prefix,
|
|
790
|
+
argument: `${argument} ("${webidl.util.Stringify(V)}")`,
|
|
791
|
+
types: ['DataView']
|
|
736
792
|
})
|
|
737
793
|
}
|
|
738
794
|
|
|
@@ -740,10 +796,10 @@ webidl.converters.DataView = function (V, prefix, name, opts) {
|
|
|
740
796
|
// with the [AllowShared] extended attribute, and
|
|
741
797
|
// IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true,
|
|
742
798
|
// then throw a TypeError.
|
|
743
|
-
if (
|
|
799
|
+
if (!webidl.util.HasFlag(flags, webidl.attributes.AllowShared) && types.isSharedArrayBuffer(V.buffer)) {
|
|
744
800
|
throw webidl.errors.exception({
|
|
745
|
-
header:
|
|
746
|
-
message:
|
|
801
|
+
header: prefix,
|
|
802
|
+
message: `${argument} cannot be a view on a shared array buffer.`
|
|
747
803
|
})
|
|
748
804
|
}
|
|
749
805
|
|
|
@@ -751,10 +807,10 @@ webidl.converters.DataView = function (V, prefix, name, opts) {
|
|
|
751
807
|
// with the [AllowResizable] extended attribute, and
|
|
752
808
|
// IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is
|
|
753
809
|
// true, then throw a TypeError.
|
|
754
|
-
if (
|
|
810
|
+
if (!webidl.util.HasFlag(flags, webidl.attributes.AllowResizable) && webidl.util.IsResizableArrayBuffer(V.buffer)) {
|
|
755
811
|
throw webidl.errors.exception({
|
|
756
|
-
header:
|
|
757
|
-
message:
|
|
812
|
+
header: prefix,
|
|
813
|
+
message: `${argument} cannot be a view on a resizable array buffer.`
|
|
758
814
|
})
|
|
759
815
|
}
|
|
760
816
|
|
|
@@ -763,6 +819,85 @@ webidl.converters.DataView = function (V, prefix, name, opts) {
|
|
|
763
819
|
return V
|
|
764
820
|
}
|
|
765
821
|
|
|
822
|
+
// https://webidl.spec.whatwg.org/#ArrayBufferView
|
|
823
|
+
webidl.converters.ArrayBufferView = function (V, prefix, argument, flags) {
|
|
824
|
+
if (
|
|
825
|
+
webidl.util.Type(V) !== OBJECT ||
|
|
826
|
+
!types.isArrayBufferView(V)
|
|
827
|
+
) {
|
|
828
|
+
throw webidl.errors.conversionFailed({
|
|
829
|
+
prefix,
|
|
830
|
+
argument: `${argument} ("${webidl.util.Stringify(V)}")`,
|
|
831
|
+
types: ['ArrayBufferView']
|
|
832
|
+
})
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
if (!webidl.util.HasFlag(flags, webidl.attributes.AllowShared) && types.isSharedArrayBuffer(V.buffer)) {
|
|
836
|
+
throw webidl.errors.exception({
|
|
837
|
+
header: prefix,
|
|
838
|
+
message: `${argument} cannot be a view on a shared array buffer.`
|
|
839
|
+
})
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
if (!webidl.util.HasFlag(flags, webidl.attributes.AllowResizable) && webidl.util.IsResizableArrayBuffer(V.buffer)) {
|
|
843
|
+
throw webidl.errors.exception({
|
|
844
|
+
header: prefix,
|
|
845
|
+
message: `${argument} cannot be a view on a resizable array buffer.`
|
|
846
|
+
})
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
return V
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// https://webidl.spec.whatwg.org/#BufferSource
|
|
853
|
+
webidl.converters.BufferSource = function (V, prefix, argument, flags) {
|
|
854
|
+
if (types.isArrayBuffer(V)) {
|
|
855
|
+
return webidl.converters.ArrayBuffer(V, prefix, argument, flags)
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
if (types.isArrayBufferView(V)) {
|
|
859
|
+
flags &= ~webidl.attributes.AllowShared
|
|
860
|
+
|
|
861
|
+
return webidl.converters.ArrayBufferView(V, prefix, argument, flags)
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Make this explicit for easier debugging
|
|
865
|
+
if (types.isSharedArrayBuffer(V)) {
|
|
866
|
+
throw webidl.errors.exception({
|
|
867
|
+
header: prefix,
|
|
868
|
+
message: `${argument} cannot be a SharedArrayBuffer.`
|
|
869
|
+
})
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
throw webidl.errors.conversionFailed({
|
|
873
|
+
prefix,
|
|
874
|
+
argument: `${argument} ("${webidl.util.Stringify(V)}")`,
|
|
875
|
+
types: ['ArrayBuffer', 'ArrayBufferView']
|
|
876
|
+
})
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// https://webidl.spec.whatwg.org/#AllowSharedBufferSource
|
|
880
|
+
webidl.converters.AllowSharedBufferSource = function (V, prefix, argument, flags) {
|
|
881
|
+
if (types.isArrayBuffer(V)) {
|
|
882
|
+
return webidl.converters.ArrayBuffer(V, prefix, argument, flags)
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (types.isSharedArrayBuffer(V)) {
|
|
886
|
+
return webidl.converters.SharedArrayBuffer(V, prefix, argument, flags)
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
if (types.isArrayBufferView(V)) {
|
|
890
|
+
flags |= webidl.attributes.AllowShared
|
|
891
|
+
return webidl.converters.ArrayBufferView(V, prefix, argument, flags)
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
throw webidl.errors.conversionFailed({
|
|
895
|
+
prefix,
|
|
896
|
+
argument: `${argument} ("${webidl.util.Stringify(V)}")`,
|
|
897
|
+
types: ['ArrayBuffer', 'SharedArrayBuffer', 'ArrayBufferView']
|
|
898
|
+
})
|
|
899
|
+
}
|
|
900
|
+
|
|
766
901
|
webidl.converters['sequence<ByteString>'] = webidl.sequenceConverter(
|
|
767
902
|
webidl.converters.ByteString
|
|
768
903
|
)
|
|
@@ -783,6 +918,34 @@ webidl.converters.AbortSignal = webidl.interfaceConverter(
|
|
|
783
918
|
'AbortSignal'
|
|
784
919
|
)
|
|
785
920
|
|
|
921
|
+
/**
|
|
922
|
+
* [LegacyTreatNonObjectAsNull]
|
|
923
|
+
* callback EventHandlerNonNull = any (Event event);
|
|
924
|
+
* typedef EventHandlerNonNull? EventHandler;
|
|
925
|
+
* @param {*} V
|
|
926
|
+
*/
|
|
927
|
+
webidl.converters.EventHandlerNonNull = function (V) {
|
|
928
|
+
if (webidl.util.Type(V) !== OBJECT) {
|
|
929
|
+
return null
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
// [I]f the value is not an object, it will be converted to null, and if the value is not callable,
|
|
933
|
+
// it will be converted to a callback function value that does nothing when called.
|
|
934
|
+
if (typeof V === 'function') {
|
|
935
|
+
return V
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
return () => {}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
webidl.attributes = {
|
|
942
|
+
Clamp: 1 << 0,
|
|
943
|
+
EnforceRange: 1 << 1,
|
|
944
|
+
AllowShared: 1 << 2,
|
|
945
|
+
AllowResizable: 1 << 3,
|
|
946
|
+
LegacyNullToEmptyString: 1 << 4
|
|
947
|
+
}
|
|
948
|
+
|
|
786
949
|
module.exports = {
|
|
787
950
|
webidl
|
|
788
951
|
}
|
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { uid, states, sentCloseFrameState, emptyBuffer, opcodes } = require('./constants')
|
|
4
|
-
const { parseExtensions, isClosed, isClosing, isEstablished, validateCloseCodeAndReason } = require('./util')
|
|
4
|
+
const { parseExtensions, isClosed, isClosing, isEstablished, isConnecting, validateCloseCodeAndReason } = require('./util')
|
|
5
5
|
const { makeRequest } = require('../fetch/request')
|
|
6
6
|
const { fetching } = require('../fetch/index')
|
|
7
7
|
const { Headers, getHeadersList } = require('../fetch/headers')
|
|
8
8
|
const { getDecodeSplit } = require('../fetch/util')
|
|
9
9
|
const { WebsocketFrameSend } = require('./frame')
|
|
10
10
|
const assert = require('node:assert')
|
|
11
|
+
const { runtimeFeatures } = require('../../util/runtime-features')
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
crypto = require('node:crypto')
|
|
16
|
-
/* c8 ignore next 3 */
|
|
17
|
-
} catch {
|
|
13
|
+
const crypto = runtimeFeatures.has('crypto')
|
|
14
|
+
? require('node:crypto')
|
|
15
|
+
: null
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
let warningEmitted = false
|
|
20
18
|
|
|
21
19
|
/**
|
|
22
20
|
* @see https://websockets.spec.whatwg.org/#concept-websocket-establish
|
|
@@ -95,17 +93,27 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
|
|
|
95
93
|
useParallelQueue: true,
|
|
96
94
|
dispatcher: options.dispatcher,
|
|
97
95
|
processResponse (response) {
|
|
98
|
-
if (response.type === 'error') {
|
|
99
|
-
// If the WebSocket connection could not be established, it is also said
|
|
100
|
-
// that _The WebSocket Connection is Closed_, but not _cleanly_.
|
|
101
|
-
handler.readyState = states.CLOSED
|
|
102
|
-
}
|
|
103
|
-
|
|
104
96
|
// 1. If response is a network error or its status is not 101,
|
|
105
97
|
// fail the WebSocket connection.
|
|
98
|
+
// if (response.type === 'error' || ((response.socket?.session != null && response.status !== 200) && response.status !== 101)) {
|
|
106
99
|
if (response.type === 'error' || response.status !== 101) {
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
// The presence of a session property on the socket indicates HTTP2
|
|
101
|
+
// HTTP1
|
|
102
|
+
if (response.socket?.session == null) {
|
|
103
|
+
failWebsocketConnection(handler, 1002, 'Received network error or non-101 status code.', response.error)
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// HTTP2
|
|
108
|
+
if (response.status !== 200) {
|
|
109
|
+
failWebsocketConnection(handler, 1002, 'Received network error or non-200 status code.', response.error)
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (warningEmitted === false && response.socket?.session != null) {
|
|
115
|
+
process.emitWarning('WebSocket over HTTP2 is experimental, and subject to change.', 'ExperimentalWarning')
|
|
116
|
+
warningEmitted = true
|
|
109
117
|
}
|
|
110
118
|
|
|
111
119
|
// 2. If protocols is not the empty list and extracting header
|
|
@@ -127,7 +135,8 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
|
|
|
127
135
|
// header field contains a value that is not an ASCII case-
|
|
128
136
|
// insensitive match for the value "websocket", the client MUST
|
|
129
137
|
// _Fail the WebSocket Connection_.
|
|
130
|
-
|
|
138
|
+
// For H2, no upgrade header is expected.
|
|
139
|
+
if (response.socket.session == null && response.headersList.get('Upgrade')?.toLowerCase() !== 'websocket') {
|
|
131
140
|
failWebsocketConnection(handler, 1002, 'Server did not set Upgrade header to "websocket".')
|
|
132
141
|
return
|
|
133
142
|
}
|
|
@@ -136,7 +145,8 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
|
|
|
136
145
|
// |Connection| header field doesn't contain a token that is an
|
|
137
146
|
// ASCII case-insensitive match for the value "Upgrade", the client
|
|
138
147
|
// MUST _Fail the WebSocket Connection_.
|
|
139
|
-
|
|
148
|
+
// For H2, no connection header is expected.
|
|
149
|
+
if (response.socket.session == null && response.headersList.get('Connection')?.toLowerCase() !== 'upgrade') {
|
|
140
150
|
failWebsocketConnection(handler, 1002, 'Server did not set Connection header to "upgrade".')
|
|
141
151
|
return
|
|
142
152
|
}
|
|
@@ -149,7 +159,7 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
|
|
|
149
159
|
// trailing whitespace, the client MUST _Fail the WebSocket
|
|
150
160
|
// Connection_.
|
|
151
161
|
const secWSAccept = response.headersList.get('Sec-WebSocket-Accept')
|
|
152
|
-
const digest = crypto.
|
|
162
|
+
const digest = crypto.hash('sha1', keyValue + uid, 'base64')
|
|
153
163
|
if (secWSAccept !== digest) {
|
|
154
164
|
failWebsocketConnection(handler, 1002, 'Incorrect hash received in Sec-WebSocket-Accept header.')
|
|
155
165
|
return
|
|
@@ -303,11 +313,12 @@ function failWebsocketConnection (handler, code, reason, cause) {
|
|
|
303
313
|
|
|
304
314
|
handler.controller.abort()
|
|
305
315
|
|
|
306
|
-
if (handler.
|
|
316
|
+
if (isConnecting(handler.readyState)) {
|
|
317
|
+
// If the connection was not established, we must still emit an 'error' and 'close' events
|
|
318
|
+
handler.onSocketClose()
|
|
319
|
+
} else if (handler.socket?.destroyed === false) {
|
|
307
320
|
handler.socket.destroy()
|
|
308
321
|
}
|
|
309
|
-
|
|
310
|
-
handler.onFail(code, reason, cause)
|
|
311
322
|
}
|
|
312
323
|
|
|
313
324
|
module.exports = {
|
|
@@ -1,33 +1,27 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { runtimeFeatures } = require('../../util/runtime-features')
|
|
3
4
|
const { maxUnsigned16Bit, opcodes } = require('./constants')
|
|
4
5
|
|
|
5
6
|
const BUFFER_SIZE = 8 * 1024
|
|
6
7
|
|
|
7
|
-
/** @type {import('crypto')} */
|
|
8
|
-
let crypto
|
|
9
8
|
let buffer = null
|
|
10
9
|
let bufIdx = BUFFER_SIZE
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
randomFillSync: function randomFillSync (buffer, _offset, _size) {
|
|
19
|
-
for (let i = 0; i < buffer.length; ++i) {
|
|
20
|
-
buffer[i] = Math.random() * 255 | 0
|
|
21
|
-
}
|
|
22
|
-
return buffer
|
|
11
|
+
const randomFillSync = runtimeFeatures.has('crypto')
|
|
12
|
+
? require('node:crypto').randomFillSync
|
|
13
|
+
// not full compatibility, but minimum.
|
|
14
|
+
: function randomFillSync (buffer, _offset, _size) {
|
|
15
|
+
for (let i = 0; i < buffer.length; ++i) {
|
|
16
|
+
buffer[i] = Math.random() * 255 | 0
|
|
23
17
|
}
|
|
18
|
+
return buffer
|
|
24
19
|
}
|
|
25
|
-
}
|
|
26
20
|
|
|
27
21
|
function generateMask () {
|
|
28
22
|
if (bufIdx === BUFFER_SIZE) {
|
|
29
23
|
bufIdx = 0
|
|
30
|
-
|
|
24
|
+
randomFillSync((buffer ??= Buffer.allocUnsafeSlow(BUFFER_SIZE)), 0, BUFFER_SIZE)
|
|
31
25
|
}
|
|
32
26
|
return [buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++]]
|
|
33
27
|
}
|
|
@@ -5,7 +5,28 @@ const { validateCloseCodeAndReason } = require('../util')
|
|
|
5
5
|
const { kConstruct } = require('../../../core/symbols')
|
|
6
6
|
const { kEnumerableProperty } = require('../../../core/util')
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
function createInheritableDOMException () {
|
|
9
|
+
// https://github.com/nodejs/node/issues/59677
|
|
10
|
+
class Test extends DOMException {
|
|
11
|
+
get reason () {
|
|
12
|
+
return ''
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (new Test().reason !== undefined) {
|
|
17
|
+
return DOMException
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return new Proxy(DOMException, {
|
|
21
|
+
construct (target, args, newTarget) {
|
|
22
|
+
const instance = Reflect.construct(target, args, target)
|
|
23
|
+
Object.setPrototypeOf(instance, newTarget.prototype)
|
|
24
|
+
return instance
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class WebSocketError extends createInheritableDOMException() {
|
|
9
30
|
#closeCode
|
|
10
31
|
#reason
|
|
11
32
|
|