1+ 'use strict'
2+
13const { test } = require ( 'node:test' )
2- const http = require ( 'node:http' )
3- const crypto = require ( 'node:crypto' )
4+ const { once } = require ( 'node:events' )
5+ const { createServer } = require ( 'node:http' )
6+ const { WebSocketServer } = require ( 'ws' )
7+
48const { WebSocket } = require ( '../..' )
5- const { createDeferredPromise } = require ( '../../lib/util/promise' )
9+ const { closeServerAsPromise } = require ( '../utils/node-http' )
10+
11+ // https://github.com/nodejs/undici/issues/4889
12+ test ( 'websocket auth retry preserves path when URL contains credentials' , async ( t ) => {
13+ const expectedAuth = `Basic ${ Buffer . from ( 'user:pass' ) . toString ( 'base64' ) } `
14+
15+ let attempts = 0
16+
17+ const server = createServer ( )
18+ const wss = new WebSocketServer ( { noServer : true } )
19+
20+ t . after ( async ( ) => {
21+ for ( const client of wss . clients ) {
22+ client . terminate ( )
23+ }
24+
25+ await new Promise ( ( resolve ) => wss . close ( resolve ) )
26+ await closeServerAsPromise ( server ) ( )
27+ } )
628
7- test ( 'WebSocket basic auth' , ( t ) => {
8- const server = http . createServer ( )
29+ server . on ( 'upgrade' , ( req , socket , head ) => {
30+ attempts ++
31+ t . assert . strictEqual ( req . url , '/path' )
932
10- server . on ( 'upgrade' , ( req , socket ) => {
11- const auth = req . headers . authorization
12- if ( ! auth || auth !== `Basic ${ Buffer . from ( 'user:pass' ) . toString ( 'base64' ) } ` ) {
33+ if ( attempts === 1 ) {
34+ t . assert . strictEqual ( req . headers . authorization , undefined )
1335 socket . write (
1436 'HTTP/1.1 401 Unauthorized\r\n' +
1537 'WWW-Authenticate: Basic realm="test"\r\n' +
@@ -20,43 +42,26 @@ test('WebSocket basic auth', (t) => {
2042 return
2143 }
2244
23- const key = req . headers [ 'sec-websocket-key' ]
24- const accept = crypto
25- . createHash ( 'sha1' )
26- . update ( key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' )
27- . digest ( 'base64' )
28-
29- socket . write (
30- 'HTTP/1.1 101 Switching Protocols\r\n' +
31- 'Upgrade: websocket\r\n' +
32- 'Connection: Upgrade\r\n' +
33- 'Sec-WebSocket-Accept: ' + accept + '\r\n' +
34- '\r\n'
35- )
36-
37- socket . on ( 'data' , ( ) => socket . destroy ( ) )
38- } ) . listen ( 0 )
39-
40- const { port } = server . address ( )
41- const url = `ws://user:pass@127.0.0.1:${ port } /path`
42-
43- const ws = new WebSocket ( url )
45+ if ( attempts === 2 ) {
46+ t . assert . strictEqual ( req . headers . authorization , expectedAuth )
47+ wss . handleUpgrade ( req , socket , head , ( websocket ) => {
48+ wss . emit ( 'connection' , websocket , req )
49+ } )
50+ return
51+ }
4452
45- t . after ( ( ) => {
46- ws . close ( )
47- server . close ( )
53+ t . assert . fail ( `unexpected upgrade attempt #${ attempts } ` )
4854 } )
4955
50- const promise = createDeferredPromise ( )
56+ server . listen ( 0 , '127.0.0.1' )
57+ await once ( server , 'listening' )
5158
52- ws . addEventListener ( 'open' , ( ) => {
53- promise . resolve ( )
54- ws . send ( 'h' )
55- } )
59+ const ws = new WebSocket ( `ws://user:pass@127.0.0.1:${ server . address ( ) . port } /path` )
5660
57- ws . addEventListener ( 'error' , ( e ) => {
58- promise . reject ( e )
61+ await new Promise ( ( resolve , reject ) => {
62+ ws . addEventListener ( 'open' , resolve , { once : true } )
63+ ws . addEventListener ( 'error' , ( { error } ) => reject ( error ) , { once : true } )
5964 } )
6065
61- return promise . promise
66+ t . assert . strictEqual ( attempts , 2 )
6267} )
0 commit comments