em-websocket 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +16 -1
- data/README.md +42 -1
- data/examples/test.html +3 -1
- data/lib/em-websocket/close03.rb +2 -0
- data/lib/em-websocket/close05.rb +2 -0
- data/lib/em-websocket/close06.rb +2 -0
- data/lib/em-websocket/close75.rb +2 -1
- data/lib/em-websocket/connection.rb +44 -19
- data/lib/em-websocket/framing03.rb +2 -1
- data/lib/em-websocket/framing05.rb +2 -1
- data/lib/em-websocket/framing07.rb +2 -1
- data/lib/em-websocket/handler.rb +8 -2
- data/lib/em-websocket/handler76.rb +2 -0
- data/lib/em-websocket/handshake.rb +5 -1
- data/lib/em-websocket/handshake04.rb +0 -5
- data/lib/em-websocket/masking04.rb +1 -5
- data/lib/em-websocket/message_processor_03.rb +5 -2
- data/lib/em-websocket/message_processor_06.rb +13 -6
- data/lib/em-websocket/version.rb +1 -1
- data/lib/em-websocket/websocket.rb +4 -0
- data/spec/helper.rb +52 -46
- data/spec/integration/common_spec.rb +11 -5
- data/spec/integration/draft03_spec.rb +82 -55
- data/spec/integration/draft05_spec.rb +13 -8
- data/spec/integration/draft06_spec.rb +65 -3
- data/spec/integration/draft13_spec.rb +31 -20
- data/spec/integration/draft75_spec.rb +32 -19
- data/spec/integration/draft76_spec.rb +62 -43
- data/spec/integration/shared_examples.rb +80 -0
- data/spec/unit/framing_spec.rb +3 -1
- data/spec/unit/masking_spec.rb +2 -0
- metadata +4 -4
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'helper'
|
2
|
+
require 'integration/shared_examples'
|
2
3
|
|
3
4
|
describe "draft05" do
|
4
5
|
include EM::SpecHelper
|
@@ -22,26 +23,30 @@ describe "draft05" do
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def start_server
|
25
|
-
EM::WebSocket.
|
26
|
-
yield ws
|
26
|
+
EM::WebSocket.run(:host => "0.0.0.0", :port => 12345) { |ws|
|
27
|
+
yield ws if block_given?
|
27
28
|
}
|
28
29
|
end
|
29
30
|
|
30
31
|
def start_client
|
31
|
-
client = EM.connect('0.0.0.0', 12345,
|
32
|
+
client = EM.connect('0.0.0.0', 12345, Draft05FakeWebSocketClient)
|
32
33
|
client.send_data(format_request(@request))
|
33
34
|
yield client if block_given?
|
35
|
+
return client
|
34
36
|
end
|
35
37
|
|
36
|
-
|
38
|
+
it_behaves_like "a websocket server" do
|
39
|
+
let(:version) { 5 }
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should report that close codes are not supported" do
|
37
43
|
em {
|
38
|
-
start_server { |
|
39
|
-
|
40
|
-
|
44
|
+
start_server { |ws|
|
45
|
+
ws.onopen {
|
46
|
+
ws.supports_close_codes?.should == false
|
41
47
|
done
|
42
48
|
}
|
43
49
|
}
|
44
|
-
|
45
50
|
start_client
|
46
51
|
}
|
47
52
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'helper'
|
2
|
+
require 'integration/shared_examples'
|
2
3
|
|
3
4
|
describe "draft06" do
|
4
5
|
include EM::SpecHelper
|
@@ -31,17 +32,22 @@ describe "draft06" do
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def start_server
|
34
|
-
EM::WebSocket.
|
35
|
-
yield ws
|
35
|
+
EM::WebSocket.run(:host => "0.0.0.0", :port => 12345) { |ws|
|
36
|
+
yield ws if block_given?
|
36
37
|
}
|
37
38
|
end
|
38
39
|
|
39
40
|
def start_client
|
40
|
-
client = EM.connect('0.0.0.0', 12345,
|
41
|
+
client = EM.connect('0.0.0.0', 12345, Draft05FakeWebSocketClient)
|
41
42
|
client.send_data(format_request(@request))
|
42
43
|
yield client if block_given?
|
44
|
+
return client
|
43
45
|
end
|
44
46
|
|
47
|
+
it_behaves_like "a websocket server" do
|
48
|
+
let(:version) { 6 }
|
49
|
+
end
|
50
|
+
|
45
51
|
it "should open connection" do
|
46
52
|
em {
|
47
53
|
start_server { |server|
|
@@ -82,4 +88,60 @@ describe "draft06" do
|
|
82
88
|
}
|
83
89
|
}
|
84
90
|
end
|
91
|
+
|
92
|
+
it "should return close code and reason if closed via handshake" do
|
93
|
+
em {
|
94
|
+
start_server { |ws|
|
95
|
+
ws.onclose { |event|
|
96
|
+
# 2. Receive close event in server
|
97
|
+
event.should == {
|
98
|
+
:code => 4004,
|
99
|
+
:reason => "close reason",
|
100
|
+
:was_clean => true,
|
101
|
+
}
|
102
|
+
done
|
103
|
+
}
|
104
|
+
}
|
105
|
+
start_client { |client|
|
106
|
+
client.onopen {
|
107
|
+
# 1: Send close handshake
|
108
|
+
close_data = [4004].pack('n')
|
109
|
+
close_data << "close reason"
|
110
|
+
client.send_frame(:close, close_data)
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should return close code 1005 if no code was specified" do
|
117
|
+
em {
|
118
|
+
start_server { |ws|
|
119
|
+
ws.onclose { |event|
|
120
|
+
event.should == {
|
121
|
+
:code => 1005,
|
122
|
+
:reason => "",
|
123
|
+
:was_clean => true,
|
124
|
+
}
|
125
|
+
done
|
126
|
+
}
|
127
|
+
}
|
128
|
+
start_client { |client|
|
129
|
+
client.onopen {
|
130
|
+
client.send_frame(:close, '')
|
131
|
+
}
|
132
|
+
}
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should report that close codes are supported" do
|
137
|
+
em {
|
138
|
+
start_server { |ws|
|
139
|
+
ws.onopen {
|
140
|
+
ws.supports_close_codes?.should == true
|
141
|
+
done
|
142
|
+
}
|
143
|
+
}
|
144
|
+
start_client
|
145
|
+
}
|
146
|
+
end
|
85
147
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
|
1
3
|
require 'helper'
|
2
4
|
require 'integration/shared_examples'
|
3
5
|
|
@@ -31,29 +33,28 @@ describe "draft13" do
|
|
31
33
|
}
|
32
34
|
end
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
+
def start_server
|
37
|
+
EM::WebSocket.run(:host => "0.0.0.0", :port => 12345) { |ws|
|
38
|
+
yield ws if block_given?
|
39
|
+
}
|
40
|
+
end
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
+
return client
|
47
|
+
end
|
42
48
|
|
43
|
-
|
44
|
-
|
45
|
-
client.send_data(format_request(@request))
|
46
|
-
yield client if block_given?
|
47
|
-
end
|
49
|
+
it_behaves_like "a websocket server" do
|
50
|
+
let(:version) { 13 }
|
48
51
|
end
|
49
52
|
|
50
53
|
it "should send back the correct handshake response" do
|
51
54
|
em {
|
52
|
-
|
55
|
+
start_server
|
53
56
|
|
54
|
-
|
55
|
-
connection = EM.connect('0.0.0.0', 12345, Draft07FakeWebSocketClient)
|
56
|
-
connection.send_data(format_request(@request))
|
57
|
+
connection = start_client
|
57
58
|
|
58
59
|
connection.onopen {
|
59
60
|
connection.handshake_response.lines.sort.
|
@@ -66,7 +67,7 @@ describe "draft13" do
|
|
66
67
|
# TODO: This test would be much nicer with a real websocket client...
|
67
68
|
it "should support sending pings and binding to onpong" do
|
68
69
|
em {
|
69
|
-
|
70
|
+
start_server { |ws|
|
70
71
|
ws.onopen {
|
71
72
|
ws.should be_pingable
|
72
73
|
EM.next_tick {
|
@@ -80,9 +81,7 @@ describe "draft13" do
|
|
80
81
|
}
|
81
82
|
}
|
82
83
|
|
83
|
-
|
84
|
-
connection = EM.connect('0.0.0.0', 12345, Draft07FakeWebSocketClient)
|
85
|
-
connection.send_data(format_request(@request))
|
84
|
+
connection = start_client
|
86
85
|
|
87
86
|
# Confusing, fake onmessage means any data after the handshake
|
88
87
|
connection.onmessage { |data|
|
@@ -93,4 +92,16 @@ describe "draft13" do
|
|
93
92
|
}
|
94
93
|
}
|
95
94
|
end
|
95
|
+
|
96
|
+
it "should report that close codes are supported" do
|
97
|
+
em {
|
98
|
+
start_server { |ws|
|
99
|
+
ws.onopen {
|
100
|
+
ws.supports_close_codes?.should == true
|
101
|
+
done
|
102
|
+
}
|
103
|
+
}
|
104
|
+
start_client
|
105
|
+
}
|
106
|
+
end
|
96
107
|
end
|
@@ -9,19 +9,20 @@ describe "WebSocket server draft75" do
|
|
9
9
|
include EM::SpecHelper
|
10
10
|
default_timeout 1
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
def start_server
|
13
|
+
EM::WebSocket.run(:host => "0.0.0.0", :port => 12345) { |ws|
|
14
|
+
yield ws if block_given?
|
15
|
+
}
|
16
|
+
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
def start_client
|
19
|
+
client = Draft75WebSocketClient.new
|
20
|
+
yield client if block_given?
|
21
|
+
return client
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
yield client if block_given?
|
24
|
-
end
|
24
|
+
it_behaves_like "a websocket server" do
|
25
|
+
let(:version) { 75 }
|
25
26
|
end
|
26
27
|
|
27
28
|
it "should automatically complete WebSocket handshake" do
|
@@ -38,11 +39,11 @@ describe "WebSocket server draft75" do
|
|
38
39
|
}
|
39
40
|
end
|
40
41
|
|
41
|
-
|
42
|
+
start_server { |ws|
|
42
43
|
ws.onopen {
|
43
44
|
ws.send MSG
|
44
45
|
}
|
45
|
-
|
46
|
+
}
|
46
47
|
}
|
47
48
|
end
|
48
49
|
|
@@ -62,7 +63,7 @@ describe "WebSocket server draft75" do
|
|
62
63
|
}
|
63
64
|
end
|
64
65
|
|
65
|
-
|
66
|
+
start_server { |ws|
|
66
67
|
ws.onopen {}
|
67
68
|
ws.onclose {}
|
68
69
|
ws.onmessage {|msg|
|
@@ -71,7 +72,7 @@ describe "WebSocket server draft75" do
|
|
71
72
|
|
72
73
|
EventMachine.stop if received.size == messages.size
|
73
74
|
}
|
74
|
-
|
75
|
+
}
|
75
76
|
}
|
76
77
|
end
|
77
78
|
|
@@ -87,13 +88,13 @@ describe "WebSocket server draft75" do
|
|
87
88
|
http.stream{|msg|}
|
88
89
|
end
|
89
90
|
|
90
|
-
|
91
|
+
start_server { |ws|
|
91
92
|
ws.onopen {}
|
92
93
|
ws.onclose {
|
93
94
|
ws.state.should == :closed
|
94
95
|
EventMachine.stop
|
95
96
|
}
|
96
|
-
|
97
|
+
}
|
97
98
|
}
|
98
99
|
end
|
99
100
|
|
@@ -105,7 +106,7 @@ describe "WebSocket server draft75" do
|
|
105
106
|
http.callback { fail }
|
106
107
|
end
|
107
108
|
|
108
|
-
|
109
|
+
start_server { |ws|
|
109
110
|
ws.onopen { fail }
|
110
111
|
ws.onclose { EventMachine.stop }
|
111
112
|
ws.onerror {|e|
|
@@ -113,7 +114,19 @@ describe "WebSocket server draft75" do
|
|
113
114
|
e.message.should match('Not an upgrade request')
|
114
115
|
EventMachine.stop
|
115
116
|
}
|
116
|
-
|
117
|
+
}
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should report that close codes are not supported" do
|
122
|
+
em {
|
123
|
+
start_server { |ws|
|
124
|
+
ws.onopen {
|
125
|
+
ws.supports_close_codes?.should == false
|
126
|
+
done
|
127
|
+
}
|
128
|
+
}
|
129
|
+
start_client
|
117
130
|
}
|
118
131
|
end
|
119
132
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: BINARY
|
2
|
+
|
1
3
|
require 'helper'
|
2
4
|
require 'integration/shared_examples'
|
3
5
|
|
@@ -34,45 +36,42 @@ describe "WebSocket server draft76" do
|
|
34
36
|
}
|
35
37
|
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
def start_server
|
40
|
+
EM::WebSocket.run(:host => "0.0.0.0", :port => 12345) { |ws|
|
41
|
+
yield ws if block_given?
|
42
|
+
}
|
43
|
+
end
|
39
44
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
+
def start_client
|
46
|
+
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
47
|
+
client.send_data(format_request(@request))
|
48
|
+
yield client if block_given?
|
49
|
+
return client
|
50
|
+
end
|
45
51
|
|
46
|
-
|
47
|
-
|
48
|
-
client.send_data(format_request(@request))
|
49
|
-
yield client if block_given?
|
50
|
-
end
|
52
|
+
it_behaves_like "a websocket server" do
|
53
|
+
let(:version) { 76 }
|
51
54
|
end
|
52
55
|
|
53
56
|
it "should send back the correct handshake response" do
|
54
57
|
em {
|
55
|
-
|
56
|
-
|
57
|
-
# Create a fake client which sends draft 76 handshake
|
58
|
-
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
59
|
-
connection.send_data(format_request(@request))
|
58
|
+
start_server
|
60
59
|
|
61
|
-
|
62
|
-
connection.
|
63
|
-
|
64
|
-
|
60
|
+
start_client { |connection|
|
61
|
+
connection.onopen {
|
62
|
+
connection.handshake_response.lines.sort.
|
63
|
+
should == format_response(@response).lines.sort
|
64
|
+
done
|
65
|
+
}
|
65
66
|
}
|
66
67
|
}
|
67
68
|
end
|
68
69
|
|
69
70
|
it "should send closing frame back and close the connection after recieving closing frame" do
|
70
71
|
em {
|
71
|
-
|
72
|
+
start_server
|
72
73
|
|
73
|
-
|
74
|
-
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
75
|
-
connection.send_data(format_request(@request))
|
74
|
+
connection = start_client
|
76
75
|
|
77
76
|
# Send closing frame after handshake complete
|
78
77
|
connection.onopen {
|
@@ -91,16 +90,14 @@ describe "WebSocket server draft76" do
|
|
91
90
|
|
92
91
|
it "should ignore any data received after the closing frame" do
|
93
92
|
em {
|
94
|
-
|
93
|
+
start_server { |ws|
|
95
94
|
# Fail if foobar message is received
|
96
95
|
ws.onmessage { |msg|
|
97
96
|
fail
|
98
97
|
}
|
99
98
|
}
|
100
99
|
|
101
|
-
|
102
|
-
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
103
|
-
connection.send_data(format_request(@request))
|
100
|
+
connection = start_client
|
104
101
|
|
105
102
|
# Send closing frame after handshake complete, followed by another msg
|
106
103
|
connection.onopen {
|
@@ -116,15 +113,13 @@ describe "WebSocket server draft76" do
|
|
116
113
|
|
117
114
|
it "should accept null bytes within the frame after a line return" do
|
118
115
|
em {
|
119
|
-
|
116
|
+
start_server { |ws|
|
120
117
|
ws.onmessage { |msg|
|
121
118
|
msg.should == "\n\000"
|
122
119
|
}
|
123
120
|
}
|
124
121
|
|
125
|
-
|
126
|
-
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
127
|
-
connection.send_data(format_request(@request))
|
122
|
+
connection = start_client
|
128
123
|
|
129
124
|
# Send closing frame after handshake complete
|
130
125
|
connection.onopen {
|
@@ -140,7 +135,7 @@ describe "WebSocket server draft76" do
|
|
140
135
|
|
141
136
|
it "should handle unreasonable frame lengths by calling onerror callback" do
|
142
137
|
em {
|
143
|
-
|
138
|
+
start_server { |server|
|
144
139
|
server.onerror { |error|
|
145
140
|
error.should be_an_instance_of EM::WebSocket::WSMessageTooBigError
|
146
141
|
error.message.should == "Frame length too long (1180591620717411303296 bytes)"
|
@@ -148,9 +143,7 @@ describe "WebSocket server draft76" do
|
|
148
143
|
}
|
149
144
|
}
|
150
145
|
|
151
|
-
|
152
|
-
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
153
|
-
client.send_data(format_request(@request))
|
146
|
+
client = start_client
|
154
147
|
|
155
148
|
# This particular frame indicates a message length of
|
156
149
|
# 1180591620717411303296 bytes. Such a message would previously cause
|
@@ -164,7 +157,7 @@ describe "WebSocket server draft76" do
|
|
164
157
|
|
165
158
|
it "should handle impossible frames by calling onerror callback" do
|
166
159
|
em {
|
167
|
-
|
160
|
+
start_server { |server|
|
168
161
|
server.onerror { |error|
|
169
162
|
error.should be_an_instance_of EM::WebSocket::WSProtocolError
|
170
163
|
error.message.should == "Invalid frame received"
|
@@ -172,9 +165,7 @@ describe "WebSocket server draft76" do
|
|
172
165
|
}
|
173
166
|
}
|
174
167
|
|
175
|
-
|
176
|
-
client = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
177
|
-
client.send_data(format_request(@request))
|
168
|
+
client = start_client
|
178
169
|
|
179
170
|
client.onopen {
|
180
171
|
client.send_data("foobar") # Does not start with \x00 or \xff
|
@@ -184,7 +175,7 @@ describe "WebSocket server draft76" do
|
|
184
175
|
|
185
176
|
it "should handle invalid http requests by raising HandshakeError passed to onerror callback" do
|
186
177
|
em {
|
187
|
-
|
178
|
+
start_server { |server|
|
188
179
|
server.onerror { |error|
|
189
180
|
error.should be_an_instance_of EM::WebSocket::HandshakeError
|
190
181
|
error.message.should == "Invalid HTTP header: Could not parse data entirely"
|
@@ -199,7 +190,7 @@ describe "WebSocket server draft76" do
|
|
199
190
|
|
200
191
|
it "should handle handshake request split into two TCP packets" do
|
201
192
|
em {
|
202
|
-
|
193
|
+
start_server
|
203
194
|
|
204
195
|
# Create a fake client which sends draft 76 handshake
|
205
196
|
connection = EM.connect('0.0.0.0', 12345, FakeWebSocketClient)
|
@@ -219,4 +210,32 @@ describe "WebSocket server draft76" do
|
|
219
210
|
end
|
220
211
|
}
|
221
212
|
end
|
213
|
+
|
214
|
+
it "should report that close codes are not supported" do
|
215
|
+
em {
|
216
|
+
start_server { |ws|
|
217
|
+
ws.onopen {
|
218
|
+
ws.supports_close_codes?.should == false
|
219
|
+
done
|
220
|
+
}
|
221
|
+
}
|
222
|
+
start_client
|
223
|
+
}
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should call onclose when the server closes the connection [antiregression]" do
|
227
|
+
em {
|
228
|
+
start_server { |ws|
|
229
|
+
ws.onopen {
|
230
|
+
EM.add_timer(0.1) {
|
231
|
+
ws.close()
|
232
|
+
}
|
233
|
+
}
|
234
|
+
ws.onclose {
|
235
|
+
done
|
236
|
+
}
|
237
|
+
}
|
238
|
+
start_client
|
239
|
+
}
|
240
|
+
end
|
222
241
|
end
|