sockjs 0.2.1
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/LICENCE +19 -0
- data/README.textile +118 -0
- data/lib/meta-state.rb +151 -0
- data/lib/rack/sockjs.rb +173 -0
- data/lib/sockjs.rb +59 -0
- data/lib/sockjs/callbacks.rb +19 -0
- data/lib/sockjs/connection.rb +45 -0
- data/lib/sockjs/delayed-response-body.rb +99 -0
- data/lib/sockjs/duck-punch-rack-mount.rb +12 -0
- data/lib/sockjs/duck-punch-thin-response.rb +15 -0
- data/lib/sockjs/examples/protocol_conformance_test.rb +73 -0
- data/lib/sockjs/faye.rb +15 -0
- data/lib/sockjs/protocol.rb +97 -0
- data/lib/sockjs/servers/request.rb +136 -0
- data/lib/sockjs/servers/response.rb +169 -0
- data/lib/sockjs/session.rb +388 -0
- data/lib/sockjs/transport.rb +354 -0
- data/lib/sockjs/transports/eventsource.rb +30 -0
- data/lib/sockjs/transports/htmlfile.rb +69 -0
- data/lib/sockjs/transports/iframe.rb +68 -0
- data/lib/sockjs/transports/info.rb +48 -0
- data/lib/sockjs/transports/jsonp.rb +84 -0
- data/lib/sockjs/transports/websocket.rb +166 -0
- data/lib/sockjs/transports/welcome_screen.rb +17 -0
- data/lib/sockjs/transports/xhr.rb +75 -0
- data/lib/sockjs/version.rb +13 -0
- data/spec/sockjs/protocol_spec.rb +49 -0
- data/spec/sockjs/session_spec.rb +51 -0
- data/spec/sockjs/transport_spec.rb +73 -0
- data/spec/sockjs/transports/eventsource_spec.rb +56 -0
- data/spec/sockjs/transports/htmlfile_spec.rb +72 -0
- data/spec/sockjs/transports/iframe_spec.rb +66 -0
- data/spec/sockjs/transports/jsonp_spec.rb +252 -0
- data/spec/sockjs/transports/websocket_spec.rb +101 -0
- data/spec/sockjs/transports/welcome_screen_spec.rb +36 -0
- data/spec/sockjs/transports/xhr_spec.rb +314 -0
- data/spec/sockjs/version_spec.rb +18 -0
- data/spec/sockjs_spec.rb +8 -0
- data/spec/spec_helper.rb +121 -0
- data/spec/support/async-test.rb +42 -0
- metadata +171 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
#!/usr/bin/env bundle exec rspec
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
require "sockjs"
|
7
|
+
require "sockjs/transports/websocket"
|
8
|
+
|
9
|
+
describe SockJS::Transports::WebSocket, :type => :transport do
|
10
|
+
transport_handler_eql "/websocket", "GET"
|
11
|
+
|
12
|
+
let :request_options do
|
13
|
+
{}
|
14
|
+
end
|
15
|
+
|
16
|
+
let :request do
|
17
|
+
env = {
|
18
|
+
"HTTP_CONNECTION" => "Upgrade",
|
19
|
+
"HTTP_UPGRADE" => "WebSocket"}
|
20
|
+
FakeRequest.new(env.merge(request_options)).tap do |request|
|
21
|
+
request.path_info = "/a/b/websocket"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#handle(request)" do
|
26
|
+
context "if the transport is disabled" do
|
27
|
+
let :transport_options do
|
28
|
+
{:websocket => false}
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should report itself disabled" do
|
32
|
+
transport.should be_disabled
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should respond with 404 and an error message" do
|
36
|
+
response.status.should eql(404)
|
37
|
+
response.chunks.last.should eql("WebSockets Are Disabled")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "if HTTP_UPGRADE isn't WebSocket" do
|
42
|
+
let :request_options do
|
43
|
+
{ "HTTP_UPGRADE" => "something" }
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should respond with 400 and an error message" do
|
47
|
+
response.status.should eql(400)
|
48
|
+
response.chunks.last.should eql('Can "Upgrade" only to "WebSocket".')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
context "if HTTP_CONNECTION isn't Upgrade" do
|
54
|
+
let :request_options do
|
55
|
+
{"HTTP_CONNECTION" => "something"}
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should respond with 400 and an error message" do
|
59
|
+
response.status.should eql(400)
|
60
|
+
response.chunks.last.should eql('"Connection" must be "Upgrade".')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# The following three statements are meant to be documentation rather than specs itselves.
|
65
|
+
it "should call #handle_open(request) when the connection is being open"
|
66
|
+
|
67
|
+
it "should call #handle_message(request, event) on a new message"
|
68
|
+
|
69
|
+
it "should call #handle_close(request, event) when the connection is being closed"
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#handle_open(request)" do
|
73
|
+
it "should send the opening frame"
|
74
|
+
it "should open a new session"
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#handle_message(request, event)" do
|
78
|
+
let(:app) do
|
79
|
+
Proc.new do |connection|
|
80
|
+
connection.subscribe do |session, message|
|
81
|
+
session.send(message.upcase)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should receive the message"
|
87
|
+
it "should run user code"
|
88
|
+
it "should send messages"
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#handle_close(request, event)" do
|
92
|
+
it "should send the closing frame"
|
93
|
+
it "should open a new session"
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#send" do
|
97
|
+
it "should be defined, but it should do nothing" do
|
98
|
+
transport.should respond_to(:send)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env bundle exec rspec
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
require "sockjs"
|
7
|
+
require "sockjs/transports/welcome_screen"
|
8
|
+
|
9
|
+
describe SockJS::Transports::WelcomeScreen do
|
10
|
+
describe "#handle(request)" do
|
11
|
+
let(:transport) do
|
12
|
+
described_class.new(Object.new, Hash.new)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:request) do
|
16
|
+
@request ||= FakeRequest.new
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:response) do
|
20
|
+
transport.handle(request)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should respond with HTTP 200" do
|
24
|
+
response.status.should eql(200)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should respond with plain text MIME type" do
|
28
|
+
response.headers["Content-Type"].should match("text/plain")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return greeting in the body" do
|
32
|
+
response # Run the handler.
|
33
|
+
response.chunks.last.should eql("Welcome to SockJS!\n")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,314 @@
|
|
1
|
+
#!/usr/bin/env bundle exec rspec
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
require "sockjs"
|
7
|
+
require "sockjs/transports/xhr"
|
8
|
+
|
9
|
+
describe "XHR", :type => :transport, :em => true do
|
10
|
+
describe SockJS::Transports::XHRPost do
|
11
|
+
transport_handler_eql "/xhr", "POST"
|
12
|
+
|
13
|
+
describe "#handle(request)" do
|
14
|
+
let(:request) do
|
15
|
+
FakeRequest.new.tap do |request|
|
16
|
+
request.session_key = Array.new(7) { rand(256) }.pack("C*").unpack("H*").first
|
17
|
+
request.path_info = "/xhr"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "with a session" do
|
22
|
+
before :each do
|
23
|
+
session
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:request) do
|
27
|
+
FakeRequest.new.tap do |request|
|
28
|
+
request.path_info = "/xhr"
|
29
|
+
request.session_key = "b"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should respond with HTTP 200" do
|
34
|
+
response.status.should eql(200)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should respond with javascript MIME type" do
|
38
|
+
response.headers["Content-Type"].should match("application/javascript")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should run user code"
|
42
|
+
end
|
43
|
+
|
44
|
+
context "without a session" do
|
45
|
+
let :session do
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should create one and send an opening frame" do
|
49
|
+
response.chunks.last.should eql("o\n")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should respond with HTTP 200" do
|
53
|
+
response.status.should eql(200)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should respond with javascript MIME type" do
|
57
|
+
response.headers["Content-Type"].should match("application/javascript")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should set access control" do
|
61
|
+
response.headers["Access-Control-Allow-Origin"].should eql(request.origin)
|
62
|
+
response.headers["Access-Control-Allow-Credentials"].should eql("true")
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should set session ID" do
|
66
|
+
cookie = response.headers["Set-Cookie"]
|
67
|
+
cookie.should match("JSESSIONID=#{request.session_id}; path=/")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe SockJS::Transports::XHROptions do
|
74
|
+
transport_handler_eql "/xhr", "OPTIONS"
|
75
|
+
|
76
|
+
describe "#handle(request)" do
|
77
|
+
let(:request) do
|
78
|
+
FakeRequest.new
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should respond with HTTP 204" do
|
82
|
+
response.status.should eql(204)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should set access control" do
|
86
|
+
response.headers["Access-Control-Allow-Origin"].should eql(request.origin)
|
87
|
+
response.headers["Access-Control-Allow-Credentials"].should eql("true")
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should set cache control to be valid for the next year" do
|
91
|
+
time = Time.now + 31536000
|
92
|
+
|
93
|
+
response.headers["Cache-Control"].should eql("public, max-age=31536000")
|
94
|
+
response.headers["Expires"].should eql(time.gmtime.to_s)
|
95
|
+
response.headers["Access-Control-Max-Age"].should eql("1000001")
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should set Allow header to OPTIONS, POST" do
|
99
|
+
response.headers["Allow"].should eql("OPTIONS, POST")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe SockJS::Transports::XHRSendPost do
|
105
|
+
transport_handler_eql "/xhr_send", "POST"
|
106
|
+
|
107
|
+
describe "#handle(request)" do
|
108
|
+
let(:request) do
|
109
|
+
FakeRequest.new.tap do |request|
|
110
|
+
request.session_key = rand(1 << 32).to_s
|
111
|
+
request.path_info = "/xhr_send"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "with a session" do
|
116
|
+
before :each do
|
117
|
+
session
|
118
|
+
end
|
119
|
+
|
120
|
+
context "well formed request" do
|
121
|
+
|
122
|
+
let(:request) do
|
123
|
+
FakeRequest.new.tap do |request|
|
124
|
+
request.path_info = "/xhr_send"
|
125
|
+
request.session_key = 'b'
|
126
|
+
request.data = '["message"]'
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should respond with HTTP 204" do
|
131
|
+
response.status.should eql(204)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should respond with plain text MIME type" do
|
135
|
+
response.headers["Content-Type"].should match("text/plain")
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should set session ID" do
|
139
|
+
cookie = response.headers["Set-Cookie"]
|
140
|
+
cookie.should match("JSESSIONID=#{request.session_id}; path=/")
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should set access control" do
|
144
|
+
response.headers["Access-Control-Allow-Origin"].should eql(request.origin)
|
145
|
+
response.headers["Access-Control-Allow-Credentials"].should eql("true")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context "badly formed JSON" do
|
150
|
+
let(:request) do
|
151
|
+
FakeRequest.new.tap do |request|
|
152
|
+
request.path_info = "/xhr_send"
|
153
|
+
request.session_key = 'b'
|
154
|
+
request.data = '["message"'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should respond with HTTP 500" do
|
159
|
+
response.status.should eql(500)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should report JSON error" do
|
163
|
+
response
|
164
|
+
request.chunks.join("").should =~ /Broken JSON encoding/
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "empty body" do
|
169
|
+
let(:request) do
|
170
|
+
FakeRequest.new.tap do |request|
|
171
|
+
request.path_info = "/xhr_send"
|
172
|
+
request.session_key = 'b'
|
173
|
+
request.data = ''
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should respond with HTTP 500" do
|
178
|
+
response.status.should eql(500)
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should report JSON error" do
|
182
|
+
response
|
183
|
+
request.chunks.join("").should =~ /Payload expected\./
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "without a session" do
|
189
|
+
it "should respond with HTTP 404" do
|
190
|
+
response.status.should eql(404)
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should respond with plain text MIME type" do
|
194
|
+
response.headers["Content-Type"].should match("text/plain")
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should return error message in the body" do
|
198
|
+
response # Run the handler.
|
199
|
+
request.chunks.last.should match(/Session is not open\!/)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe SockJS::Transports::XHRSendOptions do
|
206
|
+
transport_handler_eql "/xhr_send", "OPTIONS"
|
207
|
+
|
208
|
+
describe "#handle(request)" do
|
209
|
+
let(:request) do
|
210
|
+
FakeRequest.new
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should respond with HTTP 204" do
|
214
|
+
response.status.should eql(204)
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should set access control" do
|
218
|
+
response.headers["Access-Control-Allow-Origin"].should eql(request.origin)
|
219
|
+
response.headers["Access-Control-Allow-Credentials"].should eql("true")
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should set cache control to be valid for the next year" do
|
223
|
+
time = Time.now + 31536000
|
224
|
+
|
225
|
+
response.headers["Cache-Control"].should eql("public, max-age=31536000")
|
226
|
+
response.headers["Expires"].should eql(time.gmtime.to_s)
|
227
|
+
response.headers["Access-Control-Max-Age"].should eql("1000001")
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should set Allow header to OPTIONS, POST" do
|
231
|
+
response.headers["Allow"].should eql("OPTIONS, POST")
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe SockJS::Transports::XHRStreamingPost do
|
237
|
+
transport_handler_eql "/xhr_streaming", "POST"
|
238
|
+
|
239
|
+
describe "#handle(request)" do
|
240
|
+
let :session do
|
241
|
+
end
|
242
|
+
|
243
|
+
let(:transport) do
|
244
|
+
transport = described_class.new(connection, Hash.new)
|
245
|
+
|
246
|
+
def transport.try_timer_if_valid(*)
|
247
|
+
end
|
248
|
+
|
249
|
+
transport
|
250
|
+
end
|
251
|
+
|
252
|
+
let(:request) do
|
253
|
+
FakeRequest.new.tap do |request|
|
254
|
+
request.path_info = "/a/b/xhr_streaming"
|
255
|
+
request.session_key = "b"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should respond with HTTP 200" do
|
260
|
+
response.status.should eql(200)
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should respond with prelude + open frame" do
|
264
|
+
response
|
265
|
+
request.chunks.join("").should =~ /hhhhhhhhh\no/
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should respond with javascript MIME type" do
|
269
|
+
response.headers["Content-Type"].should match("application/javascript")
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should set access control" do
|
273
|
+
response.headers["Access-Control-Allow-Origin"].should eql(request.origin)
|
274
|
+
response.headers["Access-Control-Allow-Credentials"].should eql("true")
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should set session ID" do
|
278
|
+
cookie = response.headers["Set-Cookie"]
|
279
|
+
cookie.should match("JSESSIONID=#{request.session_id}; path=/")
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe SockJS::Transports::XHRStreamingOptions do
|
285
|
+
transport_handler_eql "/xhr_streaming", "OPTIONS"
|
286
|
+
|
287
|
+
describe "#handle(request)" do
|
288
|
+
let(:request) do
|
289
|
+
FakeRequest.new
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should respond with HTTP 204" do
|
293
|
+
response.status.should eql(204)
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should set access control" do
|
297
|
+
response.headers["Access-Control-Allow-Origin"].should eql(request.origin)
|
298
|
+
response.headers["Access-Control-Allow-Credentials"].should eql("true")
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should set cache control to be valid for the next year" do
|
302
|
+
time = Time.now + 31536000
|
303
|
+
|
304
|
+
response.headers["Cache-Control"].should eql("public, max-age=31536000")
|
305
|
+
response.headers["Expires"].should eql(time.gmtime.to_s)
|
306
|
+
response.headers["Access-Control-Max-Age"].should eql("1000001")
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should set Allow header to OPTIONS, POST" do
|
310
|
+
response.headers["Allow"].should eql("OPTIONS, POST")
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|