sonixlabs-em-websocket 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/CHANGELOG.rdoc +80 -0
- data/Gemfile +3 -0
- data/README.md +98 -0
- data/Rakefile +11 -0
- data/em-websocket.gemspec +27 -0
- data/examples/echo.rb +8 -0
- data/examples/flash_policy_file_server.rb +21 -0
- data/examples/js/FABridge.js +604 -0
- data/examples/js/WebSocketMain.swf +0 -0
- data/examples/js/swfobject.js +4 -0
- data/examples/js/web_socket.js +312 -0
- data/examples/multicast.rb +47 -0
- data/examples/test.html +30 -0
- data/lib/em-websocket/client_connection.rb +19 -0
- data/lib/em-websocket/close03.rb +11 -0
- data/lib/em-websocket/close05.rb +11 -0
- data/lib/em-websocket/close06.rb +16 -0
- data/lib/em-websocket/close75.rb +10 -0
- data/lib/em-websocket/connection.rb +184 -0
- data/lib/em-websocket/debugger.rb +17 -0
- data/lib/em-websocket/framing03.rb +167 -0
- data/lib/em-websocket/framing04.rb +15 -0
- data/lib/em-websocket/framing05.rb +168 -0
- data/lib/em-websocket/framing07.rb +180 -0
- data/lib/em-websocket/framing76.rb +114 -0
- data/lib/em-websocket/handler.rb +56 -0
- data/lib/em-websocket/handler03.rb +10 -0
- data/lib/em-websocket/handler05.rb +10 -0
- data/lib/em-websocket/handler06.rb +10 -0
- data/lib/em-websocket/handler07.rb +10 -0
- data/lib/em-websocket/handler08.rb +10 -0
- data/lib/em-websocket/handler13.rb +10 -0
- data/lib/em-websocket/handler75.rb +9 -0
- data/lib/em-websocket/handler76.rb +12 -0
- data/lib/em-websocket/handler_factory.rb +107 -0
- data/lib/em-websocket/handshake04.rb +75 -0
- data/lib/em-websocket/handshake75.rb +21 -0
- data/lib/em-websocket/handshake76.rb +71 -0
- data/lib/em-websocket/masking04.rb +63 -0
- data/lib/em-websocket/message_processor_03.rb +38 -0
- data/lib/em-websocket/message_processor_06.rb +52 -0
- data/lib/em-websocket/version.rb +5 -0
- data/lib/em-websocket/websocket.rb +45 -0
- data/lib/em-websocket.rb +23 -0
- data/lib/sonixlabs-em-websocket.rb +1 -0
- data/spec/helper.rb +146 -0
- data/spec/integration/client_examples.rb +48 -0
- data/spec/integration/common_spec.rb +118 -0
- data/spec/integration/draft03_spec.rb +270 -0
- data/spec/integration/draft05_spec.rb +48 -0
- data/spec/integration/draft06_spec.rb +88 -0
- data/spec/integration/draft13_spec.rb +75 -0
- data/spec/integration/draft75_spec.rb +117 -0
- data/spec/integration/draft76_spec.rb +230 -0
- data/spec/integration/shared_examples.rb +91 -0
- data/spec/unit/framing_spec.rb +325 -0
- data/spec/unit/handler_spec.rb +147 -0
- data/spec/unit/masking_spec.rb +27 -0
- data/spec/unit/message_processor_spec.rb +36 -0
- metadata +198 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'integration/client_examples'
|
3
|
+
|
4
|
+
describe "draft06" do
|
5
|
+
include EM::SpecHelper
|
6
|
+
default_timeout 1
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@request = {
|
10
|
+
:port => 80,
|
11
|
+
:method => "GET",
|
12
|
+
:path => "/demo",
|
13
|
+
:headers => {
|
14
|
+
'Host' => 'example.com',
|
15
|
+
'Upgrade' => 'websocket',
|
16
|
+
'Connection' => 'Upgrade',
|
17
|
+
'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==',
|
18
|
+
'Sec-WebSocket-Protocol' => 'sample',
|
19
|
+
'Sec-WebSocket-Origin' => 'http://example.com',
|
20
|
+
'Sec-WebSocket-Version' => '6'
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
@response = {
|
25
|
+
:protocol => "HTTP/1.1 101 Switching Protocols\r\n",
|
26
|
+
:headers => {
|
27
|
+
"Upgrade" => "websocket",
|
28
|
+
"Connection" => "Upgrade",
|
29
|
+
"Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
|
30
|
+
}
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def start_server
|
35
|
+
EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
|
36
|
+
yield ws
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def start_client
|
41
|
+
client = EM.connect('0.0.0.0', 12345, Draft03FakeWebSocketClient)
|
42
|
+
client.send_data(format_request(@request))
|
43
|
+
yield client if block_given?
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should open connection" do
|
47
|
+
em {
|
48
|
+
start_server { |server|
|
49
|
+
server.onopen {
|
50
|
+
server.instance_variable_get(:@handler).class.should == EventMachine::WebSocket::Handler06
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
start_client { |client|
|
55
|
+
client.onopen {
|
56
|
+
client.handshake_response.lines.sort.
|
57
|
+
should == format_response(@response).lines.sort
|
58
|
+
done
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should accept a single-frame text message (masked)" do
|
65
|
+
em {
|
66
|
+
start_server { |server|
|
67
|
+
server.onmessage { |msg|
|
68
|
+
msg.should == 'Hello'
|
69
|
+
if msg.respond_to?(:encoding)
|
70
|
+
msg.encoding.should == Encoding.find("UTF-8")
|
71
|
+
end
|
72
|
+
done
|
73
|
+
}
|
74
|
+
server.onerror {
|
75
|
+
fail
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
start_client { |client|
|
80
|
+
client.onopen {
|
81
|
+
client.send_data("\x00\x00\x01\x00\x84\x05Ielln")
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
it_should_behave_like "a websocket client"
|
88
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'integration/shared_examples'
|
3
|
+
require 'integration/client_examples'
|
4
|
+
|
5
|
+
describe "draft13" do
|
6
|
+
include EM::SpecHelper
|
7
|
+
default_timeout 1
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
@request = {
|
11
|
+
:port => 80,
|
12
|
+
:method => "GET",
|
13
|
+
:path => "/demo",
|
14
|
+
:headers => {
|
15
|
+
'Host' => 'example.com',
|
16
|
+
'Upgrade' => 'websocket',
|
17
|
+
'Connection' => 'Upgrade',
|
18
|
+
'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==',
|
19
|
+
'Sec-WebSocket-Protocol' => 'sample',
|
20
|
+
'Sec-WebSocket-Origin' => 'http://example.com',
|
21
|
+
'Sec-WebSocket-Version' => '13'
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
@response = {
|
26
|
+
:protocol => "HTTP/1.1 101 Switching Protocols\r\n",
|
27
|
+
:headers => {
|
28
|
+
"Upgrade" => "websocket",
|
29
|
+
"Connection" => "Upgrade",
|
30
|
+
"Sec-WebSocket-Accept" => "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
it_behaves_like "a websocket server" do
|
36
|
+
def start_server
|
37
|
+
EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
|
38
|
+
yield ws
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def start_client
|
43
|
+
client = EM.connect('0.0.0.0', 12345, Draft07FakeWebSocketClient)
|
44
|
+
client.send_data(format_request(@request))
|
45
|
+
yield client if block_given?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should send back the correct handshake response" do
|
50
|
+
em {
|
51
|
+
EM.add_timer(0.1) do
|
52
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { }
|
53
|
+
|
54
|
+
# Create a fake client which sends draft 07 handshake
|
55
|
+
connection = EM.connect('0.0.0.0', 12345, Draft07FakeWebSocketClient)
|
56
|
+
connection.send_data(format_request(@request))
|
57
|
+
|
58
|
+
connection.onopen {
|
59
|
+
connection.handshake_response.lines.sort.
|
60
|
+
should == format_response(@response).lines.sort
|
61
|
+
done
|
62
|
+
}
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
it_should_behave_like "a websocket client" do
|
68
|
+
def start_server
|
69
|
+
EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
|
70
|
+
yield ws
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'integration/shared_examples'
|
3
|
+
|
4
|
+
# These integration tests are older and use a different testing style to the
|
5
|
+
# integration tests for newer drafts. They use EM::HttpRequest which happens
|
6
|
+
# to currently estabish a websocket connection using the draft75 protocol.
|
7
|
+
#
|
8
|
+
describe "WebSocket server draft75" do
|
9
|
+
include EM::SpecHelper
|
10
|
+
default_timeout 1
|
11
|
+
|
12
|
+
it_behaves_like "a websocket server" do
|
13
|
+
def start_server
|
14
|
+
EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
|
15
|
+
yield ws
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def start_client
|
20
|
+
client = Draft75WebSocketClient.new
|
21
|
+
yield client if block_given?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should automatically complete WebSocket handshake" do
|
26
|
+
em {
|
27
|
+
MSG = "Hello World!"
|
28
|
+
EventMachine.add_timer(0.1) do
|
29
|
+
http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
|
30
|
+
http.errback { fail }
|
31
|
+
http.callback { http.response_header.status.should == 101 }
|
32
|
+
|
33
|
+
http.stream { |msg|
|
34
|
+
msg.should == MSG
|
35
|
+
EventMachine.stop
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
40
|
+
ws.onopen {
|
41
|
+
ws.send MSG
|
42
|
+
}
|
43
|
+
end
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should split multiple messages into separate callbacks" do
|
48
|
+
em {
|
49
|
+
messages = %w[1 2]
|
50
|
+
received = []
|
51
|
+
|
52
|
+
EventMachine.add_timer(0.1) do
|
53
|
+
http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
|
54
|
+
http.errback { fail }
|
55
|
+
http.stream {|msg|}
|
56
|
+
http.callback {
|
57
|
+
http.response_header.status.should == 101
|
58
|
+
http.send messages[0]
|
59
|
+
http.send messages[1]
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
64
|
+
ws.onopen {}
|
65
|
+
ws.onclose {}
|
66
|
+
ws.onmessage {|msg|
|
67
|
+
msg.should == messages[received.size]
|
68
|
+
received.push msg
|
69
|
+
|
70
|
+
EventMachine.stop if received.size == messages.size
|
71
|
+
}
|
72
|
+
end
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should call onclose callback when client closes connection" do
|
77
|
+
em {
|
78
|
+
EventMachine.add_timer(0.1) do
|
79
|
+
http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
|
80
|
+
http.errback { fail }
|
81
|
+
http.callback {
|
82
|
+
http.response_header.status.should == 101
|
83
|
+
http.close_connection
|
84
|
+
}
|
85
|
+
http.stream{|msg|}
|
86
|
+
end
|
87
|
+
|
88
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
89
|
+
ws.onopen {}
|
90
|
+
ws.onclose {
|
91
|
+
ws.state.should == :closed
|
92
|
+
EventMachine.stop
|
93
|
+
}
|
94
|
+
end
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should call onerror callback with raised exception and close connection on bad handshake" do
|
99
|
+
em {
|
100
|
+
EventMachine.add_timer(0.1) do
|
101
|
+
http = EventMachine::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
|
102
|
+
http.errback { http.response_header.status.should == 0 }
|
103
|
+
http.callback { fail }
|
104
|
+
end
|
105
|
+
|
106
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
|
107
|
+
ws.onopen { fail }
|
108
|
+
ws.onclose { EventMachine.stop }
|
109
|
+
ws.onerror {|e|
|
110
|
+
e.should be_an_instance_of EventMachine::WebSocket::HandshakeError
|
111
|
+
e.message.should match('Connection and Upgrade headers required')
|
112
|
+
EventMachine.stop
|
113
|
+
}
|
114
|
+
end
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'integration/shared_examples'
|
3
|
+
|
4
|
+
describe "WebSocket server draft76" do
|
5
|
+
include EM::SpecHelper
|
6
|
+
default_timeout 1
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@request = {
|
10
|
+
:port => 80,
|
11
|
+
:method => "GET",
|
12
|
+
:path => "/demo",
|
13
|
+
:headers => {
|
14
|
+
'Host' => 'example.com',
|
15
|
+
'Connection' => 'Upgrade',
|
16
|
+
'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00',
|
17
|
+
'Sec-WebSocket-Protocol' => 'sample',
|
18
|
+
'Upgrade' => 'WebSocket',
|
19
|
+
'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5',
|
20
|
+
'Origin' => 'http://example.com'
|
21
|
+
},
|
22
|
+
:body => '^n:ds[4U'
|
23
|
+
}
|
24
|
+
|
25
|
+
@response = {
|
26
|
+
:headers => {
|
27
|
+
"Upgrade" => "WebSocket",
|
28
|
+
"Connection" => "Upgrade",
|
29
|
+
"Sec-WebSocket-Location" => "ws://example.com/demo",
|
30
|
+
"Sec-WebSocket-Origin" => "http://example.com",
|
31
|
+
"Sec-WebSocket-Protocol" => "sample"
|
32
|
+
},
|
33
|
+
:body => "8jKS\'y:G*Co,Wxa-"
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
it_behaves_like "a websocket server" do
|
38
|
+
def start_server
|
39
|
+
EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
|
40
|
+
yield ws
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def start_client
|
45
|
+
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
46
|
+
client.send_data(format_request(@request))
|
47
|
+
yield client if block_given?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should send back the correct handshake response" do
|
52
|
+
em {
|
53
|
+
EM.add_timer(0.1) do
|
54
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { }
|
55
|
+
|
56
|
+
# Create a fake client which sends draft 76 handshake
|
57
|
+
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
58
|
+
connection.send_data(format_request(@request))
|
59
|
+
|
60
|
+
connection.onopen {
|
61
|
+
connection.handshake_response.lines.sort.
|
62
|
+
should == format_response(@response).lines.sort
|
63
|
+
done
|
64
|
+
}
|
65
|
+
end
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should send closing frame back and close the connection after recieving closing frame" do
|
70
|
+
em {
|
71
|
+
EM.add_timer(0.1) do
|
72
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { }
|
73
|
+
|
74
|
+
# Create a fake client which sends draft 76 handshake
|
75
|
+
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
76
|
+
connection.send_data(format_request(@request))
|
77
|
+
|
78
|
+
# Send closing frame after handshake complete
|
79
|
+
connection.onopen {
|
80
|
+
connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
|
81
|
+
}
|
82
|
+
|
83
|
+
# Check that this causes a termination string to be returned and the
|
84
|
+
# connection close
|
85
|
+
connection.onclose {
|
86
|
+
connection.packets[0].should ==
|
87
|
+
EM::WebSocket::Handler76::TERMINATE_STRING
|
88
|
+
done
|
89
|
+
}
|
90
|
+
end
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should ignore any data received after the closing frame" do
|
95
|
+
em {
|
96
|
+
EM.add_timer(0.1) do
|
97
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
|
98
|
+
# Fail if foobar message is received
|
99
|
+
ws.onmessage { |msg|
|
100
|
+
fail
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
# Create a fake client which sends draft 76 handshake
|
105
|
+
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
106
|
+
connection.send_data(format_request(@request))
|
107
|
+
|
108
|
+
# Send closing frame after handshake complete, followed by another msg
|
109
|
+
connection.onopen {
|
110
|
+
connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
|
111
|
+
connection.send('foobar')
|
112
|
+
}
|
113
|
+
|
114
|
+
connection.onclose {
|
115
|
+
done
|
116
|
+
}
|
117
|
+
end
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should accept null bytes within the frame after a line return" do
|
122
|
+
em {
|
123
|
+
EM.add_timer(0.1) do
|
124
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
|
125
|
+
ws.onmessage { |msg|
|
126
|
+
msg.should == "\n\000"
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
# Create a fake client which sends draft 76 handshake
|
131
|
+
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
132
|
+
connection.send_data(format_request(@request))
|
133
|
+
|
134
|
+
# Send closing frame after handshake complete
|
135
|
+
connection.onopen {
|
136
|
+
connection.send_data("\000\n\000\377")
|
137
|
+
connection.send_data(EM::WebSocket::Handler76::TERMINATE_STRING)
|
138
|
+
}
|
139
|
+
|
140
|
+
connection.onclose {
|
141
|
+
done
|
142
|
+
}
|
143
|
+
end
|
144
|
+
}
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should handle unreasonable frame lengths by calling onerror callback" do
|
148
|
+
em {
|
149
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |server|
|
150
|
+
server.onerror { |error|
|
151
|
+
error.should be_an_instance_of EM::WebSocket::DataError
|
152
|
+
error.message.should == "Frame length too long (1180591620717411303296 bytes)"
|
153
|
+
done
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
# Create a fake client which sends draft 76 handshake
|
158
|
+
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
159
|
+
client.send_data(format_request(@request))
|
160
|
+
|
161
|
+
# This particular frame indicates a message length of
|
162
|
+
# 1180591620717411303296 bytes. Such a message would previously cause
|
163
|
+
# a "bignum too big to convert into `long'" error.
|
164
|
+
# However it is clearly unreasonable and should be rejected.
|
165
|
+
client.onopen {
|
166
|
+
client.send_data("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00")
|
167
|
+
}
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should handle impossible frames by calling onerror callback" do
|
172
|
+
em {
|
173
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |server|
|
174
|
+
server.onerror { |error|
|
175
|
+
error.should be_an_instance_of EM::WebSocket::DataError
|
176
|
+
error.message.should == "Invalid frame received"
|
177
|
+
done
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
# Create a fake client which sends draft 76 handshake
|
182
|
+
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
183
|
+
client.send_data(format_request(@request))
|
184
|
+
|
185
|
+
client.onopen {
|
186
|
+
client.send_data("foobar") # Does not start with \x00 or \xff
|
187
|
+
}
|
188
|
+
}
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should handle invalid http requests by raising HandshakeError passed to onerror callback" do
|
192
|
+
em {
|
193
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |server|
|
194
|
+
server.onerror { |error|
|
195
|
+
error.should be_an_instance_of EM::WebSocket::HandshakeError
|
196
|
+
error.message.should == "Invalid HTTP header"
|
197
|
+
done
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
202
|
+
client.send_data("This is not a HTTP header\r\n\r\n")
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should handle handshake request split into two TCP packets" do
|
207
|
+
em {
|
208
|
+
EM.add_timer(0.1) do
|
209
|
+
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { }
|
210
|
+
|
211
|
+
# Create a fake client which sends draft 76 handshake
|
212
|
+
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
213
|
+
data = format_request(@request)
|
214
|
+
# Sends first half of the request
|
215
|
+
connection.send_data(data[0...(data.length / 2)])
|
216
|
+
|
217
|
+
connection.onopen {
|
218
|
+
connection.handshake_response.lines.sort.
|
219
|
+
should == format_response(@response).lines.sort
|
220
|
+
done
|
221
|
+
}
|
222
|
+
|
223
|
+
EM.add_timer(0.1) do
|
224
|
+
# Sends second half of the request
|
225
|
+
connection.send_data(data[(data.length / 2)..-1])
|
226
|
+
end
|
227
|
+
end
|
228
|
+
}
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
shared_examples_for "a websocket server" do
|
4
|
+
it "should call onerror if an application error raised in onopen" do
|
5
|
+
em {
|
6
|
+
start_server { |ws|
|
7
|
+
ws.onopen {
|
8
|
+
raise "application error"
|
9
|
+
}
|
10
|
+
|
11
|
+
ws.onerror { |e|
|
12
|
+
e.message.should == "application error"
|
13
|
+
done
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
start_client
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should call onerror if an application error raised in onmessage" do
|
22
|
+
em {
|
23
|
+
start_server { |server|
|
24
|
+
server.onmessage {
|
25
|
+
raise "application error"
|
26
|
+
}
|
27
|
+
|
28
|
+
server.onerror { |e|
|
29
|
+
e.message.should == "application error"
|
30
|
+
done
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
start_client { |client|
|
35
|
+
client.onopen {
|
36
|
+
client.send('a message')
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should call onerror in an application error raised in onclose" do
|
43
|
+
em {
|
44
|
+
start_server { |server|
|
45
|
+
server.onclose {
|
46
|
+
raise "application error"
|
47
|
+
}
|
48
|
+
|
49
|
+
server.onerror { |e|
|
50
|
+
e.message.should == "application error"
|
51
|
+
done
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
start_client { |client|
|
56
|
+
client.onopen {
|
57
|
+
EM.add_timer(0.1) {
|
58
|
+
client.close_connection
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Only run these tests on ruby 1.9
|
66
|
+
if "a".respond_to?(:force_encoding)
|
67
|
+
it "should raise error if you try to send non utf8 text data to ws" do
|
68
|
+
em {
|
69
|
+
start_server { |server|
|
70
|
+
server.onopen {
|
71
|
+
# Create a string which claims to be UTF-8 but which is not
|
72
|
+
s = "ê" # utf-8 string
|
73
|
+
s.encode!("ISO-8859-1")
|
74
|
+
s.force_encoding("UTF-8")
|
75
|
+
s.valid_encoding?.should == false # now invalid utf8
|
76
|
+
|
77
|
+
# Send non utf8 encoded data
|
78
|
+
server.send(s)
|
79
|
+
}
|
80
|
+
server.onerror { |error|
|
81
|
+
error.class.should == EventMachine::WebSocket::WebSocketError
|
82
|
+
error.message.should == "Data sent to WebSocket must be valid UTF-8 but was UTF-8 (valid: false)"
|
83
|
+
done
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
start_client { }
|
88
|
+
}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|