@@ -24,6 +24,7 @@ const { format, parse } = require('./extension');
24
24
const { toBuffer } = require ( './buffer-util' ) ;
25
25
26
26
const readyStates = [ 'CONNECTING' , 'OPEN' , 'CLOSING' , 'CLOSED' ] ;
27
+ const subprotocolRegex = / ^ [ ! # $ % & ' * + \- . 0 - 9 A - Z ^ _ ` | a - z ~ ] + $ / ;
27
28
const protocolVersions = [ 8 , 13 ] ;
28
29
const closeTimeout = 30 * 1000 ;
29
30
@@ -61,11 +62,15 @@ class WebSocket extends EventEmitter {
61
62
this . _isServer = false ;
62
63
this . _redirects = 0 ;
63
64
64
- if ( Array . isArray ( protocols ) ) {
65
- protocols = protocols . join ( ', ' ) ;
66
- } else if ( typeof protocols === 'object' && protocols !== null ) {
67
- options = protocols ;
68
- protocols = undefined ;
65
+ if ( protocols === undefined ) {
66
+ protocols = [ ] ;
67
+ } else if ( ! Array . isArray ( protocols ) ) {
68
+ if ( typeof protocols === 'object' && protocols !== null ) {
69
+ options = protocols ;
70
+ protocols = [ ] ;
71
+ } else {
72
+ protocols = [ protocols ] ;
73
+ }
69
74
}
70
75
71
76
initAsClient ( this , address , protocols , options ) ;
@@ -558,7 +563,7 @@ module.exports = WebSocket;
558
563
*
559
564
* @param {WebSocket } websocket The client to initialize
560
565
* @param {(String|URL) } address The URL to which to connect
561
- * @param {String } [ protocols] The subprotocols
566
+ * @param {Array } protocols The subprotocols
562
567
* @param {Object } [options] Connection options
563
568
* @param {(Boolean|Object) } [options.perMessageDeflate=true] Enable/disable
564
569
* permessage-deflate
@@ -623,6 +628,7 @@ function initAsClient(websocket, address, protocols, options) {
623
628
const defaultPort = isSecure ? 443 : 80 ;
624
629
const key = randomBytes ( 16 ) . toString ( 'base64' ) ;
625
630
const get = isSecure ? https . get : http . get ;
631
+ const protocolSet = new Set ( ) ;
626
632
let perMessageDeflate ;
627
633
628
634
opts . createConnection = isSecure ? tlsConnect : netConnect ;
@@ -651,8 +657,22 @@ function initAsClient(websocket, address, protocols, options) {
651
657
[ PerMessageDeflate . extensionName ] : perMessageDeflate . offer ( )
652
658
} ) ;
653
659
}
654
- if ( protocols ) {
655
- opts . headers [ 'Sec-WebSocket-Protocol' ] = protocols ;
660
+ if ( protocols . length ) {
661
+ for ( const protocol of protocols ) {
662
+ if (
663
+ typeof protocol !== 'string' ||
664
+ ! subprotocolRegex . test ( protocol ) ||
665
+ protocolSet . has ( protocol )
666
+ ) {
667
+ throw new SyntaxError (
668
+ 'An invalid or duplicated subprotocol was specified'
669
+ ) ;
670
+ }
671
+
672
+ protocolSet . add ( protocol ) ;
673
+ }
674
+
675
+ opts . headers [ 'Sec-WebSocket-Protocol' ] = protocols . join ( ',' ) ;
656
676
}
657
677
if ( opts . origin ) {
658
678
if ( opts . protocolVersion < 13 ) {
@@ -739,15 +759,16 @@ function initAsClient(websocket, address, protocols, options) {
739
759
}
740
760
741
761
const serverProt = res . headers [ 'sec-websocket-protocol' ] ;
742
- const protList = ( protocols || '' ) . split ( / , * / ) ;
743
762
let protError ;
744
763
745
- if ( ! protocols && serverProt ) {
746
- protError = 'Server sent a subprotocol but none was requested' ;
747
- } else if ( protocols && ! serverProt ) {
764
+ if ( serverProt ) {
765
+ if ( ! protocolSet . size ) {
766
+ protError = 'Server sent a subprotocol but none was requested' ;
767
+ } else if ( ! protocolSet . has ( serverProt ) ) {
768
+ protError = 'Server sent an invalid subprotocol' ;
769
+ }
770
+ } else if ( protocolSet . size ) {
748
771
protError = 'Server sent no subprotocol' ;
749
- } else if ( serverProt && ! protList . includes ( serverProt ) ) {
750
- protError = 'Server sent an invalid subprotocol' ;
751
772
}
752
773
753
774
if ( protError ) {
0 commit comments