sonixlabs-em-websocket 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG.rdoc +80 -0
  3. data/Gemfile +3 -0
  4. data/README.md +98 -0
  5. data/Rakefile +11 -0
  6. data/em-websocket.gemspec +27 -0
  7. data/examples/echo.rb +8 -0
  8. data/examples/flash_policy_file_server.rb +21 -0
  9. data/examples/js/FABridge.js +604 -0
  10. data/examples/js/WebSocketMain.swf +0 -0
  11. data/examples/js/swfobject.js +4 -0
  12. data/examples/js/web_socket.js +312 -0
  13. data/examples/multicast.rb +47 -0
  14. data/examples/test.html +30 -0
  15. data/lib/em-websocket/client_connection.rb +19 -0
  16. data/lib/em-websocket/close03.rb +11 -0
  17. data/lib/em-websocket/close05.rb +11 -0
  18. data/lib/em-websocket/close06.rb +16 -0
  19. data/lib/em-websocket/close75.rb +10 -0
  20. data/lib/em-websocket/connection.rb +184 -0
  21. data/lib/em-websocket/debugger.rb +17 -0
  22. data/lib/em-websocket/framing03.rb +167 -0
  23. data/lib/em-websocket/framing04.rb +15 -0
  24. data/lib/em-websocket/framing05.rb +168 -0
  25. data/lib/em-websocket/framing07.rb +180 -0
  26. data/lib/em-websocket/framing76.rb +114 -0
  27. data/lib/em-websocket/handler.rb +56 -0
  28. data/lib/em-websocket/handler03.rb +10 -0
  29. data/lib/em-websocket/handler05.rb +10 -0
  30. data/lib/em-websocket/handler06.rb +10 -0
  31. data/lib/em-websocket/handler07.rb +10 -0
  32. data/lib/em-websocket/handler08.rb +10 -0
  33. data/lib/em-websocket/handler13.rb +10 -0
  34. data/lib/em-websocket/handler75.rb +9 -0
  35. data/lib/em-websocket/handler76.rb +12 -0
  36. data/lib/em-websocket/handler_factory.rb +107 -0
  37. data/lib/em-websocket/handshake04.rb +75 -0
  38. data/lib/em-websocket/handshake75.rb +21 -0
  39. data/lib/em-websocket/handshake76.rb +71 -0
  40. data/lib/em-websocket/masking04.rb +63 -0
  41. data/lib/em-websocket/message_processor_03.rb +38 -0
  42. data/lib/em-websocket/message_processor_06.rb +52 -0
  43. data/lib/em-websocket/version.rb +5 -0
  44. data/lib/em-websocket/websocket.rb +45 -0
  45. data/lib/em-websocket.rb +23 -0
  46. data/lib/sonixlabs-em-websocket.rb +1 -0
  47. data/spec/helper.rb +146 -0
  48. data/spec/integration/client_examples.rb +48 -0
  49. data/spec/integration/common_spec.rb +118 -0
  50. data/spec/integration/draft03_spec.rb +270 -0
  51. data/spec/integration/draft05_spec.rb +48 -0
  52. data/spec/integration/draft06_spec.rb +88 -0
  53. data/spec/integration/draft13_spec.rb +75 -0
  54. data/spec/integration/draft75_spec.rb +117 -0
  55. data/spec/integration/draft76_spec.rb +230 -0
  56. data/spec/integration/shared_examples.rb +91 -0
  57. data/spec/unit/framing_spec.rb +325 -0
  58. data/spec/unit/handler_spec.rb +147 -0
  59. data/spec/unit/masking_spec.rb +27 -0
  60. data/spec/unit/message_processor_spec.rb +36 -0
  61. metadata +198 -0
@@ -0,0 +1,167 @@
1
+ # encoding: BINARY
2
+
3
+ module EventMachine
4
+ module WebSocket
5
+ module Framing03
6
+
7
+ # Set the max frame lenth to very high value (10MB) until there is a
8
+ # limit specified in the spec to protect against malicious attacks
9
+ MAXIMUM_FRAME_LENGTH = 10 * 1024 * 1024
10
+
11
+ def initialize_framing
12
+ @data = ''
13
+ @application_data_buffer = '' # Used for MORE frames
14
+ end
15
+
16
+ def process_data(newdata)
17
+ error = false
18
+
19
+ while !error && @data.size > 1
20
+ pointer = 0
21
+
22
+ more = ((@data.getbyte(pointer) & 0b10000000) == 0b10000000) ^ fin
23
+ # Ignoring rsv1-3 for now
24
+ opcode = @data.getbyte(0) & 0b00001111
25
+ pointer += 1
26
+
27
+ # Ignoring rsv4
28
+ length = @data.getbyte(pointer) & 0b01111111
29
+ pointer += 1
30
+
31
+ payload_length = case length
32
+ when 127 # Length defined by 8 bytes
33
+ # Check buffer size
34
+ if @data.getbyte(pointer+8-1) == nil
35
+ debug [:buffer_incomplete, @data]
36
+ error = true
37
+ next
38
+ end
39
+
40
+ # Only using the last 4 bytes for now, till I work out how to
41
+ # unpack 8 bytes. I'm sure 4GB frames will do for now :)
42
+ l = @data[(pointer+4)..(pointer+7)].unpack('N').first
43
+ pointer += 8
44
+ l
45
+ when 126 # Length defined by 2 bytes
46
+ # Check buffer size
47
+ if @data.getbyte(pointer+2-1) == nil
48
+ debug [:buffer_incomplete, @data]
49
+ error = true
50
+ next
51
+ end
52
+
53
+ l = @data[pointer..(pointer+1)].unpack('n').first
54
+ pointer += 2
55
+ l
56
+ else
57
+ length
58
+ end
59
+
60
+ # Addition to the spec to protect against malicious requests
61
+ if payload_length > MAXIMUM_FRAME_LENGTH
62
+ raise DataError, "Frame length too long (#{payload_length} bytes)"
63
+ end
64
+
65
+ # Check buffer size
66
+ if @data.getbyte(pointer+payload_length-1) == nil
67
+ debug [:buffer_incomplete, @data]
68
+ error = true
69
+ next
70
+ end
71
+
72
+ # Throw away data up to pointer
73
+ @data.slice!(0...pointer)
74
+
75
+ # Read application data
76
+ application_data = @data.slice!(0...payload_length)
77
+
78
+ frame_type = opcode_to_type(opcode)
79
+
80
+ if frame_type == :continuation && !@frame_type
81
+ raise WebSocketError, 'Continuation frame not expected'
82
+ end
83
+
84
+ if more
85
+ debug [:moreframe, frame_type, application_data]
86
+ @application_data_buffer << application_data
87
+ # The message type is passed in the first frame
88
+ @frame_type ||= frame_type
89
+ else
90
+ # Message is complete
91
+ if frame_type == :continuation
92
+ @application_data_buffer << application_data
93
+ message(@frame_type, '', @application_data_buffer)
94
+ @application_data_buffer = ''
95
+ @frame_type = nil
96
+ else
97
+ message(frame_type, '', application_data)
98
+ end
99
+ end
100
+ end # end while
101
+ end
102
+
103
+ def send_frame(frame_type, application_data)
104
+ debug [:sending_frame, frame_type, application_data]
105
+
106
+ if @state == :closing && data_frame?(frame_type)
107
+ raise WebSocketError, "Cannot send data frame since connection is closing"
108
+ end
109
+
110
+ frame = ''
111
+
112
+ opcode = type_to_opcode(frame_type)
113
+ byte1 = opcode # since more, rsv1-3 are 0
114
+ frame << byte1
115
+
116
+ length = application_data.size
117
+ if length <= 125
118
+ byte2 = length # since rsv4 is 0
119
+ frame << byte2
120
+ elsif length < 65536 # write 2 byte length
121
+ frame << 126
122
+ frame << [length].pack('n')
123
+ else # write 8 byte length
124
+ frame << 127
125
+ frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
126
+ end
127
+
128
+ frame << application_data
129
+
130
+ @connection.send_data(frame)
131
+ end
132
+
133
+ def send_text_frame(data)
134
+ send_frame(:text, data)
135
+ end
136
+
137
+ private
138
+
139
+ # This allows flipping the more bit to fin for draft 04
140
+ def fin; false; end
141
+
142
+ FRAME_TYPES = {
143
+ :continuation => 0,
144
+ :close => 1,
145
+ :ping => 2,
146
+ :pong => 3,
147
+ :text => 4,
148
+ :binary => 5
149
+ }
150
+ FRAME_TYPES_INVERSE = FRAME_TYPES.invert
151
+ # Frames are either data frames or control frames
152
+ DATA_FRAMES = [:text, :binary, :continuation]
153
+
154
+ def type_to_opcode(frame_type)
155
+ FRAME_TYPES[frame_type] || raise("Unknown frame type")
156
+ end
157
+
158
+ def opcode_to_type(opcode)
159
+ FRAME_TYPES_INVERSE[opcode] || raise(DataError, "Unknown opcode")
160
+ end
161
+
162
+ def data_frame?(type)
163
+ DATA_FRAMES.include?(type)
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: BINARY
2
+
3
+ module EventMachine
4
+ module WebSocket
5
+ # The only difference between draft 03 framing and draft 04 framing is
6
+ # that the MORE bit has been changed to a FIN bit
7
+ module Framing04
8
+ include Framing03
9
+
10
+ private
11
+
12
+ def fin; true; end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,168 @@
1
+ # encoding: BINARY
2
+
3
+ module EventMachine
4
+ module WebSocket
5
+ module Framing05
6
+
7
+ # Set the max frame lenth to very high value (10MB) until there is a
8
+ # limit specified in the spec to protect against malicious attacks
9
+ MAXIMUM_FRAME_LENGTH = 10 * 1024 * 1024
10
+
11
+ def initialize_framing
12
+ @data = MaskedString.new
13
+ @application_data_buffer = '' # Used for MORE frames
14
+ end
15
+
16
+ def process_data(newdata)
17
+ error = false
18
+
19
+ while !error && @data.size > 5 # mask plus first byte present
20
+ pointer = 0
21
+
22
+ @data.read_mask
23
+ pointer += 4
24
+
25
+ fin = (@data.getbyte(pointer) & 0b10000000) == 0b10000000
26
+ # Ignoring rsv1-3 for now
27
+ opcode = @data.getbyte(pointer) & 0b00001111
28
+ pointer += 1
29
+
30
+ # Ignoring rsv4
31
+ length = @data.getbyte(pointer) & 0b01111111
32
+ pointer += 1
33
+
34
+ payload_length = case length
35
+ when 127 # Length defined by 8 bytes
36
+ # Check buffer size
37
+ if @data.getbyte(pointer+8-1) == nil
38
+ debug [:buffer_incomplete, @data]
39
+ error = true
40
+ next
41
+ end
42
+
43
+ # Only using the last 4 bytes for now, till I work out how to
44
+ # unpack 8 bytes. I'm sure 4GB frames will do for now :)
45
+ l = @data.getbytes(pointer+4, 4).unpack('N').first
46
+ pointer += 8
47
+ l
48
+ when 126 # Length defined by 2 bytes
49
+ # Check buffer size
50
+ if @data.getbyte(pointer+2-1) == nil
51
+ debug [:buffer_incomplete, @data]
52
+ error = true
53
+ next
54
+ end
55
+
56
+ l = @data.getbytes(pointer, 2).unpack('n').first
57
+ pointer += 2
58
+ l
59
+ else
60
+ length
61
+ end
62
+
63
+ # Addition to the spec to protect against malicious requests
64
+ if payload_length > MAXIMUM_FRAME_LENGTH
65
+ raise DataError, "Frame length too long (#{payload_length} bytes)"
66
+ end
67
+
68
+ # Check buffer size
69
+ if @data.getbyte(pointer+payload_length-1) == nil
70
+ debug [:buffer_incomplete, @data]
71
+ error = true
72
+ next
73
+ end
74
+
75
+ # Read application data
76
+ application_data = @data.getbytes(pointer, payload_length)
77
+ pointer += payload_length
78
+
79
+ # Throw away data up to pointer
80
+ @data.unset_mask
81
+ @data.slice!(0...pointer)
82
+
83
+ frame_type = opcode_to_type(opcode)
84
+
85
+ if frame_type == :continuation && !@frame_type
86
+ raise WebSocketError, 'Continuation frame not expected'
87
+ end
88
+
89
+ if !fin
90
+ debug [:moreframe, frame_type, application_data]
91
+ @application_data_buffer << application_data
92
+ @frame_type = frame_type
93
+ else
94
+ # Message is complete
95
+ if frame_type == :continuation
96
+ @application_data_buffer << application_data
97
+ message(@frame_type, '', @application_data_buffer)
98
+ @application_data_buffer = ''
99
+ @frame_type = nil
100
+ else
101
+ message(frame_type, '', application_data)
102
+ end
103
+ end
104
+ end # end while
105
+ end
106
+
107
+ def send_frame(frame_type, application_data)
108
+ debug [:sending_frame, frame_type, application_data]
109
+
110
+ if @state == :closing && data_frame?(frame_type)
111
+ raise WebSocketError, "Cannot send data frame since connection is closing"
112
+ end
113
+
114
+ frame = ''
115
+
116
+ opcode = type_to_opcode(frame_type)
117
+ byte1 = opcode | 0b10000000 # fin bit set, rsv1-3 are 0
118
+ frame << byte1
119
+
120
+ length = application_data.size
121
+ if length <= 125
122
+ byte2 = length # since rsv4 is 0
123
+ frame << byte2
124
+ elsif length < 65536 # write 2 byte length
125
+ frame << 126
126
+ frame << [length].pack('n')
127
+ else # write 8 byte length
128
+ frame << 127
129
+ frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
130
+ end
131
+
132
+ frame << application_data
133
+
134
+ @connection.send_data(frame)
135
+ end
136
+
137
+ def send_text_frame(data)
138
+ send_frame(:text, data)
139
+ end
140
+
141
+ private
142
+
143
+ FRAME_TYPES = {
144
+ :continuation => 0,
145
+ :close => 1,
146
+ :ping => 2,
147
+ :pong => 3,
148
+ :text => 4,
149
+ :binary => 5
150
+ }
151
+ FRAME_TYPES_INVERSE = FRAME_TYPES.invert
152
+ # Frames are either data frames or control frames
153
+ DATA_FRAMES = [:text, :binary, :continuation]
154
+
155
+ def type_to_opcode(frame_type)
156
+ FRAME_TYPES[frame_type] || raise("Unknown frame type")
157
+ end
158
+
159
+ def opcode_to_type(opcode)
160
+ FRAME_TYPES_INVERSE[opcode] || raise(DataError, "Unknown opcode")
161
+ end
162
+
163
+ def data_frame?(type)
164
+ DATA_FRAMES.include?(type)
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,180 @@
1
+ # encoding: BINARY
2
+
3
+ module EventMachine
4
+ module WebSocket
5
+ module Framing07
6
+
7
+ attr_accessor :mask_outbound_messages, :require_masked_inbound_messages
8
+
9
+ def initialize_framing
10
+ @data = MaskedString.new
11
+ @application_data_buffer = '' # Used for MORE frames
12
+ @mask_outbound_messages = false
13
+ @require_masked_inbound_messages = true
14
+ end
15
+
16
+ def process_data(newdata)
17
+ error = false
18
+
19
+ while !error && @data.size >= 2
20
+ pointer = 0
21
+
22
+ fin = (@data.getbyte(pointer) & 0b10000000) == 0b10000000
23
+ # Ignoring rsv1-3 for now
24
+ opcode = @data.getbyte(pointer) & 0b00001111
25
+ pointer += 1
26
+
27
+ mask = (@data.getbyte(pointer) & 0b10000000) == 0b10000000
28
+ length = @data.getbyte(pointer) & 0b01111111
29
+ pointer += 1
30
+
31
+ if require_masked_inbound_messages
32
+ raise WebSocketError, 'Data from client must be masked' unless mask
33
+ end
34
+
35
+ payload_length = case length
36
+ when 127 # Length defined by 8 bytes
37
+ # Check buffer size
38
+ if @data.getbyte(pointer+8-1) == nil
39
+ debug [:buffer_incomplete, @data]
40
+ error = true
41
+ next
42
+ end
43
+
44
+ # Only using the last 4 bytes for now, till I work out how to
45
+ # unpack 8 bytes. I'm sure 4GB frames will do for now :)
46
+ l = @data.getbytes(pointer+4, 4).unpack('N').first
47
+ pointer += 8
48
+ l
49
+ when 126 # Length defined by 2 bytes
50
+ # Check buffer size
51
+ if @data.getbyte(pointer+2-1) == nil
52
+ debug [:buffer_incomplete, @data]
53
+ error = true
54
+ next
55
+ end
56
+
57
+ l = @data.getbytes(pointer, 2).unpack('n').first
58
+ pointer += 2
59
+ l
60
+ else
61
+ length
62
+ end
63
+
64
+ # Compute the expected frame length
65
+ frame_length = pointer + payload_length
66
+ frame_length += 4 if mask
67
+
68
+ # Check buffer size
69
+ if @data.getbyte(frame_length - 1) == nil
70
+ debug [:buffer_incomplete, @data]
71
+ error = true
72
+ next
73
+ end
74
+
75
+ # Remove frame header
76
+ @data.slice!(0...pointer)
77
+ pointer = 0
78
+
79
+ # Read application data (unmasked if required)
80
+ @data.read_mask if mask
81
+ pointer += 4 if mask
82
+ application_data = @data.getbytes(pointer, payload_length)
83
+ pointer += payload_length
84
+ @data.unset_mask if mask
85
+
86
+ # Throw away data up to pointer
87
+ @data.slice!(0...pointer)
88
+
89
+ frame_type = opcode_to_type(opcode)
90
+
91
+ if frame_type == :continuation && !@frame_type
92
+ raise WebSocketError, 'Continuation frame not expected'
93
+ end
94
+
95
+ if !fin
96
+ debug [:moreframe, frame_type, application_data]
97
+ @application_data_buffer << application_data
98
+ # The message type is passed in the first frame
99
+ @frame_type ||= frame_type
100
+ else
101
+ # Message is complete
102
+ if frame_type == :continuation
103
+ @application_data_buffer << application_data
104
+ message(@frame_type, '', @application_data_buffer)
105
+ @application_data_buffer = ''
106
+ @frame_type = nil
107
+ else
108
+ message(frame_type, '', application_data)
109
+ end
110
+ end
111
+ end # end while
112
+ end
113
+
114
+ def send_frame(frame_type, application_data)
115
+ debug [:sending_frame, frame_type, application_data]
116
+
117
+ if @state == :closing && data_frame?(frame_type)
118
+ raise WebSocketError, "Cannot send data frame since connection is closing"
119
+ end
120
+
121
+ frame = ''
122
+
123
+ opcode = type_to_opcode(frame_type)
124
+ byte1 = opcode | 0b10000000 # fin bit set, rsv1-3 are 0
125
+ frame << byte1
126
+
127
+ mask = mask_outbound_messages ? 0b10000000 : 0b00000000 # must be masked if from client
128
+ length = application_data.size
129
+ if length <= 125
130
+ byte2 = length # since rsv4 is 0
131
+ frame << (mask | byte2)
132
+ elsif length < 65536 # write 2 byte length
133
+ frame << (mask | 126)
134
+ frame << [length].pack('n')
135
+ else # write 8 byte length
136
+ frame << (mask | 127)
137
+ frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
138
+ end
139
+
140
+ if mask_outbound_messages
141
+ frame << MaskedString.create_masked_string(application_data)
142
+ else
143
+ frame << application_data
144
+ end
145
+
146
+ @connection.send_data(frame)
147
+ end
148
+
149
+ def send_text_frame(data)
150
+ send_frame(:text, data)
151
+ end
152
+
153
+ private
154
+
155
+ FRAME_TYPES = {
156
+ :continuation => 0,
157
+ :text => 1,
158
+ :binary => 2,
159
+ :close => 8,
160
+ :ping => 9,
161
+ :pong => 10,
162
+ }
163
+ FRAME_TYPES_INVERSE = FRAME_TYPES.invert
164
+ # Frames are either data frames or control frames
165
+ DATA_FRAMES = [:text, :binary, :continuation]
166
+
167
+ def type_to_opcode(frame_type)
168
+ FRAME_TYPES[frame_type] || raise("Unknown frame type")
169
+ end
170
+
171
+ def opcode_to_type(opcode)
172
+ FRAME_TYPES_INVERSE[opcode] || raise(DataError, "Unknown opcode")
173
+ end
174
+
175
+ def data_frame?(type)
176
+ DATA_FRAMES.include?(type)
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,114 @@
1
+ # encoding: BINARY
2
+
3
+ module EventMachine
4
+ module WebSocket
5
+ module Framing76
6
+
7
+ # Set the max frame lenth to very high value (10MB) until there is a
8
+ # limit specified in the spec to protect against malicious attacks
9
+ MAXIMUM_FRAME_LENGTH = 10 * 1024 * 1024
10
+
11
+ def initialize_framing
12
+ @data = ''
13
+ end
14
+
15
+ def process_data(newdata)
16
+ debug [:message, @data]
17
+
18
+ # This algorithm comes straight from the spec
19
+ # http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#section-5.3
20
+
21
+ error = false
22
+
23
+ while !error
24
+ return if @data.size == 0
25
+
26
+ pointer = 0
27
+ frame_type = @data.getbyte(pointer)
28
+ pointer += 1
29
+
30
+ if (frame_type & 0x80) == 0x80
31
+ # If the high-order bit of the /frame type/ byte is set
32
+ length = 0
33
+
34
+ loop do
35
+ return false if !@data.getbyte(pointer)
36
+ b = @data.getbyte(pointer)
37
+ pointer += 1
38
+ b_v = b & 0x7F
39
+ length = length * 128 + b_v
40
+ break unless (b & 0x80) == 0x80
41
+ end
42
+
43
+ # Addition to the spec to protect against malicious requests
44
+ if length > MAXIMUM_FRAME_LENGTH
45
+ raise DataError, "Frame length too long (#{length} bytes)"
46
+ end
47
+
48
+ if @data.getbyte(pointer+length-1) == nil
49
+ debug [:buffer_incomplete, @data]
50
+ # Incomplete data - leave @data to accumulate
51
+ error = true
52
+ else
53
+ # Straight from spec - I'm sure this isn't crazy...
54
+ # 6. Read /length/ bytes.
55
+ # 7. Discard the read bytes.
56
+ @data = @data[(pointer+length)..-1]
57
+
58
+ # If the /frame type/ is 0xFF and the /length/ was 0, then close
59
+ if length == 0
60
+ @connection.send_data("\xff\x00")
61
+ @state = :closing
62
+ @connection.close_connection_after_writing
63
+ else
64
+ error = true
65
+ end
66
+ end
67
+ else
68
+ # If the high-order bit of the /frame type/ byte is _not_ set
69
+
70
+ if @data.getbyte(0) != 0x00
71
+ # Close the connection since this buffer can never match
72
+ raise DataError, "Invalid frame received"
73
+ end
74
+
75
+ # Addition to the spec to protect against malicious requests
76
+ if @data.size > MAXIMUM_FRAME_LENGTH
77
+ raise DataError, "Frame length too long (#{@data.size} bytes)"
78
+ end
79
+
80
+ # Optimization to avoid calling slice! unnecessarily
81
+ error = true and next unless newdata =~ /\xff/
82
+
83
+ msg = @data.slice!(/\A\x00[^\xff]*\xff/)
84
+ if msg
85
+ msg.gsub!(/\A\x00|\xff\z/, '')
86
+ if @state == :closing
87
+ debug [:ignored_message, msg]
88
+ else
89
+ msg.force_encoding('UTF-8') if msg.respond_to?(:force_encoding)
90
+ @connection.trigger_on_message(msg)
91
+ end
92
+ else
93
+ error = true
94
+ end
95
+ end
96
+ end
97
+
98
+ false
99
+ end
100
+
101
+ # frames need to start with 0x00-0x7f byte and end with
102
+ # an 0xFF byte. Per spec, we can also set the first
103
+ # byte to a value betweent 0x80 and 0xFF, followed by
104
+ # a leading length indicator
105
+ def send_text_frame(data)
106
+ debug [:sending_text_frame, data]
107
+ ary = ["\x00", data, "\xff"]
108
+ ary.collect{ |s| s.force_encoding('UTF-8') if s.respond_to?(:force_encoding) }
109
+ @connection.send_data(ary.join)
110
+ end
111
+
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,56 @@
1
+ module EventMachine
2
+ module WebSocket
3
+ class Handler
4
+ include Debugger
5
+
6
+ attr_reader :request, :state
7
+
8
+ def initialize(connection, request, debug = false)
9
+ @connection, @request = connection, request
10
+ @debug = debug
11
+ @state = :handshake
12
+ initialize_framing
13
+ end
14
+
15
+ def run_server
16
+ @connection.send_data handshake_server
17
+ @state = :connected
18
+ @connection.trigger_on_open
19
+ end
20
+
21
+ def run_client
22
+ self.mask_outbound_messages = true
23
+ self.require_masked_inbound_messages = false
24
+ @connection.send_data handshake_client
25
+ end
26
+
27
+ # Handshake response
28
+ def handshake
29
+ # Implemented in subclass
30
+ end
31
+
32
+ def handshake_server
33
+ handshake #backwards compatibility
34
+ end
35
+
36
+ # Handshake initiation
37
+ def handshake_client
38
+ # Implemented in subclass
39
+ end
40
+
41
+ def receive_data(data)
42
+ @data << data
43
+ process_data(data)
44
+ end
45
+
46
+ def close_websocket(code, body)
47
+ # Implemented in subclass
48
+ end
49
+
50
+ def unbind
51
+ @state = :closed
52
+ @connection.trigger_on_close
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,10 @@
1
+ module EventMachine
2
+ module WebSocket
3
+ class Handler03 < Handler
4
+ include Handshake76
5
+ include Framing03
6
+ include MessageProcessor03
7
+ include Close03
8
+ end
9
+ end
10
+ end