sonixlabs-em-websocket 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|