sonixlabs-em-websocket 0.3.8 → 0.5.1.1
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.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +69 -0
- data/Gemfile +6 -0
- data/LICENCE +7 -0
- data/README.md +100 -56
- data/README.md.BACKUP.14928.md +195 -0
- data/README.md.BASE.14928.md +77 -0
- data/README.md.LOCAL.14928.md +98 -0
- data/README.md.REMOTE.14928.md +142 -0
- data/examples/echo.rb +23 -7
- data/examples/ping.rb +24 -0
- data/examples/test.html +5 -6
- data/lib/em-websocket.rb +4 -2
- data/lib/em-websocket/close03.rb +3 -0
- data/lib/em-websocket/close05.rb +3 -0
- data/lib/em-websocket/close06.rb +3 -0
- data/lib/em-websocket/close75.rb +2 -1
- data/lib/em-websocket/connection.rb +219 -73
- data/lib/em-websocket/framing03.rb +6 -11
- data/lib/em-websocket/framing05.rb +6 -11
- data/lib/em-websocket/framing07.rb +25 -20
- data/lib/em-websocket/framing76.rb +6 -15
- data/lib/em-websocket/handler.rb +69 -28
- data/lib/em-websocket/handler03.rb +0 -1
- data/lib/em-websocket/handler05.rb +0 -1
- data/lib/em-websocket/handler06.rb +0 -1
- data/lib/em-websocket/handler07.rb +0 -1
- data/lib/em-websocket/handler08.rb +0 -1
- data/lib/em-websocket/handler13.rb +0 -1
- data/lib/em-websocket/handler76.rb +2 -0
- data/lib/em-websocket/handshake.rb +156 -0
- data/lib/em-websocket/handshake04.rb +18 -56
- data/lib/em-websocket/handshake75.rb +15 -8
- data/lib/em-websocket/handshake76.rb +15 -14
- data/lib/em-websocket/masking04.rb +4 -30
- data/lib/em-websocket/message_processor_03.rb +13 -4
- data/lib/em-websocket/message_processor_06.rb +25 -13
- data/lib/em-websocket/version.rb +1 -1
- data/lib/em-websocket/websocket.rb +35 -24
- data/spec/helper.rb +82 -55
- data/spec/integration/common_spec.rb +90 -70
- data/spec/integration/draft03_spec.rb +84 -56
- data/spec/integration/draft05_spec.rb +14 -12
- data/spec/integration/draft06_spec.rb +66 -9
- data/spec/integration/draft13_spec.rb +59 -29
- data/spec/integration/draft75_spec.rb +46 -40
- data/spec/integration/draft76_spec.rb +113 -109
- data/spec/integration/gte_03_examples.rb +42 -0
- data/spec/integration/shared_examples.rb +174 -0
- data/spec/unit/framing_spec.rb +83 -110
- data/spec/unit/handshake_spec.rb +216 -0
- data/spec/unit/masking_spec.rb +2 -0
- metadata +31 -71
- data/examples/flash_policy_file_server.rb +0 -21
- data/examples/js/FABridge.js +0 -604
- data/examples/js/WebSocketMain.swf +0 -0
- data/examples/js/swfobject.js +0 -4
- data/examples/js/web_socket.js +0 -312
- data/lib/em-websocket/handler_factory.rb +0 -107
- data/spec/unit/handler_spec.rb +0 -147
@@ -1,118 +1,138 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
# These tests are not
|
4
|
-
#
|
3
|
+
# These tests are not specific to any particular draft of the specification
|
4
|
+
#
|
5
5
|
describe "WebSocket server" do
|
6
6
|
include EM::SpecHelper
|
7
7
|
default_timeout 1
|
8
8
|
|
9
9
|
it "should fail on non WebSocket requests" do
|
10
10
|
em {
|
11
|
-
|
12
|
-
http =
|
11
|
+
EM.add_timer(0.1) do
|
12
|
+
http = EM::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
|
13
13
|
http.errback { done }
|
14
14
|
http.callback { fail }
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
start_server
|
18
18
|
}
|
19
19
|
end
|
20
|
-
|
21
|
-
it "should
|
20
|
+
|
21
|
+
it "should expose the WebSocket request headers, path and query params" do
|
22
22
|
em {
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
}
|
30
|
-
http.stream { |msg| }
|
23
|
+
EM.add_timer(0.1) do
|
24
|
+
ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/',
|
25
|
+
:origin => 'http://example.com')
|
26
|
+
ws.errback { fail }
|
27
|
+
ws.callback { ws.close_connection }
|
28
|
+
ws.stream { |msg| }
|
31
29
|
end
|
32
30
|
|
33
|
-
|
34
|
-
ws.onopen {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
31
|
+
start_server do |ws|
|
32
|
+
ws.onopen { |handshake|
|
33
|
+
headers = handshake.headers
|
34
|
+
headers["Connection"].should == "Upgrade"
|
35
|
+
headers["Upgrade"].should == "websocket"
|
36
|
+
headers["Host"].to_s.should == "127.0.0.1:12345"
|
37
|
+
handshake.path.should == "/"
|
38
|
+
handshake.query.should == {}
|
39
|
+
handshake.origin.should == 'http://example.com'
|
41
40
|
}
|
42
41
|
ws.onclose {
|
43
42
|
ws.state.should == :closed
|
44
|
-
|
43
|
+
done
|
45
44
|
}
|
46
45
|
end
|
47
46
|
}
|
48
47
|
end
|
49
|
-
|
50
|
-
it "should
|
48
|
+
|
49
|
+
it "should expose the WebSocket path and query params when nonempty" do
|
51
50
|
em {
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
http.close_connection
|
51
|
+
EM.add_timer(0.1) do
|
52
|
+
ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/hello?foo=bar&baz=qux')
|
53
|
+
ws.errback { fail }
|
54
|
+
ws.callback {
|
55
|
+
ws.close_connection
|
58
56
|
}
|
59
|
-
|
57
|
+
ws.stream { |msg| }
|
60
58
|
end
|
61
59
|
|
62
|
-
|
63
|
-
ws.onopen {
|
64
|
-
path
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
ws.request["query"]["baz"].should == "qux"
|
60
|
+
start_server do |ws|
|
61
|
+
ws.onopen { |handshake|
|
62
|
+
handshake.path.should == '/hello'
|
63
|
+
handshake.query_string.split('&').sort.
|
64
|
+
should == ["baz=qux", "foo=bar"]
|
65
|
+
handshake.query.should == {"foo"=>"bar", "baz"=>"qux"}
|
69
66
|
}
|
70
67
|
ws.onclose {
|
71
68
|
ws.state.should == :closed
|
72
|
-
|
69
|
+
done
|
73
70
|
}
|
74
71
|
end
|
75
72
|
}
|
76
73
|
end
|
77
|
-
|
78
|
-
it "should
|
74
|
+
|
75
|
+
it "should raise an exception if frame sent before handshake complete" do
|
79
76
|
em {
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
77
|
+
# 1. Start WebSocket server
|
78
|
+
start_server { |ws|
|
79
|
+
# 3. Try to send a message to the socket
|
80
|
+
lambda {
|
81
|
+
ws.send('early message')
|
82
|
+
}.should raise_error('Cannot send data before onopen callback')
|
83
|
+
done
|
84
|
+
}
|
85
|
+
|
86
|
+
# 2. Connect a dumb TCP connection (will not send handshake)
|
87
|
+
EM.connect('0.0.0.0', 12345, EM::Connection)
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should allow the server to be started inside an existing EM" do
|
92
|
+
em {
|
93
|
+
EM.add_timer(0.1) do
|
94
|
+
http = EM::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
|
95
|
+
http.errback { |e| done }
|
96
|
+
http.callback { fail }
|
88
97
|
end
|
89
98
|
|
90
|
-
|
91
|
-
ws.onopen {
|
92
|
-
|
93
|
-
|
99
|
+
start_server do |ws|
|
100
|
+
ws.onopen { |handshake|
|
101
|
+
headers = handshake.headers
|
102
|
+
headers["Host"].to_s.should == "127.0.0.1:12345"
|
94
103
|
}
|
95
104
|
ws.onclose {
|
96
105
|
ws.state.should == :closed
|
97
|
-
|
106
|
+
done
|
98
107
|
}
|
99
108
|
end
|
100
109
|
}
|
101
110
|
end
|
102
|
-
|
103
|
-
it "should raise an exception if frame sent before handshake complete" do
|
104
|
-
em {
|
105
|
-
EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |c|
|
106
|
-
# We're not using a real client so the handshake will not be sent
|
107
|
-
EM.add_timer(0.1) {
|
108
|
-
lambda {
|
109
|
-
c.send('early message')
|
110
|
-
}.should raise_error('Cannot send data before onopen callback')
|
111
|
-
done
|
112
|
-
}
|
113
|
-
}
|
114
111
|
|
115
|
-
|
116
|
-
|
112
|
+
context "outbound limit set" do
|
113
|
+
it "should close the connection if the limit is reached" do
|
114
|
+
em {
|
115
|
+
start_server(:outbound_limit => 150) do |ws|
|
116
|
+
# Increase the message size by one on each loop
|
117
|
+
ws.onmessage{|msg| ws.send(msg + "x") }
|
118
|
+
ws.onclose{|status|
|
119
|
+
status[:code].should == 1006 # Unclean
|
120
|
+
status[:was_clean].should be_false
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
EM.add_timer(0.1) do
|
125
|
+
ws = EventMachine::WebSocketClient.connect('ws://127.0.0.1:12345/')
|
126
|
+
ws.callback { ws.send_msg "hello" }
|
127
|
+
ws.disconnect { done } # Server closed the connection
|
128
|
+
ws.stream { |msg|
|
129
|
+
# minus frame size ? (getting 146 max here)
|
130
|
+
msg.data.size.should <= 150
|
131
|
+
# Return back the message
|
132
|
+
ws.send_msg(msg.data)
|
133
|
+
}
|
134
|
+
end
|
135
|
+
}
|
136
|
+
end
|
117
137
|
end
|
118
138
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'helper'
|
2
|
-
require 'integration/shared_examples'
|
3
2
|
|
4
3
|
describe "draft03" do
|
5
4
|
include EM::SpecHelper
|
@@ -35,18 +34,19 @@ describe "draft03" do
|
|
35
34
|
}
|
36
35
|
end
|
37
36
|
|
37
|
+
def start_client
|
38
|
+
client = EM.connect('0.0.0.0', 12345, Draft03FakeWebSocketClient)
|
39
|
+
client.send_data(format_request(@request))
|
40
|
+
yield client if block_given?
|
41
|
+
return client
|
42
|
+
end
|
43
|
+
|
38
44
|
it_behaves_like "a websocket server" do
|
39
|
-
|
40
|
-
|
41
|
-
yield ws
|
42
|
-
}
|
43
|
-
end
|
45
|
+
let(:version) { 3 }
|
46
|
+
end
|
44
47
|
|
45
|
-
|
46
|
-
|
47
|
-
client.send_data(format_request(@request))
|
48
|
-
yield client if block_given?
|
49
|
-
end
|
48
|
+
it_behaves_like "a WebSocket server drafts 3 and above" do
|
49
|
+
let(:version) { 3 }
|
50
50
|
end
|
51
51
|
|
52
52
|
# These examples are straight from the spec
|
@@ -54,36 +54,30 @@ describe "draft03" do
|
|
54
54
|
describe "examples from the spec" do
|
55
55
|
it "should accept a single-frame text message" do
|
56
56
|
em {
|
57
|
-
|
57
|
+
start_server { |ws|
|
58
58
|
ws.onmessage { |msg|
|
59
59
|
msg.should == 'Hello'
|
60
60
|
done
|
61
61
|
}
|
62
62
|
}
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
# Send frame
|
69
|
-
connection.onopen {
|
70
|
-
connection.send_data("\x04\x05Hello")
|
63
|
+
start_client { |client|
|
64
|
+
client.onopen {
|
65
|
+
client.send_data("\x04\x05Hello")
|
66
|
+
}
|
71
67
|
}
|
72
68
|
}
|
73
69
|
end
|
74
70
|
|
75
71
|
it "should accept a fragmented text message" do
|
76
72
|
em {
|
77
|
-
|
73
|
+
start_server { |ws|
|
78
74
|
ws.onmessage { |msg|
|
79
75
|
msg.should == 'Hello'
|
80
76
|
done
|
81
77
|
}
|
82
78
|
}
|
83
79
|
|
84
|
-
|
85
|
-
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
86
|
-
connection.send_data(format_request(@request))
|
80
|
+
connection = start_client
|
87
81
|
|
88
82
|
# Send frame
|
89
83
|
connection.onopen {
|
@@ -95,11 +89,9 @@ describe "draft03" do
|
|
95
89
|
|
96
90
|
it "should accept a ping request and respond with the same body" do
|
97
91
|
em {
|
98
|
-
|
92
|
+
start_server
|
99
93
|
|
100
|
-
|
101
|
-
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
102
|
-
connection.send_data(format_request(@request))
|
94
|
+
connection = start_client
|
103
95
|
|
104
96
|
# Send frame
|
105
97
|
connection.onopen {
|
@@ -118,16 +110,15 @@ describe "draft03" do
|
|
118
110
|
em {
|
119
111
|
data = "a" * 256
|
120
112
|
|
121
|
-
|
122
|
-
ws.
|
113
|
+
start_server { |ws|
|
114
|
+
ws.onbinary { |msg|
|
115
|
+
msg.encoding.should == Encoding.find("BINARY") if defined?(Encoding)
|
123
116
|
msg.should == data
|
124
117
|
done
|
125
118
|
}
|
126
119
|
}
|
127
120
|
|
128
|
-
|
129
|
-
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
130
|
-
connection.send_data(format_request(@request))
|
121
|
+
connection = start_client
|
131
122
|
|
132
123
|
# Send frame
|
133
124
|
connection.onopen {
|
@@ -140,16 +131,15 @@ describe "draft03" do
|
|
140
131
|
em {
|
141
132
|
data = "a" * 65536
|
142
133
|
|
143
|
-
|
144
|
-
ws.
|
134
|
+
start_server { |ws|
|
135
|
+
ws.onbinary { |msg|
|
136
|
+
msg.encoding.should == Encoding.find("BINARY") if defined?(Encoding)
|
145
137
|
msg.should == data
|
146
138
|
done
|
147
139
|
}
|
148
140
|
}
|
149
141
|
|
150
|
-
|
151
|
-
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
152
|
-
connection.send_data(format_request(@request))
|
142
|
+
connection = start_client
|
153
143
|
|
154
144
|
# Send frame
|
155
145
|
connection.onopen {
|
@@ -162,11 +152,9 @@ describe "draft03" do
|
|
162
152
|
describe "close handling" do
|
163
153
|
it "should respond to a new close frame with a close frame" do
|
164
154
|
em {
|
165
|
-
|
155
|
+
start_server
|
166
156
|
|
167
|
-
|
168
|
-
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
169
|
-
connection.send_data(format_request(@request))
|
157
|
+
connection = start_client
|
170
158
|
|
171
159
|
# Send close frame
|
172
160
|
connection.onopen {
|
@@ -181,22 +169,31 @@ describe "draft03" do
|
|
181
169
|
}
|
182
170
|
end
|
183
171
|
|
184
|
-
it "should close the connection on receiving a close acknowlegement" do
|
172
|
+
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
|
185
173
|
em {
|
186
174
|
ack_received = false
|
187
175
|
|
188
|
-
|
176
|
+
start_server { |ws|
|
189
177
|
ws.onopen {
|
190
178
|
# 2. Send a close frame
|
191
179
|
EM.next_tick {
|
192
|
-
ws.
|
180
|
+
ws.close
|
193
181
|
}
|
194
182
|
}
|
183
|
+
|
184
|
+
# 5. Onclose event on server
|
185
|
+
ws.onclose { |event|
|
186
|
+
event.should == {
|
187
|
+
:code => 1005,
|
188
|
+
:reason => "",
|
189
|
+
:was_clean => true,
|
190
|
+
}
|
191
|
+
done
|
192
|
+
}
|
195
193
|
}
|
196
194
|
|
197
195
|
# 1. Create a fake client which sends draft 76 handshake
|
198
|
-
connection =
|
199
|
-
connection.send_data(format_request(@request))
|
196
|
+
connection = start_client
|
200
197
|
|
201
198
|
# 3. Check that close frame recieved and acknowlege it
|
202
199
|
connection.onmessage { |frame|
|
@@ -208,18 +205,39 @@ describe "draft03" do
|
|
208
205
|
# 4. Check that connection is closed _after_ the ack
|
209
206
|
connection.onclose {
|
210
207
|
ack_received.should == true
|
211
|
-
|
208
|
+
}
|
209
|
+
}
|
210
|
+
end
|
211
|
+
|
212
|
+
# it "should repur"
|
213
|
+
#
|
214
|
+
it "should return close code 1005 and was_clean=true after closing handshake (initiated by client)" do
|
215
|
+
em {
|
216
|
+
start_server { |ws|
|
217
|
+
ws.onclose { |event|
|
218
|
+
event.should == {
|
219
|
+
:code => 1005,
|
220
|
+
:reason => "",
|
221
|
+
:was_clean => true,
|
222
|
+
}
|
223
|
+
done
|
224
|
+
}
|
225
|
+
}
|
226
|
+
start_client { |client|
|
227
|
+
client.onopen {
|
228
|
+
client.send_data("\x01\x00")
|
229
|
+
}
|
212
230
|
}
|
213
231
|
}
|
214
232
|
end
|
215
233
|
|
216
234
|
it "should not allow data frame to be sent after close frame sent" do
|
217
235
|
em {
|
218
|
-
|
236
|
+
start_server { |ws|
|
219
237
|
ws.onopen {
|
220
238
|
# 2. Send a close frame
|
221
239
|
EM.next_tick {
|
222
|
-
ws.
|
240
|
+
ws.close
|
223
241
|
}
|
224
242
|
|
225
243
|
# 3. Check that exception raised if I attempt to send more data
|
@@ -233,25 +251,23 @@ describe "draft03" do
|
|
233
251
|
}
|
234
252
|
|
235
253
|
# 1. Create a fake client which sends draft 76 handshake
|
236
|
-
|
237
|
-
connection.send_data(format_request(@request))
|
254
|
+
start_client
|
238
255
|
}
|
239
256
|
end
|
240
257
|
|
241
258
|
it "should still respond to control frames after close frame sent" do
|
242
259
|
em {
|
243
|
-
|
260
|
+
start_server { |ws|
|
244
261
|
ws.onopen {
|
245
262
|
# 2. Send a close frame
|
246
263
|
EM.next_tick {
|
247
|
-
ws.
|
264
|
+
ws.close
|
248
265
|
}
|
249
266
|
}
|
250
267
|
}
|
251
268
|
|
252
269
|
# 1. Create a fake client which sends draft 76 handshake
|
253
|
-
connection =
|
254
|
-
connection.send_data(format_request(@request))
|
270
|
+
connection = start_client
|
255
271
|
|
256
272
|
connection.onmessage { |frame|
|
257
273
|
if frame == "\x01\x00"
|
@@ -266,5 +282,17 @@ describe "draft03" do
|
|
266
282
|
}
|
267
283
|
}
|
268
284
|
end
|
285
|
+
|
286
|
+
it "should report that close codes are not supported" do
|
287
|
+
em {
|
288
|
+
start_server { |ws|
|
289
|
+
ws.onopen {
|
290
|
+
ws.supports_close_codes?.should == false
|
291
|
+
done
|
292
|
+
}
|
293
|
+
}
|
294
|
+
start_client
|
295
|
+
}
|
296
|
+
end
|
269
297
|
end
|
270
298
|
end
|