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,248 @@
1
+ # Protocol references:
2
+ #
3
+ # * http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
4
+ # * http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
5
+ # * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
6
+
7
+ require 'base64'
8
+ require 'digest/md5'
9
+ require 'digest/sha1'
10
+ require 'securerandom'
11
+ require 'set'
12
+ require 'stringio'
13
+ require 'uri'
14
+ require 'websocket/extensions'
15
+
16
+ module WebSocket
17
+ autoload :HTTP, File.expand_path('../http', __FILE__)
18
+
19
+ class Driver
20
+
21
+ root = File.expand_path('../driver', __FILE__)
22
+
23
+ begin
24
+ # Load C native extension
25
+ require 'websocket_mask'
26
+ rescue LoadError
27
+ # Fall back to pure-Ruby implementation
28
+ require 'websocket/mask'
29
+ end
30
+
31
+
32
+ if RUBY_PLATFORM =~ /java/
33
+ require 'jruby'
34
+ com.jcoglan.websocket.WebsocketMaskService.new.basicLoad(JRuby.runtime)
35
+ end
36
+
37
+ unless Mask.respond_to?(:mask)
38
+ def Mask.mask(payload, mask)
39
+ @instance ||= new
40
+ @instance.mask(payload, mask)
41
+ end
42
+ end
43
+
44
+ MAX_LENGTH = 0x3ffffff
45
+ PORTS = { 'ws' => 80, 'wss' => 443 }
46
+ STATES = [:connecting, :open, :closing, :closed]
47
+
48
+ ConnectEvent = Struct.new(nil)
49
+ OpenEvent = Struct.new(nil)
50
+ MessageEvent = Struct.new(:data)
51
+ PingEvent = Struct.new(:data)
52
+ PongEvent = Struct.new(:data)
53
+ CloseEvent = Struct.new(:code, :reason)
54
+
55
+ ProtocolError = Class.new(StandardError)
56
+ URIError = Class.new(ArgumentError)
57
+ ConfigurationError = Class.new(ArgumentError)
58
+
59
+ autoload :Client, root + '/client'
60
+ autoload :Draft75, root + '/draft75'
61
+ autoload :Draft76, root + '/draft76'
62
+ autoload :EventEmitter, root + '/event_emitter'
63
+ autoload :Headers, root + '/headers'
64
+ autoload :Hybi, root + '/hybi'
65
+ autoload :Proxy, root + '/proxy'
66
+ autoload :Server, root + '/server'
67
+ autoload :StreamReader, root + '/stream_reader'
68
+
69
+ include EventEmitter
70
+ attr_reader :protocol, :ready_state
71
+
72
+ def initialize(socket, options = {})
73
+ super()
74
+ Driver.validate_options(options, [:max_length, :masking, :require_masking, :protocols, :binary_data_format])
75
+
76
+ @socket = socket
77
+ @reader = StreamReader.new
78
+ @options = options
79
+ @max_length = options[:max_length] || MAX_LENGTH
80
+ @headers = Headers.new
81
+ @queue = []
82
+ @ready_state = 0
83
+
84
+ @binary_data_format = options[:binary_data_format] || :string
85
+ end
86
+
87
+ def state
88
+ return nil unless @ready_state >= 0
89
+ STATES[@ready_state]
90
+ end
91
+
92
+ def add_extension(extension)
93
+ false
94
+ end
95
+
96
+ def set_header(name, value)
97
+ return false unless @ready_state <= 0
98
+ @headers[name] = value
99
+ true
100
+ end
101
+
102
+ def start
103
+ return false unless @ready_state == 0
104
+
105
+ unless Driver.websocket?(@socket.env)
106
+ return fail_handshake(ProtocolError.new('Not a WebSocket request'))
107
+ end
108
+
109
+ begin
110
+ response = handshake_response
111
+ rescue => error
112
+ return fail_handshake(error)
113
+ end
114
+
115
+ @socket.write(response)
116
+ open unless @stage == -1
117
+ true
118
+ end
119
+
120
+ def text(message)
121
+ message = Driver.encode(message, Encoding::UTF_8)
122
+ frame(message, :text)
123
+ end
124
+
125
+ def binary(message)
126
+ false
127
+ end
128
+
129
+ def ping(*args)
130
+ false
131
+ end
132
+
133
+ def pong(*args)
134
+ false
135
+ end
136
+
137
+ def close(reason = nil, code = nil)
138
+ return false unless @ready_state == 1
139
+ @ready_state = 3
140
+ emit(:close, CloseEvent.new(nil, nil))
141
+ true
142
+ end
143
+
144
+ private
145
+
146
+ def fail_handshake(error)
147
+ headers = Headers.new
148
+ headers['Content-Type'] = 'text/plain'
149
+ headers['Content-Length'] = error.message.bytesize
150
+
151
+ headers = ['HTTP/1.1 400 Bad Request', headers.to_s, error.message]
152
+ @socket.write(headers.join("\r\n"))
153
+ fail(:protocol_error, error.message)
154
+
155
+ false
156
+ end
157
+
158
+ def fail(type, message)
159
+ @ready_state = 2
160
+ emit(:error, ProtocolError.new(message))
161
+ close
162
+ end
163
+
164
+ def open
165
+ @ready_state = 1
166
+ @queue.each { |message| frame(*message) }
167
+ @queue = []
168
+ emit(:open, OpenEvent.new)
169
+ end
170
+
171
+ def queue(message)
172
+ @queue << message
173
+ true
174
+ end
175
+
176
+ def self.client(socket, options = {})
177
+ Client.new(socket, options.merge(:masking => true))
178
+ end
179
+
180
+ def self.server(socket, options = {})
181
+ Server.new(socket, options.merge(:require_masking => true))
182
+ end
183
+
184
+ def self.rack(socket, options = {})
185
+ env = socket.env
186
+ version = env['HTTP_SEC_WEBSOCKET_VERSION']
187
+ key = env['HTTP_SEC_WEBSOCKET_KEY']
188
+ key1 = env['HTTP_SEC_WEBSOCKET_KEY1']
189
+ key2 = env['HTTP_SEC_WEBSOCKET_KEY2']
190
+
191
+ if version or key
192
+ Hybi.new(socket, options.merge(:require_masking => true))
193
+ elsif key1 or key2
194
+ Draft76.new(socket, options)
195
+ else
196
+ Draft75.new(socket, options)
197
+ end
198
+ end
199
+
200
+ def self.encode(data, encoding = nil)
201
+ if Array === data
202
+ data = data.pack('C*')
203
+ encoding ||= Encoding::BINARY
204
+ end
205
+
206
+ return data if encoding.nil? or data.encoding == encoding
207
+
208
+ if data.encoding == Encoding::BINARY
209
+ data = data.dup if data.frozen?
210
+ data.force_encoding(encoding)
211
+ else
212
+ data.encode(encoding)
213
+ end
214
+ end
215
+
216
+ def self.host_header(uri)
217
+ host = uri.host
218
+ if uri.port and uri.port != PORTS[uri.scheme]
219
+ host += ":#{uri.port}"
220
+ end
221
+ host
222
+ end
223
+
224
+ def self.validate_options(options, valid_keys)
225
+ options.keys.each do |key|
226
+ unless valid_keys.include?(key)
227
+ raise ConfigurationError, "Unrecognized option: #{ key.inspect }"
228
+ end
229
+ end
230
+
231
+ if options[:binary_data_format]
232
+ unless [:array, :string].include?(options[:binary_data_format])
233
+ raise ConfigurationError, "Invalid :binary_data_format: #{options[:binary_data_format].inspect}"
234
+ end
235
+ end
236
+ end
237
+
238
+ def self.websocket?(env)
239
+ connection = env['HTTP_CONNECTION'] || ''
240
+ upgrade = env['HTTP_UPGRADE'] || ''
241
+
242
+ env['REQUEST_METHOD'] == 'GET' and
243
+ connection.downcase.split(/ *, */).include?('upgrade') and
244
+ upgrade.downcase == 'websocket'
245
+ end
246
+
247
+ end
248
+ end
@@ -0,0 +1,112 @@
1
+ module WebSocket
2
+ module HTTP
3
+
4
+ module Headers
5
+ MAX_LINE_LENGTH = 4096
6
+ CR = 0x0D
7
+ LF = 0x0A
8
+
9
+ # RFC 2616 grammar rules:
10
+ #
11
+ # CHAR = <any US-ASCII character (octets 0 - 127)>
12
+ #
13
+ # CTL = <any US-ASCII control character
14
+ # (octets 0 - 31) and DEL (127)>
15
+ #
16
+ # SP = <US-ASCII SP, space (32)>
17
+ #
18
+ # HT = <US-ASCII HT, horizontal-tab (9)>
19
+ #
20
+ # token = 1*<any CHAR except CTLs or separators>
21
+ #
22
+ # separators = "(" | ")" | "<" | ">" | "@"
23
+ # | "," | ";" | ":" | "\" | <">
24
+ # | "/" | "[" | "]" | "?" | "="
25
+ # | "{" | "}" | SP | HT
26
+ #
27
+ # Or, as redefined in RFC 7230:
28
+ #
29
+ # token = 1*tchar
30
+ #
31
+ # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
32
+ # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
33
+ # / DIGIT / ALPHA
34
+ # ; any VCHAR, except delimiters
35
+
36
+ HEADER_LINE = /^([!#\$%&'\*\+\-\.\^_`\|~0-9a-z]+):\s*([\x20-\x7e]*?)\s*$/i
37
+
38
+ attr_reader :headers
39
+
40
+ def initialize
41
+ @buffer = []
42
+ @env = {}
43
+ @headers = {}
44
+ @stage = 0
45
+ end
46
+
47
+ def complete?
48
+ @stage == 2
49
+ end
50
+
51
+ def error?
52
+ @stage == -1
53
+ end
54
+
55
+ def parse(chunk)
56
+ chunk.each_byte do |octet|
57
+ if octet == LF and @stage < 2
58
+ @buffer.pop if @buffer.last == CR
59
+ if @buffer.empty?
60
+ complete if @stage == 1
61
+ else
62
+ result = case @stage
63
+ when 0 then start_line(string_buffer)
64
+ when 1 then header_line(string_buffer)
65
+ end
66
+
67
+ if result
68
+ @stage = 1
69
+ else
70
+ error
71
+ end
72
+ end
73
+ @buffer = []
74
+ else
75
+ @buffer << octet if @stage >= 0
76
+ error if @stage < 2 and @buffer.size > MAX_LINE_LENGTH
77
+ end
78
+ end
79
+ @env['rack.input'] = StringIO.new(string_buffer)
80
+ end
81
+
82
+ private
83
+
84
+ def complete
85
+ @stage = 2
86
+ end
87
+
88
+ def error
89
+ @stage = -1
90
+ end
91
+
92
+ def header_line(line)
93
+ return false unless parsed = line.scan(HEADER_LINE).first
94
+
95
+ key = HTTP.normalize_header(parsed[0])
96
+ value = parsed[1].strip
97
+
98
+ if @headers.has_key?(key)
99
+ @headers[key] << ', ' << value
100
+ else
101
+ @headers[key] = value
102
+ end
103
+ true
104
+ end
105
+
106
+ def string_buffer
107
+ @buffer.pack('C*')
108
+ end
109
+ end
110
+
111
+ end
112
+ end
@@ -0,0 +1,45 @@
1
+ module WebSocket
2
+ module HTTP
3
+
4
+ class Request
5
+ include Headers
6
+
7
+ REQUEST_LINE = /^(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT) ([\x21-\x7e]+) (HTTP\/[0-9]+\.[0-9]+)$/
8
+ REQUEST_TARGET = /^(.*?)(\?(.*))?$/
9
+ RESERVED_HEADERS = %w[content-length content-type]
10
+
11
+ attr_reader :env
12
+
13
+ private
14
+
15
+ def start_line(line)
16
+ return false unless parsed = line.scan(REQUEST_LINE).first
17
+
18
+ target = parsed[1].scan(REQUEST_TARGET).first
19
+
20
+ @env = {
21
+ 'REQUEST_METHOD' => parsed[0],
22
+ 'SCRIPT_NAME' => '',
23
+ 'PATH_INFO' => target[0],
24
+ 'QUERY_STRING' => target[2] || ''
25
+ }
26
+ true
27
+ end
28
+
29
+ def complete
30
+ super
31
+ @headers.each do |name, value|
32
+ rack_name = name.upcase.gsub(/-/, '_')
33
+ rack_name = "HTTP_#{ rack_name }" unless RESERVED_HEADERS.include?(name)
34
+ @env[rack_name] = value
35
+ end
36
+ if host = @env['HTTP_HOST']
37
+ uri = URI.parse("http://#{ host }")
38
+ @env['SERVER_NAME'] = uri.host
39
+ @env['SERVER_PORT'] = uri.port.to_s
40
+ end
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ module WebSocket
2
+ module HTTP
3
+
4
+ class Response
5
+ include Headers
6
+
7
+ STATUS_LINE = /^(HTTP\/[0-9]+\.[0-9]+) ([0-9]{3}) ([\x20-\x7e]*)$/
8
+
9
+ attr_reader :code
10
+
11
+ def [](name)
12
+ @headers[HTTP.normalize_header(name)]
13
+ end
14
+
15
+ def body
16
+ @buffer.pack('C*')
17
+ end
18
+
19
+ private
20
+
21
+ def start_line(line)
22
+ return false unless parsed = line.scan(STATUS_LINE).first
23
+ @code = parsed[1].to_i
24
+ true
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ module WebSocket
2
+ module HTTP
3
+
4
+ root = File.expand_path('../http', __FILE__)
5
+
6
+ autoload :Headers, root + '/headers'
7
+ autoload :Request, root + '/request'
8
+ autoload :Response, root + '/response'
9
+
10
+ def self.normalize_header(name)
11
+ name.to_s.strip.downcase.gsub(/^http_/, '').gsub(/_/, '-')
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module WebSocket
2
+ module Mask
3
+ def self.mask(payload, mask)
4
+ return payload if mask.nil? || payload.empty?
5
+
6
+ payload.tap do |result|
7
+ payload.bytesize.times do |i|
8
+ result.setbyte(i, payload.getbyte(i) ^ mask.getbyte(i % 4))
9
+ end
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ # Load C native extension
2
+
3
+ begin
4
+ ruby_version = /(\d+\.\d+)/.match(::RUBY_VERSION)
5
+
6
+ require "#{ruby_version}/websocket_mask.so"
7
+ rescue LoadError
8
+ require "websocket_mask.so"
9
+ end
metadata ADDED
@@ -0,0 +1,160 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ed3-precompiled_websocket-driver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ platform: arm64-darwin
6
+ authors:
7
+ - James Coglan
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: base64
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: websocket-extensions
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.1.0
40
+ - !ruby/object:Gem::Dependency
41
+ name: eventmachine
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: permessage_deflate
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rake-compiler
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: rspec
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ email: jcoglan@gmail.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files:
100
+ - README.md
101
+ files:
102
+ - CHANGELOG.md
103
+ - LICENSE.md
104
+ - README.md
105
+ - ext/websocket-driver/WebsocketMaskService.java
106
+ - ext/websocket-driver/extconf.rb
107
+ - ext/websocket-driver/websocket_mask.c
108
+ - lib/3.0/websocket_mask.bundle
109
+ - lib/3.1/websocket_mask.bundle
110
+ - lib/3.2/websocket_mask.bundle
111
+ - lib/3.3/websocket_mask.bundle
112
+ - lib/3.4/websocket_mask.bundle
113
+ - lib/websocket/driver.rb
114
+ - lib/websocket/driver/client.rb
115
+ - lib/websocket/driver/draft75.rb
116
+ - lib/websocket/driver/draft76.rb
117
+ - lib/websocket/driver/event_emitter.rb
118
+ - lib/websocket/driver/headers.rb
119
+ - lib/websocket/driver/hybi.rb
120
+ - lib/websocket/driver/hybi/frame.rb
121
+ - lib/websocket/driver/hybi/message.rb
122
+ - lib/websocket/driver/proxy.rb
123
+ - lib/websocket/driver/server.rb
124
+ - lib/websocket/driver/stream_reader.rb
125
+ - lib/websocket/http.rb
126
+ - lib/websocket/http/headers.rb
127
+ - lib/websocket/http/request.rb
128
+ - lib/websocket/http/response.rb
129
+ - lib/websocket/mask.rb
130
+ - lib/websocket/websocket_mask.rb
131
+ homepage: https://github.com/faye/websocket-driver-ruby
132
+ licenses:
133
+ - Apache-2.0
134
+ metadata:
135
+ changelog_uri: https://github.com/faye/websocket-driver-ruby/blob/main/CHANGELOG.md
136
+ rdoc_options:
137
+ - "--main"
138
+ - README.md
139
+ - "--markup"
140
+ - markdown
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '3.0'
148
+ - - "<"
149
+ - !ruby/object:Gem::Version
150
+ version: 3.5.dev
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubygems_version: 3.6.7
158
+ specification_version: 4
159
+ summary: WebSocket protocol handler with pluggable I/O
160
+ test_files: []