require 'helper' require 'integration/shared_examples' describe "draft03" do include EM::SpecHelper default_timeout 1 before :each do @request = { :port => 80, :method => "GET", :path => "/demo", :headers => { 'Host' => 'example.com', 'Connection' => 'Upgrade', 'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00', 'Sec-WebSocket-Protocol' => 'sample', 'Upgrade' => 'WebSocket', 'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5', 'Origin' => 'http://example.com', 'Sec-WebSocket-Draft' => '3' }, :body => '^n:ds[4U' } @response = { :headers => { "Upgrade" => "WebSocket", "Connection" => "Upgrade", "Sec-WebSocket-Location" => "ws://example.com/demo", "Sec-WebSocket-Origin" => "http://example.com", "Sec-WebSocket-Protocol" => "sample" }, :body => "8jKS\'y:G*Co,Wxa-" } end it_behaves_like "a websocket server" do def start_server EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| yield ws } end def start_client client = EM.connect('0.0.0.0', 12345, Draft03FakeWebSocketClient) client.send_data(format_request(@request)) yield client if block_given? end end # These examples are straight from the spec # http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6 describe "examples from the spec" do it "should accept a single-frame text message" do em { EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| ws.onmessage { |msg| msg.should == 'Hello' done } } # Create a fake client which sends draft 76 handshake connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) connection.send_data(format_request(@request)) # Send frame connection.onopen { connection.send_data("\x04\x05Hello") } } end it "should accept a fragmented text message" do em { EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| ws.onmessage { |msg| msg.should == 'Hello' done } } # Create a fake client which sends draft 76 handshake connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) connection.send_data(format_request(@request)) # Send frame connection.onopen { connection.send_data("\x84\x03Hel") connection.send_data("\x00\x02lo") } } end it "should accept a ping request and respond with the same body" do em { EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| } # Create a fake client which sends draft 76 handshake connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) connection.send_data(format_request(@request)) # Send frame connection.onopen { connection.send_data("\x02\x05Hello") } connection.onmessage { |frame| next if frame.nil? frame.should == "\x03\x05Hello" done } } end it "should accept a 256 bytes binary message in a single frame" do em { data = "a" * 256 EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| ws.onmessage { |msg| msg.should == data done } } # Create a fake client which sends draft 76 handshake connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) connection.send_data(format_request(@request)) # Send frame connection.onopen { connection.send_data("\x05\x7E\x01\x00" + data) } } end it "should accept a 64KiB binary message in a single frame" do em { data = "a" * 65536 EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| ws.onmessage { |msg| msg.should == data done } } # Create a fake client which sends draft 76 handshake connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) connection.send_data(format_request(@request)) # Send frame connection.onopen { connection.send_data("\x05\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data) } } end end describe "close handling" do it "should respond to a new close frame with a close frame" do em { EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| } # Create a fake client which sends draft 76 handshake connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) connection.send_data(format_request(@request)) # Send close frame connection.onopen { connection.send_data("\x01\x00") } # Check that close ack received connection.onmessage { |frame| frame.should == "\x01\x00" done } } end it "should close the connection on receiving a close acknowlegement" do em { ack_received = false EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| ws.onopen { # 2. Send a close frame EM.next_tick { ws.close_websocket } } } # 1. Create a fake client which sends draft 76 handshake connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) connection.send_data(format_request(@request)) # 3. Check that close frame recieved and acknowlege it connection.onmessage { |frame| frame.should == "\x01\x00" ack_received = true connection.send_data("\x01\x00") } # 4. Check that connection is closed _after_ the ack connection.onclose { ack_received.should == true done } } end it "should not allow data frame to be sent after close frame sent" do em { EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| ws.onopen { # 2. Send a close frame EM.next_tick { ws.close_websocket } # 3. Check that exception raised if I attempt to send more data EM.add_timer(0.1) { lambda { ws.send('hello world') }.should raise_error(EM::WebSocket::WebSocketError, 'Cannot send data frame since connection is closing') done } } } # 1. Create a fake client which sends draft 76 handshake connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) connection.send_data(format_request(@request)) } end it "should still respond to control frames after close frame sent" do em { EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| ws.onopen { # 2. Send a close frame EM.next_tick { ws.close_websocket } } } # 1. Create a fake client which sends draft 76 handshake connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient) connection.send_data(format_request(@request)) connection.onmessage { |frame| if frame == "\x01\x00" # 3. After the close frame is received send a ping frame, but # don't respond with a close ack connection.send_data("\x02\x05Hello") else # 4. Check that the pong is received frame.should == "\x03\x05Hello" done end } } end end end