@@ -47,6 +47,44 @@ const getPort = (io: Server): number => {
4747 return io . httpServer . address ( ) . port ;
4848} ;
4949
50+ // TODO: update superagent as latest release now supports promises
51+ const eioHandshake = ( httpServer ) : Promise < string > => {
52+ return new Promise ( ( resolve ) => {
53+ request ( httpServer )
54+ . get ( "/socket.io/" )
55+ . query ( { transport : "polling" , EIO : 4 } )
56+ . end ( ( err , res ) => {
57+ const sid = JSON . parse ( res . text . substring ( 1 ) ) . sid ;
58+ resolve ( sid ) ;
59+ } ) ;
60+ } ) ;
61+ } ;
62+
63+ const eioPush = ( httpServer , sid : string , body : string ) : Promise < void > => {
64+ return new Promise ( ( resolve ) => {
65+ request ( httpServer )
66+ . post ( "/socket.io/" )
67+ . send ( body )
68+ . query ( { transport : "polling" , EIO : 4 , sid } )
69+ . expect ( 200 )
70+ . end ( ( ) => {
71+ resolve ( ) ;
72+ } ) ;
73+ } ) ;
74+ } ;
75+
76+ const eioPoll = ( httpServer , sid ) : Promise < string > => {
77+ return new Promise ( ( resolve ) => {
78+ request ( httpServer )
79+ . get ( "/socket.io/" )
80+ . query ( { transport : "polling" , EIO : 4 , sid } )
81+ . expect ( 200 )
82+ . end ( ( err , res ) => {
83+ resolve ( res . text ) ;
84+ } ) ;
85+ } ) ;
86+ } ;
87+
5088describe ( "socket.io" , ( ) => {
5189 it ( "should be the same version as client" , ( ) => {
5290 const version = require ( "../package" ) . version ;
@@ -378,6 +416,66 @@ describe("socket.io", () => {
378416 exec ( fixture ( "server-close.ts" ) , done ) ;
379417 } ) ;
380418 } ) ;
419+
420+ describe ( "protocol violations" , ( ) => {
421+ it ( "should close the connection when receiving several CONNECT packets" , async ( ) => {
422+ const httpServer = createServer ( ) ;
423+ const io = new Server ( httpServer ) ;
424+
425+ httpServer . listen ( 0 ) ;
426+
427+ const sid = await eioHandshake ( httpServer ) ;
428+ // send a first CONNECT packet
429+ await eioPush ( httpServer , sid , "40" ) ;
430+ // send another CONNECT packet
431+ await eioPush ( httpServer , sid , "40" ) ;
432+ // session is cleanly closed (not discarded, see 'client.close()')
433+ // first, we receive the Socket.IO handshake response
434+ await eioPoll ( httpServer , sid ) ;
435+ // then a close packet
436+ const body = await eioPoll ( httpServer , sid ) ;
437+ expect ( body ) . to . be ( "6\u001e1" ) ;
438+
439+ io . close ( ) ;
440+ } ) ;
441+
442+ it ( "should close the connection when receiving an EVENT packet while not connected" , async ( ) => {
443+ const httpServer = createServer ( ) ;
444+ const io = new Server ( httpServer ) ;
445+
446+ httpServer . listen ( 0 ) ;
447+
448+ const sid = await eioHandshake ( httpServer ) ;
449+ // send an EVENT packet
450+ await eioPush ( httpServer , sid , '42["some event"]' ) ;
451+ // session is cleanly closed, we receive a close packet
452+ const body = await eioPoll ( httpServer , sid ) ;
453+ expect ( body ) . to . be ( "6\u001e1" ) ;
454+
455+ io . close ( ) ;
456+ } ) ;
457+
458+ it ( "should close the connection when receiving an invalid packet" , async ( ) => {
459+ const httpServer = createServer ( ) ;
460+ const io = new Server ( httpServer ) ;
461+
462+ httpServer . listen ( 0 ) ;
463+
464+ const sid = await eioHandshake ( httpServer ) ;
465+ // send a CONNECT packet
466+ await eioPush ( httpServer , sid , "40" ) ;
467+ // send an invalid packet
468+ await eioPush ( httpServer , sid , "4abc" ) ;
469+ // session is cleanly closed (not discarded, see 'client.close()')
470+ // first, we receive the Socket.IO handshake response
471+ await eioPoll ( httpServer , sid ) ;
472+ // then a close packet
473+ const body = await eioPoll ( httpServer , sid ) ;
474+ expect ( body ) . to . be ( "6\u001e1" ) ;
475+
476+ io . close ( ) ;
477+ } ) ;
478+ } ) ;
381479 } ) ;
382480
383481 describe ( "namespaces" , ( ) => {
0 commit comments