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,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
|