iodine 0.1.21 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +3 -2
- data/.travis.yml +23 -2
- data/CHANGELOG.md +9 -2
- data/README.md +232 -179
- data/Rakefile +13 -1
- data/bin/config.ru +63 -0
- data/bin/console +6 -0
- data/bin/echo +42 -32
- data/bin/http-hello +62 -0
- data/bin/http-playground +124 -0
- data/bin/playground +62 -0
- data/bin/poc/Gemfile.lock +23 -0
- data/bin/poc/README.md +37 -0
- data/bin/poc/config.ru +66 -0
- data/bin/poc/gemfile +1 -0
- data/bin/poc/www/index.html +57 -0
- data/bin/raw-rbhttp +35 -0
- data/bin/raw_broadcast +66 -0
- data/bin/test_with_faye +40 -0
- data/bin/ws-broadcast +108 -0
- data/bin/ws-echo +108 -0
- data/exe/iodine +59 -0
- data/ext/iodine/base64.c +264 -0
- data/ext/iodine/base64.h +72 -0
- data/ext/iodine/bscrypt-common.h +109 -0
- data/ext/iodine/bscrypt.h +49 -0
- data/ext/iodine/extconf.rb +41 -0
- data/ext/iodine/hex.c +123 -0
- data/ext/iodine/hex.h +70 -0
- data/ext/iodine/http.c +200 -0
- data/ext/iodine/http.h +128 -0
- data/ext/iodine/http1.c +402 -0
- data/ext/iodine/http1.h +56 -0
- data/ext/iodine/http1_simple_parser.c +473 -0
- data/ext/iodine/http1_simple_parser.h +59 -0
- data/ext/iodine/http_request.h +128 -0
- data/ext/iodine/http_response.c +1606 -0
- data/ext/iodine/http_response.h +393 -0
- data/ext/iodine/http_response_http1.h +374 -0
- data/ext/iodine/iodine_core.c +641 -0
- data/ext/iodine/iodine_core.h +70 -0
- data/ext/iodine/iodine_http.c +615 -0
- data/ext/iodine/iodine_http.h +19 -0
- data/ext/iodine/iodine_websocket.c +430 -0
- data/ext/iodine/iodine_websocket.h +21 -0
- data/ext/iodine/libasync.c +552 -0
- data/ext/iodine/libasync.h +117 -0
- data/ext/iodine/libreact.c +347 -0
- data/ext/iodine/libreact.h +244 -0
- data/ext/iodine/libserver.c +912 -0
- data/ext/iodine/libserver.h +435 -0
- data/ext/iodine/libsock.c +950 -0
- data/ext/iodine/libsock.h +478 -0
- data/ext/iodine/misc.c +181 -0
- data/ext/iodine/misc.h +76 -0
- data/ext/iodine/random.c +193 -0
- data/ext/iodine/random.h +48 -0
- data/ext/iodine/rb-call.c +127 -0
- data/ext/iodine/rb-call.h +60 -0
- data/ext/iodine/rb-libasync.h +79 -0
- data/ext/iodine/rb-rack-io.c +389 -0
- data/ext/iodine/rb-rack-io.h +17 -0
- data/ext/iodine/rb-registry.c +213 -0
- data/ext/iodine/rb-registry.h +33 -0
- data/ext/iodine/sha1.c +359 -0
- data/ext/iodine/sha1.h +85 -0
- data/ext/iodine/sha2.c +825 -0
- data/ext/iodine/sha2.h +138 -0
- data/ext/iodine/siphash.c +136 -0
- data/ext/iodine/siphash.h +15 -0
- data/ext/iodine/spnlock.h +235 -0
- data/ext/iodine/websockets.c +696 -0
- data/ext/iodine/websockets.h +120 -0
- data/ext/iodine/xor-crypt.c +189 -0
- data/ext/iodine/xor-crypt.h +107 -0
- data/iodine.gemspec +25 -18
- data/lib/iodine.rb +57 -58
- data/lib/iodine/http.rb +0 -189
- data/lib/iodine/protocol.rb +36 -245
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +145 -2
- metadata +115 -37
- data/bin/core_http_test +0 -51
- data/bin/em playground +0 -56
- data/bin/hello_world +0 -75
- data/bin/setup +0 -7
- data/lib/iodine/client.rb +0 -5
- data/lib/iodine/core.rb +0 -102
- data/lib/iodine/core_init.rb +0 -143
- data/lib/iodine/http/hpack.rb +0 -553
- data/lib/iodine/http/http1.rb +0 -251
- data/lib/iodine/http/http2.rb +0 -507
- data/lib/iodine/http/rack_support.rb +0 -108
- data/lib/iodine/http/request.rb +0 -462
- data/lib/iodine/http/response.rb +0 -474
- data/lib/iodine/http/session.rb +0 -143
- data/lib/iodine/http/websocket_client.rb +0 -335
- data/lib/iodine/http/websocket_handler.rb +0 -101
- data/lib/iodine/http/websockets.rb +0 -336
- data/lib/iodine/io.rb +0 -56
- data/lib/iodine/logging.rb +0 -46
- data/lib/iodine/settings.rb +0 -158
- data/lib/iodine/ssl_connector.rb +0 -48
- data/lib/iodine/timers.rb +0 -95
data/lib/iodine/logging.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
module Iodine
|
2
|
-
public
|
3
|
-
|
4
|
-
# Gets the logging object and allows you to call logging methods (i.e. `Iodine.log.info "Running"`).
|
5
|
-
def logger
|
6
|
-
@logger
|
7
|
-
end
|
8
|
-
|
9
|
-
# logs info
|
10
|
-
# @return [String, Exception, Object] always returns the Object sent to the log.
|
11
|
-
def info data, &block
|
12
|
-
@logger.info data, &block if @logger
|
13
|
-
data
|
14
|
-
end
|
15
|
-
# logs debug info
|
16
|
-
# @return [String, Exception, Object] always returns the Object sent to the log.
|
17
|
-
def debug data, &block
|
18
|
-
@logger.debug data, &block if @logger
|
19
|
-
data
|
20
|
-
end
|
21
|
-
# logs warning
|
22
|
-
# @return [String, Exception, Object] always returns the Object sent to the log.
|
23
|
-
def warn data, &block
|
24
|
-
@logger.warn data, &block if @logger
|
25
|
-
data
|
26
|
-
end
|
27
|
-
# logs errors
|
28
|
-
# @return [String, Exception, Object] always returns the Object sent to the log.
|
29
|
-
def error data, &block
|
30
|
-
@logger.error data, &block if @logger
|
31
|
-
data
|
32
|
-
end
|
33
|
-
# logs a fatal error
|
34
|
-
# @return [String, Exception, Object] always returns the Object sent to the log.
|
35
|
-
def fatal data, &block
|
36
|
-
@logger.fatal data, &block if @logger
|
37
|
-
data
|
38
|
-
end
|
39
|
-
# logs a raw text
|
40
|
-
# @return [String] always returns the Object sent to the log.
|
41
|
-
def log raw_text
|
42
|
-
@logger << raw_text if @logger
|
43
|
-
raw_text
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
data/lib/iodine/settings.rb
DELETED
@@ -1,158 +0,0 @@
|
|
1
|
-
module Iodine
|
2
|
-
public
|
3
|
-
|
4
|
-
#######################
|
5
|
-
## Settings - methods that change the way Iodine behaves should go here.
|
6
|
-
|
7
|
-
# Sets the logging object, which needs to act like `Logger`. The default logger is `Logger.new(STDOUT)`.
|
8
|
-
def logger= obj
|
9
|
-
@logger = obj
|
10
|
-
end
|
11
|
-
|
12
|
-
# Sets the number of threads in the thread pool used for executing the tasks. Defaults to 1 thread.
|
13
|
-
def threads= count
|
14
|
-
@thread_count = count
|
15
|
-
end
|
16
|
-
|
17
|
-
# Gets the number of threads in the thread pool used for executing the tasks. Returns `nil` unless previously set or Iodine is running.
|
18
|
-
def threads
|
19
|
-
@thread_count
|
20
|
-
end
|
21
|
-
|
22
|
-
# Sets the number of processes that should be spawned in Server mode. Defaults to 1 (no processes spawned).
|
23
|
-
#
|
24
|
-
# * Forking (spwaning processes) might NOT work on all systems (forking is supported by Ruby on Unix systems).
|
25
|
-
# * Please make sure your code is safe to fork into different processes. For instance, Websocket broadcasting and unicasting won't work across different processes unless synced using an external Pub/Sub service/database such as Redis.
|
26
|
-
# * Forking might cause some tasks (such as time based tasks) to be performed twice (once for each process). This is a feature. To avoid duplicated task performance, use a task (delayed execution) to initialize any tasks you want to perform only once. While the initial time based tasks and the server are shared across processes, the initial task stack will only run on the main process.
|
27
|
-
def processes= count
|
28
|
-
@spawn_count = count
|
29
|
-
end
|
30
|
-
|
31
|
-
# Gets the number of processes that should be spawned in Server mode. Defaults to 1 (no processes spawned). See {Iodine#processes=}.
|
32
|
-
def processes
|
33
|
-
@spawn_count
|
34
|
-
end
|
35
|
-
|
36
|
-
# Sets Iodine's server port. Defaults to the command line `-p` argument, or the ENV['PORT'] or 3000 (in this order).
|
37
|
-
def port= port
|
38
|
-
@port = port
|
39
|
-
end
|
40
|
-
# Gets Iodine's server port. Defaults to the command line `-p` argument, or the ENV['PORT'] or 3000 (in this order).
|
41
|
-
def port
|
42
|
-
@port
|
43
|
-
end
|
44
|
-
# Sets the IP binding address. Defaults to the command line `-ip` argument, or the ENV['IP'] or 0.0.0.0 (in this order).
|
45
|
-
def bind= address
|
46
|
-
@bind = address
|
47
|
-
end
|
48
|
-
# Gets the IP binding address. Defaults to the command line `-ip` argument, or the ENV['IP'] or 0.0.0.0 (in this order).
|
49
|
-
def bind
|
50
|
-
@bind
|
51
|
-
end
|
52
|
-
|
53
|
-
# Sets the Protocol the Iodine Server will use. Should be a child of {Iodine::Protocol}. Defaults to nil (no server).
|
54
|
-
#
|
55
|
-
# If the protocol passed does NOT inherit from {Iodine::Protocol}, Iodine will cycle without initiating a server until stopped (TimedEvent mode).
|
56
|
-
def protocol= protocol
|
57
|
-
@stop = protocol ? false : true
|
58
|
-
@protocol = protocol
|
59
|
-
end
|
60
|
-
# Returns the cutrently active Iodine protocol (if exists).
|
61
|
-
def protocol
|
62
|
-
@protocol
|
63
|
-
end
|
64
|
-
|
65
|
-
# Sets the SSL flag, so that Iodine will require that new connection be encrypted.
|
66
|
-
# Defaults to false unless the `ssl` command line flag is present.
|
67
|
-
def ssl= required
|
68
|
-
@ssl = required && true
|
69
|
-
end
|
70
|
-
# Returns true if Iodine will require that new connection be encrypted.
|
71
|
-
def ssl
|
72
|
-
@ssl
|
73
|
-
end
|
74
|
-
|
75
|
-
# Sets the SSL Context to be used when using an encrypted connection. Defaults to a self signed certificate and no verification.
|
76
|
-
#
|
77
|
-
# Manually setting the context will automatically set the SSL flag,
|
78
|
-
# so that Iodine will require encryption for new incoming connections.
|
79
|
-
def ssl_context= context
|
80
|
-
@ssl = true
|
81
|
-
@ssl_context = context
|
82
|
-
end
|
83
|
-
|
84
|
-
# Gets the SSL Context to be used when using an encrypted connection.
|
85
|
-
def ssl_context
|
86
|
-
@ssl_context ||= init_ssl_context
|
87
|
-
end
|
88
|
-
|
89
|
-
# Sets the an SSL Protocol Hash (`'name' => Protocol`), allowing dynamic Protocol Negotiation.
|
90
|
-
# At the moment only NPN is supported. ALPN support should be established in a future release.
|
91
|
-
#
|
92
|
-
# * please notice that using allowing dynamic Protocol Negotiation could cause unexpected protocol choices when attempting to implement Opportunistic Encryption with {Iodine::SSLConnector}.
|
93
|
-
def ssl_protocols= protocol_hash
|
94
|
-
raise TypeError, "Iodine.ssl_protocols should be a Hash with Strings for keys (protocol identifiers) and Classes as values (Protocol classes)." unless protocol_hash.is_a?(Hash)
|
95
|
-
@ssl = true
|
96
|
-
ssl_context.npn_protocols = protocol_hash.keys
|
97
|
-
@ssl_protocols = protocol_hash
|
98
|
-
end
|
99
|
-
|
100
|
-
# Gets the SSL Protocol Hash used for
|
101
|
-
def ssl_protocols
|
102
|
-
@ssl_protocols
|
103
|
-
end
|
104
|
-
|
105
|
-
|
106
|
-
protected
|
107
|
-
|
108
|
-
#initializes a default SSLContext
|
109
|
-
def init_ssl_context
|
110
|
-
ssl_context = OpenSSL::SSL::SSLContext.new
|
111
|
-
ssl_context.set_params verify_mode: OpenSSL::SSL::VERIFY_NONE
|
112
|
-
ssl_context.cert_store = OpenSSL::X509::Store.new
|
113
|
-
ssl_context.cert_store.set_default_paths
|
114
|
-
ssl_context.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL #SESSION_CACHE_OFF
|
115
|
-
ssl_context.cert, ssl_context.key = create_cert
|
116
|
-
ssl_context
|
117
|
-
end
|
118
|
-
|
119
|
-
#creates a self-signed certificate
|
120
|
-
def create_cert bits=2048, cn=nil, comment='a self signed certificate for when we only need encryption and no more.'
|
121
|
-
unless cn
|
122
|
-
host_name = Socket::gethostbyname(Socket::gethostname)[0].split('.')
|
123
|
-
cn = String.new
|
124
|
-
host_name.each {|n| cn << "/DC=#{n}"}
|
125
|
-
cn << "/CN=Iodine.#{host_name.join('.')}"
|
126
|
-
end
|
127
|
-
# cn ||= "CN=#{Socket::gethostbyname(Socket::gethostname)[0] rescue Socket::gethostname}"
|
128
|
-
|
129
|
-
time = Time.now
|
130
|
-
rsa = OpenSSL::PKey::RSA.new(bits)
|
131
|
-
cert = OpenSSL::X509::Certificate.new
|
132
|
-
cert.version = 2
|
133
|
-
cert.serial = 1
|
134
|
-
name = OpenSSL::X509::Name.parse(cn)
|
135
|
-
cert.subject = name
|
136
|
-
cert.issuer = name
|
137
|
-
cert.not_before = time
|
138
|
-
cert.not_after = time + (365*24*60*60)
|
139
|
-
cert.public_key = rsa.public_key
|
140
|
-
|
141
|
-
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
142
|
-
ef.issuer_certificate = cert
|
143
|
-
cert.extensions = [
|
144
|
-
ef.create_extension("basicConstraints","CA:FALSE"),
|
145
|
-
ef.create_extension("keyUsage", "keyEncipherment"),
|
146
|
-
ef.create_extension("subjectKeyIdentifier", "hash"),
|
147
|
-
ef.create_extension("extendedKeyUsage", "serverAuth"),
|
148
|
-
ef.create_extension("nsComment", comment),
|
149
|
-
]
|
150
|
-
aki = ef.create_extension("authorityKeyIdentifier",
|
151
|
-
"keyid:always,issuer:always")
|
152
|
-
cert.add_extension(aki)
|
153
|
-
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
154
|
-
|
155
|
-
return cert, rsa
|
156
|
-
end
|
157
|
-
|
158
|
-
end
|
data/lib/iodine/ssl_connector.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
module Iodine
|
2
|
-
|
3
|
-
# This is a mini-protocol used only to implement the SSL Handshake in a non-blocking manner,
|
4
|
-
# allowing for a hardcoded timeout (which you can monkey patch) of 3 seconds.
|
5
|
-
class SSLConnector < Protocol
|
6
|
-
def initialize io, protocol, options = nil
|
7
|
-
@protocol = protocol
|
8
|
-
@options = options
|
9
|
-
super(io)
|
10
|
-
end
|
11
|
-
TIMEOUT = 3 # hardcoded SSL/TLS handshake timeout
|
12
|
-
def on_open
|
13
|
-
set_timeout TIMEOUT
|
14
|
-
@ssl_socket = ::OpenSSL::SSL::SSLSocket.new(@io, ::Iodine.ssl_context)
|
15
|
-
@ssl_socket.sync_close = true
|
16
|
-
end
|
17
|
-
|
18
|
-
# atempt an SSL Handshale
|
19
|
-
def call
|
20
|
-
return if @locker.locked?
|
21
|
-
return unless @locker.try_lock
|
22
|
-
begin
|
23
|
-
@ssl_socket.accept_nonblock
|
24
|
-
rescue ::IO::WaitReadable, ::IO::WaitWritable
|
25
|
-
return
|
26
|
-
rescue ::OpenSSL::SSL::SSLError
|
27
|
-
@e = ::OpenSSL::SSL::SSLError.new "Self-signed Certificate?".freeze
|
28
|
-
close
|
29
|
-
return
|
30
|
-
rescue => e
|
31
|
-
::Iodine.warn "SSL Handshake failed with: #{e.message}".freeze
|
32
|
-
@e = e
|
33
|
-
close
|
34
|
-
return
|
35
|
-
ensure
|
36
|
-
@locker.unlock
|
37
|
-
end
|
38
|
-
( (@ssl_socket.npn_protocol && ::Iodine.ssl_protocols[@ssl_socket.npn_protocol]) || @protocol).new @ssl_socket, @options
|
39
|
-
end
|
40
|
-
def on_close
|
41
|
-
# inform
|
42
|
-
::Iodine.warn "SSL Handshake #{@e ? "failed with: #{@e.message} (#{@e.class.name})" : 'timed-out.'}".freeze
|
43
|
-
# the core @io is already closed, but let's make sure the SSL object is closed as well.
|
44
|
-
@ssl_socket.close unless @ssl_socket.closed?
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
data/lib/iodine/timers.rb
DELETED
@@ -1,95 +0,0 @@
|
|
1
|
-
module Iodine
|
2
|
-
|
3
|
-
#######################
|
4
|
-
## Timers
|
5
|
-
|
6
|
-
|
7
|
-
# Every timed event is a member of the TimedEvent class and responds to it's methods.
|
8
|
-
class TimedEvent
|
9
|
-
|
10
|
-
# Sets/gets how often a timed event repeats, in seconds.
|
11
|
-
attr_accessor :interval
|
12
|
-
# Sets/gets how many times a timed event repeats.
|
13
|
-
# If set to false or -1, the timed event will repead until the application quits.
|
14
|
-
attr_accessor :repeat_limit
|
15
|
-
# Allows you to acess or change the timer's Proc object.
|
16
|
-
attr_accessor :job
|
17
|
-
|
18
|
-
# Initialize a timed event.
|
19
|
-
def initialize reactor, interval, repeat_limit = -1, args=[], job=nil
|
20
|
-
@reactor = reactor
|
21
|
-
@interval = interval
|
22
|
-
@repeat_limit = repeat_limit ? repeat_limit.to_i : -1
|
23
|
-
@job = job || (Proc.new { stop! })
|
24
|
-
@next = @reactor.time + interval
|
25
|
-
args << self
|
26
|
-
@args = args
|
27
|
-
end
|
28
|
-
|
29
|
-
# stops a timed event.
|
30
|
-
# @return [Iodine::TimedEvent] returns the TimedEvent object.
|
31
|
-
def stop!
|
32
|
-
@repeat_limit = 0
|
33
|
-
@next = @reactor.time
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
# Returns true if the timer is finished.
|
38
|
-
#
|
39
|
-
# If the timed event is due, this method will also add the event to the queue.
|
40
|
-
# @return [true, false]
|
41
|
-
def done?
|
42
|
-
return false unless @next <= @reactor.time
|
43
|
-
return true if @repeat_limit == 0
|
44
|
-
@repeat_limit -= 1 if @repeat_limit.to_i > 0
|
45
|
-
@reactor.run(*@args, &@job)
|
46
|
-
@next = @reactor.time + @interval
|
47
|
-
@repeat_limit == 0
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
public
|
52
|
-
|
53
|
-
# pushes a timed event to the timers's stack
|
54
|
-
#
|
55
|
-
# accepts:
|
56
|
-
# seconds:: the minimal amount of seconds to wait before calling the handler's `call` method.
|
57
|
-
# *arg:: any arguments that will be passed to the handler's `call` method.
|
58
|
-
# &block:: the block to execute.
|
59
|
-
#
|
60
|
-
# A block is required.
|
61
|
-
#
|
62
|
-
# On top of the arguments passed to the `run_after` method, the timer object will be passed as the last agrument to the receiving block.
|
63
|
-
#
|
64
|
-
# Timed event's time of execution is dependant on the workload and continuous uptime of the process (timed events AREN'T persistent).
|
65
|
-
#
|
66
|
-
# @return [Iodine::TimedEvent] returns the new TimedEvent object.
|
67
|
-
def run_after seconds, *args, &block
|
68
|
-
timed_job seconds, 1, args, block
|
69
|
-
end
|
70
|
-
|
71
|
-
# pushes a repeated timed event to the timers's stack
|
72
|
-
#
|
73
|
-
# accepts:
|
74
|
-
# seconds:: the minimal amount of seconds to wait before calling the handler's `call` method.
|
75
|
-
# *arg:: any arguments that will be passed to the handler's `call` method.
|
76
|
-
# &block:: the block to execute.
|
77
|
-
#
|
78
|
-
# A block is required.
|
79
|
-
#
|
80
|
-
# On top of the arguments passed to the `run_after` method, the timer object will be passed as the last agrument to the receiving block.
|
81
|
-
#
|
82
|
-
# Timed event's time of execution is dependant on the workload and continuous uptime of the process (timed events AREN'T persistent unless you save and reload them yourself).
|
83
|
-
#
|
84
|
-
# @return [Iodine::TimedEvent] returns the new TimedEvent object.
|
85
|
-
def run_every seconds, *args, &block
|
86
|
-
timed_job seconds, -1, args, block
|
87
|
-
end
|
88
|
-
|
89
|
-
protected
|
90
|
-
|
91
|
-
# Creates a TimedEvent object and adds it to the Timers stack.
|
92
|
-
def timed_job seconds, limit = false, args = [], block = nil
|
93
|
-
@timer_locker.synchronize {@timers << TimedEvent.new(self, seconds, limit, args, block); @timers.last}
|
94
|
-
end
|
95
|
-
end
|