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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b5ee2e6d64a08ec88c75a4e0eaed1d15586310e8
4
- data.tar.gz: fe61017b3b92e43efb5cf1ca9331e5143940ec8c
3
+ metadata.gz: 52bb724586bb147b6db24a2a5c5ca7192ac27cc3
4
+ data.tar.gz: 685c1496be7ec7c13181910c9748d91814345ec0
5
5
  SHA512:
6
- metadata.gz: a9e83552a00e1799096ef2b0515ed417a18eab511c0460743a4f6f003613ae47114b55abe14ec0dd1243a9dd846032ad30f59b3786c71673192e504fa0a2ebed
7
- data.tar.gz: 40989499a5b70e09fb35dcd29ebcc8fd3326ff5b9e886ea7800b6e9f01c4ef01fd99b587ebff92aad9ff03d7d5e5ada3489bc18c9887864be4148e2263cdc3eb
6
+ metadata.gz: 72420d26e15261d76f196f4d9df9262b675747c468e3b9119adf68ec2bc3e0e5d6a4e57c48421731fb9263c42d542dfceb66c765176cfc4566730bfb8f54f3be
7
+ data.tar.gz: 535428c459b044ed1ab7ea3caccc4540e01acb32fdb7d57e910ba61f5b87162796052cd494b32ea7274a71b5f0d863a5f5ab7885faed60f32282c26d9b2b3743
data/.gitignore CHANGED
@@ -7,3 +7,7 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+
11
+ .ruby-version
12
+
13
+ *.bundle
@@ -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:
@@ -21,7 +21,10 @@ require "iodine/http"
21
21
 
22
22
  # Iodine.processes = 4
23
23
 
24
- Iodine::Http.on_http { "Hello World!" }
24
+ HELLO = "Hello World!"
25
+ Iodine::Http.on_http { HELLO }
26
+
27
+ Iodine.logger = nil
25
28
 
26
29
 
27
30
  class WSChatServer < Iodine::Http::WebsocketHandler
@@ -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{ IOdine makes writing evented server applications easy to write. }
13
- spec.description = %q{ IOdine is a super easy way to write network services and tasking scripts.}
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
@@ -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}#{ ' to SSL/TLS connections.' if @ssl}\n"
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
@@ -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] = Time.now
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
- until request[:body_complete] && request[:headers_complete]
53
- if request['transfer-coding'.freeze] == 'chunked'.freeze
54
- # ad mid chunk logic here
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
- elsif request['content-length'.freeze] && request['content-length'.freeze].to_i != 0
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
- elsif request['content-type'.freeze]
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
- end
85
- if request[:body] && request[:body].size > ::Iodine::Http.max_body_size
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
@@ -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] ||= Time.now
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
@@ -43,9 +43,4 @@ module Iodine
43
43
  raw_text
44
44
  end
45
45
 
46
-
47
- protected
48
-
49
- @logger = Logger.new(STDOUT)
50
-
51
46
  end
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = "0.1.20"
2
+ VERSION = "0.1.21"
3
3
  end
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.20
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: 2015-12-10 00:00:00.000000000 Z
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: " IOdine is a super easy way to write network services and tasking scripts."
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: IOdine makes writing evented server applications easy to write.
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: