em-websocket 0.4.0 → 0.5.0
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/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
|