faye-websocket 0.4.6 → 0.4.7
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.
Potentially problematic release.
This version of faye-websocket might be problematic. Click here for more details.
- data/CHANGELOG.txt +7 -0
- data/README.rdoc +24 -24
- data/examples/app.rb +10 -10
- data/examples/autobahn_client.rb +16 -11
- data/examples/client.rb +4 -4
- data/examples/config.ru +3 -3
- data/examples/sse.html +8 -8
- data/examples/ws.html +8 -8
- data/ext/faye_websocket_mask/FayeWebsocketMaskService.java +7 -7
- data/ext/faye_websocket_mask/faye_websocket_mask.c +2 -2
- data/lib/faye/adapters/goliath.rb +5 -5
- data/lib/faye/adapters/rainbows.rb +3 -3
- data/lib/faye/adapters/rainbows_client.rb +12 -12
- data/lib/faye/adapters/thin.rb +10 -9
- data/lib/faye/eventsource.rb +26 -26
- data/lib/faye/websocket.rb +40 -40
- data/lib/faye/websocket/adapter.rb +5 -5
- data/lib/faye/websocket/api.rb +28 -25
- data/lib/faye/websocket/api/event.rb +7 -7
- data/lib/faye/websocket/api/event_target.rb +8 -8
- data/lib/faye/websocket/client.rb +18 -18
- data/lib/faye/websocket/draft75_parser.rb +13 -13
- data/lib/faye/websocket/draft76_parser.rb +17 -17
- data/lib/faye/websocket/hybi_parser.rb +4 -4
- data/lib/faye/websocket/utf8_match.rb +2 -2
- data/spec/faye/websocket/client_spec.rb +32 -49
- data/spec/faye/websocket/draft75_parser_examples.rb +7 -7
- data/spec/faye/websocket/draft75_parser_spec.rb +4 -4
- data/spec/faye/websocket/draft76_parser_spec.rb +5 -5
- data/spec/spec_helper.rb +4 -4
- metadata +22 -6
data/CHANGELOG.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
=== 0.4.7 / 2013-02-14
|
2
|
+
|
3
|
+
* Emit the 'close' event if TCP is closed before CLOSE frame is acked
|
4
|
+
* Treat the 'Upgrade: websocket' header case-insensitively because of IE10
|
5
|
+
* Don't suppress headers in the Thin and Rainbows adapters unless the status is 101
|
6
|
+
|
7
|
+
|
1
8
|
=== 0.4.6 / 2012-07-09
|
2
9
|
|
3
10
|
* Add 'Connection: close' to EventSource response
|
data/README.rdoc
CHANGED
@@ -40,23 +40,23 @@ and sending messages. For example this is how you'd implement an echo server:
|
|
40
40
|
|
41
41
|
# app.rb
|
42
42
|
require 'faye/websocket'
|
43
|
-
|
43
|
+
|
44
44
|
App = lambda do |env|
|
45
45
|
if Faye::WebSocket.websocket?(env)
|
46
46
|
ws = Faye::WebSocket.new(env)
|
47
|
-
|
47
|
+
|
48
48
|
ws.onmessage = lambda do |event|
|
49
49
|
ws.send(event.data)
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
ws.onclose = lambda do |event|
|
53
53
|
p [:close, event.code, event.reason]
|
54
54
|
ws = nil
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
# Return async Rack response
|
58
58
|
ws.rack_response
|
59
|
-
|
59
|
+
|
60
60
|
else
|
61
61
|
# Normal HTTP request
|
62
62
|
[200, {'Content-Type' => 'text/plain'}, ['Hello']]
|
@@ -104,19 +104,19 @@ browser. On the wire it identifies itself as hybi-13.
|
|
104
104
|
|
105
105
|
require 'faye/websocket'
|
106
106
|
require 'eventmachine'
|
107
|
-
|
107
|
+
|
108
108
|
EM.run {
|
109
109
|
ws = Faye::WebSocket::Client.new('ws://www.example.com/')
|
110
|
-
|
110
|
+
|
111
111
|
ws.onopen = lambda do |event|
|
112
112
|
p [:open]
|
113
113
|
ws.send('Hello, world!')
|
114
114
|
end
|
115
|
-
|
115
|
+
|
116
116
|
ws.onmessage = lambda do |event|
|
117
117
|
p [:message, event.data]
|
118
118
|
end
|
119
|
-
|
119
|
+
|
120
120
|
ws.onclose = lambda do |event|
|
121
121
|
p [:close, event.code, event.reason]
|
122
122
|
ws = nil
|
@@ -178,23 +178,23 @@ message has an optional event-type and ID.
|
|
178
178
|
|
179
179
|
# app.rb
|
180
180
|
require 'faye/websocket'
|
181
|
-
|
181
|
+
|
182
182
|
App = lambda do |env|
|
183
183
|
if Faye::EventSource.eventsource?(env)
|
184
184
|
es = Faye::EventSource.new(env)
|
185
185
|
p [:open, es.url, es.last_event_id]
|
186
|
-
|
186
|
+
|
187
187
|
# Periodically send messages
|
188
188
|
loop = EM.add_periodic_timer(1) { es.send('Hello') }
|
189
|
-
|
189
|
+
|
190
190
|
es.onclose = lambda do |event|
|
191
191
|
EM.cancel_timer(loop)
|
192
192
|
es = nil
|
193
193
|
end
|
194
|
-
|
194
|
+
|
195
195
|
# Return async Rack response
|
196
196
|
es.rack_response
|
197
|
-
|
197
|
+
|
198
198
|
else
|
199
199
|
# Normal HTTP request
|
200
200
|
[200, {'Content-Type' => 'text/plain'}, ['Hello']]
|
@@ -260,10 +260,10 @@ further in a block passed to +run+:
|
|
260
260
|
require 'rack'
|
261
261
|
require 'thin'
|
262
262
|
require './app'
|
263
|
-
|
263
|
+
|
264
264
|
EM.run {
|
265
265
|
thin = Rack::Handler.get('thin')
|
266
|
-
|
266
|
+
|
267
267
|
thin.run(App, :Port => 9292) do |server|
|
268
268
|
# You can set options on the server here, for example to set up SSL:
|
269
269
|
server.ssl_options = {
|
@@ -296,15 +296,15 @@ Rainbows also has a Ruby API for starting a server:
|
|
296
296
|
|
297
297
|
require 'rainbows'
|
298
298
|
require './app'
|
299
|
-
|
299
|
+
|
300
300
|
rackup = Unicorn::Configurator::RACKUP
|
301
301
|
rackup[:port] = 9292
|
302
302
|
rackup[:set_listener] = true
|
303
303
|
options = rackup[:options]
|
304
304
|
options[:config_file] = 'path/to/rainbows.conf'
|
305
|
-
|
305
|
+
|
306
306
|
server = Rainbows::HttpServer.new(App, options)
|
307
|
-
|
307
|
+
|
308
308
|
# This is non-blocking; use server.start.join to block
|
309
309
|
server.start
|
310
310
|
|
@@ -316,7 +316,7 @@ Goliath can be made to run arbitrary Rack apps by delegating to them from a
|
|
316
316
|
|
317
317
|
require 'goliath'
|
318
318
|
require './app'
|
319
|
-
|
319
|
+
|
320
320
|
class EchoServer < Goliath::API
|
321
321
|
def response(env)
|
322
322
|
App.call(env)
|
@@ -327,15 +327,15 @@ Goliath can be made to run arbitrary Rack apps by delegating to them from a
|
|
327
327
|
|
328
328
|
require 'goliath'
|
329
329
|
require 'faye/websocket'
|
330
|
-
|
330
|
+
|
331
331
|
class EchoServer < Goliath::API
|
332
332
|
def response(env)
|
333
333
|
ws = Faye::WebSocket.new(env)
|
334
|
-
|
334
|
+
|
335
335
|
ws.onmessage = lambda do |event|
|
336
336
|
ws.send(event.data)
|
337
337
|
end
|
338
|
-
|
338
|
+
|
339
339
|
ws.rack_response
|
340
340
|
end
|
341
341
|
end
|
@@ -345,7 +345,7 @@ Goliath can be made to run arbitrary Rack apps by delegating to them from a
|
|
345
345
|
|
346
346
|
(The MIT License)
|
347
347
|
|
348
|
-
Copyright (c) 2009-
|
348
|
+
Copyright (c) 2009-2013 James Coglan
|
349
349
|
|
350
350
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
351
351
|
this software and associated documentation files (the 'Software'), to deal in
|
data/examples/app.rb
CHANGED
@@ -7,24 +7,24 @@ App = lambda do |env|
|
|
7
7
|
if Faye::WebSocket.websocket?(env)
|
8
8
|
ws = Faye::WebSocket.new(env, ['irc', 'xmpp'], :ping => 5)
|
9
9
|
p [:open, ws.url, ws.version, ws.protocol]
|
10
|
-
|
10
|
+
|
11
11
|
ws.onmessage = lambda do |event|
|
12
12
|
ws.send(event.data)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
ws.onclose = lambda do |event|
|
16
16
|
p [:close, event.code, event.reason]
|
17
17
|
ws = nil
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
ws.rack_response
|
21
|
-
|
21
|
+
|
22
22
|
elsif Faye::EventSource.eventsource?(env)
|
23
23
|
es = Faye::EventSource.new(env)
|
24
24
|
time = es.last_event_id.to_i
|
25
|
-
|
25
|
+
|
26
26
|
p [:open, es.url, es.last_event_id]
|
27
|
-
|
27
|
+
|
28
28
|
loop = EM.add_periodic_timer(2) do
|
29
29
|
time += 1
|
30
30
|
es.send("Time: #{time}")
|
@@ -32,17 +32,17 @@ App = lambda do |env|
|
|
32
32
|
es.send('Update!!', :event => 'update', :id => time) if es
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
es.send("Welcome!\n\nThis is an EventSource server.")
|
37
|
-
|
37
|
+
|
38
38
|
es.onclose = lambda do |event|
|
39
39
|
EM.cancel_timer(loop)
|
40
40
|
p [:close, es.url]
|
41
41
|
es = nil
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
es.rack_response
|
45
|
-
|
45
|
+
|
46
46
|
else
|
47
47
|
static.call(env)
|
48
48
|
end
|
data/examples/autobahn_client.rb
CHANGED
@@ -1,43 +1,48 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require File.expand_path('../../lib/faye/websocket', __FILE__)
|
3
3
|
require 'cgi'
|
4
|
+
require 'progressbar'
|
4
5
|
|
5
6
|
EM.run {
|
6
7
|
host = 'ws://localhost:9001'
|
7
|
-
agent = "
|
8
|
+
agent = "Ruby #{RUBY_VERSION}"
|
8
9
|
cases = 0
|
9
10
|
skip = []
|
10
|
-
|
11
|
-
socket
|
12
|
-
|
11
|
+
|
12
|
+
socket = Faye::WebSocket::Client.new("#{host}/getCaseCount")
|
13
|
+
progress = nil
|
14
|
+
|
13
15
|
socket.onmessage = lambda do |event|
|
14
16
|
puts "Total cases to run: #{event.data}"
|
15
17
|
cases = event.data.to_i
|
18
|
+
progress = ProgressBar.new('Autobahn', cases)
|
16
19
|
end
|
17
|
-
|
20
|
+
|
18
21
|
socket.onclose = lambda do |event|
|
19
22
|
run_case = lambda do |n|
|
23
|
+
progress.inc
|
24
|
+
|
20
25
|
if n > cases
|
21
26
|
socket = Faye::WebSocket::Client.new("#{host}/updateReports?agent=#{CGI.escape agent}")
|
27
|
+
progress.finish
|
22
28
|
socket.onclose = lambda { |e| EM.stop }
|
23
|
-
|
29
|
+
|
24
30
|
elsif skip.include?(n)
|
25
31
|
EM.next_tick { run_case.call(n+1) }
|
26
|
-
|
32
|
+
|
27
33
|
else
|
28
|
-
puts "Running test case ##{n} ..."
|
29
34
|
socket = Faye::WebSocket::Client.new("#{host}/runCase?case=#{n}&agent=#{CGI.escape agent}")
|
30
|
-
|
35
|
+
|
31
36
|
socket.onmessage = lambda do |event|
|
32
37
|
socket.send(event.data)
|
33
38
|
end
|
34
|
-
|
39
|
+
|
35
40
|
socket.onclose = lambda do |event|
|
36
41
|
run_case.call(n + 1)
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
40
|
-
|
45
|
+
|
41
46
|
run_case.call(1)
|
42
47
|
end
|
43
48
|
}
|
data/examples/client.rb
CHANGED
@@ -9,19 +9,19 @@ EM.run {
|
|
9
9
|
scheme = secure ? 'wss' : 'ws'
|
10
10
|
url = "#{scheme}://localhost:#{port}/"
|
11
11
|
socket = Faye::WebSocket::Client.new(url)
|
12
|
-
|
12
|
+
|
13
13
|
puts "Connecting to #{socket.url}"
|
14
|
-
|
14
|
+
|
15
15
|
socket.onopen = lambda do |event|
|
16
16
|
p [:open]
|
17
17
|
socket.send("Hello, WebSocket!")
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
socket.onmessage = lambda do |event|
|
21
21
|
p [:message, event.data]
|
22
22
|
# socket.close 1002, 'Going away'
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
socket.onclose = lambda do |event|
|
26
26
|
p [:close, event.code, event.reason]
|
27
27
|
EM.stop
|
data/examples/config.ru
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# Run using your favourite async server:
|
2
|
-
#
|
2
|
+
#
|
3
3
|
# thin start -R examples/config.ru -p 7000
|
4
4
|
# rainbows -c spec/rainbows.conf -E production examples/config.ru -p 7000
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# If you run using one of these commands, the webserver is loaded before this
|
7
7
|
# file, so Faye::WebSocket can figure out which adapter to load. If instead you
|
8
8
|
# run using `rackup`, you need the `load_adapter` line below.
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# rackup -E production -s thin examples/config.ru -p 7000
|
11
11
|
|
12
12
|
require 'rubygems'
|
data/examples/sse.html
CHANGED
@@ -5,35 +5,35 @@
|
|
5
5
|
<title>EventSource test</title>
|
6
6
|
</head>
|
7
7
|
<body>
|
8
|
-
|
8
|
+
|
9
9
|
<h1>EventSource test</h1>
|
10
10
|
<ul></ul>
|
11
|
-
|
11
|
+
|
12
12
|
<script type="text/javascript">
|
13
13
|
var logger = document.getElementsByTagName('ul')[0],
|
14
14
|
socket = new EventSource('/');
|
15
|
-
|
15
|
+
|
16
16
|
var log = function(text) {
|
17
17
|
logger.innerHTML += '<li>' + text + '</li>';
|
18
18
|
};
|
19
|
-
|
19
|
+
|
20
20
|
socket.onopen = function() {
|
21
21
|
log('OPEN');
|
22
22
|
};
|
23
|
-
|
23
|
+
|
24
24
|
socket.onmessage = function(event) {
|
25
25
|
log('MESSAGE: ' + event.data);
|
26
26
|
};
|
27
|
-
|
27
|
+
|
28
28
|
socket.addEventListener('update', function(event) {
|
29
29
|
log('UPDATE(' + event.lastEventId + '): ' + event.data);
|
30
30
|
});
|
31
|
-
|
31
|
+
|
32
32
|
socket.onerror = function(event) {
|
33
33
|
log('ERROR: ' + event.message);
|
34
34
|
};
|
35
35
|
</script>
|
36
|
-
|
36
|
+
|
37
37
|
</body>
|
38
38
|
</html>
|
39
39
|
|
data/examples/ws.html
CHANGED
@@ -5,40 +5,40 @@
|
|
5
5
|
<title>WebSocket test</title>
|
6
6
|
</head>
|
7
7
|
<body>
|
8
|
-
|
8
|
+
|
9
9
|
<h1>WebSocket test</h1>
|
10
10
|
<ul></ul>
|
11
|
-
|
11
|
+
|
12
12
|
<script type="text/javascript">
|
13
13
|
var logger = document.getElementsByTagName('ul')[0],
|
14
14
|
Socket = window.MozWebSocket || window.WebSocket,
|
15
15
|
protos = ['foo', 'bar', 'xmpp'],
|
16
16
|
socket = new Socket('ws://' + location.hostname + ':' + location.port + '/', protos),
|
17
17
|
index = 0;
|
18
|
-
|
18
|
+
|
19
19
|
var log = function(text) {
|
20
20
|
logger.innerHTML += '<li>' + text + '</li>';
|
21
21
|
};
|
22
|
-
|
22
|
+
|
23
23
|
socket.addEventListener('open', function() {
|
24
24
|
log('OPEN: ' + socket.protocol);
|
25
25
|
socket.send('Hello, world');
|
26
26
|
});
|
27
|
-
|
27
|
+
|
28
28
|
socket.onerror = function(event) {
|
29
29
|
log('ERROR: ' + event.message);
|
30
30
|
};
|
31
|
-
|
31
|
+
|
32
32
|
socket.onmessage = function(event) {
|
33
33
|
log('MESSAGE: ' + event.data);
|
34
34
|
setTimeout(function() { socket.send(++index + ' ' + event.data) }, 2000);
|
35
35
|
};
|
36
|
-
|
36
|
+
|
37
37
|
socket.onclose = function(event) {
|
38
38
|
log('CLOSE: ' + event.code + ', ' + event.reason);
|
39
39
|
};
|
40
40
|
</script>
|
41
|
-
|
41
|
+
|
42
42
|
</body>
|
43
43
|
</html>
|
44
44
|
|
@@ -17,39 +17,39 @@ import org.jruby.runtime.load.BasicLibraryService;
|
|
17
17
|
|
18
18
|
public class FayeWebsocketMaskService implements BasicLibraryService {
|
19
19
|
private Ruby runtime;
|
20
|
-
|
20
|
+
|
21
21
|
public boolean basicLoad(Ruby runtime) throws IOException {
|
22
22
|
this.runtime = runtime;
|
23
23
|
RubyModule faye = runtime.defineModule("Faye");
|
24
|
-
|
24
|
+
|
25
25
|
RubyClass webSocketMask = faye.defineClassUnder("WebSocketMask", runtime.getObject(), new ObjectAllocator() {
|
26
26
|
public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
|
27
27
|
return new WebsocketMask(runtime, rubyClass);
|
28
28
|
}
|
29
29
|
});
|
30
|
-
|
30
|
+
|
31
31
|
webSocketMask.defineAnnotatedMethods(WebsocketMask.class);
|
32
32
|
return true;
|
33
33
|
}
|
34
|
-
|
34
|
+
|
35
35
|
public class WebsocketMask extends RubyObject {
|
36
36
|
public WebsocketMask(final Ruby runtime, RubyClass rubyClass) {
|
37
37
|
super(runtime, rubyClass);
|
38
38
|
}
|
39
|
-
|
39
|
+
|
40
40
|
@JRubyMethod
|
41
41
|
public IRubyObject mask(ThreadContext context, IRubyObject payload, IRubyObject mask) {
|
42
42
|
int n = ((RubyArray)payload).getLength(), i;
|
43
43
|
long p, m;
|
44
44
|
RubyArray unmasked = RubyArray.newArray(runtime, n);
|
45
|
-
|
45
|
+
|
46
46
|
long[] maskArray = {
|
47
47
|
(Long)((RubyArray)mask).get(0),
|
48
48
|
(Long)((RubyArray)mask).get(1),
|
49
49
|
(Long)((RubyArray)mask).get(2),
|
50
50
|
(Long)((RubyArray)mask).get(3)
|
51
51
|
};
|
52
|
-
|
52
|
+
|
53
53
|
for (i = 0; i < n; i++) {
|
54
54
|
p = (Long)((RubyArray)payload).get(i);
|
55
55
|
m = maskArray[i % 4];
|