faye-websocket 0.4.7 → 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.

Potentially problematic release.


This version of faye-websocket might be problematic. Click here for more details.

Files changed (38) hide show
  1. data/CHANGELOG.md +81 -0
  2. data/README.md +408 -0
  3. data/examples/app.rb +4 -1
  4. data/examples/autobahn_client.rb +8 -6
  5. data/examples/client.rb +2 -1
  6. data/examples/config.ru +6 -9
  7. data/{spec → examples}/rainbows.conf +0 -0
  8. data/examples/server.rb +10 -1
  9. data/lib/faye/adapters/rainbows.rb +15 -16
  10. data/lib/faye/adapters/rainbows_client.rb +15 -16
  11. data/lib/faye/adapters/thin.rb +15 -16
  12. data/lib/faye/eventsource.rb +38 -46
  13. data/lib/faye/rack_stream.rb +70 -0
  14. data/lib/faye/websocket.rb +39 -162
  15. data/lib/faye/websocket/api.rb +70 -60
  16. data/lib/faye/websocket/api/event.rb +1 -1
  17. data/lib/faye/websocket/api/event_target.rb +35 -12
  18. data/lib/faye/websocket/client.rb +5 -38
  19. metadata +62 -45
  20. data/CHANGELOG.txt +0 -74
  21. data/README.rdoc +0 -366
  22. data/ext/faye_websocket_mask/FayeWebsocketMaskService.java +0 -61
  23. data/ext/faye_websocket_mask/extconf.rb +0 -5
  24. data/ext/faye_websocket_mask/faye_websocket_mask.c +0 -33
  25. data/lib/faye/websocket/draft75_parser.rb +0 -87
  26. data/lib/faye/websocket/draft76_parser.rb +0 -84
  27. data/lib/faye/websocket/hybi_parser.rb +0 -321
  28. data/lib/faye/websocket/hybi_parser/handshake.rb +0 -78
  29. data/lib/faye/websocket/hybi_parser/stream_reader.rb +0 -29
  30. data/lib/faye/websocket/utf8_match.rb +0 -8
  31. data/spec/faye/websocket/client_spec.rb +0 -162
  32. data/spec/faye/websocket/draft75_parser_examples.rb +0 -48
  33. data/spec/faye/websocket/draft75_parser_spec.rb +0 -27
  34. data/spec/faye/websocket/draft76_parser_spec.rb +0 -34
  35. data/spec/faye/websocket/hybi_parser_spec.rb +0 -149
  36. data/spec/server.crt +0 -15
  37. data/spec/server.key +0 -15
  38. data/spec/spec_helper.rb +0 -68
@@ -1,61 +0,0 @@
1
- package com.jcoglan.faye;
2
-
3
- import java.lang.Long;
4
- import java.io.IOException;
5
-
6
- import org.jruby.Ruby;
7
- import org.jruby.RubyArray;
8
- import org.jruby.RubyClass;
9
- import org.jruby.RubyFixnum;
10
- import org.jruby.RubyModule;
11
- import org.jruby.RubyObject;
12
- import org.jruby.anno.JRubyMethod;
13
- import org.jruby.runtime.ObjectAllocator;
14
- import org.jruby.runtime.ThreadContext;
15
- import org.jruby.runtime.builtin.IRubyObject;
16
- import org.jruby.runtime.load.BasicLibraryService;
17
-
18
- public class FayeWebsocketMaskService implements BasicLibraryService {
19
- private Ruby runtime;
20
-
21
- public boolean basicLoad(Ruby runtime) throws IOException {
22
- this.runtime = runtime;
23
- RubyModule faye = runtime.defineModule("Faye");
24
-
25
- RubyClass webSocketMask = faye.defineClassUnder("WebSocketMask", runtime.getObject(), new ObjectAllocator() {
26
- public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
27
- return new WebsocketMask(runtime, rubyClass);
28
- }
29
- });
30
-
31
- webSocketMask.defineAnnotatedMethods(WebsocketMask.class);
32
- return true;
33
- }
34
-
35
- public class WebsocketMask extends RubyObject {
36
- public WebsocketMask(final Ruby runtime, RubyClass rubyClass) {
37
- super(runtime, rubyClass);
38
- }
39
-
40
- @JRubyMethod
41
- public IRubyObject mask(ThreadContext context, IRubyObject payload, IRubyObject mask) {
42
- int n = ((RubyArray)payload).getLength(), i;
43
- long p, m;
44
- RubyArray unmasked = RubyArray.newArray(runtime, n);
45
-
46
- long[] maskArray = {
47
- (Long)((RubyArray)mask).get(0),
48
- (Long)((RubyArray)mask).get(1),
49
- (Long)((RubyArray)mask).get(2),
50
- (Long)((RubyArray)mask).get(3)
51
- };
52
-
53
- for (i = 0; i < n; i++) {
54
- p = (Long)((RubyArray)payload).get(i);
55
- m = maskArray[i % 4];
56
- unmasked.set(i, p ^ m);
57
- }
58
- return unmasked;
59
- }
60
- }
61
- }
@@ -1,5 +0,0 @@
1
- require 'mkmf'
2
- extension_name = 'faye_websocket_mask'
3
- dir_config(extension_name)
4
- create_makefile(extension_name)
5
-
@@ -1,33 +0,0 @@
1
- #include <ruby.h>
2
-
3
- VALUE Faye = Qnil;
4
- VALUE FayeWebSocketMask = Qnil;
5
-
6
- void Init_faye_websocket_mask();
7
- VALUE method_faye_websocket_mask(VALUE self, VALUE payload, VALUE mask);
8
-
9
- void Init_faye_websocket_mask() {
10
- Faye = rb_define_module("Faye");
11
- FayeWebSocketMask = rb_define_module_under(Faye, "WebSocketMask");
12
- rb_define_singleton_method(FayeWebSocketMask, "mask", method_faye_websocket_mask, 2);
13
- }
14
-
15
- VALUE method_faye_websocket_mask(VALUE self, VALUE payload, VALUE mask) {
16
- int n = RARRAY_LEN(payload), i, p, m;
17
- VALUE unmasked = rb_ary_new2(n);
18
-
19
- int mask_array[] = {
20
- NUM2INT(rb_ary_entry(mask, 0)),
21
- NUM2INT(rb_ary_entry(mask, 1)),
22
- NUM2INT(rb_ary_entry(mask, 2)),
23
- NUM2INT(rb_ary_entry(mask, 3))
24
- };
25
-
26
- for (i = 0; i < n; i++) {
27
- p = NUM2INT(rb_ary_entry(payload, i));
28
- m = mask_array[i % 4];
29
- rb_ary_store(unmasked, i, INT2NUM(p ^ m));
30
- }
31
- return unmasked;
32
- }
33
-
@@ -1,87 +0,0 @@
1
- module Faye
2
- class WebSocket
3
-
4
- class Draft75Parser
5
- attr_reader :protocol
6
-
7
- def initialize(web_socket, options = {})
8
- @socket = web_socket
9
- @stage = 0
10
- end
11
-
12
- def version
13
- 'hixie-75'
14
- end
15
-
16
- def handshake_response
17
- upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
18
- upgrade << "Upgrade: WebSocket\r\n"
19
- upgrade << "Connection: Upgrade\r\n"
20
- upgrade << "WebSocket-Origin: #{@socket.env['HTTP_ORIGIN']}\r\n"
21
- upgrade << "WebSocket-Location: #{@socket.url}\r\n"
22
- upgrade << "\r\n"
23
- upgrade
24
- end
25
-
26
- def open?
27
- true
28
- end
29
-
30
- def parse(buffer)
31
- buffer.each_byte do |data|
32
- case @stage
33
- when 0 then
34
- parse_leading_byte(data)
35
-
36
- when 1 then
37
- value = (data & 0x7F)
38
- @length = value + 128 * @length
39
-
40
- if @closing and @length.zero?
41
- @socket.close(nil, nil, false)
42
- elsif (0x80 & data) != 0x80
43
- if @length.zero?
44
- @socket.receive('')
45
- @stage = 0
46
- else
47
- @buffer = []
48
- @stage = 2
49
- end
50
- end
51
-
52
- when 2 then
53
- if data == 0xFF
54
- @socket.receive(WebSocket.encode(@buffer))
55
- @stage = 0
56
- else
57
- @buffer << data
58
- if @length and @buffer.size == @length
59
- @stage = 0
60
- end
61
- end
62
- end
63
- end
64
-
65
- nil
66
- end
67
-
68
- def parse_leading_byte(data)
69
- if (0x80 & data) == 0x80
70
- @length = 0
71
- @stage = 1
72
- else
73
- @length = nil
74
- @buffer = []
75
- @stage = 2
76
- end
77
- end
78
-
79
- def frame(data, type = nil, error_type = nil)
80
- return WebSocket.encode(data) if Array === data
81
- ["\x00", data, "\xFF"].map(&WebSocket.method(:encode)) * ''
82
- end
83
- end
84
-
85
- end
86
- end
87
-
@@ -1,84 +0,0 @@
1
- module Faye
2
- class WebSocket
3
-
4
- class Draft76Parser < Draft75Parser
5
- def version
6
- 'hixie-76'
7
- end
8
-
9
- def handshake_response
10
- env = @socket.env
11
- signature = handshake_signature(env['rack.input'].read)
12
-
13
- upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
14
- upgrade << "Upgrade: WebSocket\r\n"
15
- upgrade << "Connection: Upgrade\r\n"
16
- upgrade << "Sec-WebSocket-Origin: #{env['HTTP_ORIGIN']}\r\n"
17
- upgrade << "Sec-WebSocket-Location: #{@socket.url}\r\n"
18
- upgrade << "\r\n"
19
- upgrade << signature if signature
20
- upgrade
21
- end
22
-
23
- def handshake_signature(head)
24
- return nil if head.empty?
25
- env = @socket.env
26
-
27
- key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
28
- value1 = number_from_key(key1) / spaces_in_key(key1)
29
-
30
- key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
31
- value2 = number_from_key(key2) / spaces_in_key(key2)
32
-
33
- @handshake_complete = true
34
-
35
- Digest::MD5.digest(big_endian(value1) +
36
- big_endian(value2) +
37
- head)
38
- end
39
-
40
- def open?
41
- !!@handshake_complete
42
- end
43
-
44
- def parse(data)
45
- return super if @handshake_complete
46
- handshake_signature(data)
47
- end
48
-
49
- def close(code = nil, reason = nil, &callback)
50
- return if @closed
51
- @socket.send([0xFF, 0x00]) if @closing
52
- @closed = true
53
- callback.call if callback
54
- end
55
-
56
- private
57
-
58
- def parse_leading_byte(data)
59
- return super unless data == 0xFF
60
- @closing = true
61
- @length = 0
62
- @stage = 1
63
- end
64
-
65
- def number_from_key(key)
66
- key.scan(/[0-9]/).join('').to_i(10)
67
- end
68
-
69
- def spaces_in_key(key)
70
- key.scan(/ /).size
71
- end
72
-
73
- def big_endian(number)
74
- string = ''
75
- [24,16,8,0].each do |offset|
76
- string << (number >> offset & 0xFF).chr
77
- end
78
- string
79
- end
80
- end
81
-
82
- end
83
- end
84
-
@@ -1,321 +0,0 @@
1
- module Faye
2
- class WebSocket
3
-
4
- class HybiParser
5
- root = File.expand_path('../hybi_parser', __FILE__)
6
- autoload :Handshake, root + '/handshake'
7
- autoload :StreamReader, root + '/stream_reader'
8
-
9
- BYTE = 0b11111111
10
- FIN = MASK = 0b10000000
11
- RSV1 = 0b01000000
12
- RSV2 = 0b00100000
13
- RSV3 = 0b00010000
14
- OPCODE = 0b00001111
15
- LENGTH = 0b01111111
16
-
17
- OPCODES = {
18
- :continuation => 0,
19
- :text => 1,
20
- :binary => 2,
21
- :close => 8,
22
- :ping => 9,
23
- :pong => 10
24
- }
25
-
26
- FRAGMENTED_OPCODES = OPCODES.values_at(:continuation, :text, :binary)
27
- OPENING_OPCODES = OPCODES.values_at(:text, :binary)
28
-
29
- ERRORS = {
30
- :normal_closure => 1000,
31
- :going_away => 1001,
32
- :protocol_error => 1002,
33
- :unacceptable => 1003,
34
- :encoding_error => 1007,
35
- :policy_violation => 1008,
36
- :too_large => 1009,
37
- :extension_error => 1010,
38
- :unexpected_condition => 1011
39
- }
40
-
41
- ERROR_CODES = ERRORS.values
42
-
43
- attr_reader :protocol
44
-
45
- def initialize(web_socket, options = {})
46
- reset
47
- @socket = web_socket
48
- @reader = StreamReader.new
49
- @stage = 0
50
- @masking = options[:masking]
51
- @protocols = options[:protocols]
52
- @protocols = @protocols.split(/\s*,\s*/) if String === @protocols
53
-
54
- @ping_callbacks = {}
55
- end
56
-
57
- def version
58
- "hybi-#{@socket.env['HTTP_SEC_WEBSOCKET_VERSION']}"
59
- end
60
-
61
- def handshake_response
62
- sec_key = @socket.env['HTTP_SEC_WEBSOCKET_KEY']
63
- return '' unless String === sec_key
64
-
65
- accept = Base64.encode64(Digest::SHA1.digest(sec_key + Handshake::GUID)).strip
66
- protos = @socket.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
67
- supported = @protocols
68
- proto = nil
69
-
70
- headers = [
71
- "HTTP/1.1 101 Switching Protocols",
72
- "Upgrade: websocket",
73
- "Connection: Upgrade",
74
- "Sec-WebSocket-Accept: #{accept}"
75
- ]
76
-
77
- if protos and supported
78
- protos = protos.split(/\s*,\s*/) if String === protos
79
- proto = protos.find { |p| supported.include?(p) }
80
- if proto
81
- @protocol = proto
82
- headers << "Sec-WebSocket-Protocol: #{proto}"
83
- end
84
- end
85
-
86
- (headers + ['','']).join("\r\n")
87
- end
88
-
89
- def create_handshake
90
- Handshake.new(@socket.uri, @protocols)
91
- end
92
-
93
- def open?
94
- true
95
- end
96
-
97
- def parse(data)
98
- @reader.put(data.bytes.to_a)
99
- buffer = true
100
- while buffer
101
- case @stage
102
- when 0 then
103
- buffer = @reader.read(1)
104
- parse_opcode(buffer[0]) if buffer
105
-
106
- when 1 then
107
- buffer = @reader.read(1)
108
- parse_length(buffer[0]) if buffer
109
-
110
- when 2 then
111
- buffer = @reader.read(@length_size)
112
- parse_extended_length(buffer) if buffer
113
-
114
- when 3 then
115
- buffer = @reader.read(4)
116
- if buffer
117
- @mask = buffer
118
- @stage = 4
119
- end
120
-
121
- when 4 then
122
- buffer = @reader.read(@length)
123
- if buffer
124
- @payload = buffer
125
- emit_frame
126
- @stage = 0
127
- end
128
- end
129
- end
130
-
131
- nil
132
- end
133
-
134
- def frame(data, type = nil, code = nil)
135
- return nil if @closed
136
-
137
- is_text = (String === data)
138
- opcode = OPCODES[type || (is_text ? :text : :binary)]
139
- buffer = data.respond_to?(:bytes) ? data.bytes.to_a : data
140
- insert = code ? 2 : 0
141
- length = buffer.size + insert
142
- header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10)
143
- offset = header + (@masking ? 4 : 0)
144
- masked = @masking ? MASK : 0
145
- frame = Array.new(offset)
146
-
147
- frame[0] = FIN | opcode
148
-
149
- if length <= 125
150
- frame[1] = masked | length
151
- elsif length <= 65535
152
- frame[1] = masked | 126
153
- frame[2] = (length >> 8) & BYTE
154
- frame[3] = length & BYTE
155
- else
156
- frame[1] = masked | 127
157
- frame[2] = (length >> 56) & BYTE
158
- frame[3] = (length >> 48) & BYTE
159
- frame[4] = (length >> 40) & BYTE
160
- frame[5] = (length >> 32) & BYTE
161
- frame[6] = (length >> 24) & BYTE
162
- frame[7] = (length >> 16) & BYTE
163
- frame[8] = (length >> 8) & BYTE
164
- frame[9] = length & BYTE
165
- end
166
-
167
- if code
168
- buffer = [(code >> 8) & BYTE, code & BYTE] + buffer
169
- end
170
-
171
- if @masking
172
- mask = [rand(256), rand(256), rand(256), rand(256)]
173
- frame[header...offset] = mask
174
- buffer = WebSocketMask.mask(buffer, mask)
175
- end
176
-
177
- frame.concat(buffer)
178
-
179
- WebSocket.encode(frame)
180
- end
181
-
182
- def ping(message = '', &callback)
183
- @ping_callbacks[message] = callback if callback
184
- @socket.send(message, :ping)
185
- end
186
-
187
- def close(code = nil, reason = nil, &callback)
188
- return if @closed
189
- @closing_callback ||= callback
190
- @socket.send(reason || '', :close, code || ERRORS[:normal_closure])
191
- @closed = true
192
- end
193
-
194
- private
195
-
196
- def parse_opcode(data)
197
- if [RSV1, RSV2, RSV3].any? { |rsv| (data & rsv) == rsv }
198
- return @socket.close(ERRORS[:protocol_error], nil, false)
199
- end
200
-
201
- @final = (data & FIN) == FIN
202
- @opcode = (data & OPCODE)
203
- @mask = []
204
- @payload = []
205
-
206
- unless OPCODES.values.include?(@opcode)
207
- return @socket.close(ERRORS[:protocol_error], nil, false)
208
- end
209
-
210
- unless FRAGMENTED_OPCODES.include?(@opcode) or @final
211
- return @socket.close(ERRORS[:protocol_error], nil, false)
212
- end
213
-
214
- if @mode and OPENING_OPCODES.include?(@opcode)
215
- return @socket.close(ERRORS[:protocol_error], nil, false)
216
- end
217
-
218
- @stage = 1
219
- end
220
-
221
- def parse_length(data)
222
- @masked = (data & MASK) == MASK
223
- @length = (data & LENGTH)
224
-
225
- if @length <= 125
226
- @stage = @masked ? 3 : 4
227
- else
228
- @length_size = (@length == 126) ? 2 : 8
229
- @stage = 2
230
- end
231
- end
232
-
233
- def parse_extended_length(buffer)
234
- @length = integer(buffer)
235
- @stage = @masked ? 3 : 4
236
- end
237
-
238
- def emit_frame
239
- payload = @masked ? WebSocketMask.mask(@payload, @mask) : @payload
240
-
241
- case @opcode
242
- when OPCODES[:continuation] then
243
- return @socket.close(ERRORS[:protocol_error], nil, false) unless @mode
244
- @buffer.concat(payload)
245
- if @final
246
- message = @buffer
247
- message = WebSocket.encode(message, true) if @mode == :text
248
- reset
249
- if message
250
- @socket.receive(message)
251
- else
252
- @socket.close(ERRORS[:encoding_error], nil, false)
253
- end
254
- end
255
-
256
- when OPCODES[:text] then
257
- if @final
258
- message = WebSocket.encode(payload, true)
259
- if message
260
- @socket.receive(message)
261
- else
262
- @socket.close(ERRORS[:encoding_error], nil, false)
263
- end
264
- else
265
- @mode = :text
266
- @buffer.concat(payload)
267
- end
268
-
269
- when OPCODES[:binary] then
270
- if @final
271
- @socket.receive(payload)
272
- else
273
- @mode = :binary
274
- @buffer.concat(payload)
275
- end
276
-
277
- when OPCODES[:close] then
278
- code = (payload.size >= 2) ? 256 * payload[0] + payload[1] : nil
279
-
280
- unless (payload.size == 0) or
281
- (code && code >= 3000 && code < 5000) or
282
- ERROR_CODES.include?(code)
283
- code = ERRORS[:protocol_error]
284
- end
285
-
286
- if payload.size > 125 or not WebSocket.valid_utf8?(payload[2..-1] || [])
287
- code = ERRORS[:protocol_error]
288
- end
289
-
290
- reason = (payload.size > 2) ? WebSocket.encode(payload[2..-1], true) : nil
291
- @socket.close(code, reason, false)
292
- @closing_callback.call if @closing_callback
293
-
294
- when OPCODES[:ping] then
295
- return @socket.close(ERRORS[:protocol_error], nil, false) if payload.size > 125
296
- @socket.send(payload, :pong)
297
-
298
- when OPCODES[:pong] then
299
- message = WebSocket.encode(payload, true)
300
- callback = @ping_callbacks[message]
301
- @ping_callbacks.delete(message)
302
- callback.call if callback
303
- end
304
- end
305
-
306
- def reset
307
- @buffer = []
308
- @mode = nil
309
- end
310
-
311
- def integer(bytes)
312
- number = 0
313
- bytes.each_with_index do |data, i|
314
- number += data << (8 * (bytes.size - 1 - i))
315
- end
316
- number
317
- end
318
- end
319
-
320
- end
321
- end