diff --git a/lib/em-websocket.rb b/lib/em-websocket.rb index 7e41459..0c109a9 100644 --- a/lib/em-websocket.rb +++ b/lib/em-websocket.rb @@ -9,7 +9,7 @@ close75 close03 close05 close06 masking04 message_processor_03 message_processor_06 - handler_factory handler handler75 handler76 handler03 handler05 handler06 handler07 handler08 + handler_factory handler handler75 handler76 handler03 handler05 handler06 handler07 handler08 handler13 ].each do |file| require "em-websocket/#{file}" end diff --git a/lib/em-websocket/handler13.rb b/lib/em-websocket/handler13.rb new file mode 100644 index 0000000..8684a89 --- /dev/null +++ b/lib/em-websocket/handler13.rb @@ -0,0 +1,10 @@ +module EventMachine + module WebSocket + class Handler13 < Handler + include Handshake04 + include Framing07 + include MessageProcessor06 + include Close06 + end + end +end diff --git a/lib/em-websocket/handler_factory.rb b/lib/em-websocket/handler_factory.rb index 6e94a6d..d3bc1d0 100644 --- a/lib/em-websocket/handler_factory.rb +++ b/lib/em-websocket/handler_factory.rb @@ -90,7 +90,13 @@ def self.build_with_request(connection, request, remains, secure = false, debug when 7 Handler07.new(connection, request, debug) when 8 + # drafts 9, 10, 11 and 12 should never change the version + # number as they are all the same as version 08. Handler08.new(connection, request, debug) + when 13 + # drafts 13 to 17 all identify as version 13 as they are + # only minor changes or text changes. + Handler13.new(connection, request, debug) else # According to spec should abort the connection raise WebSocketError, "Protocol version #{version} not supported" diff --git a/spec/helper.rb b/spec/helper.rb index 248a6f3..d1a0c50 100644 --- a/spec/helper.rb +++ b/spec/helper.rb @@ -69,6 +69,32 @@ def send(application_data) end end +class Draft07FakeWebSocketClient < FakeWebSocketClient + def send(application_data) + frame = '' + opcode = 1 # fake only supports text frames + byte1 = opcode | 0b10000000 # since more, rsv1-3 are 0 + frame << byte1 + + length = application_data.size + if length <= 125 + byte2 = length # since rsv4 is 0 + frame << byte2 + elsif length < 65536 # write 2 byte length + frame << 126 + frame << [length].pack('n') + else # write 8 byte length + frame << 127 + frame << [length >> 32, length & 0xFFFFFFFF].pack("NN") + end + + frame << application_data + + send_data(frame) + end +end + + # Wrap EM:HttpRequest in a websocket like interface so that it can be used in the specs with the same interface as FakeWebSocketClient class Draft75WebSocketClient def onopen(&blk); @onopen = blk; end diff --git a/spec/integration/draft13_spec.rb b/spec/integration/draft13_spec.rb new file mode 100644 index 0000000..b78c6c6 --- /dev/null +++ b/spec/integration/draft13_spec.rb @@ -0,0 +1,65 @@ +require 'helper' +require 'integration/shared_examples' + +describe "draft13" do + include EM::SpecHelper + default_timeout 1 + + before :each do + @request = { + :port => 80, + :method => "GET", + :path => "/demo", + :headers => { + 'Host' => 'example.com', + 'Upgrade' => 'websocket', + 'Connection' => 'Upgrade', + 'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==', + 'Sec-WebSocket-Protocol' => 'sample', + 'Sec-WebSocket-Origin' => 'http://example.com', + 'Sec-WebSocket-Version' => '13' + } + } + + @response = { + :protocol => "HTTP/1.1 101 Switching Protocols\r\n", + :headers => { + "Upgrade" => "websocket", + "Connection" => "Upgrade", + "Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", + } + } + 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, Draft07FakeWebSocketClient) + client.send_data(format_request(@request)) + yield client if block_given? + end + end + + it "should send back the correct handshake response" do + em { + EM.add_timer(0.1) do + EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { } + + # Create a fake client which sends draft 07 handshake + connection = EM.connect('0.0.0.0', 12345, Draft07FakeWebSocketClient) + connection.send_data(format_request(@request)) + + connection.onopen { + connection.handshake_response.lines.sort. + should == format_response(@response).lines.sort + done + } + end + } + end +end