spec/mongrel2/websocket_spec.rb in mongrel2-0.52.1 vs spec/mongrel2/websocket_spec.rb in mongrel2-0.52.2

- old
+ new

@@ -44,20 +44,23 @@ it "is the registered request type for WEBSOCKET_HANDSHAKE requests" do expect( Mongrel2::Request.request_types[:WEBSOCKET_HANDSHAKE] ).to eq( Mongrel2::WebSocket::ClientHandshake ) end + it "knows what subprotocols were requested" do handshake = @factory.handshake( '/websock', 'echo', 'superecho' ) expect( handshake.protocols ).to eq( ['echo', 'superecho'] ) end + it "doesn't error if no subprotocols were requested" do handshake = @factory.handshake( '/websock' ) expect( handshake.protocols ).to eq( [] ) end + it "can create a response WebSocket::ServerHandshake for itself" do handshake = @factory.handshake( '/websock' ) result = handshake.response handshake.body.rewind @@ -71,10 +74,11 @@ result.body.rewind expect( result.body.read ).to eq( '' ) end + it "can create a response WebSocket::ServerHandshake with a valid sub-protocol for itself" do handshake = @factory.handshake( '/websock', 'echo', 'superecho' ) result = handshake.response( :superecho ) handshake.body.rewind @@ -89,18 +93,20 @@ result.body.rewind expect( result.body.read ).to eq( '' ) end + it "raises an exception if the specified protocol is not one of the client's advertised ones" do handshake = @factory.handshake( '/websock', 'echo', 'superecho' ) expect { handshake.response( :map_updates ) }.to raise_error( Mongrel2::WebSocket::HandshakeError, /map_updates/i ) end + it "has a socket identifier" do handshake = @factory.handshake( '/websock', 'echo', 'superecho' ) expect( handshake.socket_id ).to eq( "#{handshake.sender_id}:#{handshake.conn_id}" ) end @@ -112,124 +118,150 @@ it "is the registered request type for WEBSOCKET requests" do expect( Mongrel2::Request.request_types[:WEBSOCKET] ).to eq( Mongrel2::WebSocket::Frame ) end + it "knows that its FIN flag is not set if its FLAG header doesn't include that bit" do frame = @factory.text( '/websock', 'Hello!' ) frame.flags ^= ( frame.flags & Mongrel2::WebSocket::FIN_FLAG ) expect( frame ).to_not be_fin() end + it "knows that its FIN flag is set if its FLAG header includes that bit" do frame = @factory.text( '/websock', 'Hello!', :fin ) expect( frame ).to be_fin() end + it "can unset its FIN flag" do frame = @factory.text( '/websock', 'Hello!', :fin ) frame.fin = false expect( frame ).to_not be_fin() end + it "can set its FIN flag" do frame = @factory.text( '/websock', 'Hello!' ) frame.fin = true expect( frame ).to be_fin() end + it "knows that its opcode is continuation if its opcode is 0x0" do expect( @factory.continuation( '/websock' ).opcode ).to eq( :continuation ) end + it "knows that is opcode is 'text' if its opcode is 0x1" do expect( @factory.text( '/websock', 'Hello!' ).opcode ).to eq( :text ) end + it "knows that is opcode is 'binary' if its opcode is 0x2" do expect( @factory.binary( '/websock', 'Hello!' ).opcode ).to eq( :binary ) end + it "knows that is opcode is 'close' if its opcode is 0x8" do expect( @factory.close( '/websock' ).opcode ).to eq( :close ) end + it "knows that is opcode is 'ping' if its opcode is 0x9" do expect( @factory.ping( '/websock' ).opcode ).to eq( :ping ) end + it "knows that is opcode is 'pong' if its opcode is 0xA" do expect( @factory.pong( '/websock' ).opcode ).to eq( :pong ) end + it "knows that its opcode is one of the reserved ones if it's 0x3" do expect( @factory.create( '/websocket', '', 0x3 ).opcode ).to eq( :reserved ) end + it "knows that its opcode is one of the reserved ones if it's 0x4" do expect( @factory.create( '/websocket', '', 0x4 ).opcode ).to eq( :reserved ) end + it "knows that its opcode is one of the reserved ones if it's 0xB" do expect( @factory.create( '/websocket', '', 0xB ).opcode ).to eq( :reserved ) end + it "knows that its opcode is one of the reserved ones if it's 0xD" do expect( @factory.create( '/websocket', '', 0xD ).opcode ).to eq( :reserved ) end + it "knows that its opcode is one of the reserved ones if it's 0xF" do expect( @factory.create( '/websocket', '', 0xF ).opcode ).to eq( :reserved ) end + it "allows its opcode to be set Symbolically" do frame = @factory.text( '/websocket', 'data' ) frame.opcode = :binary expect( frame.numeric_opcode ).to eq( OPCODE[:binary] ) end + it "allows its opcode to be set Numerically" do frame = @factory.binary( '/websocket', 'data' ) frame.opcode = :text expect( frame.numeric_opcode ).to eq( OPCODE[:text] ) end + it "allows its opcode to be set to one of the reserved opcodes Numerically" do frame = @factory.binary( '/websocket', 'data' ) frame.opcode = 0xC expect( frame.opcode ).to eq( :reserved ) expect( frame.numeric_opcode ).to eq( 0xC ) end + it "knows that its RSV1 flag is set if its FLAG header includes that bit" do expect( @factory.ping( '/websock', 'test', :rsv1 ) ).to be_rsv1() end + it "knows that its RSV2 flag is set if its FLAG header includes that bit" do expect( @factory.ping( '/websock', 'test', :rsv2 ) ).to be_rsv2() end + it "knows that its RSV3 flag is set if its FLAG header includes that bit" do expect( @factory.ping( '/websock', 'test', :rsv3 ) ).to be_rsv3() end + it "knows that one of its RSV flags is set if its FLAG header includes RSV1" do expect( @factory.ping( '/websock', 'test', :rsv1 ) ).to have_rsv_flags() end + it "knows that one of its RSV flags is set if its FLAG header includes RSV2" do expect( @factory.ping( '/websock', 'test', :rsv2 ) ).to have_rsv_flags() end + it "knows that one of its RSV flags is set if its FLAG header includes RSV3" do expect( @factory.ping( '/websock', 'test', :rsv3 ) ).to have_rsv_flags() end + it "knows that no RSV flags are set if its FLAG header doesn't have any RSV bits" do expect( @factory.ping( '/websock', 'test' ) ).to_not have_rsv_flags() end + it "can create a response WebSocket::Frame for itself" do frame = @factory.text( '/websock', "Hi, here's a message!", :fin ) result = frame.response @@ -240,10 +272,11 @@ result.payload.rewind expect( result.payload.read ).to eq( '' ) end + it "creates PONG responses with the same payload for PING frames" do frame = @factory.ping( '/websock', "WOO" ) result = frame.response @@ -254,10 +287,11 @@ result.payload.rewind expect( result.payload.read ).to eq( 'WOO' ) end + it "allows header flags and/or opcode to be specified when creating a response" do frame = @factory.text( '/websock', "some bad data" ) result = frame.response( :close, :fin ) @@ -269,10 +303,11 @@ result.payload.rewind expect( result.payload.read ).to eq( '' ) end + it "allows reserved opcodes to be specified when creating a response" do frame = @factory.text( '/websock', "some bad data" ) result = frame.response( 0xB ) @@ -284,10 +319,11 @@ result.payload.rewind expect( result.payload.read ).to eq( '' ) end + it "can be streamed in chunks instead of read all at once" do data = BINARY_DATA * 256 binary = @factory.binary( '/websock', data, :fin ) binary.chunksize = 16 @@ -295,10 +331,11 @@ "\x82\x7F\x00\x00\x00\x00\x00\x01\x00\x00\a\xBD\xB3\xFE\x87\xEB".force_encoding('binary'), "\xA9\x0En2q\xCE\x85\xAF)\x88w_d\xD6M\x9E".force_encoding('binary'), ]) end + it "has a socket identifier" do frame = @factory.text( '/websock', "data" ) expect( frame.socket_id ).to eq( "#{frame.sender_id}:#{frame.conn_id}" ) end @@ -309,10 +346,11 @@ before( :each ) do @frame = @factory.text( '/websock', '', :fin ) end + it "automatically transcodes its payload to UTF8" do text = "Стрелке!".encode( Encoding::KOI8_U ) @frame << text # 2-byte header @@ -323,28 +361,33 @@ end describe "a WebSocket binary frame" do + before( :each ) do @frame = @factory.binary( '/websock', BINARY_DATA, :fin ) end + it "doesn't try to transcode non-UTF8 data" do # 4-byte header expect( @frame.bytes.to_a[ 4, 16 ] ). to eq([ 0x07, 0xbd, 0xb3, 0xfe, 0x87, 0xeb, 0xa9, 0x0e, 0x6e, 0x32, 0x71, 0xce, 0x85, 0xaf, 0x29, 0x88 ]) end + end describe "a WebSocket close frame" do + before( :each ) do @frame = @factory.close( '/websock' ) end + it "has convenience methods for setting its payload via integer status code" do @frame.set_status( CLOSE_BAD_DATA ) @frame.payload.rewind expect( @frame.payload.read ). to eq( "%d %s\n" % [CLOSE_BAD_DATA, CLOSING_STATUS_DESC[CLOSE_BAD_DATA]] ) @@ -352,10 +395,11 @@ end describe "WebSocket control frames" do + before( :each ) do @frame = @factory.close( '/websock', "1002 Protocol error" ) end @@ -364,10 +408,11 @@ expect { @frame.validate }.to raise_error( Mongrel2::WebSocket::FrameError, /cannot exceed 125 bytes/i ) end + it "raises an exception if it's fragmented" do @frame.fin = false expect { @frame.validate }.to raise_error( Mongrel2::WebSocket::FrameError, /fragmented/i ) @@ -382,18 +427,20 @@ raw_response = @factory.text( '/websock', "Hello", :fin ).to_s expect( raw_response.bytes.to_a ).to eq( [ 0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f ] ) expect( raw_response.encoding ).to eq( Encoding::BINARY ) end + it "generates both parts of a fragmented unmasked text message correctly" do first = @factory.text( '/websock', 'Hel' ) last = @factory.continuation( '/websock', 'lo', :fin ) expect( first.bytes.to_a ).to eq( [ 0x01, 0x03, 0x48, 0x65, 0x6c ] ) expect( last.bytes.to_a ).to eq( [ 0x80, 0x02, 0x6c, 0x6f ] ) end + # The RFC's example is a masked response, but we're never a client, so never # generate masked payloads. it "generates a unmasked Ping request and (un)masked Ping response correctly" do ping = @factory.ping( '/websock', 'Hello' ) pong = @factory.pong( '/websock', 'Hello' ) @@ -408,9 +455,10 @@ # 1 + 1 + 2 expect( binary.bytes.to_a[0,4] ).to eq( [ 0x82, 0x7E, 0x01, 0x00 ] ) expect( binary.to_s[4..-1] ).to eq( BINARY_DATA ) end + it "generates a 64KiB binary message in a single unmasked frame correctly" do data = BINARY_DATA * 256 binary = @factory.binary( '/websock', data, :fin )