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,325 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe EM::WebSocket::Framing03 do
|
4
|
+
class FramingContainer
|
5
|
+
include EM::WebSocket::Framing03
|
6
|
+
|
7
|
+
def <<(data)
|
8
|
+
@data << data
|
9
|
+
process_data(data)
|
10
|
+
end
|
11
|
+
|
12
|
+
def debug(*args); end
|
13
|
+
end
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
@f = FramingContainer.new
|
17
|
+
@f.initialize_framing
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "basic examples" do
|
21
|
+
it "connection close" do
|
22
|
+
@f.should_receive(:message).with(:close, '', '')
|
23
|
+
@f << 0b00000001
|
24
|
+
@f << 0b00000000
|
25
|
+
end
|
26
|
+
|
27
|
+
it "ping" do
|
28
|
+
@f.should_receive(:message).with(:ping, '', '')
|
29
|
+
@f << 0b00000010
|
30
|
+
@f << 0b00000000
|
31
|
+
end
|
32
|
+
|
33
|
+
it "pong" do
|
34
|
+
@f.should_receive(:message).with(:pong, '', '')
|
35
|
+
@f << 0b00000011
|
36
|
+
@f << 0b00000000
|
37
|
+
end
|
38
|
+
|
39
|
+
it "text" do
|
40
|
+
@f.should_receive(:message).with(:text, '', 'foo')
|
41
|
+
@f << 0b00000100
|
42
|
+
@f << 0b00000011
|
43
|
+
@f << 'foo'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "Text in two frames" do
|
47
|
+
@f.should_receive(:message).with(:text, '', 'hello world')
|
48
|
+
@f << 0b10000100
|
49
|
+
@f << 0b00000110
|
50
|
+
@f << "hello "
|
51
|
+
@f << 0b00000000
|
52
|
+
@f << 0b00000101
|
53
|
+
@f << "world"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "2 byte extended payload length text frame" do
|
57
|
+
data = 'a' * 256
|
58
|
+
@f.should_receive(:message).with(:text, '', data)
|
59
|
+
@f << 0b00000100 # Single frame, text
|
60
|
+
@f << 0b01111110 # Length 126 (so read 2 bytes)
|
61
|
+
@f << 0b00000001 # Two bytes in network byte order (256)
|
62
|
+
@f << 0b00000000
|
63
|
+
@f << data
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# These examples are straight from the spec
|
68
|
+
# http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6
|
69
|
+
describe "examples from the spec" do
|
70
|
+
it "a single-frame text message" do
|
71
|
+
@f.should_receive(:message).with(:text, '', 'Hello')
|
72
|
+
@f << "\x04\x05Hello"
|
73
|
+
end
|
74
|
+
|
75
|
+
it "a fragmented text message" do
|
76
|
+
@f.should_receive(:message).with(:text, '', 'Hello')
|
77
|
+
@f << "\x84\x03Hel"
|
78
|
+
@f << "\x00\x02lo"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "Ping request and response" do
|
82
|
+
@f.should_receive(:message).with(:ping, '', 'Hello')
|
83
|
+
@f << "\x02\x05Hello"
|
84
|
+
end
|
85
|
+
|
86
|
+
it "256 bytes binary message in a single frame" do
|
87
|
+
data = "a"*256
|
88
|
+
@f.should_receive(:message).with(:binary, '', data)
|
89
|
+
@f << "\x05\x7E\x01\x00" + data
|
90
|
+
end
|
91
|
+
|
92
|
+
it "64KiB binary message in a single frame" do
|
93
|
+
data = "a"*65536
|
94
|
+
@f.should_receive(:message).with(:binary, '', data)
|
95
|
+
@f << "\x05\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "other tests" do
|
100
|
+
it "should accept a fragmented unmasked text message in 3 frames" do
|
101
|
+
@f.should_receive(:message).with(:text, '', 'Hello world')
|
102
|
+
@f << "\x84\x03Hel"
|
103
|
+
@f << "\x80\x02lo"
|
104
|
+
@f << "\x00\x06 world"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "error cases" do
|
109
|
+
it "should raise an exception on continuation frame without preceeding more frame" do
|
110
|
+
lambda {
|
111
|
+
@f << 0b00000000 # Single frame, continuation
|
112
|
+
@f << 0b00000001 # Length 1
|
113
|
+
@f << 'f'
|
114
|
+
}.should raise_error(EM::WebSocket::WebSocketError, 'Continuation frame not expected')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# These examples are straight from the spec
|
120
|
+
# http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6
|
121
|
+
describe EM::WebSocket::Framing04 do
|
122
|
+
class FramingContainer04
|
123
|
+
include EM::WebSocket::Framing04
|
124
|
+
|
125
|
+
def <<(data)
|
126
|
+
@data << data
|
127
|
+
process_data(data)
|
128
|
+
end
|
129
|
+
|
130
|
+
def debug(*args); end
|
131
|
+
end
|
132
|
+
|
133
|
+
before :each do
|
134
|
+
@f = FramingContainer04.new
|
135
|
+
@f.initialize_framing
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "examples from the spec" do
|
139
|
+
it "a single-frame text message" do
|
140
|
+
@f.should_receive(:message).with(:text, '', 'Hello')
|
141
|
+
@f << "\x84\x05\x48\x65\x6c\x6c\x6f" # "\x84\x05Hello"
|
142
|
+
end
|
143
|
+
|
144
|
+
it "a fragmented text message" do
|
145
|
+
@f.should_receive(:message).with(:text, '', 'Hello')
|
146
|
+
@f << "\x04\x03Hel"
|
147
|
+
@f << "\x80\x02lo"
|
148
|
+
end
|
149
|
+
|
150
|
+
it "Ping request" do
|
151
|
+
@f.should_receive(:message).with(:ping, '', 'Hello')
|
152
|
+
@f << "\x82\x05Hello"
|
153
|
+
end
|
154
|
+
|
155
|
+
it "a pong response" do
|
156
|
+
@f.should_receive(:message).with(:pong, '', 'Hello')
|
157
|
+
@f << "\x83\x05Hello"
|
158
|
+
end
|
159
|
+
|
160
|
+
it "256 bytes binary message in a single frame" do
|
161
|
+
data = "a"*256
|
162
|
+
@f.should_receive(:message).with(:binary, '', data)
|
163
|
+
@f << "\x85\x7E\x01\x00" + data
|
164
|
+
end
|
165
|
+
|
166
|
+
it "64KiB binary message in a single frame" do
|
167
|
+
data = "a"*65536
|
168
|
+
@f.should_receive(:message).with(:binary, '', data)
|
169
|
+
@f << "\x85\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "other tests" do
|
174
|
+
it "should accept a fragmented unmasked text message in 3 frames" do
|
175
|
+
@f.should_receive(:message).with(:text, '', 'Hello world')
|
176
|
+
@f << "\x04\x03Hel"
|
177
|
+
@f << "\x00\x02lo"
|
178
|
+
@f << "\x80\x06 world"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe EM::WebSocket::Framing07 do
|
184
|
+
class FramingContainer07
|
185
|
+
include EM::WebSocket::Framing07
|
186
|
+
|
187
|
+
def <<(data)
|
188
|
+
@data << data
|
189
|
+
process_data(data)
|
190
|
+
end
|
191
|
+
|
192
|
+
def debug(*args); end
|
193
|
+
end
|
194
|
+
|
195
|
+
before :each do
|
196
|
+
@f = FramingContainer07.new
|
197
|
+
@f.initialize_framing
|
198
|
+
end
|
199
|
+
|
200
|
+
# These examples are straight from the spec
|
201
|
+
# http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07#section-4.6
|
202
|
+
# NOTE I modified these to be compliant with the rule that client data must be masked
|
203
|
+
describe "server side" do
|
204
|
+
describe "examples from the spec" do
|
205
|
+
it "rejects a single-frame unmasked text message from the client" do
|
206
|
+
lambda {
|
207
|
+
@f << "\x81\x05\x48\x65\x6c\x6c\x6f" # "\x84\x05Hello"
|
208
|
+
}.should raise_error(EventMachine::WebSocket::WebSocketError, 'Data from client must be masked')
|
209
|
+
end
|
210
|
+
|
211
|
+
it "a single-frame masked text message" do
|
212
|
+
@f.should_receive(:message).with(:text, '', 'Hello')
|
213
|
+
@f << "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58" # "\x84\x05Hello"
|
214
|
+
end
|
215
|
+
|
216
|
+
it "a fragmented masked text message" do
|
217
|
+
@f.should_receive(:message).with(:text, '', 'Hello')
|
218
|
+
@f << "\x01\x83\x01\x01\x01\x01Idm" # with mask x01x01x01x01, Hello -> Idmmn
|
219
|
+
@f << "\x80\x82\x01\x01\x01\x01mn"
|
220
|
+
end
|
221
|
+
|
222
|
+
it "Ping request" do
|
223
|
+
@f.should_receive(:message).with(:ping, '', 'Hello')
|
224
|
+
@f << "\x89\x85\x01\x01\x01\x01Idmmn"
|
225
|
+
end
|
226
|
+
|
227
|
+
it "a pong response" do
|
228
|
+
@f.should_receive(:message).with(:pong, '', 'Hello')
|
229
|
+
@f << "\x8a\x85\x01\x01\x01\x01Idmmn"
|
230
|
+
end
|
231
|
+
|
232
|
+
it "256 bytes binary message in a single masked frame" do
|
233
|
+
data = "b"*256
|
234
|
+
masked_data = "c"*256
|
235
|
+
@f.should_receive(:message).with(:binary, '', data)
|
236
|
+
@f << "\x82\xFE\x01\x00\x01\x01\x01\x01" + masked_data
|
237
|
+
end
|
238
|
+
|
239
|
+
it "64KiB binary message in a single masked frame" do
|
240
|
+
data = "b"*65536
|
241
|
+
masked_data = "c"*65536
|
242
|
+
@f.should_receive(:message).with(:binary, '', data)
|
243
|
+
@f << "\x82\xFF\x00\x00\x00\x00\x00\x01\x00\x00\x01\x01\x01\x01" + masked_data
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe "other tests" do
|
248
|
+
it "should raise a DataError if an invalid frame type is requested" do
|
249
|
+
lambda {
|
250
|
+
# Opcode 3 is not supported by this draft
|
251
|
+
@f << "\x83\x85\x01\x01\x01\x01Idmmn"
|
252
|
+
}.should raise_error(EventMachine::WebSocket::DataError, "Unknown opcode")
|
253
|
+
end
|
254
|
+
|
255
|
+
it "should accept a fragmented masked text message in 3 frames" do
|
256
|
+
@f.should_receive(:message).with(:text, '', 'Hello world')
|
257
|
+
@f << "\x01\x83\x01\x01\x01\x01Idm"
|
258
|
+
@f << "\x00\x82\x01\x01\x01\x01mn"
|
259
|
+
@f << "\x80\x86\x01\x01\x01\x01\x21vnsme"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "client side" do
|
265
|
+
before do
|
266
|
+
@f.mask_outbound_messages = true
|
267
|
+
@f.require_masked_inbound_messages = false
|
268
|
+
end
|
269
|
+
describe "examples from the spec" do
|
270
|
+
it "accepts a single-frame unmasked text message from the client" do
|
271
|
+
@f.should_receive(:message).with(:text, '', 'Hello')
|
272
|
+
@f << "\x81\x05\x48\x65\x6c\x6c\x6f" # "\x84\x05Hello"
|
273
|
+
end
|
274
|
+
|
275
|
+
it "a single-frame masked text message" do
|
276
|
+
@f.should_receive(:message).with(:text, '', 'Hello')
|
277
|
+
@f << "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58" # "\x84\x05Hello"
|
278
|
+
end
|
279
|
+
|
280
|
+
it "a fragmented unmasked text message" do
|
281
|
+
@f.should_receive(:message).with(:text, '', 'Hello')
|
282
|
+
@f << "\x01\x03\Hel"
|
283
|
+
@f << "\x80\x02\lo"
|
284
|
+
end
|
285
|
+
|
286
|
+
it "Ping request" do
|
287
|
+
@f.should_receive(:message).with(:ping, '', 'Hello')
|
288
|
+
@f << "\x89\x05Hello"
|
289
|
+
end
|
290
|
+
|
291
|
+
it "a pong response" do
|
292
|
+
@f.should_receive(:message).with(:pong, '', 'Hello')
|
293
|
+
@f << "\x8a\x05Hello"
|
294
|
+
end
|
295
|
+
|
296
|
+
it "256 bytes binary message in a single unmasked frame" do
|
297
|
+
data = "a"*256
|
298
|
+
@f.should_receive(:message).with(:binary, '', data)
|
299
|
+
@f << "\x82\x7E\x01\x00" + data
|
300
|
+
end
|
301
|
+
|
302
|
+
it "64KiB binary message in a single unmasked frame" do
|
303
|
+
data = "a"*65536
|
304
|
+
@f.should_receive(:message).with(:binary, '', data)
|
305
|
+
@f << "\x82\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
describe "other tests" do
|
310
|
+
it "should raise a DataError if an invalid frame type is requested" do
|
311
|
+
lambda {
|
312
|
+
# Opcode 3 is not supported by this draft
|
313
|
+
@f << "\x83\x05Hello"
|
314
|
+
}.should raise_error(EventMachine::WebSocket::DataError, "Unknown opcode")
|
315
|
+
end
|
316
|
+
|
317
|
+
it "should accept a fragmented unmasked text message in 3 frames" do
|
318
|
+
@f.should_receive(:message).with(:text, '', 'Hello world')
|
319
|
+
@f << "\x01\x03Hel"
|
320
|
+
@f << "\x00\x02lo"
|
321
|
+
@f << "\x80\x06 world"
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe "EventMachine::WebSocket::Handler" do
|
4
|
+
before :each do
|
5
|
+
@request = {
|
6
|
+
:port => 80,
|
7
|
+
:method => "GET",
|
8
|
+
:path => "/demo",
|
9
|
+
:headers => {
|
10
|
+
'Host' => 'example.com',
|
11
|
+
'Connection' => 'Upgrade',
|
12
|
+
'Sec-WebSocket-Key2' => '12998 5 Y3 1 .P00',
|
13
|
+
'Sec-WebSocket-Protocol' => 'sample',
|
14
|
+
'Upgrade' => 'WebSocket',
|
15
|
+
'Sec-WebSocket-Key1' => '4 @1 46546xW%0l 1 5',
|
16
|
+
'Origin' => 'http://example.com'
|
17
|
+
},
|
18
|
+
:body => '^n:ds[4U'
|
19
|
+
}
|
20
|
+
@secure_request = @request.merge(:port => 443)
|
21
|
+
|
22
|
+
@response = {
|
23
|
+
:headers => {
|
24
|
+
"Upgrade" => "WebSocket",
|
25
|
+
"Connection" => "Upgrade",
|
26
|
+
"Sec-WebSocket-Location" => "ws://example.com/demo",
|
27
|
+
"Sec-WebSocket-Origin" => "http://example.com",
|
28
|
+
"Sec-WebSocket-Protocol" => "sample"
|
29
|
+
},
|
30
|
+
:body => "8jKS\'y:G*Co,Wxa-"
|
31
|
+
}
|
32
|
+
@secure_response = @response.merge(:headers => @response[:headers].merge('Sec-WebSocket-Location' => "wss://example.com/demo"))
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should handle good request" do
|
36
|
+
handler(@request).should send_handshake(@response)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should handle good request to secure default port if secure mode is enabled" do
|
40
|
+
handler(@secure_request, true).should send_handshake(@secure_response)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not handle good request to secure default port if secure mode is disabled" do
|
44
|
+
handler(@secure_request, false).should_not send_handshake(@secure_response)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should handle good request on nondefault port" do
|
48
|
+
@request[:port] = 8081
|
49
|
+
@request[:headers]['Host'] = 'example.com:8081'
|
50
|
+
@response[:headers]['Sec-WebSocket-Location'] =
|
51
|
+
'ws://example.com:8081/demo'
|
52
|
+
|
53
|
+
handler(@request).should send_handshake(@response)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should handle good request to secure nondefault port" do
|
57
|
+
@secure_request[:port] = 8081
|
58
|
+
@secure_request[:headers]['Host'] = 'example.com:8081'
|
59
|
+
@secure_response[:headers]['Sec-WebSocket-Location'] = 'wss://example.com:8081/demo'
|
60
|
+
handler(@secure_request, true).should send_handshake(@secure_response)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should handle good request with no protocol" do
|
64
|
+
@request[:headers].delete('Sec-WebSocket-Protocol')
|
65
|
+
@response[:headers].delete("Sec-WebSocket-Protocol")
|
66
|
+
|
67
|
+
handler(@request).should send_handshake(@response)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should handle extra headers by simply ignoring them" do
|
71
|
+
@request[:headers]['EmptyValue'] = ""
|
72
|
+
@request[:headers]['AKey'] = "AValue"
|
73
|
+
|
74
|
+
handler(@request).should send_handshake(@response)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should raise error on HTTP request" do
|
78
|
+
@request[:headers] = {
|
79
|
+
'Host' => 'www.google.com',
|
80
|
+
'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',
|
81
|
+
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
82
|
+
'Accept-Language' => 'en-us,en;q=0.5',
|
83
|
+
'Accept-Encoding' => 'gzip,deflate',
|
84
|
+
'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
|
85
|
+
'Keep-Alive' => '300',
|
86
|
+
'Connection' => 'keep-alive',
|
87
|
+
}
|
88
|
+
|
89
|
+
lambda {
|
90
|
+
handler(@request).handshake
|
91
|
+
}.should raise_error(EM::WebSocket::HandshakeError)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should raise error on wrong method" do
|
95
|
+
@request[:method] = 'POST'
|
96
|
+
|
97
|
+
lambda {
|
98
|
+
handler(@request).handshake
|
99
|
+
}.should raise_error(EM::WebSocket::HandshakeError)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should raise error if upgrade header incorrect" do
|
103
|
+
@request[:headers]['Upgrade'] = 'NonWebSocket'
|
104
|
+
|
105
|
+
lambda {
|
106
|
+
handler(@request).handshake
|
107
|
+
}.should raise_error(EM::WebSocket::HandshakeError)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should raise error if Sec-WebSocket-Protocol is empty" do
|
111
|
+
@request[:headers]['Sec-WebSocket-Protocol'] = ''
|
112
|
+
|
113
|
+
lambda {
|
114
|
+
handler(@request).handshake
|
115
|
+
}.should raise_error(EM::WebSocket::HandshakeError)
|
116
|
+
end
|
117
|
+
|
118
|
+
%w[Sec-WebSocket-Key1 Sec-WebSocket-Key2].each do |header|
|
119
|
+
it "should raise error if #{header} has zero spaces" do
|
120
|
+
@request[:headers][header] = 'nospaces'
|
121
|
+
|
122
|
+
lambda {
|
123
|
+
handler(@request).handshake
|
124
|
+
}.should raise_error(EM::WebSocket::HandshakeError, 'Websocket Key1 or Key2 does not contain spaces - this is a symptom of a cross-protocol attack')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should raise error if spaces do not divide numbers in Sec-WebSocket-Key* " do
|
129
|
+
@request[:headers]['Sec-WebSocket-Key2'] = '12998 5 Y3 1.P00'
|
130
|
+
|
131
|
+
lambda {
|
132
|
+
handler(@request).handshake
|
133
|
+
}.should raise_error(EM::WebSocket::HandshakeError, 'Invalid Key "12998 5 Y3 1.P00"')
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should leave request with incomplete header" do
|
137
|
+
data = format_request(@request)
|
138
|
+
# Sends only half of the request
|
139
|
+
EM::WebSocket::HandlerFactory.build(mock(EM::WebSocket::Connection), data[0...(data.length / 2)]).should == nil
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should leave request with incomplete third key" do
|
143
|
+
data = format_request(@request)
|
144
|
+
# Removes last two bytes of the third key
|
145
|
+
EM::WebSocket::HandlerFactory.build(mock(EM::WebSocket::Connection), data[0...(data.length - 2)]).should == nil
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
describe EM::WebSocket::MaskedString do
|
6
|
+
it "should allow reading 4 byte mask and unmasking byte / bytes" do
|
7
|
+
t = EM::WebSocket::MaskedString.new("\x00\x00\x00\x01\x00\x01\x00\x01")
|
8
|
+
t.read_mask
|
9
|
+
t.getbyte(3).should == 0x00
|
10
|
+
t.getbytes(4, 4).should == "\x00\x01\x00\x00"
|
11
|
+
t.getbytes(5, 3).should == "\x01\x00\x00"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return nil from getbyte if index requested is out of range" do
|
15
|
+
t = EM::WebSocket::MaskedString.new("\x00\x00\x00\x00\x53")
|
16
|
+
t.read_mask
|
17
|
+
t.getbyte(4).should == 0x53
|
18
|
+
t.getbyte(5).should == nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should allow switching masking on and off" do
|
22
|
+
t = EM::WebSocket::MaskedString.new("\x02\x00\x00\x00\x03")
|
23
|
+
t.getbyte(4).should == 0x03
|
24
|
+
t.read_mask
|
25
|
+
t.getbyte(4).should == 0x01
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe EM::WebSocket::MessageProcessor06 do
|
4
|
+
class MessageProcessorContainer06
|
5
|
+
attr_accessor :connection
|
6
|
+
include EM::WebSocket::MessageProcessor06
|
7
|
+
def debug(*args); end
|
8
|
+
end
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
@mp = MessageProcessorContainer06.new
|
12
|
+
@mp.connection = Object.new
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#message" do
|
16
|
+
it "accepts a close"
|
17
|
+
it "accepts a ping"
|
18
|
+
|
19
|
+
it "accepts a pong" do
|
20
|
+
@mp.connection.should_receive(:trigger_on_message).with(:rock, :pong)
|
21
|
+
@mp.message :pong, :fraggle, :rock
|
22
|
+
end
|
23
|
+
|
24
|
+
it "accepts a binary message" do
|
25
|
+
@mp.connection.should_receive(:trigger_on_message).with(:rock, :binary)
|
26
|
+
@mp.message :binary, :fraggle, :rock
|
27
|
+
end
|
28
|
+
|
29
|
+
it "accepts a non-UTF8 text message"
|
30
|
+
|
31
|
+
it "accepts a text message" do
|
32
|
+
@mp.connection.should_receive(:trigger_on_message).with(:rock, :text)
|
33
|
+
@mp.message :text, :fraggle, :rock
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|