iodine 0.1.20 → 0.1.21
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 +4 -0
- data/CHANGELOG.md +10 -0
- data/README.md +17 -0
- data/bin/hello_world +4 -1
- data/iodine.gemspec +10 -2
- data/lib/iodine/core_init.rb +3 -3
- data/lib/iodine/http/http1.rb +40 -23
- data/lib/iodine/http/http2.rb +5 -4
- data/lib/iodine/logging.rb +0 -5
- data/lib/iodine/version.rb +1 -1
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52bb724586bb147b6db24a2a5c5ca7192ac27cc3
|
4
|
+
data.tar.gz: 685c1496be7ec7c13181910c9748d91814345ec0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72420d26e15261d76f196f4d9df9262b675747c468e3b9119adf68ec2bc3e0e5d6a4e57c48421731fb9263c42d542dfceb66c765176cfc4566730bfb8f54f3be
|
7
|
+
data.tar.gz: 535428c459b044ed1ab7ea3caccc4540e01acb32fdb7d57e910ba61f5b87162796052cd494b32ea7274a71b5f0d863a5f5ab7885faed60f32282c26d9b2b3743
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -8,6 +8,16 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
8
8
|
|
9
9
|
***
|
10
10
|
|
11
|
+
Change log v.0.1.21
|
12
|
+
|
13
|
+
**Optimization**: Minor optimizations. i.e. - creates 1 less Time object per request (The logging still creates a Time object unless disabled using `Iodine.logger = nil`).
|
14
|
+
|
15
|
+
**Security**: Http/1 now reviews the Body's size as it grows (similar to Http/2), mitigating any potential attacks related to the size of the data sent.
|
16
|
+
|
17
|
+
**Logs**: Log the number of threads utilized when starting up the server.
|
18
|
+
|
19
|
+
***
|
20
|
+
|
11
21
|
Change log v.0.1.20
|
12
22
|
|
13
23
|
**Update/Fix**: Updated the `x-forwarded-for` header recognition, to accommodate an Array formatting sometimes used (`["ip1", "ip2", ...]`).
|
data/README.md
CHANGED
@@ -11,6 +11,23 @@ To use Iodine, you just set up your tasks - including a single server, if you wa
|
|
11
11
|
|
12
12
|
Iodine is used by [the Plezi Ruby framework for real-time applications](http://www.plezi.io).
|
13
13
|
|
14
|
+
## Notice! and limitations...
|
15
|
+
|
16
|
+
Iodine 0.1.x is implemented in Ruby, using a `select` system call.
|
17
|
+
|
18
|
+
`select` is limited to 1024 open connections! after 1024 connection, `select` could cause "undefined behavior", including a possible "crash"... sometimes it's not important... some hosting environments only allow 1024 connections anyway... EventMachine crashes on my system after 1024 connections too...
|
19
|
+
|
20
|
+
...but websockets are connection hungry beasts.
|
21
|
+
|
22
|
+
Hence, a move to kqueue/epoll is required.
|
23
|
+
|
24
|
+
Iodine 0.2.x will include (hopefully), a kpoll / epoll implementation for Linux/BSD server environments, such as Heroku dynos (which run a flavor of unbuto 14).
|
25
|
+
|
26
|
+
However, it is unlikely that Iodine's beautiful API could survive this shift.
|
27
|
+
|
28
|
+
The 0.1.x API should be considered deprecated while a new API is under development (assuming I will manage to link some decent C code to Ruby)... I satrted out by displiking EventMachine's API, now it seems they might not have had a choice.
|
29
|
+
|
30
|
+
|
14
31
|
## Installation
|
15
32
|
|
16
33
|
Add this line to your application's Gemfile:
|
data/bin/hello_world
CHANGED
data/iodine.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Boaz Segev"]
|
10
10
|
spec.email = ["Boaz@2be.co.il"]
|
11
11
|
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.description = %q{
|
12
|
+
spec.summary = %q{ The Iodine v.0.1.X line and API is deprecated and will not be supported after v. 0.2.0 is released. }
|
13
|
+
spec.description = %q{ The Iodine v.0.1.X line and API is deprecated and will not be supported after v. 0.2.0 is released. }
|
14
14
|
spec.homepage = "https://github.com/boazsegev/iodine"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
@@ -30,4 +30,12 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency "bundler", "~> 1.10"
|
31
31
|
spec.add_development_dependency "rake", "~> 10.0"
|
32
32
|
spec.add_development_dependency "minitest"
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
spec.post_install_message = "The Iodine 0.1.x API is now deprecated.\n"+
|
37
|
+
"Version 0.2.x will include a drastic change and it WILL break existing code.\n" +
|
38
|
+
"DON'T UPGRADE BEYOND THIS POINT UNLESS YOU'RE PREPARED FOR A HUGE CANGE.\n" +
|
39
|
+
"Future version of Iodine will be written in C and require a Linux/Unix machine."
|
40
|
+
|
33
41
|
end
|
data/lib/iodine/core_init.rb
CHANGED
@@ -103,7 +103,7 @@ module Iodine
|
|
103
103
|
@server = ::TCPServer.new(@bind, @port)
|
104
104
|
rescue => e
|
105
105
|
fatal e.message
|
106
|
-
fatal "Running existing tasks and exiting."
|
106
|
+
fatal "Running existing tasks with #{@thread_count} thread(s) and exiting."
|
107
107
|
@queue << @reactor
|
108
108
|
Process.kill("INT", 0)
|
109
109
|
next
|
@@ -113,7 +113,7 @@ module Iodine
|
|
113
113
|
log "Stopped listening to port #{@port}.\n"
|
114
114
|
end
|
115
115
|
::Iodine::Base::Listener.accept(@server, false)
|
116
|
-
log "Iodine #{VERSION} is listening on port #{@port}#{ '
|
116
|
+
log "Iodine #{VERSION} is listening on port #{@port}#{ ' (SSL/TLS)' if @ssl} with #{@thread_count} thread(s).\n"
|
117
117
|
if @spawn_count && @spawn_count.to_i > 1 && Process.respond_to?(:fork)
|
118
118
|
log "Server will run using #{@spawn_count.to_i} processes - Spawning #{@spawn_count.to_i - 1 } more processes.\n"
|
119
119
|
(@spawn_count.to_i - 1).times do
|
@@ -129,7 +129,7 @@ module Iodine
|
|
129
129
|
end
|
130
130
|
log "Press ^C to stop the server.\n"
|
131
131
|
else
|
132
|
-
log "#{self == Iodine ? 'Iodine' : "#{self.name} (Iodine)"} #{VERSION} is running.\n"
|
132
|
+
log "#{self == Iodine ? 'Iodine' : "#{self.name} (Iodine)"} #{VERSION} is running with #{@thread_count} thread(s).\n"
|
133
133
|
log "Press ^C to stop the cycling.\n"
|
134
134
|
end
|
135
135
|
on_shutdown do
|
data/lib/iodine/http/http1.rb
CHANGED
@@ -4,7 +4,6 @@ module Iodine
|
|
4
4
|
def on_open
|
5
5
|
set_timeout 1
|
6
6
|
@refuse_requests = false
|
7
|
-
@bytes_sent = 0
|
8
7
|
@parser = {}
|
9
8
|
end
|
10
9
|
def on_message data
|
@@ -25,15 +24,24 @@ module Iodine
|
|
25
24
|
request[:method], request[:query], request[:version] = l.split(/[\s]+/.freeze, 3)
|
26
25
|
return (Iodine.warn('Http1 Protocol Error, closing connection.'.freeze, l, request) && close) unless request[:method] =~ HTTP_METHODS_REGEXP
|
27
26
|
request[:version] = (request[:version] || '1.1'.freeze).match(/[\d\.]+/.freeze)[0]
|
28
|
-
request[:time_recieved] =
|
27
|
+
request[:time_recieved] = Iodine.time
|
29
28
|
end
|
30
29
|
until request[:headers_complete] || (l = data.gets).nil?
|
30
|
+
# if l.bytesize > 16_384
|
31
|
+
# write "HTTP/1.0 413 Entity Too Large\r\ncontent-length: 16\r\n\r\nEntity Too Large".freeze
|
32
|
+
# Iodine.warn "Http/1 Header data too large, closing connection.".freeze
|
33
|
+
# return close
|
34
|
+
# end
|
31
35
|
if l.include? ':'.freeze
|
32
36
|
# n = l.slice!(0, l.index(':')); l.slice! 0
|
33
37
|
# n.strip! ; n.downcase!; n.freeze
|
34
38
|
# request[n] ? (request[n].is_a?(Array) ? (request[n] << l) : request[n] = [request[n], l ]) : (request[n] = l)
|
35
39
|
request[:headers_size] ||= 0
|
36
40
|
request[:headers_size] += l.bytesize
|
41
|
+
if request.length > 2096 || request[:headers_size] > 262_144
|
42
|
+
write "HTTP/1.0 431 Request Header Fields Too Large\r\ncontent-length: 31\r\n\r\nRequest Header Fields Too Large".freeze
|
43
|
+
return (Iodine.warn('Http1 header overloading, closing connection.'.freeze) && close)
|
44
|
+
end
|
37
45
|
l = l.strip.split(/:[\s]?/.freeze, 2)
|
38
46
|
l[0].strip! ; l[0].downcase!;
|
39
47
|
request[l[0]] ? (request[l[0]].is_a?(Array) ? (request[l[0]] << l[1]) : request[l[0]] = [request[l[0]], l[1] ]) : (request[l[0]] = l[1])
|
@@ -44,14 +52,11 @@ module Iodine
|
|
44
52
|
Iodine.warn 'Protocol Error, closing connection.'.freeze
|
45
53
|
return close
|
46
54
|
end
|
47
|
-
if request.length > 2096 || request[:headers_size] > 262_144
|
48
|
-
write "HTTP/1.0 431 Request Header Fields Too Large\r\ncontent-length: 31\r\n\r\nRequest Header Fields Too Large".freeze
|
49
|
-
return (Iodine.warn('Http1 header overloading, closing connection.'.freeze) && close)
|
50
|
-
end
|
51
55
|
end
|
52
|
-
|
53
|
-
|
54
|
-
|
56
|
+
next unless request[:headers_complete]
|
57
|
+
if request['transfer-coding'.freeze] == 'chunked'.freeze
|
58
|
+
until request[:body_complete]
|
59
|
+
# add mid chunk logic here
|
55
60
|
if @parser[:length].to_i == 0
|
56
61
|
chunk = data.gets
|
57
62
|
return false unless chunk
|
@@ -66,27 +71,28 @@ module Iodine
|
|
66
71
|
request[:body] << chunk
|
67
72
|
@parser[:act_length] += chunk.bytesize
|
68
73
|
(@parser[:act_length] = @parser[:length] = 0) && (data.gets) if @parser[:act_length] >= @parser[:length]
|
69
|
-
|
74
|
+
return if bad_body_size?
|
75
|
+
end
|
76
|
+
elsif request['content-length'.freeze] && request['content-length'.freeze].to_i != 0
|
77
|
+
until request[:body_complete]
|
70
78
|
request[:body] ||= Tempfile.new('iodine'.freeze, :encoding => 'binary'.freeze)
|
71
79
|
packet = data.read(request['content-length'.freeze].to_i - request[:body].size)
|
72
80
|
return false unless packet
|
73
81
|
request[:body] << packet
|
82
|
+
return if bad_body_size?
|
74
83
|
request[:body_complete] = true if request['content-length'.freeze].to_i - request[:body].size <= 0
|
75
|
-
|
84
|
+
end
|
85
|
+
elsif request['content-type'.freeze]
|
86
|
+
until request[:body_complete]
|
76
87
|
Iodine.warn 'Body type protocol error.'.freeze unless request[:body]
|
77
88
|
line = data.gets
|
78
89
|
return false unless line
|
79
90
|
(request[:body] ||= Tempfile.new('iodine'.freeze, :encoding => 'binary'.freeze) ) << line
|
91
|
+
return if bad_body_size?
|
80
92
|
request[:body_complete] = true if line =~ EOHEADERS
|
81
|
-
else
|
82
|
-
request[:body_complete] = true
|
83
93
|
end
|
84
|
-
|
85
|
-
|
86
|
-
Iodine.warn("Http1 message body too big, closing connection (Iodine::Http.max_body_size == #{::Iodine::Http.max_body_size} bytes) - #{request[:body].size} bytes.")
|
87
|
-
request.delete(:body).tap {|f| f.close unless f.closed? } rescue false
|
88
|
-
write "HTTP/1.0 413 Payload Too Large\r\ncontent-length: 17\r\n\r\nPayload Too Large".freeze
|
89
|
-
return close
|
94
|
+
else
|
95
|
+
request[:body_complete] = true
|
90
96
|
end
|
91
97
|
(@request = ::Iodine::Http::Request.new(self)) && ( (::Iodine::Http.http2 && ::Iodine::Http::Http2.handshake(request, self, data)) || dispatch(request, data) ) if request.delete :body_complete
|
92
98
|
end
|
@@ -219,13 +225,24 @@ module Iodine
|
|
219
225
|
end
|
220
226
|
|
221
227
|
def log_finished response
|
222
|
-
@bytes_sent = 0
|
223
228
|
request = response.request
|
224
229
|
return if Iodine.logger.nil? || request[:no_log]
|
225
230
|
t_n = Time.now
|
226
|
-
(Thread.current[:log_buffer] ||= String.new).clear
|
227
|
-
Thread.current[:log_buffer] << "#{request[:client_ip]} [#{t_n.utc}] \"#{request[:method]} #{request[:original_path]} #{request[:scheme]}\/#{request[:version]}\" #{response.status} #{response.bytes_written.to_s} #{((t_n - request[:time_recieved])*1000).round(2)}ms\n"
|
228
|
-
Iodine.log(Thread.current[:log_buffer])
|
231
|
+
# (Thread.current[:log_buffer] ||= String.new).clear
|
232
|
+
# Thread.current[:log_buffer] << "#{request[:client_ip]} [#{t_n.utc}] \"#{request[:method]} #{request[:original_path]} #{request[:scheme]}\/#{request[:version]}\" #{response.status} #{response.bytes_written.to_s} #{((t_n - request[:time_recieved])*1000).round(2)}ms\n"
|
233
|
+
# Iodine.log(Thread.current[:log_buffer])
|
234
|
+
Iodine.log("#{request[:client_ip]} [#{t_n.utc}] \"#{request[:method]} #{request[:original_path]} #{request[:scheme]}\/#{request[:version]}\" #{response.status} #{response.bytes_written.to_s} #{((t_n - request[:time_recieved])*1000).round(2)}ms\n").clear
|
235
|
+
end
|
236
|
+
|
237
|
+
def bad_body_size?
|
238
|
+
request = @request
|
239
|
+
if request[:body] && request[:body].size > ::Iodine::Http.max_body_size
|
240
|
+
Iodine.warn("Http1 message body too big, closing connection (Iodine::Http.max_body_size == #{::Iodine::Http.max_body_size} bytes) - #{request[:body].size} bytes.")
|
241
|
+
request.delete(:body).tap {|f| f.close unless f.closed? } rescue false
|
242
|
+
write "HTTP/1.0 413 Payload Too Large\r\ncontent-length: 17\r\n\r\nPayload Too Large".freeze
|
243
|
+
return true
|
244
|
+
end
|
245
|
+
false
|
229
246
|
end
|
230
247
|
end
|
231
248
|
end
|
data/lib/iodine/http/http2.rb
CHANGED
@@ -139,9 +139,10 @@ module Iodine
|
|
139
139
|
request = response.request
|
140
140
|
return if Iodine.logger.nil? || request[:no_log]
|
141
141
|
t_n = Time.now
|
142
|
-
(Thread.current[:log_buffer] ||= String.new).clear
|
143
|
-
Thread.current[:log_buffer] << "#{request[:client_ip]} [#{t_n.utc}] #{request[:method]} #{request[:original_path]} #{request[:scheme]}\/2 #{response.status} #{response.bytes_written.to_s} #{((t_n - request[:time_recieved])*1000).round(2)}ms\n"
|
144
|
-
Iodine.log Thread.current[:log_buffer]
|
142
|
+
# (Thread.current[:log_buffer] ||= String.new).clear
|
143
|
+
# Thread.current[:log_buffer] << "#{request[:client_ip]} [#{t_n.utc}] #{request[:method]} #{request[:original_path]} #{request[:scheme]}\/2 #{response.status} #{response.bytes_written.to_s} #{((t_n - request[:time_recieved])*1000).round(2)}ms\n"
|
144
|
+
# Iodine.log Thread.current[:log_buffer]
|
145
|
+
Iodine.log("#{request[:client_ip]} [#{t_n.utc}] #{request[:method]} #{request[:original_path]} #{request[:scheme]}\/2 #{response.status} #{response.bytes_written.to_s} #{((t_n - request[:time_recieved])*1000).round(2)}ms\n").clear
|
145
146
|
end
|
146
147
|
|
147
148
|
def send_headers response, request
|
@@ -315,7 +316,7 @@ module Iodine
|
|
315
316
|
|
316
317
|
frame[:stream].update @hpack.decode(@header_buffer) # this is where HPACK comes in
|
317
318
|
return (Iodine.warn('Http2 header overloading, closing connection.') && connection_error( ENHANCE_YOUR_CALM ) ) if frame[:stream].length > 2096
|
318
|
-
frame[:stream][:time_recieved] ||=
|
319
|
+
frame[:stream][:time_recieved] ||= Iodine.time
|
319
320
|
frame[:stream][:version] ||= '2'.freeze
|
320
321
|
|
321
322
|
process_request(@open_streams.delete frame[:sid]) if @header_end_stream
|
data/lib/iodine/logging.rb
CHANGED
data/lib/iodine/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iodine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,7 +52,8 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
-
description: "
|
55
|
+
description: " The Iodine v.0.1.X line and API is deprecated and will not be supported
|
56
|
+
after v. 0.2.0 is released. "
|
56
57
|
email:
|
57
58
|
- Boaz@2be.co.il
|
58
59
|
executables: []
|
@@ -101,7 +102,11 @@ licenses:
|
|
101
102
|
- MIT
|
102
103
|
metadata:
|
103
104
|
allowed_push_host: https://rubygems.org
|
104
|
-
post_install_message:
|
105
|
+
post_install_message: |-
|
106
|
+
The Iodine 0.1.x API is now deprecated.
|
107
|
+
Version 0.2.x will include a drastic change and it WILL break existing code.
|
108
|
+
DON'T UPGRADE BEYOND THIS POINT UNLESS YOU'RE PREPARED FOR A HUGE CANGE.
|
109
|
+
Future version of Iodine will be written in C and require a Linux/Unix machine.
|
105
110
|
rdoc_options: []
|
106
111
|
require_paths:
|
107
112
|
- lib
|
@@ -120,6 +125,6 @@ rubyforge_project:
|
|
120
125
|
rubygems_version: 2.4.5.1
|
121
126
|
signing_key:
|
122
127
|
specification_version: 4
|
123
|
-
summary:
|
128
|
+
summary: The Iodine v.0.1.X line and API is deprecated and will not be supported after
|
129
|
+
v. 0.2.0 is released.
|
124
130
|
test_files: []
|
125
|
-
has_rdoc:
|