summaryrefslogtreecommitdiff
path: root/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec')
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/helper.rb173
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/common_spec.rb138
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft03_spec.rb298
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft05_spec.rb50
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft06_spec.rb145
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft13_spec.rb105
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft75_spec.rb123
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft76_spec.rb234
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/gte_03_examples.rb42
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/shared_examples.rb265
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/framing_spec.rb298
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/handshake_spec.rb216
-rw-r--r--vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/masking_spec.rb29
13 files changed, 2116 insertions, 0 deletions
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/helper.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/helper.rb
new file mode 100644
index 0000000..76e45b5
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/helper.rb
@@ -0,0 +1,173 @@
+# encoding: BINARY
+
+require 'rubygems'
+require 'rspec'
+require 'em-spec/rspec'
+require 'em-http'
+
+require 'em-websocket'
+require 'em-websocket-client'
+
+require 'integration/shared_examples'
+require 'integration/gte_03_examples'
+
+RSpec.configure do |c|
+ c.mock_with :rspec
+end
+
+class FakeWebSocketClient < EM::Connection
+ attr_reader :handshake_response, :packets
+
+ def onopen(&blk); @onopen = blk; end
+ def onclose(&blk); @onclose = blk; end
+ def onerror(&blk); @onerror = blk; end
+ def onmessage(&blk); @onmessage = blk; end
+
+ def initialize
+ @state = :new
+ @packets = []
+ end
+
+ def receive_data(data)
+ # puts "RECEIVE DATA #{data}"
+ if @state == :new
+ @handshake_response = data
+ @onopen.call if defined? @onopen
+ @state = :open
+ else
+ @onmessage.call(data) if defined? @onmessage
+ @packets << data
+ end
+ end
+
+ def send(application_data)
+ send_frame(:text, application_data)
+ end
+
+ def send_frame(type, application_data)
+ send_data construct_frame(type, application_data)
+ end
+
+ def unbind
+ @onclose.call if defined? @onclose
+ end
+
+ private
+
+ def construct_frame(type, data)
+ "\x00#{data}\xff"
+ end
+end
+
+class Draft03FakeWebSocketClient < FakeWebSocketClient
+ private
+
+ def construct_frame(type, data)
+ frame = ""
+ frame << EM::WebSocket::Framing03::FRAME_TYPES[type]
+ frame << encoded_length(data.size)
+ frame << data
+ end
+
+ def encoded_length(length)
+ if length <= 125
+ [length].pack('C') # since rsv4 is 0
+ elsif length < 65536 # write 2 byte length
+ "\126#{[length].pack('n')}"
+ else # write 8 byte length
+ "\127#{[length >> 32, length & 0xFFFFFFFF].pack("NN")}"
+ end
+ end
+end
+
+class Draft05FakeWebSocketClient < Draft03FakeWebSocketClient
+ private
+
+ def construct_frame(type, data)
+ frame = ""
+ frame << "\x00\x00\x00\x00" # Mask with nothing for simplicity
+ frame << (EM::WebSocket::Framing05::FRAME_TYPES[type] | 0b10000000)
+ frame << encoded_length(data.size)
+ frame << data
+ end
+end
+
+class Draft07FakeWebSocketClient < Draft05FakeWebSocketClient
+ private
+
+ def construct_frame(type, data)
+ frame = ""
+ frame << (EM::WebSocket::Framing07::FRAME_TYPES[type] | 0b10000000)
+ # Should probably mask the data, but I get away without bothering since
+ # the server doesn't enforce that incoming frames are masked
+ frame << encoded_length(data.size)
+ frame << data
+ end
+end
+
+# Wrapper around em-websocket-client
+class Draft75WebSocketClient
+ def onopen(&blk); @onopen = blk; end
+ def onclose(&blk); @onclose = blk; end
+ def onerror(&blk); @onerror = blk; end
+ def onmessage(&blk); @onmessage = blk; end
+
+ def initialize
+ @ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/',
+ :version => 75,
+ :origin => 'http://example.com')
+ @ws.errback { |err| @onerror.call if defined? @onerror }
+ @ws.callback { @onopen.call if defined? @onopen }
+ @ws.stream { |msg| @onmessage.call(msg) if defined? @onmessage }
+ @ws.disconnect { @onclose.call if defined? @onclose }
+ end
+
+ def send(message)
+ @ws.send_msg(message)
+ end
+
+ def close_connection
+ @ws.close_connection
+ end
+end
+
+def start_server(opts = {})
+ EM::WebSocket.run({:host => "0.0.0.0", :port => 12345}.merge(opts)) { |ws|
+ yield ws if block_given?
+ }
+end
+
+def format_request(r)
+ data = "#{r[:method]} #{r[:path]} HTTP/1.1\r\n"
+ header_lines = r[:headers].map { |k,v| "#{k}: #{v}" }
+ data << [header_lines, '', r[:body]].join("\r\n")
+ data
+end
+
+def format_response(r)
+ data = r[:protocol] || "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
+ header_lines = r[:headers].map { |k,v| "#{k}: #{v}" }
+ data << [header_lines, '', r[:body]].join("\r\n")
+ data
+end
+
+RSpec::Matchers.define :succeed_with_upgrade do |response|
+ match do |actual|
+ success = nil
+ actual.callback { |upgrade_response, handler_klass|
+ success = (upgrade_response.lines.sort == format_response(response).lines.sort)
+ }
+ success
+ end
+end
+
+RSpec::Matchers.define :fail_with_error do |error_klass, error_message|
+ match do |actual|
+ success = nil
+ actual.errback { |e|
+ success = (e.class == error_klass)
+ success &= (e.message == error_message) if error_message
+ }
+ success
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/common_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/common_spec.rb
new file mode 100644
index 0000000..c89f871
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/common_spec.rb
@@ -0,0 +1,138 @@
+require 'helper'
+
+# These tests are not specific to any particular draft of the specification
+#
+describe "WebSocket server" do
+ include EM::SpecHelper
+ default_timeout 1
+
+ it "should fail on non WebSocket requests" do
+ em {
+ EM.add_timer(0.1) do
+ http = EM::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
+ http.errback { done }
+ http.callback { fail }
+ end
+
+ start_server
+ }
+ end
+
+ it "should expose the WebSocket request headers, path and query params" do
+ em {
+ EM.add_timer(0.1) do
+ ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/',
+ :origin => 'http://example.com')
+ ws.errback { fail }
+ ws.callback { ws.close_connection }
+ ws.stream { |msg| }
+ end
+
+ start_server do |ws|
+ ws.onopen { |handshake|
+ headers = handshake.headers
+ headers["Connection"].should == "Upgrade"
+ headers["Upgrade"].should == "websocket"
+ headers["Host"].to_s.should == "127.0.0.1:12345"
+ handshake.path.should == "/"
+ handshake.query.should == {}
+ handshake.origin.should == 'http://example.com'
+ }
+ ws.onclose {
+ ws.state.should == :closed
+ done
+ }
+ end
+ }
+ end
+
+ it "should expose the WebSocket path and query params when nonempty" do
+ em {
+ EM.add_timer(0.1) do
+ ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/hello?foo=bar&baz=qux')
+ ws.errback { fail }
+ ws.callback {
+ ws.close_connection
+ }
+ ws.stream { |msg| }
+ end
+
+ start_server do |ws|
+ ws.onopen { |handshake|
+ handshake.path.should == '/hello'
+ handshake.query_string.split('&').sort.
+ should == ["baz=qux", "foo=bar"]
+ handshake.query.should == {"foo"=>"bar", "baz"=>"qux"}
+ }
+ ws.onclose {
+ ws.state.should == :closed
+ done
+ }
+ end
+ }
+ end
+
+ it "should raise an exception if frame sent before handshake complete" do
+ em {
+ # 1. Start WebSocket server
+ start_server { |ws|
+ # 3. Try to send a message to the socket
+ lambda {
+ ws.send('early message')
+ }.should raise_error('Cannot send data before onopen callback')
+ done
+ }
+
+ # 2. Connect a dumb TCP connection (will not send handshake)
+ EM.connect('0.0.0.0', 12345, EM::Connection)
+ }
+ end
+
+ it "should allow the server to be started inside an existing EM" do
+ em {
+ EM.add_timer(0.1) do
+ http = EM::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
+ http.errback { |e| done }
+ http.callback { fail }
+ end
+
+ start_server do |ws|
+ ws.onopen { |handshake|
+ headers = handshake.headers
+ headers["Host"].to_s.should == "127.0.0.1:12345"
+ }
+ ws.onclose {
+ ws.state.should == :closed
+ done
+ }
+ end
+ }
+ end
+
+ context "outbound limit set" do
+ it "should close the connection if the limit is reached" do
+ em {
+ start_server(:outbound_limit => 150) do |ws|
+ # Increase the message size by one on each loop
+ ws.onmessage{|msg| ws.send(msg + "x") }
+ ws.onclose{|status|
+ status[:code].should == 1006 # Unclean
+ status[:was_clean].should be false
+ }
+ end
+
+ EM.add_timer(0.1) do
+ ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
+ ws.callback { ws.send_msg "hello" }
+ ws.disconnect { done } # Server closed the connection
+ ws.stream { |msg|
+ # minus frame size ? (getting 146 max here)
+ msg.data.size.should <= 150
+ # Return back the message
+ ws.send_msg(msg.data)
+ }
+ end
+ }
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft03_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft03_spec.rb
new file mode 100644
index 0000000..f299ab6
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft03_spec.rb
@@ -0,0 +1,298 @@
+require 'helper'
+
+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
+
+ def start_client
+ client = EM.connect('0.0.0.0', 12345, Draft03FakeWebSocketClient)
+ client.send_data(format_request(@request))
+ yield client if block_given?
+ return client
+ end
+
+ it_behaves_like "a websocket server" do
+ let(:version) { 3 }
+ end
+
+ it_behaves_like "a WebSocket server drafts 3 and above" do
+ let(:version) { 3 }
+ 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 {
+ start_server { |ws|
+ ws.onmessage { |msg|
+ msg.should == 'Hello'
+ done
+ }
+ }
+ start_client { |client|
+ client.onopen {
+ client.send_data("\x04\x05Hello")
+ }
+ }
+ }
+ end
+
+ it "should accept a fragmented text message" do
+ em {
+ start_server { |ws|
+ ws.onmessage { |msg|
+ msg.should == 'Hello'
+ done
+ }
+ }
+
+ connection = start_client
+
+ # 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 {
+ start_server
+
+ connection = start_client
+
+ # 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
+
+ start_server { |ws|
+ ws.onbinary { |msg|
+ msg.encoding.should == Encoding.find("BINARY") if defined?(Encoding)
+ msg.should == data
+ done
+ }
+ }
+
+ connection = start_client
+
+ # 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
+
+ start_server { |ws|
+ ws.onbinary { |msg|
+ msg.encoding.should == Encoding.find("BINARY") if defined?(Encoding)
+ msg.should == data
+ done
+ }
+ }
+
+ connection = start_client
+
+ # 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 {
+ start_server
+
+ connection = start_client
+
+ # 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 and call onclose with close code 1005 and was_clean=true (initiated by server)" do
+ em {
+ ack_received = false
+
+ start_server { |ws|
+ ws.onopen {
+ # 2. Send a close frame
+ EM.next_tick {
+ ws.close
+ }
+ }
+
+ # 5. Onclose event on server
+ ws.onclose { |event|
+ event.should == {
+ :code => 1005,
+ :reason => "",
+ :was_clean => true,
+ }
+ done
+ }
+ }
+
+ # 1. Create a fake client which sends draft 76 handshake
+ connection = start_client
+
+ # 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
+ }
+ }
+ end
+
+ # it "should repur"
+ #
+ it "should return close code 1005 and was_clean=true after closing handshake (initiated by client)" do
+ em {
+ start_server { |ws|
+ ws.onclose { |event|
+ event.should == {
+ :code => 1005,
+ :reason => "",
+ :was_clean => true,
+ }
+ done
+ }
+ }
+ start_client { |client|
+ client.onopen {
+ client.send_data("\x01\x00")
+ }
+ }
+ }
+ end
+
+ it "should not allow data frame to be sent after close frame sent" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ # 2. Send a close frame
+ EM.next_tick {
+ ws.close
+ }
+
+ # 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
+ start_client
+ }
+ end
+
+ it "should still respond to control frames after close frame sent" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ # 2. Send a close frame
+ EM.next_tick {
+ ws.close
+ }
+ }
+ }
+
+ # 1. Create a fake client which sends draft 76 handshake
+ connection = start_client
+
+ 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
+
+ it "should report that close codes are not supported" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ ws.supports_close_codes?.should == false
+ done
+ }
+ }
+ start_client
+ }
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft05_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft05_spec.rb
new file mode 100644
index 0000000..e07ea28
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft05_spec.rb
@@ -0,0 +1,50 @@
+require 'helper'
+
+describe "draft05" 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' => '5'
+ }
+ }
+ end
+
+ def start_client
+ client = EM.connect('0.0.0.0', 12345, Draft05FakeWebSocketClient)
+ client.send_data(format_request(@request))
+ yield client if block_given?
+ return client
+ end
+
+ it_behaves_like "a websocket server" do
+ let(:version) { 5 }
+ end
+
+ it_behaves_like "a WebSocket server drafts 3 and above" do
+ let(:version) { 5 }
+ end
+
+ it "should report that close codes are not supported" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ ws.supports_close_codes?.should == false
+ done
+ }
+ }
+ start_client
+ }
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft06_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft06_spec.rb
new file mode 100644
index 0000000..ae213cb
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft06_spec.rb
@@ -0,0 +1,145 @@
+require 'helper'
+
+describe "draft06" 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' => '6'
+ }
+ }
+
+ @response = {
+ :protocol => "HTTP/1.1 101 Switching Protocols\r\n",
+ :headers => {
+ "Upgrade" => "websocket",
+ "Connection" => "Upgrade",
+ "Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
+ "Sec-WebSocket-Protocol" => "sample",
+ }
+ }
+ end
+
+ def start_client
+ client = EM.connect('0.0.0.0', 12345, Draft05FakeWebSocketClient)
+ client.send_data(format_request(@request))
+ yield client if block_given?
+ return client
+ end
+
+ it_behaves_like "a websocket server" do
+ let(:version) { 6 }
+ end
+
+ it_behaves_like "a WebSocket server drafts 3 and above" do
+ let(:version) { 6 }
+ end
+
+ it "should open connection" do
+ em {
+ start_server { |server|
+ server.onopen {
+ server.instance_variable_get(:@handler).class.should == EventMachine::WebSocket::Handler06
+ }
+ }
+
+ start_client { |client|
+ client.onopen {
+ client.handshake_response.lines.sort.
+ should == format_response(@response).lines.sort
+ done
+ }
+ }
+ }
+ end
+
+ it "should accept a single-frame text message (masked)" do
+ em {
+ start_server { |server|
+ server.onmessage { |msg|
+ msg.should == 'Hello'
+ if msg.respond_to?(:encoding)
+ msg.encoding.should == Encoding.find("UTF-8")
+ end
+ done
+ }
+ server.onerror {
+ fail
+ }
+ }
+
+ start_client { |client|
+ client.onopen {
+ client.send_data("\x00\x00\x01\x00\x84\x05Ielln")
+ }
+ }
+ }
+ end
+
+ it "should return close code and reason if closed via handshake" do
+ em {
+ start_server { |ws|
+ ws.onclose { |event|
+ # 2. Receive close event in server
+ event.should == {
+ :code => 4004,
+ :reason => "close reason",
+ :was_clean => true,
+ }
+ done
+ }
+ }
+ start_client { |client|
+ client.onopen {
+ # 1: Send close handshake
+ close_data = [4004].pack('n')
+ close_data << "close reason"
+ client.send_frame(:close, close_data)
+ }
+ }
+ }
+ end
+
+ it "should return close code 1005 if no code was specified" do
+ em {
+ start_server { |ws|
+ ws.onclose { |event|
+ event.should == {
+ :code => 1005,
+ :reason => "",
+ :was_clean => true,
+ }
+ done
+ }
+ }
+ start_client { |client|
+ client.onopen {
+ client.send_frame(:close, '')
+ }
+ }
+ }
+ end
+
+ it "should report that close codes are supported" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ ws.supports_close_codes?.should == true
+ done
+ }
+ }
+ start_client
+ }
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft13_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft13_spec.rb
new file mode 100644
index 0000000..10dc2a3
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft13_spec.rb
@@ -0,0 +1,105 @@
+# encoding: BINARY
+
+require 'helper'
+
+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=",
+ "Sec-WebSocket-Protocol" => "sample",
+ }
+ }
+ end
+
+ def start_client
+ client = EM.connect('0.0.0.0', 12345, Draft07FakeWebSocketClient)
+ client.send_data(format_request(@request))
+ yield client if block_given?
+ return client
+ end
+
+ it_behaves_like "a websocket server" do
+ let(:version) { 13 }
+ end
+
+ it_behaves_like "a WebSocket server drafts 3 and above" do
+ let(:version) { 13 }
+ end
+
+ it "should send back the correct handshake response" do
+ em {
+ start_server
+
+ connection = start_client
+
+ connection.onopen {
+ connection.handshake_response.lines.sort.
+ should == format_response(@response).lines.sort
+ done
+ }
+ }
+ end
+
+ # TODO: This test would be much nicer with a real websocket client...
+ it "should support sending pings and binding to onpong" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ ws.should be_pingable
+ EM.next_tick {
+ ws.ping('hello').should == true
+ }
+
+ }
+ ws.onpong { |data|
+ data.should == 'hello'
+ done
+ }
+ }
+
+ connection = start_client
+
+ # Confusing, fake onmessage means any data after the handshake
+ connection.onmessage { |data|
+ # This is what a ping looks like
+ data.should == "\x89\x05hello"
+ # This is what a pong looks like
+ connection.send_data("\x8a\x05hello")
+ }
+ }
+ end
+
+ it "should report that close codes are supported" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ ws.supports_close_codes?.should == true
+ done
+ }
+ }
+ start_client
+ }
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft75_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft75_spec.rb
new file mode 100644
index 0000000..8d9faec
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft75_spec.rb
@@ -0,0 +1,123 @@
+require 'helper'
+
+# These integration tests are older and use a different testing style to the
+# integration tests for newer drafts. They use EM::HttpRequest which happens
+# to currently estabish a websocket connection using the draft75 protocol.
+#
+describe "WebSocket server draft75" do
+ include EM::SpecHelper
+ default_timeout 1
+
+ def start_client
+ client = Draft75WebSocketClient.new
+ yield client if block_given?
+ return client
+ end
+
+ it_behaves_like "a websocket server" do
+ let(:version) { 75 }
+ end
+
+ it "should automatically complete WebSocket handshake" do
+ em {
+ MSG = "Hello World!"
+ EventMachine.add_timer(0.1) do
+ ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
+ ws.errback { fail }
+ ws.callback { }
+
+ ws.stream { |msg|
+ msg.data.should == MSG
+ EventMachine.stop
+ }
+ end
+
+ start_server { |ws|
+ ws.onopen {
+ ws.send MSG
+ }
+ }
+ }
+ end
+
+ it "should split multiple messages into separate callbacks" do
+ em {
+ messages = %w[1 2]
+ received = []
+
+ EventMachine.add_timer(0.1) do
+ ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
+ ws.errback { fail }
+ ws.stream {|msg|}
+ ws.callback {
+ ws.send_msg messages[0]
+ ws.send_msg messages[1]
+ }
+ end
+
+ start_server { |ws|
+ ws.onopen {}
+ ws.onclose {}
+ ws.onmessage {|msg|
+ msg.should == messages[received.size]
+ received.push msg
+
+ EventMachine.stop if received.size == messages.size
+ }
+ }
+ }
+ end
+
+ it "should call onclose callback when client closes connection" do
+ em {
+ EventMachine.add_timer(0.1) do
+ ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
+ ws.errback { fail }
+ ws.callback {
+ ws.close_connection
+ }
+ ws.stream{|msg|}
+ end
+
+ start_server { |ws|
+ ws.onopen {}
+ ws.onclose {
+ ws.state.should == :closed
+ EventMachine.stop
+ }
+ }
+ }
+ end
+
+ it "should call onerror callback with raised exception and close connection on bad handshake" do
+ em {
+ EventMachine.add_timer(0.1) do
+ http = EM::HttpRequest.new('http://127.0.0.1:12345/').get
+ http.errback { }
+ http.callback { fail }
+ end
+
+ start_server { |ws|
+ ws.onopen { fail }
+ ws.onclose { EventMachine.stop }
+ ws.onerror {|e|
+ e.should be_an_instance_of EventMachine::WebSocket::HandshakeError
+ e.message.should match('Not an upgrade request')
+ EventMachine.stop
+ }
+ }
+ }
+ end
+
+ it "should report that close codes are not supported" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ ws.supports_close_codes?.should == false
+ done
+ }
+ }
+ start_client
+ }
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft76_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft76_spec.rb
new file mode 100644
index 0000000..f1a14e6
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/draft76_spec.rb
@@ -0,0 +1,234 @@
+# encoding: BINARY
+
+require 'helper'
+
+describe "WebSocket server draft76" 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'
+ },
+ :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
+
+ def start_client
+ client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
+ client.send_data(format_request(@request))
+ yield client if block_given?
+ return client
+ end
+
+ it_behaves_like "a websocket server" do
+ let(:version) { 76 }
+ end
+
+ it "should send back the correct handshake response" do
+ em {
+ start_server
+
+ start_client { |connection|
+ connection.onopen {
+ connection.handshake_response.lines.sort.
+ should == format_response(@response).lines.sort
+ done
+ }
+ }
+ }
+ end
+
+ it "should send closing frame back and close the connection after recieving closing frame" do
+ em {
+ start_server
+
+ connection = start_client
+
+ # Send closing frame after handshake complete
+ connection.onopen {
+ connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
+ }
+
+ # Check that this causes a termination string to be returned and the
+ # connection close
+ connection.onclose {
+ connection.packets[0].should ==
+ EM::WebSocket::Handler76::TERMINATE_STRING
+ done
+ }
+ }
+ end
+
+ it "should ignore any data received after the closing frame" do
+ em {
+ start_server { |ws|
+ # Fail if foobar message is received
+ ws.onmessage { |msg|
+ fail
+ }
+ }
+
+ connection = start_client
+
+ # Send closing frame after handshake complete, followed by another msg
+ connection.onopen {
+ connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
+ connection.send('foobar')
+ }
+
+ connection.onclose {
+ done
+ }
+ }
+ end
+
+ it "should accept null bytes within the frame after a line return" do
+ em {
+ start_server { |ws|
+ ws.onmessage { |msg|
+ msg.should == "\n\000"
+ }
+ }
+
+ connection = start_client
+
+ # Send closing frame after handshake complete
+ connection.onopen {
+ connection.send_data("\000\n\000\377")
+ connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
+ }
+
+ connection.onclose {
+ done
+ }
+ }
+ end
+
+ it "should handle unreasonable frame lengths by calling onerror callback" do
+ em {
+ start_server { |server|
+ server.onerror { |error|
+ error.should be_an_instance_of EM::WebSocket::WSMessageTooBigError
+ error.message.should == "Frame length too long (1180591620717411303296 bytes)"
+ done
+ }
+ }
+
+ client = start_client
+
+ # This particular frame indicates a message length of
+ # 1180591620717411303296 bytes. Such a message would previously cause
+ # a "bignum too big to convert into `long'" error.
+ # However it is clearly unreasonable and should be rejected.
+ client.onopen {
+ client.send_data("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00")
+ }
+ }
+ end
+
+ it "should handle impossible frames by calling onerror callback" do
+ em {
+ start_server { |server|
+ server.onerror { |error|
+ error.should be_an_instance_of EM::WebSocket::WSProtocolError
+ error.message.should == "Invalid frame received"
+ done
+ }
+ }
+
+ client = start_client
+
+ client.onopen {
+ client.send_data("foobar") # Does not start with \x00 or \xff
+ }
+ }
+ end
+
+ it "should handle invalid http requests by raising HandshakeError passed to onerror callback" do
+ em {
+ start_server { |server|
+ server.onerror { |error|
+ error.should be_an_instance_of EM::WebSocket::HandshakeError
+ error.message.should == "Invalid HTTP header: Could not parse data entirely (1 != 29)"
+ done
+ }
+ }
+
+ client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
+ client.send_data("This is not a HTTP header\r\n\r\n")
+ }
+ end
+
+ it "should handle handshake request split into two TCP packets" do
+ em {
+ start_server
+
+ # Create a fake client which sends draft 76 handshake
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
+ data = format_request(@request)
+ # Sends first half of the request
+ connection.send_data(data[0...(data.length / 2)])
+
+ connection.onopen {
+ connection.handshake_response.lines.sort.
+ should == format_response(@response).lines.sort
+ done
+ }
+
+ EM.add_timer(0.1) do
+ # Sends second half of the request
+ connection.send_data(data[(data.length / 2)..-1])
+ end
+ }
+ end
+
+ it "should report that close codes are not supported" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ ws.supports_close_codes?.should == false
+ done
+ }
+ }
+ start_client
+ }
+ end
+
+ it "should call onclose when the server closes the connection [antiregression]" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ EM.add_timer(0.1) {
+ ws.close()
+ }
+ }
+ ws.onclose {
+ done
+ }
+ }
+ start_client
+ }
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/gte_03_examples.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/gte_03_examples.rb
new file mode 100644
index 0000000..f841618
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/gte_03_examples.rb
@@ -0,0 +1,42 @@
+shared_examples_for "a WebSocket server drafts 3 and above" do
+ it "should force close connections after a timeout if close handshake is not sent by the client" do
+ em {
+ server_onerror_fired = false
+ server_onclose_fired = false
+ client_got_close_handshake = false
+
+ start_server(:close_timeout => 0.1) { |ws|
+ ws.onopen {
+ # 1: Send close handshake to client
+ EM.next_tick { ws.close(4999, "Close message") }
+ }
+
+ ws.onerror { |e|
+ # 3: Client should receive onerror
+ e.class.should == EM::WebSocket::WSProtocolError
+ e.message.should == "Close handshake un-acked after 0.1s, closing tcp connection"
+ server_onerror_fired = true
+ }
+
+ ws.onclose {
+ server_onclose_fired = true
+ }
+ }
+ start_client { |client|
+ client.onmessage { |msg|
+ # 2: Client does not respond to close handshake (the fake client
+ # doesn't understand them at all hence this is in onmessage)
+ msg.should =~ /Close message/ if version >= 6
+ client_got_close_handshake = true
+ }
+
+ client.onclose {
+ server_onerror_fired.should == true
+ server_onclose_fired.should == true
+ client_got_close_handshake.should == true
+ done
+ }
+ }
+ }
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/shared_examples.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/shared_examples.rb
new file mode 100644
index 0000000..0cd6b42
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/integration/shared_examples.rb
@@ -0,0 +1,265 @@
+# encoding: UTF-8
+
+# These tests are run against all draft versions
+#
+shared_examples_for "a websocket server" do
+ it "should expose the protocol version" do
+ em {
+ start_server { |ws|
+ ws.onopen { |handshake|
+ handshake.protocol_version.should == version
+ done
+ }
+ }
+
+ start_client
+ }
+ end
+
+ it "should expose the origin header" do
+ em {
+ start_server { |ws|
+ ws.onopen { |handshake|
+ handshake.origin.should == 'http://example.com'
+ done
+ }
+ }
+
+ start_client
+ }
+ end
+
+ it "should expose the remote IP address" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ ws.remote_ip.should == "127.0.0.1"
+ done
+ }
+ }
+
+ start_client
+ }
+ end
+
+ it "should send messages successfully" do
+ em {
+ start_server { |ws|
+ ws.onmessage { |message|
+ message.should == "hello server"
+ done
+ }
+ }
+
+ start_client { |client|
+ client.onopen {
+ client.send("hello server")
+ }
+ }
+ }
+ end
+
+ it "should allow connection to be closed with valid close code" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ ws.close(4004, "Bye bye")
+ done
+ }
+ }
+
+ start_client
+ # TODO: Use a real client which understands how to respond to closing
+ # handshakes, sending the handshake currently untested
+ }
+ end
+
+ it "should raise error if if invalid close code is used" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ lambda {
+ ws.close(2000)
+ }.should raise_error("Application code may only use codes from 1000, 3000-4999")
+ done
+ }
+ }
+
+ start_client
+ }
+ end
+
+ it "should call onclose with was_clean set to false if connection closed without closing handshake by server" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ # Close tcp connection (no close handshake)
+ ws.close_connection
+ }
+ ws.onclose { |event|
+ event.should == {:code => 1006, :was_clean => false}
+ done
+ }
+ }
+ start_client
+ }
+ end
+
+ it "should call onclose with was_clean set to false if connection closed without closing handshake by client" do
+ em {
+ start_server { |ws|
+ ws.onclose { |event|
+ event.should == {:code => 1006, :was_clean => false}
+ done
+ }
+ }
+ start_client { |client|
+ client.onopen {
+ # Close tcp connection (no close handshake)
+ client.close_connection
+ }
+ }
+ }
+ end
+
+ it "should call onerror if an application error raised in onopen" do
+ em {
+ start_server { |ws|
+ ws.onopen {
+ raise "application error"
+ }
+
+ ws.onerror { |e|
+ e.message.should == "application error"
+ done
+ }
+ }
+
+ start_client
+ }
+ end
+
+ it "should call onerror if an application error raised in onmessage" do
+ em {
+ start_server { |server|
+ server.onmessage {
+ raise "application error"
+ }
+
+ server.onerror { |e|
+ e.message.should == "application error"
+ done
+ }
+ }
+
+ start_client { |client|
+ client.onopen {
+ client.send('a message')
+ }
+ }
+ }
+ end
+
+ it "should call onerror in an application error raised in onclose" do
+ em {
+ start_server { |server|
+ server.onclose {
+ raise "application error"
+ }
+
+ server.onerror { |e|
+ e.message.should == "application error"
+ done
+ }
+ }
+
+ start_client { |client|
+ client.onopen {
+ EM.add_timer(0.1) {
+ client.close_connection
+ }
+ }
+ }
+ }
+ end
+
+ it "should close the connection when a too long frame is sent" do
+ em {
+ start_server { |server|
+ server.max_frame_size = 20
+
+ server.onerror { |e|
+ # 3: Error should be reported to server
+ e.class.should == EventMachine::WebSocket::WSMessageTooBigError
+ e.message.should =~ /Frame length too long/
+ }
+ }
+
+ start_client { |client|
+ client.onopen {
+ EM.next_tick {
+ client.send("This message is longer than 20 characters")
+ }
+
+ }
+
+ client.onmessage { |msg|
+ # 4: This is actually the close message. Really need to use a real
+ # WebSocket client in these tests...
+ done
+ }
+
+ client.onclose {
+ # 4: Drafts 75 & 76 don't send a close message, they just close the
+ # connection
+ done
+ }
+ }
+ }
+ end
+
+ # Only run these tests on ruby 1.9
+ if "a".respond_to?(:force_encoding)
+ it "should raise error if you try to send non utf8 text data to ws" do
+ em {
+ start_server { |server|
+ server.onopen {
+ # Create a string which claims to be UTF-8 but which is not
+ s = "ê" # utf-8 string
+ s.encode!("ISO-8859-1")
+ s.force_encoding("UTF-8")
+ s.valid_encoding?.should == false # now invalid utf8
+
+ # Send non utf8 encoded data
+ server.send(s)
+ }
+ server.onerror { |error|
+ error.class.should == EventMachine::WebSocket::WebSocketError
+ error.message.should == "Data sent to WebSocket must be valid UTF-8 but was UTF-8 (valid: false)"
+ done
+ }
+ }
+
+ start_client { }
+ }
+ end
+
+ it "should not change the encoding of strings sent to send [antiregression]" do
+ em {
+ start_server { |server|
+ server.onopen {
+ s = "example string"
+ s.force_encoding("UTF-8")
+
+ server.send(s)
+
+ s.encoding.should == Encoding.find("UTF-8")
+ done
+ }
+ }
+
+ start_client { }
+ }
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/framing_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/framing_spec.rb
new file mode 100644
index 0000000..b2a8d33
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/framing_spec.rb
@@ -0,0 +1,298 @@
+# encoding: BINARY
+
+require 'helper'
+
+describe EM::WebSocket::Framing03 do
+ class FramingContainer
+ include EM::WebSocket::Framing03
+
+ def initialize
+ @connection = Object.new
+ def @connection.max_frame_size
+ 1000000
+ end
+ end
+
+ def <<(data)
+ @data << data
+ process_data
+ end
+
+ def debug(*args); end
+ end
+
+ before :each do
+ @f = FramingContainer.new
+ @f.initialize_framing
+ end
+
+ describe "basic examples" do
+ it "connection close" do
+ @f.should_receive(:message).with(:close, '', '')
+ @f << 0b00000001
+ @f << 0b00000000
+ end
+
+ it "ping" do
+ @f.should_receive(:message).with(:ping, '', '')
+ @f << 0b00000010
+ @f << 0b00000000
+ end
+
+ it "pong" do
+ @f.should_receive(:message).with(:pong, '', '')
+ @f << 0b00000011
+ @f << 0b00000000
+ end
+
+ it "text" do
+ @f.should_receive(:message).with(:text, '', 'foo')
+ @f << 0b00000100
+ @f << 0b00000011
+ @f << 'foo'
+ end
+
+ it "Text in two frames" do
+ @f.should_receive(:message).with(:text, '', 'hello world')
+ @f << 0b10000100
+ @f << 0b00000110
+ @f << "hello "
+ @f << 0b00000000
+ @f << 0b00000101
+ @f << "world"
+ end
+
+ it "2 byte extended payload length text frame" do
+ data = 'a' * 256
+ @f.should_receive(:message).with(:text, '', data)
+ @f << 0b00000100 # Single frame, text
+ @f << 0b01111110 # Length 126 (so read 2 bytes)
+ @f << 0b00000001 # Two bytes in network byte order (256)
+ @f << 0b00000000
+ @f << data
+ 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 "a single-frame text message" do
+ @f.should_receive(:message).with(:text, '', 'Hello')
+ @f << "\x04\x05Hello"
+ end
+
+ it "a fragmented text message" do
+ @f.should_receive(:message).with(:text, '', 'Hello')
+ @f << "\x84\x03Hel"
+ @f << "\x00\x02lo"
+ end
+
+ it "Ping request and response" do
+ @f.should_receive(:message).with(:ping, '', 'Hello')
+ @f << "\x02\x05Hello"
+ end
+
+ it "256 bytes binary message in a single frame" do
+ data = "a"*256
+ @f.should_receive(:message).with(:binary, '', data)
+ @f << "\x05\x7E\x01\x00" + data
+ end
+
+ it "64KiB binary message in a single frame" do
+ data = "a"*65536
+ @f.should_receive(:message).with(:binary, '', data)
+ @f << "\x05\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
+ end
+ end
+
+ describe "other tests" do
+ it "should accept a fragmented unmasked text message in 3 frames" do
+ @f.should_receive(:message).with(:text, '', 'Hello world')
+ @f << "\x84\x03Hel"
+ @f << "\x80\x02lo"
+ @f << "\x00\x06 world"
+ end
+ end
+
+ describe "error cases" do
+ it "should raise an exception on continuation frame without preceeding more frame" do
+ lambda {
+ @f << 0b00000000 # Single frame, continuation
+ @f << 0b00000001 # Length 1
+ @f << 'f'
+ }.should raise_error(EM::WebSocket::WebSocketError, 'Continuation frame not expected')
+ end
+ end
+end
+
+# These examples are straight from the spec
+# http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6
+describe EM::WebSocket::Framing04 do
+ class FramingContainer04
+ include EM::WebSocket::Framing04
+
+ def initialize
+ @connection = Object.new
+ def @connection.max_frame_size
+ 1000000
+ end
+ end
+
+ def <<(data)
+ @data << data
+ process_data
+ end
+
+ def debug(*args); end
+ end
+
+ before :each do
+ @f = FramingContainer04.new
+ @f.initialize_framing
+ end
+
+ describe "examples from the spec" do
+ it "a single-frame text message" do
+ @f.should_receive(:message).with(:text, '', 'Hello')
+ @f << "\x84\x05\x48\x65\x6c\x6c\x6f" # "\x84\x05Hello"
+ end
+
+ it "a fragmented text message" do
+ @f.should_receive(:message).with(:text, '', 'Hello')
+ @f << "\x04\x03Hel"
+ @f << "\x80\x02lo"
+ end
+
+ it "Ping request" do
+ @f.should_receive(:message).with(:ping, '', 'Hello')
+ @f << "\x82\x05Hello"
+ end
+
+ it "a pong response" do
+ @f.should_receive(:message).with(:pong, '', 'Hello')
+ @f << "\x83\x05Hello"
+ end
+
+ it "256 bytes binary message in a single frame" do
+ data = "a"*256
+ @f.should_receive(:message).with(:binary, '', data)
+ @f << "\x85\x7E\x01\x00" + data
+ end
+
+ it "64KiB binary message in a single frame" do
+ data = "a"*65536
+ @f.should_receive(:message).with(:binary, '', data)
+ @f << "\x85\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
+ end
+ end
+
+ describe "other tests" do
+ it "should accept a fragmented unmasked text message in 3 frames" do
+ @f.should_receive(:message).with(:text, '', 'Hello world')
+ @f << "\x04\x03Hel"
+ @f << "\x00\x02lo"
+ @f << "\x80\x06 world"
+ end
+ end
+end
+
+describe EM::WebSocket::Framing07 do
+ class FramingContainer07
+ include EM::WebSocket::Framing07
+
+ def initialize
+ @connection = Object.new
+ def @connection.max_frame_size
+ 1000000
+ end
+ end
+
+ def <<(data)
+ @data << data
+ process_data
+ end
+
+ def debug(*args); end
+ end
+
+ before :each do
+ @f = FramingContainer07.new
+ @f.initialize_framing
+ end
+
+ # These examples are straight from the spec
+ # http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07#section-4.6
+ describe "examples from the spec" do
+ it "a single-frame unmakedtext message" do
+ @f.should_receive(:message).with(:text, '', 'Hello')
+ @f << "\x81\x05\x48\x65\x6c\x6c\x6f" # "\x84\x05Hello"
+ end
+
+ it "a single-frame masked text message" do
+ @f.should_receive(:message).with(:text, '', 'Hello')
+ @f << "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58" # "\x84\x05Hello"
+ end
+
+ it "a fragmented unmasked text message" do
+ @f.should_receive(:message).with(:text, '', 'Hello')
+ @f << "\x01\x03Hel"
+ @f << "\x80\x02lo"
+ end
+
+ it "Ping request" do
+ @f.should_receive(:message).with(:ping, '', 'Hello')
+ @f << "\x89\x05Hello"
+ end
+
+ it "a pong response" do
+ @f.should_receive(:message).with(:pong, '', 'Hello')
+ @f << "\x8a\x05Hello"
+ end
+
+ it "256 bytes binary message in a single unmasked frame" do
+ data = "a"*256
+ @f.should_receive(:message).with(:binary, '', data)
+ @f << "\x82\x7E\x01\x00" + data
+ end
+
+ it "64KiB binary message in a single unmasked frame" do
+ data = "a"*65536
+ @f.should_receive(:message).with(:binary, '', data)
+ @f << "\x82\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
+ end
+ end
+
+ describe "other tests" do
+ it "should raise a WSProtocolError if an invalid frame type is requested" do
+ lambda {
+ # Opcode 3 is not supported by this draft
+ @f << "\x83\x05Hello"
+ }.should raise_error(EventMachine::WebSocket::WSProtocolError, "Unknown opcode 3")
+ end
+
+ it "should accept a fragmented unmasked text message in 3 frames" do
+ @f.should_receive(:message).with(:text, '', 'Hello world')
+ @f << "\x01\x03Hel"
+ @f << "\x00\x02lo"
+ @f << "\x80\x06 world"
+ end
+
+ it "should raise if non-fin frame is followed by a non-continuation data frame (continuation frame would be expected)" do
+ lambda {
+ @f << 0b00000001 # Not fin, text
+ @f << 0b00000001 # Length 1
+ @f << 'f'
+ @f << 0b10000001 # fin, text (continutation expected)
+ @f << 0b00000001 # Length 1
+ @f << 'b'
+ }.should raise_error(EM::WebSocket::WebSocketError, 'Continuation frame expected')
+ end
+
+ it "should raise on non-fin control frames (control frames must not be fragmented)" do
+ lambda {
+ @f << 0b00001010 # Not fin, pong (opcode 10)
+ @f << 0b00000000 # Length 1
+ }.should raise_error(EM::WebSocket::WebSocketError, 'Control frames must not be fragmented')
+ end
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/handshake_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/handshake_spec.rb
new file mode 100644
index 0000000..2754ba7
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/handshake_spec.rb
@@ -0,0 +1,216 @@
+require 'helper'
+
+describe EM::WebSocket::Handshake do
+ def handshake(request, secure = false)
+ handshake = EM::WebSocket::Handshake.new(secure)
+ handshake.receive_data(format_request(request))
+ handshake
+ end
+
+ 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'
+ },
+ :body => '^n:ds[4U'
+ }
+ @secure_request = @request.merge(:port => 443)
+
+ @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-"
+ }
+ @secure_response = @response.merge(:headers => @response[:headers].merge('Sec-WebSocket-Location' => "wss://example.com/demo"))
+ end
+
+ it "should handle good request" do
+ handshake(@request).should succeed_with_upgrade(@response)
+ end
+
+ it "should handle good request to secure default port if secure mode is enabled" do
+ handshake(@secure_request, true).
+ should succeed_with_upgrade(@secure_response)
+ end
+
+ it "should not handle good request to secure default port if secure mode is disabled" do
+ handshake(@secure_request, false).
+ should_not succeed_with_upgrade(@secure_response)
+ end
+
+ it "should handle good request on nondefault port" do
+ @request[:port] = 8081
+ @request[:headers]['Host'] = 'example.com:8081'
+ @response[:headers]['Sec-WebSocket-Location'] =
+ 'ws://example.com:8081/demo'
+
+ handshake(@request).should succeed_with_upgrade(@response)
+ end
+
+ it "should handle good request to secure nondefault port" do
+ @secure_request[:port] = 8081
+ @secure_request[:headers]['Host'] = 'example.com:8081'
+ @secure_response[:headers]['Sec-WebSocket-Location'] = 'wss://example.com:8081/demo'
+
+ handshake(@secure_request, true).
+ should succeed_with_upgrade(@secure_response)
+ end
+
+ it "should handle good request with no protocol" do
+ @request[:headers].delete('Sec-WebSocket-Protocol')
+ @response[:headers].delete("Sec-WebSocket-Protocol")
+
+ handshake(@request).should succeed_with_upgrade(@response)
+ end
+
+ it "should handle extra headers by simply ignoring them" do
+ @request[:headers]['EmptyValue'] = ""
+ @request[:headers]['AKey'] = "AValue"
+
+ handshake(@request).should succeed_with_upgrade(@response)
+ end
+
+ it "should raise error on HTTP request" do
+ @request[:headers] = {
+ 'Host' => 'www.google.com',
+ 'User-Agent' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 GTB6 GTBA',
+ 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+ 'Accept-Language' => 'en-us,en;q=0.5',
+ 'Accept-Encoding' => 'gzip,deflate',
+ 'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
+ 'Keep-Alive' => '300',
+ 'Connection' => 'keep-alive',
+ }
+
+ handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError)
+ end
+
+ it "should raise error on wrong method" do
+ @request[:method] = 'POST'
+
+ handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError)
+ end
+
+ it "should raise error if upgrade header incorrect" do
+ @request[:headers]['Upgrade'] = 'NonWebSocket'
+
+ handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError)
+ end
+
+ it "should raise error if Sec-WebSocket-Protocol is empty" do
+ @request[:headers]['Sec-WebSocket-Protocol'] = ''
+
+ handshake(@request).should fail_with_error(EM::WebSocket::HandshakeError)
+ end
+
+ %w[Sec-WebSocket-Key1 Sec-WebSocket-Key2].each do |header|
+ it "should raise error if #{header} has zero spaces" do
+ @request[:headers][header] = 'nospaces'
+
+ handshake(@request).
+ should fail_with_error(EM::WebSocket::HandshakeError, 'Websocket Key1 or Key2 does not contain spaces - this is a symptom of a cross-protocol attack')
+ end
+ end
+
+ it "should raise error if Sec-WebSocket-Key1 is missing" do
+ @request[:headers].delete("Sec-WebSocket-Key1")
+
+ # The error message isn't correct since key1 is used to heuristically
+ # determine the protocol version in use, however this test at least checks
+ # that the handshake does correctly fail
+ handshake(@request).
+ should fail_with_error(EM::WebSocket::HandshakeError, 'Extra bytes after header')
+ end
+
+ it "should raise error if Sec-WebSocket-Key2 is missing" do
+ @request[:headers].delete("Sec-WebSocket-Key2")
+
+ handshake(@request).
+ should fail_with_error(EM::WebSocket::HandshakeError, 'WebSocket key1 or key2 is missing')
+ end
+
+ it "should raise error if spaces do not divide numbers in Sec-WebSocket-Key* " do
+ @request[:headers]['Sec-WebSocket-Key2'] = '12998 5 Y3 1.P00'
+
+ handshake(@request).
+ should fail_with_error(EM::WebSocket::HandshakeError, 'Invalid Key "12998 5 Y3 1.P00"')
+ end
+
+ it "should raise error if the HTTP header is empty" do
+ handshake = EM::WebSocket::Handshake.new(false)
+ handshake.receive_data("\r\n\r\nfoobar")
+
+ handshake.
+ should fail_with_error(EM::WebSocket::HandshakeError, 'Invalid HTTP header: Could not parse data entirely (4 != 10)')
+ end
+
+ # This might seems crazy, but very occasionally we saw multiple "Upgrade:
+ # WebSocket" headers in the wild. RFC 4.2.1 isn't particularly clear on this
+ # point, so for now I have decided not to accept --@mloughran
+ it "should raise error on multiple upgrade headers" do
+ handshake = EM::WebSocket::Handshake.new(false)
+
+ # Add a duplicate upgrade header
+ headers = format_request(@request)
+ upgrade_header = "Upgrade: WebSocket\r\n"
+ headers.gsub!(upgrade_header, "#{upgrade_header}#{upgrade_header}")
+
+ handshake.receive_data(headers)
+
+ handshake.errback { |e|
+ e.class.should == EM::WebSocket::HandshakeError
+ e.message.should == 'Invalid upgrade header: ["WebSocket", "WebSocket"]'
+ }
+ end
+
+ it "should cope with requests where the header is split" do
+ request = format_request(@request)
+ incomplete_request = request[0...(request.length / 2)]
+ rest = request[(request.length / 2)..-1]
+ handshake = EM::WebSocket::Handshake.new(false)
+ handshake.receive_data(incomplete_request)
+
+ handshake.instance_variable_get(:@deferred_status).should == nil
+
+ # Send the remaining header
+ handshake.receive_data(rest)
+
+ handshake(@request).should succeed_with_upgrade(@response)
+ end
+
+ it "should cope with requests where the third key is split" do
+ request = format_request(@request)
+ # Removes last two bytes of the third key
+ incomplete_request = request[0..-3]
+ rest = request[-2..-1]
+ handshake = EM::WebSocket::Handshake.new(false)
+ handshake.receive_data(incomplete_request)
+
+ handshake.instance_variable_get(:@deferred_status).should == nil
+
+ # Send the remaining third key
+ handshake.receive_data(rest)
+
+ handshake(@request).should succeed_with_upgrade(@response)
+ end
+
+ it "should fail if the request URI is invalid" do
+ @request[:path] = "/%"
+ handshake(@request).should \
+ fail_with_error(EM::WebSocket::HandshakeError, 'Invalid request URI: /%')
+ end
+end
diff --git a/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/masking_spec.rb b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/masking_spec.rb
new file mode 100644
index 0000000..065aa95
--- /dev/null
+++ b/vendor/bundle/ruby/3.4.0/gems/em-websocket-0.5.3/spec/unit/masking_spec.rb
@@ -0,0 +1,29 @@
+# encoding: BINARY
+
+require 'helper'
+
+describe EM::WebSocket::MaskedString do
+ it "should allow reading 4 byte mask and unmasking byte / bytes" do
+ t = EM::WebSocket::MaskedString.new("\x00\x00\x00\x01\x00\x01\x00\x01")
+ t.read_mask
+ t.getbyte(3).should == 0x00
+ t.getbytes(4, 4).should == "\x00\x01\x00\x00"
+ t.getbytes(5, 3).should == "\x01\x00\x00"
+ end
+
+ it "should return nil from getbyte if index requested is out of range" do
+ t = EM::WebSocket::MaskedString.new("\x00\x00\x00\x00\x53")
+ t.read_mask
+ t.getbyte(4).should == 0x53
+ t.getbyte(5).should == nil
+ end
+
+ it "should allow switching masking on and off" do
+ t = EM::WebSocket::MaskedString.new("\x02\x00\x00\x00\x03")
+ t.getbyte(4).should == 0x03
+ t.read_mask
+ t.getbyte(4).should == 0x01
+ t.unset_mask
+ t.getbyte(4).should == 0x03
+ end
+end