sonixlabs-em-websocket 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG.rdoc +80 -0
  3. data/Gemfile +3 -0
  4. data/README.md +98 -0
  5. data/Rakefile +11 -0
  6. data/em-websocket.gemspec +27 -0
  7. data/examples/echo.rb +8 -0
  8. data/examples/flash_policy_file_server.rb +21 -0
  9. data/examples/js/FABridge.js +604 -0
  10. data/examples/js/WebSocketMain.swf +0 -0
  11. data/examples/js/swfobject.js +4 -0
  12. data/examples/js/web_socket.js +312 -0
  13. data/examples/multicast.rb +47 -0
  14. data/examples/test.html +30 -0
  15. data/lib/em-websocket/client_connection.rb +19 -0
  16. data/lib/em-websocket/close03.rb +11 -0
  17. data/lib/em-websocket/close05.rb +11 -0
  18. data/lib/em-websocket/close06.rb +16 -0
  19. data/lib/em-websocket/close75.rb +10 -0
  20. data/lib/em-websocket/connection.rb +184 -0
  21. data/lib/em-websocket/debugger.rb +17 -0
  22. data/lib/em-websocket/framing03.rb +167 -0
  23. data/lib/em-websocket/framing04.rb +15 -0
  24. data/lib/em-websocket/framing05.rb +168 -0
  25. data/lib/em-websocket/framing07.rb +180 -0
  26. data/lib/em-websocket/framing76.rb +114 -0
  27. data/lib/em-websocket/handler.rb +56 -0
  28. data/lib/em-websocket/handler03.rb +10 -0
  29. data/lib/em-websocket/handler05.rb +10 -0
  30. data/lib/em-websocket/handler06.rb +10 -0
  31. data/lib/em-websocket/handler07.rb +10 -0
  32. data/lib/em-websocket/handler08.rb +10 -0
  33. data/lib/em-websocket/handler13.rb +10 -0
  34. data/lib/em-websocket/handler75.rb +9 -0
  35. data/lib/em-websocket/handler76.rb +12 -0
  36. data/lib/em-websocket/handler_factory.rb +107 -0
  37. data/lib/em-websocket/handshake04.rb +75 -0
  38. data/lib/em-websocket/handshake75.rb +21 -0
  39. data/lib/em-websocket/handshake76.rb +71 -0
  40. data/lib/em-websocket/masking04.rb +63 -0
  41. data/lib/em-websocket/message_processor_03.rb +38 -0
  42. data/lib/em-websocket/message_processor_06.rb +52 -0
  43. data/lib/em-websocket/version.rb +5 -0
  44. data/lib/em-websocket/websocket.rb +45 -0
  45. data/lib/em-websocket.rb +23 -0
  46. data/lib/sonixlabs-em-websocket.rb +1 -0
  47. data/spec/helper.rb +146 -0
  48. data/spec/integration/client_examples.rb +48 -0
  49. data/spec/integration/common_spec.rb +118 -0
  50. data/spec/integration/draft03_spec.rb +270 -0
  51. data/spec/integration/draft05_spec.rb +48 -0
  52. data/spec/integration/draft06_spec.rb +88 -0
  53. data/spec/integration/draft13_spec.rb +75 -0
  54. data/spec/integration/draft75_spec.rb +117 -0
  55. data/spec/integration/draft76_spec.rb +230 -0
  56. data/spec/integration/shared_examples.rb +91 -0
  57. data/spec/unit/framing_spec.rb +325 -0
  58. data/spec/unit/handler_spec.rb +147 -0
  59. data/spec/unit/masking_spec.rb +27 -0
  60. data/spec/unit/message_processor_spec.rb +36 -0
  61. metadata +198 -0
data/spec/helper.rb ADDED
@@ -0,0 +1,146 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'em-spec/rspec'
4
+ require 'pp'
5
+ require 'em-http'
6
+
7
+ require 'em-websocket'
8
+
9
+ RSpec.configure do |c|
10
+ c.mock_with :rspec
11
+ end
12
+
13
+ class FakeWebSocketClient < EM::Connection
14
+ attr_reader :handshake_response, :packets
15
+
16
+ def onopen(&blk); @onopen = blk; end
17
+ def onclose(&blk); @onclose = blk; end
18
+ def onerror(&blk); @onerror = blk; end
19
+ def onmessage(&blk); @onmessage = blk; end
20
+
21
+ def initialize
22
+ @state = :new
23
+ @packets = []
24
+ end
25
+
26
+ def receive_data(data)
27
+ # puts "RECEIVE DATA #{data}"
28
+ if @state == :new
29
+ @handshake_response = data
30
+ @onopen.call if @onopen
31
+ @state = :open
32
+ else
33
+ @onmessage.call(data) if @onmessage
34
+ @packets << data
35
+ end
36
+ end
37
+
38
+ def send(data)
39
+ send_data("\x00#{data}\xff")
40
+ end
41
+
42
+ def unbind
43
+ @onclose.call if @onclose
44
+ end
45
+ end
46
+
47
+ class Draft03FakeWebSocketClient < FakeWebSocketClient
48
+ def send(application_data)
49
+ frame = ''
50
+ opcode = 4 # fake only supports text frames
51
+ byte1 = opcode # since more, rsv1-3 are 0
52
+ frame << byte1
53
+
54
+ length = application_data.size
55
+ if length <= 125
56
+ byte2 = length # since rsv4 is 0
57
+ frame << byte2
58
+ elsif length < 65536 # write 2 byte length
59
+ frame << 126
60
+ frame << [length].pack('n')
61
+ else # write 8 byte length
62
+ frame << 127
63
+ frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
64
+ end
65
+
66
+ frame << application_data
67
+
68
+ send_data(frame)
69
+ end
70
+ end
71
+
72
+ class Draft07FakeWebSocketClient < FakeWebSocketClient
73
+ def send(application_data)
74
+ frame = ''
75
+ opcode = 1 # fake only supports text frames
76
+ byte1 = opcode | 0b10000000 # since more, rsv1-3 are 0
77
+ frame << byte1
78
+
79
+ mask = 0b10000000
80
+
81
+ length = application_data.size
82
+ if length <= 125
83
+ byte2 = length # since rsv4 is 0
84
+ frame << (mask | byte2)
85
+ elsif length < 65536 # write 2 byte length
86
+ frame << (mask | 126)
87
+ frame << [length].pack('n')
88
+ else # write 8 byte length
89
+ frame << (mask | 127)
90
+ frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
91
+ end
92
+
93
+ frame << EventMachine::WebSocket::MaskedString.create_masked_string(application_data)
94
+
95
+ send_data(frame)
96
+ end
97
+ end
98
+
99
+
100
+ # Wrap EM:HttpRequest in a websocket like interface so that it can be used in the specs with the same interface as FakeWebSocketClient
101
+ class Draft75WebSocketClient
102
+ def onopen(&blk); @onopen = blk; end
103
+ def onclose(&blk); @onclose = blk; end
104
+ def onerror(&blk); @onerror = blk; end
105
+ def onmessage(&blk); @onmessage = blk; end
106
+
107
+ def initialize
108
+ @ws = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get(:timeout => 0)
109
+ @ws.errback { @onerror.call if @onerror }
110
+ @ws.callback { @onopen.call if @onopen }
111
+ @ws.stream { |msg| @onmessage.call(msg) if @onmessage }
112
+ end
113
+
114
+ def send(message)
115
+ @ws.send(message)
116
+ end
117
+
118
+ def close_connection
119
+ @ws.close_connection
120
+ end
121
+ end
122
+
123
+ def format_request(r)
124
+ data = "#{r[:method]} #{r[:path]} HTTP/1.1\r\n"
125
+ header_lines = r[:headers].map { |k,v| "#{k}: #{v}" }
126
+ data << [header_lines, '', r[:body]].join("\r\n")
127
+ data
128
+ end
129
+
130
+ def format_response(r)
131
+ data = r[:protocol] || "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
132
+ header_lines = r[:headers].map { |k,v| "#{k}: #{v}" }
133
+ data << [header_lines, '', r[:body]].join("\r\n")
134
+ data
135
+ end
136
+
137
+ def handler(request, secure = false)
138
+ connection = Object.new
139
+ EM::WebSocket::HandlerFactory.build(connection, format_request(request), secure)
140
+ end
141
+
142
+ RSpec::Matchers.define :send_handshake do |response|
143
+ match do |actual|
144
+ actual.handshake.lines.sort == format_response(response).lines.sort
145
+ end
146
+ end
@@ -0,0 +1,48 @@
1
+ # encoding: UTF-8
2
+
3
+ shared_examples_for "a websocket client" do
4
+ it "should accept a single-frame binary message" do
5
+ EM.run do
6
+ start_server { |server|
7
+ server.onmessage { |msg, type|
8
+ msg.should == '\xFF\xFF'
9
+ type.should == :binary
10
+ EM.stop
11
+ }
12
+ server.onerror {
13
+ failed
14
+ }
15
+ }
16
+
17
+ options = { :host => '0.0.0.0', :port => 12345, :debug => false }
18
+ client = EM.connect('0.0.0.0', 12345, EventMachine::WebSocket::ClientConnection, options) do |ws|
19
+ ws.onopen do
20
+ ws.send '\xFF\xFF', :binary
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ it "should accept a text message in the same frame as the server handshake response" do
27
+ EM.run do
28
+ start_server { |server|
29
+ server.onopen { server.send 'hello' }
30
+ server.onerror { failed }
31
+ }
32
+
33
+ options = { :host => '0.0.0.0', :port => 12345, :debug => false }
34
+ client = EM.connect( options[:host], options[:port], EventMachine::WebSocket::ClientConnection, options) do |ws|
35
+ ws.onmessage{ |msg, type|
36
+ msg.should == 'hello'
37
+ type.should == :text
38
+ EM.stop
39
+ }
40
+
41
+ EventMachine::add_timer 3 do
42
+ failed # ran out of time
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ end
@@ -0,0 +1,118 @@
1
+ require 'helper'
2
+
3
+ # These tests are not specifi to any particular draft of the specification
4
+ #
5
+ describe "WebSocket server" do
6
+ include EM::SpecHelper
7
+ default_timeout 1
8
+
9
+ it "should fail on non WebSocket requests" do
10
+ em {
11
+ EventMachine.add_timer(0.1) do
12
+ http = EventMachine::HttpRequest.new('http://127.0.0.1:12345/').get :timeout => 0
13
+ http.errback { done }
14
+ http.callback { fail }
15
+ end
16
+
17
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) {}
18
+ }
19
+ end
20
+
21
+ it "should populate ws.request with appropriate headers" do
22
+ em {
23
+ EventMachine.add_timer(0.1) do
24
+ http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get :timeout => 0
25
+ http.errback { fail }
26
+ http.callback {
27
+ http.response_header.status.should == 101
28
+ http.close_connection
29
+ }
30
+ http.stream { |msg| }
31
+ end
32
+
33
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
34
+ ws.onopen {
35
+ ws.request["user-agent"].should == "EventMachine HttpClient"
36
+ ws.request["connection"].should == "Upgrade"
37
+ ws.request["upgrade"].should == "WebSocket"
38
+ ws.request["path"].should == "/"
39
+ ws.request["origin"].should == "127.0.0.1"
40
+ ws.request["host"].to_s.should == "ws://127.0.0.1:12345"
41
+ }
42
+ ws.onclose {
43
+ ws.state.should == :closed
44
+ EventMachine.stop
45
+ }
46
+ end
47
+ }
48
+ end
49
+
50
+ it "should allow sending and retrieving query string args passed in on the connection request." do
51
+ em {
52
+ EventMachine.add_timer(0.1) do
53
+ http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get(:query => {'foo' => 'bar', 'baz' => 'qux'}, :timeout => 0)
54
+ http.errback { fail }
55
+ http.callback {
56
+ http.response_header.status.should == 101
57
+ http.close_connection
58
+ }
59
+ http.stream { |msg| }
60
+ end
61
+
62
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
63
+ ws.onopen {
64
+ path, query = ws.request["path"].split('?')
65
+ path.should == '/'
66
+ Hash[*query.split(/&|=/)].should == {"foo"=>"bar", "baz"=>"qux"}
67
+ ws.request["query"]["foo"].should == "bar"
68
+ ws.request["query"]["baz"].should == "qux"
69
+ }
70
+ ws.onclose {
71
+ ws.state.should == :closed
72
+ EventMachine.stop
73
+ }
74
+ end
75
+ }
76
+ end
77
+
78
+ it "should ws.response['Query'] to empty hash when no query string params passed in connection URI" do
79
+ em {
80
+ EventMachine.add_timer(0.1) do
81
+ http = EventMachine::HttpRequest.new('ws://127.0.0.1:12345/').get(:timeout => 0)
82
+ http.errback { fail }
83
+ http.callback {
84
+ http.response_header.status.should == 101
85
+ http.close_connection
86
+ }
87
+ http.stream { |msg| }
88
+ end
89
+
90
+ EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 12345) do |ws|
91
+ ws.onopen {
92
+ ws.request["path"].should == "/"
93
+ ws.request["query"].should == {}
94
+ }
95
+ ws.onclose {
96
+ ws.state.should == :closed
97
+ EventMachine.stop
98
+ }
99
+ end
100
+ }
101
+ 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
+
115
+ client = EM.connect('0.0.0.0', 12345, EM::Connection)
116
+ }
117
+ end
118
+ end
@@ -0,0 +1,270 @@
1
+ require 'helper'
2
+ require 'integration/shared_examples'
3
+
4
+ describe "draft03" 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
+ 'Sec-WebSocket-Draft' => '3'
22
+ },
23
+ :body => '^n:ds[4U'
24
+ }
25
+
26
+ @response = {
27
+ :headers => {
28
+ "Upgrade" => "WebSocket",
29
+ "Connection" => "Upgrade",
30
+ "Sec-WebSocket-Location" => "ws://example.com/demo",
31
+ "Sec-WebSocket-Origin" => "http://example.com",
32
+ "Sec-WebSocket-Protocol" => "sample"
33
+ },
34
+ :body => "8jKS\'y:G*Co,Wxa-"
35
+ }
36
+ end
37
+
38
+ it_behaves_like "a websocket server" do
39
+ def start_server
40
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
41
+ yield ws
42
+ }
43
+ end
44
+
45
+ def start_client
46
+ client = EM.connect('0.0.0.0', 12345, Draft03FakeWebSocketClient)
47
+ client.send_data(format_request(@request))
48
+ yield client if block_given?
49
+ end
50
+ end
51
+
52
+ # These examples are straight from the spec
53
+ # http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-03#section-4.6
54
+ describe "examples from the spec" do
55
+ it "should accept a single-frame text message" do
56
+ em {
57
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
58
+ ws.onmessage { |msg|
59
+ msg.should == 'Hello'
60
+ done
61
+ }
62
+ }
63
+
64
+ # Create a fake client which sends draft 76 handshake
65
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
66
+ connection.send_data(format_request(@request))
67
+
68
+ # Send frame
69
+ connection.onopen {
70
+ connection.send_data("\x04\x05Hello")
71
+ }
72
+ }
73
+ end
74
+
75
+ it "should accept a fragmented text message" do
76
+ em {
77
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
78
+ ws.onmessage { |msg|
79
+ msg.should == 'Hello'
80
+ done
81
+ }
82
+ }
83
+
84
+ # Create a fake client which sends draft 76 handshake
85
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
86
+ connection.send_data(format_request(@request))
87
+
88
+ # Send frame
89
+ connection.onopen {
90
+ connection.send_data("\x84\x03Hel")
91
+ connection.send_data("\x00\x02lo")
92
+ }
93
+ }
94
+ end
95
+
96
+ it "should accept a ping request and respond with the same body" do
97
+ em {
98
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| }
99
+
100
+ # Create a fake client which sends draft 76 handshake
101
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
102
+ connection.send_data(format_request(@request))
103
+
104
+ # Send frame
105
+ connection.onopen {
106
+ connection.send_data("\x02\x05Hello")
107
+ }
108
+
109
+ connection.onmessage { |frame|
110
+ next if frame.nil?
111
+ frame.should == "\x03\x05Hello"
112
+ done
113
+ }
114
+ }
115
+ end
116
+
117
+ it "should accept a 256 bytes binary message in a single frame" do
118
+ em {
119
+ data = "a" * 256
120
+
121
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
122
+ ws.onmessage { |msg|
123
+ msg.should == data
124
+ done
125
+ }
126
+ }
127
+
128
+ # Create a fake client which sends draft 76 handshake
129
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
130
+ connection.send_data(format_request(@request))
131
+
132
+ # Send frame
133
+ connection.onopen {
134
+ connection.send_data("\x05\x7E\x01\x00" + data)
135
+ }
136
+ }
137
+ end
138
+
139
+ it "should accept a 64KiB binary message in a single frame" do
140
+ em {
141
+ data = "a" * 65536
142
+
143
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
144
+ ws.onmessage { |msg|
145
+ msg.should == data
146
+ done
147
+ }
148
+ }
149
+
150
+ # Create a fake client which sends draft 76 handshake
151
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
152
+ connection.send_data(format_request(@request))
153
+
154
+ # Send frame
155
+ connection.onopen {
156
+ connection.send_data("\x05\x7F\x00\x00\x00\x00\x00\x01\x00\x00" + data)
157
+ }
158
+ }
159
+ end
160
+ end
161
+
162
+ describe "close handling" do
163
+ it "should respond to a new close frame with a close frame" do
164
+ em {
165
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws| }
166
+
167
+ # Create a fake client which sends draft 76 handshake
168
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
169
+ connection.send_data(format_request(@request))
170
+
171
+ # Send close frame
172
+ connection.onopen {
173
+ connection.send_data("\x01\x00")
174
+ }
175
+
176
+ # Check that close ack received
177
+ connection.onmessage { |frame|
178
+ frame.should == "\x01\x00"
179
+ done
180
+ }
181
+ }
182
+ end
183
+
184
+ it "should close the connection on receiving a close acknowlegement" do
185
+ em {
186
+ ack_received = false
187
+
188
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
189
+ ws.onopen {
190
+ # 2. Send a close frame
191
+ EM.next_tick {
192
+ ws.close_websocket
193
+ }
194
+ }
195
+ }
196
+
197
+ # 1. Create a fake client which sends draft 76 handshake
198
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
199
+ connection.send_data(format_request(@request))
200
+
201
+ # 3. Check that close frame recieved and acknowlege it
202
+ connection.onmessage { |frame|
203
+ frame.should == "\x01\x00"
204
+ ack_received = true
205
+ connection.send_data("\x01\x00")
206
+ }
207
+
208
+ # 4. Check that connection is closed _after_ the ack
209
+ connection.onclose {
210
+ ack_received.should == true
211
+ done
212
+ }
213
+ }
214
+ end
215
+
216
+ it "should not allow data frame to be sent after close frame sent" do
217
+ em {
218
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
219
+ ws.onopen {
220
+ # 2. Send a close frame
221
+ EM.next_tick {
222
+ ws.close_websocket
223
+ }
224
+
225
+ # 3. Check that exception raised if I attempt to send more data
226
+ EM.add_timer(0.1) {
227
+ lambda {
228
+ ws.send('hello world')
229
+ }.should raise_error(EM::WebSocket::WebSocketError, 'Cannot send data frame since connection is closing')
230
+ done
231
+ }
232
+ }
233
+ }
234
+
235
+ # 1. Create a fake client which sends draft 76 handshake
236
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
237
+ connection.send_data(format_request(@request))
238
+ }
239
+ end
240
+
241
+ it "should still respond to control frames after close frame sent" do
242
+ em {
243
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
244
+ ws.onopen {
245
+ # 2. Send a close frame
246
+ EM.next_tick {
247
+ ws.close_websocket
248
+ }
249
+ }
250
+ }
251
+
252
+ # 1. Create a fake client which sends draft 76 handshake
253
+ connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
254
+ connection.send_data(format_request(@request))
255
+
256
+ connection.onmessage { |frame|
257
+ if frame == "\x01\x00"
258
+ # 3. After the close frame is received send a ping frame, but
259
+ # don't respond with a close ack
260
+ connection.send_data("\x02\x05Hello")
261
+ else
262
+ # 4. Check that the pong is received
263
+ frame.should == "\x03\x05Hello"
264
+ done
265
+ end
266
+ }
267
+ }
268
+ end
269
+ end
270
+ end
@@ -0,0 +1,48 @@
1
+ require 'helper'
2
+
3
+ describe "draft05" do
4
+ include EM::SpecHelper
5
+ default_timeout 1
6
+
7
+ before :each do
8
+ @request = {
9
+ :port => 80,
10
+ :method => "GET",
11
+ :path => "/demo",
12
+ :headers => {
13
+ 'Host' => 'example.com',
14
+ 'Upgrade' => 'websocket',
15
+ 'Connection' => 'Upgrade',
16
+ 'Sec-WebSocket-Key' => 'dGhlIHNhbXBsZSBub25jZQ==',
17
+ 'Sec-WebSocket-Protocol' => 'sample',
18
+ 'Sec-WebSocket-Origin' => 'http://example.com',
19
+ 'Sec-WebSocket-Version' => '5'
20
+ }
21
+ }
22
+ end
23
+
24
+ def start_server
25
+ EM::WebSocket.start(:host => "0.0.0.0", :port => 12345) { |ws|
26
+ yield ws
27
+ }
28
+ end
29
+
30
+ def start_client
31
+ client = EM.connect('0.0.0.0', 12345, Draft03FakeWebSocketClient)
32
+ client.send_data(format_request(@request))
33
+ yield client if block_given?
34
+ end
35
+
36
+ it "should open connection" do
37
+ em {
38
+ start_server { |server|
39
+ server.onopen {
40
+ server.instance_variable_get(:@handler).class.should == EventMachine::WebSocket::Handler05
41
+ done
42
+ }
43
+ }
44
+
45
+ start_client
46
+ }
47
+ end
48
+ end