sockjs 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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