faye-websocket 0.4.7 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

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