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.
Files changed (41) hide show
  1. data/LICENCE +19 -0
  2. data/README.textile +118 -0
  3. data/lib/meta-state.rb +151 -0
  4. data/lib/rack/sockjs.rb +173 -0
  5. data/lib/sockjs.rb +59 -0
  6. data/lib/sockjs/callbacks.rb +19 -0
  7. data/lib/sockjs/connection.rb +45 -0
  8. data/lib/sockjs/delayed-response-body.rb +99 -0
  9. data/lib/sockjs/duck-punch-rack-mount.rb +12 -0
  10. data/lib/sockjs/duck-punch-thin-response.rb +15 -0
  11. data/lib/sockjs/examples/protocol_conformance_test.rb +73 -0
  12. data/lib/sockjs/faye.rb +15 -0
  13. data/lib/sockjs/protocol.rb +97 -0
  14. data/lib/sockjs/servers/request.rb +136 -0
  15. data/lib/sockjs/servers/response.rb +169 -0
  16. data/lib/sockjs/session.rb +388 -0
  17. data/lib/sockjs/transport.rb +354 -0
  18. data/lib/sockjs/transports/eventsource.rb +30 -0
  19. data/lib/sockjs/transports/htmlfile.rb +69 -0
  20. data/lib/sockjs/transports/iframe.rb +68 -0
  21. data/lib/sockjs/transports/info.rb +48 -0
  22. data/lib/sockjs/transports/jsonp.rb +84 -0
  23. data/lib/sockjs/transports/websocket.rb +166 -0
  24. data/lib/sockjs/transports/welcome_screen.rb +17 -0
  25. data/lib/sockjs/transports/xhr.rb +75 -0
  26. data/lib/sockjs/version.rb +13 -0
  27. data/spec/sockjs/protocol_spec.rb +49 -0
  28. data/spec/sockjs/session_spec.rb +51 -0
  29. data/spec/sockjs/transport_spec.rb +73 -0
  30. data/spec/sockjs/transports/eventsource_spec.rb +56 -0
  31. data/spec/sockjs/transports/htmlfile_spec.rb +72 -0
  32. data/spec/sockjs/transports/iframe_spec.rb +66 -0
  33. data/spec/sockjs/transports/jsonp_spec.rb +252 -0
  34. data/spec/sockjs/transports/websocket_spec.rb +101 -0
  35. data/spec/sockjs/transports/welcome_screen_spec.rb +36 -0
  36. data/spec/sockjs/transports/xhr_spec.rb +314 -0
  37. data/spec/sockjs/version_spec.rb +18 -0
  38. data/spec/sockjs_spec.rb +8 -0
  39. data/spec/spec_helper.rb +121 -0
  40. data/spec/support/async-test.rb +42 -0
  41. 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