@@ -661,3 +661,160 @@ test('clashing upgrade handler', async (t) => {
661661 const ws = new WebSocket ( 'ws://localhost:' + fastify . server . address ( ) . port )
662662 await once ( ws , 'error' )
663663} )
664+
665+ test ( 'Should handleUpgradeRequest successfully' , async ( t ) => {
666+ t . plan ( 4 )
667+
668+ const fastify = Fastify ( )
669+ t . after ( ( ) => fastify . close ( ) )
670+
671+ await fastify . register ( fastifyWebsocket )
672+
673+ let customUpgradeCalled = false
674+
675+ fastify . get ( '/' , {
676+ websocket : true ,
677+ handleUpgradeRequest : async ( request , socket , head ) => {
678+ customUpgradeCalled = true
679+ t . assert . equal ( typeof socket , 'object' , 'socket parameter is provided' )
680+ t . assert . equal ( Buffer . isBuffer ( head ) , true , 'head parameter is a buffer' )
681+
682+ return new Promise ( ( resolve ) => {
683+ fastify . websocketServer . handleUpgrade ( request . raw , socket , head , ( ws ) => {
684+ resolve ( ws )
685+ } )
686+ } )
687+ }
688+ } , ( socket ) => {
689+ socket . on ( 'message' , ( data ) => {
690+ socket . send ( `echo: ${ data } ` )
691+ } )
692+ t . after ( ( ) => socket . terminate ( ) )
693+ } )
694+
695+ await fastify . listen ( { port : 0 } )
696+
697+ const ws = new WebSocket ( 'ws://localhost:' + fastify . server . address ( ) . port )
698+ t . after ( ( ) => ws . close ( ) )
699+
700+ await once ( ws , 'open' )
701+ ws . send ( 'hello' )
702+
703+ const [ message ] = await once ( ws , 'message' )
704+ t . assert . equal ( message . toString ( ) , 'echo: hello' )
705+
706+ t . assert . ok ( customUpgradeCalled , 'handleUpgradeRequest was called' )
707+ } )
708+
709+ test . only ( 'Should handle errors thrown in handleUpgradeRequest' , async ( t ) => {
710+ t . plan ( 1 )
711+
712+ const fastify = Fastify ( )
713+ t . after ( ( ) => fastify . close ( ) )
714+
715+ await fastify . register ( fastifyWebsocket )
716+
717+ fastify . get ( '/' , {
718+ websocket : true ,
719+ handleUpgradeRequest : async ( ) => {
720+ throw new Error ( 'Custom upgrade error' )
721+ }
722+ } , ( ) => {
723+ t . fail ( 'websocket handler should not be called when upgrade fails' )
724+ } )
725+
726+ await fastify . listen ( { port : 0 } )
727+
728+ const ws = new WebSocket ( 'ws://localhost:' + fastify . server . address ( ) . port )
729+
730+ let wsErrorResolved
731+ const wsErrorPromise = new Promise ( ( resolve ) => {
732+ wsErrorResolved = resolve
733+ } )
734+
735+ ws . on ( 'error' , ( error ) => {
736+ wsErrorResolved ( error )
737+ } )
738+
739+ const wsError = await wsErrorPromise
740+
741+ t . assert . equal ( wsError . message , 'Unexpected server response: 500' )
742+ } )
743+
744+ test ( 'Should allow for handleUpgradeRequest to send a response to the client before throwing an error' , async ( t ) => {
745+ t . plan ( 1 )
746+
747+ const fastify = Fastify ( )
748+ t . after ( ( ) => fastify . close ( ) )
749+
750+ await fastify . register ( fastifyWebsocket )
751+
752+ fastify . get ( '/' , {
753+ websocket : true ,
754+ handleUpgradeRequest : async ( ) => {
755+ const error = new Error ( 'Forbidden' )
756+ error . statusCode = 403
757+ throw error
758+ }
759+ } , ( ) => {
760+ t . fail ( 'websocket handler should not be called when upgrade fails' )
761+ } )
762+
763+ await fastify . listen ( { port : 0 } )
764+
765+ const ws = new WebSocket ( 'ws://localhost:' + fastify . server . address ( ) . port )
766+
767+ let wsErrorResolved
768+ const wsErrorPromise = new Promise ( ( resolve ) => {
769+ wsErrorResolved = resolve
770+ } )
771+
772+ ws . on ( 'error' , ( error ) => {
773+ wsErrorResolved ( error )
774+ } )
775+
776+ const wsError = await wsErrorPromise
777+
778+ t . assert . equal ( wsError . message , 'Unexpected server response: 403' )
779+ } )
780+
781+ test ( 'Should not send a response if handleUpgradeRequest has already ended the underlying socket and thrown an error' , async ( t ) => {
782+ t . plan ( 1 )
783+
784+ const fastify = Fastify ( )
785+ t . after ( ( ) => fastify . close ( ) )
786+
787+ await fastify . register ( fastifyWebsocket )
788+
789+ fastify . get ( '/' , {
790+ websocket : true ,
791+ handleUpgradeRequest : async ( request , socket , head ) => {
792+ socket . write ( 'HTTP/1.1 400 Bad Request\r\n' )
793+ socket . write ( 'Connection: closed\r\n' )
794+ socket . write ( '\r\n' )
795+ socket . end ( )
796+ socket . destroy ( )
797+
798+ throw new Error ( 'thrown after response has ended' )
799+ }
800+ } , ( ) => {
801+ t . fail ( 'websocket handler should not be called when upgrade fails' )
802+ } )
803+
804+ await fastify . listen ( { port : 0 } )
805+
806+ const ws = new WebSocket ( 'ws://localhost:' + fastify . server . address ( ) . port )
807+
808+ let wsErrorResolved
809+ const wsErrorPromise = new Promise ( ( resolve ) => {
810+ wsErrorResolved = resolve
811+ } )
812+
813+ ws . on ( 'error' , ( error ) => {
814+ wsErrorResolved ( error )
815+ } )
816+
817+ const wsError = await wsErrorPromise
818+
819+ t . assert . equal ( wsError . message , 'Unexpected server response: 400' )
820+ } )
0 commit comments