ed3-precompiled_websocket-driver 0.8.0-arm64-darwin

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.
@@ -0,0 +1,139 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class Client < Hybi
5
+ VALID_SCHEMES = %w[ws wss]
6
+
7
+ def self.generate_key
8
+ Base64.strict_encode64(SecureRandom.random_bytes(16))
9
+ end
10
+
11
+ attr_reader :status, :headers
12
+
13
+ def initialize(socket, options = {})
14
+ super
15
+
16
+ @ready_state = -1
17
+ @key = Client.generate_key
18
+ @accept = Hybi.generate_accept(@key)
19
+ @http = HTTP::Response.new
20
+
21
+ uri = URI.parse(@socket.url)
22
+ unless VALID_SCHEMES.include?(uri.scheme)
23
+ raise URIError, "#{ socket.url } is not a valid WebSocket URL"
24
+ end
25
+
26
+ path = (uri.path == '') ? '/' : uri.path
27
+ @pathname = path + (uri.query ? '?' + uri.query : '')
28
+
29
+ @headers['Host'] = Driver.host_header(uri)
30
+ @headers['Upgrade'] = 'websocket'
31
+ @headers['Connection'] = 'Upgrade'
32
+ @headers['Sec-WebSocket-Key'] = @key
33
+ @headers['Sec-WebSocket-Version'] = VERSION
34
+
35
+ if @protocols.size > 0
36
+ @headers['Sec-WebSocket-Protocol'] = @protocols * ', '
37
+ end
38
+
39
+ if uri.user
40
+ auth = Base64.strict_encode64([uri.user, uri.password] * ':')
41
+ @headers['Authorization'] = 'Basic ' + auth
42
+ end
43
+ end
44
+
45
+ def version
46
+ "hybi-#{ VERSION }"
47
+ end
48
+
49
+ def proxy(origin, options = {})
50
+ Proxy.new(self, origin, options)
51
+ end
52
+
53
+ def start
54
+ return false unless @ready_state == -1
55
+ @socket.write(handshake_request)
56
+ @ready_state = 0
57
+ true
58
+ end
59
+
60
+ def parse(chunk)
61
+ return if @ready_state == 3
62
+ return super if @ready_state > 0
63
+
64
+ @http.parse(chunk)
65
+ return fail_handshake('Invalid HTTP response') if @http.error?
66
+ return unless @http.complete?
67
+
68
+ validate_handshake
69
+ return if @ready_state == 3
70
+
71
+ open
72
+ parse(@http.body)
73
+ end
74
+
75
+ private
76
+
77
+ def handshake_request
78
+ extensions = @extensions.generate_offer
79
+ @headers['Sec-WebSocket-Extensions'] = extensions if extensions
80
+
81
+ start = "GET #{ @pathname } HTTP/1.1"
82
+ headers = [start, @headers.to_s, '']
83
+ headers.join("\r\n")
84
+ end
85
+
86
+ def fail_handshake(message)
87
+ message = "Error during WebSocket handshake: #{ message }"
88
+ @ready_state = 3
89
+ emit(:error, ProtocolError.new(message))
90
+ emit(:close, CloseEvent.new(ERRORS[:protocol_error], message))
91
+ end
92
+
93
+ def validate_handshake
94
+ @status = @http.code
95
+ @headers = Headers.new(@http.headers)
96
+
97
+ unless @http.code == 101
98
+ return fail_handshake("Unexpected response code: #{ @http.code }")
99
+ end
100
+
101
+ upgrade = @http['Upgrade'] || ''
102
+ connection = @http['Connection'] || ''
103
+ accept = @http['Sec-WebSocket-Accept'] || ''
104
+ protocol = @http['Sec-WebSocket-Protocol'] || ''
105
+
106
+ if upgrade == ''
107
+ return fail_handshake("'Upgrade' header is missing")
108
+ elsif upgrade.downcase != 'websocket'
109
+ return fail_handshake("'Upgrade' header value is not 'WebSocket'")
110
+ end
111
+
112
+ if connection == ''
113
+ return fail_handshake("'Connection' header is missing")
114
+ elsif connection.downcase != 'upgrade'
115
+ return fail_handshake("'Connection' header value is not 'Upgrade'")
116
+ end
117
+
118
+ unless accept == @accept
119
+ return fail_handshake('Sec-WebSocket-Accept mismatch')
120
+ end
121
+
122
+ unless protocol == ''
123
+ if @protocols.include?(protocol)
124
+ @protocol = protocol
125
+ else
126
+ return fail_handshake('Sec-WebSocket-Protocol mismatch')
127
+ end
128
+ end
129
+
130
+ begin
131
+ @extensions.activate(@headers['Sec-WebSocket-Extensions'])
132
+ rescue ::WebSocket::Extensions::ExtensionError => error
133
+ return fail_handshake(error.message)
134
+ end
135
+ end
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,102 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class Draft75 < Driver
5
+ def initialize(socket, options = {})
6
+ super
7
+
8
+ @stage = 0
9
+ @closing = false
10
+
11
+ @headers['Upgrade'] = 'WebSocket'
12
+ @headers['Connection'] = 'Upgrade'
13
+ @headers['WebSocket-Origin'] = @socket.env['HTTP_ORIGIN']
14
+ @headers['WebSocket-Location'] = @socket.url
15
+ end
16
+
17
+ def version
18
+ 'hixie-75'
19
+ end
20
+
21
+ def close(reason = nil, code = nil)
22
+ return false if @ready_state == 3
23
+ @ready_state = 3
24
+ emit(:close, CloseEvent.new(nil, nil))
25
+ true
26
+ end
27
+
28
+ def parse(chunk)
29
+ return if @ready_state > 1
30
+
31
+ @reader.put(chunk)
32
+
33
+ @reader.each_byte do |octet|
34
+ case @stage
35
+ when -1 then
36
+ @body << octet
37
+ send_handshake_body
38
+
39
+ when 0 then
40
+ parse_leading_byte(octet)
41
+
42
+ when 1 then
43
+ @length = (octet & 0x7F) + 128 * @length
44
+
45
+ if @closing and @length.zero?
46
+ return close
47
+ elsif (octet & 0x80) != 0x80
48
+ if @length.zero?
49
+ @stage = 0
50
+ else
51
+ @skipped = 0
52
+ @stage = 2
53
+ end
54
+ end
55
+
56
+ when 2 then
57
+ if octet == 0xFF
58
+ @stage = 0
59
+ emit(:message, MessageEvent.new(Driver.encode(@buffer, Encoding::UTF_8)))
60
+ else
61
+ if @length
62
+ @skipped += 1
63
+ @stage = 0 if @skipped == @length
64
+ else
65
+ @buffer << octet
66
+ return close if @buffer.size > @max_length
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def frame(buffer, type = nil, error_type = nil)
74
+ return queue([buffer, type, error_type]) if @ready_state == 0
75
+ frame = [0x00, buffer, 0xFF].pack('CA*C')
76
+ @socket.write(frame)
77
+ true
78
+ end
79
+
80
+ private
81
+
82
+ def handshake_response
83
+ start = 'HTTP/1.1 101 Web Socket Protocol Handshake'
84
+ headers = [start, @headers.to_s, '']
85
+ headers.join("\r\n")
86
+ end
87
+
88
+ def parse_leading_byte(octet)
89
+ if (octet & 0x80) == 0x80
90
+ @length = 0
91
+ @stage = 1
92
+ else
93
+ @length = nil
94
+ @skipped = nil
95
+ @buffer = []
96
+ @stage = 2
97
+ end
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,99 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class Draft76 < Draft75
5
+ BODY_SIZE = 8
6
+
7
+ def initialize(socket, options = {})
8
+ super
9
+ input = (@socket.env['rack.input'] || StringIO.new('')).read
10
+ input = input.dup if input.frozen?
11
+ @stage = -1
12
+ @body = input.force_encoding(Encoding::BINARY)
13
+
14
+ @headers.clear
15
+ @headers['Upgrade'] = 'WebSocket'
16
+ @headers['Connection'] = 'Upgrade'
17
+ @headers['Sec-WebSocket-Origin'] = @socket.env['HTTP_ORIGIN']
18
+ @headers['Sec-WebSocket-Location'] = @socket.url
19
+ end
20
+
21
+ def version
22
+ 'hixie-76'
23
+ end
24
+
25
+ def start
26
+ return false unless super
27
+ send_handshake_body
28
+ true
29
+ end
30
+
31
+ def close(reason = nil, code = nil)
32
+ return false if @ready_state == 3
33
+ @socket.write([0xFF, 0x00].pack('C*')) if @ready_state == 1
34
+ @ready_state = 3
35
+ emit(:close, CloseEvent.new(nil, nil))
36
+ true
37
+ end
38
+
39
+ private
40
+
41
+ def handshake_response
42
+ env = @socket.env
43
+ key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
44
+ key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
45
+
46
+ raise ProtocolError.new('Missing required header: Sec-WebSocket-Key1') unless key1
47
+ raise ProtocolError.new('Missing required header: Sec-WebSocket-Key2') unless key2
48
+
49
+ number1 = number_from_key(key1)
50
+ spaces1 = spaces_in_key(key1)
51
+
52
+ number2 = number_from_key(key2)
53
+ spaces2 = spaces_in_key(key2)
54
+
55
+ if number1 % spaces1 != 0 or number2 % spaces2 != 0
56
+ raise ProtocolError.new('Client sent invalid Sec-WebSocket-Key headers')
57
+ end
58
+
59
+ @key_values = [number1 / spaces1, number2 / spaces2]
60
+
61
+ start = 'HTTP/1.1 101 WebSocket Protocol Handshake'
62
+ headers = [start, @headers.to_s, '']
63
+ headers.join("\r\n")
64
+ end
65
+
66
+ def handshake_signature
67
+ return nil unless @body.bytesize >= BODY_SIZE
68
+
69
+ head = @body[0...BODY_SIZE]
70
+ Digest::MD5.digest((@key_values + [head]).pack('N2A*'))
71
+ end
72
+
73
+ def send_handshake_body
74
+ return unless signature = handshake_signature
75
+ @socket.write(signature)
76
+ @stage = 0
77
+ open
78
+ parse(@body[BODY_SIZE..-1]) if @body.bytesize > BODY_SIZE
79
+ end
80
+
81
+ def parse_leading_byte(octet)
82
+ return super unless octet == 0xFF
83
+ @closing = true
84
+ @length = 0
85
+ @stage = 1
86
+ end
87
+
88
+ def number_from_key(key)
89
+ number = key.scan(/[0-9]/).join('')
90
+ number == '' ? Float::NAN : number.to_i(10)
91
+ end
92
+
93
+ def spaces_in_key(key)
94
+ key.scan(/ /).size
95
+ end
96
+ end
97
+
98
+ end
99
+ end
@@ -0,0 +1,54 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ module EventEmitter
5
+ def initialize
6
+ @listeners = Hash.new { |h,k| h[k] = [] }
7
+ end
8
+
9
+ def add_listener(event, callable = nil, &block)
10
+ listener = callable || block
11
+ @listeners[event.to_s] << listener
12
+ listener
13
+ end
14
+
15
+ def on(event, callable = nil, &block)
16
+ if callable
17
+ add_listener(event, callable)
18
+ else
19
+ add_listener(event, &block)
20
+ end
21
+ end
22
+
23
+ def remove_listener(event, callable = nil, &block)
24
+ listener = callable || block
25
+ @listeners[event.to_s].delete(listener)
26
+ listener
27
+ end
28
+
29
+ def remove_all_listeners(event = nil)
30
+ if event
31
+ @listeners.delete(event.to_s)
32
+ else
33
+ @listeners.clear
34
+ end
35
+ end
36
+
37
+ def emit(event, *args)
38
+ @listeners[event.to_s].dup.each do |listener|
39
+ listener.call(*args)
40
+ end
41
+ end
42
+
43
+ def listener_count(event)
44
+ return 0 unless @listeners.has_key?(event.to_s)
45
+ @listeners[event.to_s].size
46
+ end
47
+
48
+ def listeners(event)
49
+ @listeners[event.to_s]
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,45 @@
1
+ module WebSocket
2
+ class Driver
3
+
4
+ class Headers
5
+ ALLOWED_DUPLICATES = %w[set-cookie set-cookie2 warning www-authenticate]
6
+
7
+ def initialize(received = {})
8
+ @raw = received
9
+ clear
10
+
11
+ @received = {}
12
+ @raw.each { |k,v| @received[HTTP.normalize_header(k)] = v }
13
+ end
14
+
15
+ def clear
16
+ @sent = Set.new
17
+ @lines = []
18
+ end
19
+
20
+ def [](name)
21
+ @received[HTTP.normalize_header(name)]
22
+ end
23
+
24
+ def []=(name, value)
25
+ return if value.nil?
26
+ key = HTTP.normalize_header(name)
27
+ return unless @sent.add?(key) or ALLOWED_DUPLICATES.include?(key)
28
+ @lines << "#{ name.strip }: #{ value.to_s.strip }\r\n"
29
+ end
30
+
31
+ def inspect
32
+ @raw.inspect
33
+ end
34
+
35
+ def to_h
36
+ @raw.dup
37
+ end
38
+
39
+ def to_s
40
+ @lines.join('')
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,20 @@
1
+ module WebSocket
2
+ class Driver
3
+ class Hybi
4
+
5
+ class Frame
6
+ attr_accessor :final,
7
+ :rsv1,
8
+ :rsv2,
9
+ :rsv3,
10
+ :opcode,
11
+ :masked,
12
+ :masking_key,
13
+ :length_bytes,
14
+ :length,
15
+ :payload
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module WebSocket
2
+ class Driver
3
+ class Hybi
4
+
5
+ class Message
6
+ attr_accessor :rsv1,
7
+ :rsv2,
8
+ :rsv3,
9
+ :opcode,
10
+ :data
11
+
12
+ def initialize
13
+ @rsv1 = false
14
+ @rsv2 = false
15
+ @rsv3 = false
16
+ @opcode = nil
17
+ @data = String.new('').force_encoding(Encoding::BINARY)
18
+ end
19
+
20
+ def <<(frame)
21
+ @rsv1 ||= frame.rsv1
22
+ @rsv2 ||= frame.rsv2
23
+ @rsv3 ||= frame.rsv3
24
+ @opcode ||= frame.opcode
25
+ @data << frame.payload
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end