iodine 0.1.15 → 0.1.16

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: 688611fe0ab9da4acb64bac423d6f72899e981a0
4
- data.tar.gz: afa9582b3fde67b3ea77aa7389d078cc00c762ba
3
+ metadata.gz: b4d5413250301e7bf147d2768d9989815d00ea67
4
+ data.tar.gz: a4225e75c91425af46c034a37db12fdfca468a3c
5
5
  SHA512:
6
- metadata.gz: acf6eb30f924bb79ed5026bfef62e4ee30ca09dd07b93a33fc4db8be8237da6f273ac8f9208622099a5c55c3a94894826e65baebdca4c8b87009254206ed4e1a
7
- data.tar.gz: 2d9ab314382fe82fa514cc5f38def28d79e39ff5e5c8e66277e972347a788481129f556aafa81bbf54ad0a3410664814844c91cc71876fe41b914e57d1fc3a08
6
+ metadata.gz: 8e41378d248d5607120b26d96c2b94ad85de20ced37e9ac2091afe4dd8c618e04ffe427a319cd70febae126bfcb79a3a33e7979d5ca291141fac1263a2b7399e
7
+ data.tar.gz: a6b209fc737a540af696e11c85a981fae392e83e46325e2b3b10dd6fcea9bbc111043313a3ae4af3c3ab7480092458b381074693aa293adfa69d2047b328ab57
@@ -8,6 +8,12 @@ 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.16
12
+
13
+ **Performance**: Http/1 and Http/2 connections now share and recycle their write buffer when while reading the response body and writing it to the IO. This (hopefuly) prevents excess `malloc` calls by the interperter.
14
+
15
+ ***
16
+
11
17
  Change log v.0.1.15
12
18
 
13
19
  **Update**: IO reactor will now update IO status even when tasks are pending. IO will still be read only when there are no more tasks to handle, but this allows chained tasks to relate to the updated IO status. i.e. this should improve websocket availability for broadcasting (delay from connection to availability might occure until IO is registered).
@@ -20,7 +26,7 @@ Change log v.0.1.14
20
26
 
21
27
  **Update**: the Response now supports `redirect_to` for both permanent and temporary redirection, with an optional `flash` cookie setup.
22
28
 
23
- **Performance**: the Protocol class now recycles the data string as a thread global socket buffer (different threads have different buffer strings), preventing excessice `malloc` called by the Ruby interpreter. To keep the `data` (in `on_message(data)`) past the `on_message` method's scope, make sure to duplicate it using `data.dup`, or the string's buffer will be recycled.
29
+ **Performance**: the Protocol class now recycles the data string as a thread global socket buffer (different threads have different buffer strings), preventing excessive `malloc` calls by the Ruby interpreter. To keep the `data` (in `on_message(data)`) past the `on_message` method's scope, be sure to duplicate it using `data.dup`, or the string's buffer will be recycled.
24
30
 
25
31
  ***
26
32
 
@@ -72,7 +72,7 @@ module Iodine
72
72
  def startup use_rescue = false, hide_message = false
73
73
  @force_running = true
74
74
  threads = []
75
- (@thread_count ||= 1).times { threads << Thread.new { Thread.current[:buffer] ||= String.new; cycle } }
75
+ (@thread_count ||= 1).times { threads << Thread.new { Thread.current[:buffer] ||= String.new; Thread.current[:write_buffer] ||= String.new; cycle } }
76
76
  unless @stop
77
77
  if use_rescue
78
78
  sleep rescue true
@@ -17,13 +17,13 @@ module Iodine
17
17
  unless request[:method]
18
18
  l = data.gets.strip
19
19
  if l.bytesize > 16_384
20
- write "HTTP/1.0 414 Request-URI Too Long\r\ncontent-length: 20\r\n\r\nRequest URI too Long"
21
- Iodine.warn "Http/1 URI too long, closing connection."
20
+ write "HTTP/1.0 414 Request-URI Too Long\r\ncontent-length: 20\r\n\r\nRequest URI too Long".freeze
21
+ Iodine.warn "Http/1 URI too long, closing connection.".freeze
22
22
  return close
23
23
  end
24
24
  next if l.empty?
25
25
  request[:method], request[:query], request[:version] = l.split(/[\s]+/.freeze, 3)
26
- return (Iodine.warn('Htt1 Protocol Error, closing connection.') && close) unless request[:method] =~ HTTP_METHODS_REGEXP
26
+ return (Iodine.warn('Htt1 Protocol Error, closing connection.'.freeze) && close) unless request[:method] =~ HTTP_METHODS_REGEXP
27
27
  request[:version] = (request[:version] || '1.1'.freeze).match(/[\d\.]+/.freeze)[0]
28
28
  request[:time_recieved] = Time.now
29
29
  end
@@ -41,12 +41,12 @@ module Iodine
41
41
  request[:headers_complete] = true
42
42
  else
43
43
  #protocol error
44
- Iodine.warn 'Protocol Error, closing connection.'
44
+ Iodine.warn 'Protocol Error, closing connection.'.freeze
45
45
  return close
46
46
  end
47
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"
49
- return (Iodine.warn('Http1 header overloading, closing connection.') && close)
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
50
  end
51
51
  end
52
52
  until request[:body_complete] && request[:headers_complete]
@@ -56,7 +56,7 @@ module Iodine
56
56
  chunk = data.gets
57
57
  return false unless chunk
58
58
  @parser[:length] = chunk.to_i(16)
59
- return (Iodine.warn('Protocol Error, closing connection.') && close) unless @parser[:length]
59
+ return (Iodine.warn('Protocol Error, closing connection.'.freeze) && close) unless @parser[:length]
60
60
  request[:body_complete] = true && break if @parser[:length] == 0
61
61
  @parser[:act_length] = 0
62
62
  request[:body] ||= Tempfile.new('iodine'.freeze, :encoding => 'binary'.freeze)
@@ -73,7 +73,7 @@ module Iodine
73
73
  request[:body] << packet
74
74
  request[:body_complete] = true if request['content-length'.freeze].to_i - request[:body].size <= 0
75
75
  elsif request['content-type'.freeze]
76
- Iodine.warn 'Body type protocol error.' unless request[:body]
76
+ Iodine.warn 'Body type protocol error.'.freeze unless request[:body]
77
77
  line = data.gets
78
78
  return false unless line
79
79
  (request[:body] ||= Tempfile.new('iodine'.freeze, :encoding => 'binary'.freeze) ) << line
@@ -85,7 +85,7 @@ module Iodine
85
85
  if request[:body] && request[:body].size > ::Iodine::Http.max_http_buffer
86
86
  Iodine.warn("Http1 message body too big, closing connection (Iodine::Http.max_http_buffer == #{::Iodine::Http.max_http_buffer} bytes) - #{request[:body].size} bytes.")
87
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"
88
+ write "HTTP/1.0 413 Payload Too Large\r\ncontent-length: 17\r\n\r\nPayload Too Large".freeze
89
89
  return close
90
90
  end
91
91
  (@request = ::Iodine::Http::Request.new(self)) && ( (::Iodine::Http.http2 && ::Iodine::Http::Http2.handshake(request, self, data)) || dispatch(request, data) ) if request.delete :body_complete
@@ -109,17 +109,15 @@ module Iodine
109
109
  else
110
110
  headers['connection'.freeze] ||= 'close'.freeze
111
111
  end
112
-
113
112
  send_headers response
114
113
  return log_finished(response) && (body && body.close) if request.head? || body.nil?
115
- buffer = String.new
114
+
116
115
  until body.eof?
117
- written = write(body.read 65_536, buffer)
116
+ written = write(body.read 65_536, Thread.current[:write_buffer])
118
117
  return Iodine.warn("Http/1 couldn't send response because connection was lost.".freeze) && body.close unless written
119
118
  response.bytes_written += written
120
119
  end
121
120
  body.close
122
- buffer.clear
123
121
  close unless keep_alive
124
122
  log_finished response
125
123
  end
@@ -133,9 +131,8 @@ module Iodine
133
131
  end
134
132
  return if response.request.head?
135
133
  body = response.extract_body
136
- buffer = String.new
137
134
  until body.eof?
138
- written = stream_data(body.read 65_536, buffer)
135
+ written = stream_data(body.read 65_536, Thread.current[:write_buffer])
139
136
  return Iodine.warn("Http/1 couldn't send response because connection was lost.".freeze) && body.close unless written
140
137
  response.bytes_written += written
141
138
  end if body
@@ -144,7 +141,6 @@ module Iodine
144
141
  log_finished response
145
142
  close unless response.keep_alive
146
143
  end
147
- buffer.clear
148
144
  body.close if body
149
145
  true
150
146
  end
@@ -197,8 +193,9 @@ module Iodine
197
193
  headers = response.headers
198
194
 
199
195
  # response['date'.freeze] ||= request[:time_recieved].httpdate
196
+ (out = (Thread.current[:headers_buffer] ||= String.new)).clear
200
197
 
201
- out = "HTTP/#{request[:version]} #{response.status} #{::Iodine::Http::Response::STATUS_CODES[response.status] || 'unknown'}\r\n"
198
+ out << "HTTP/#{request[:version]} #{response.status} #{::Iodine::Http::Response::STATUS_CODES[response.status] || 'unknown'}\r\n"
202
199
 
203
200
  out << request[:time_recieved].utc.strftime("Date: %a, %d %b %Y %H:%M:%S GMT\r\n".freeze) unless headers['date'.freeze]
204
201
 
@@ -209,7 +206,6 @@ module Iodine
209
206
  out << "\r\n"
210
207
 
211
208
  response.bytes_written += (write(out) || 0)
212
- out.clear
213
209
  headers.freeze
214
210
  response.raw_cookies.freeze
215
211
  end
@@ -222,7 +218,9 @@ module Iodine
222
218
  request = response.request
223
219
  return if Iodine.logger.nil? || request[:no_log]
224
220
  t_n = Time.now
225
- 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
221
+ (Thread.current[:log_buffer] ||= String.new).clear
222
+ 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"
223
+ Iodine.log(Thread.current[:log_buffer])
226
224
  end
227
225
  end
228
226
  end
@@ -57,7 +57,6 @@ module Iodine
57
57
  data = ::StringIO.new data
58
58
  parse_preface data unless @connected
59
59
  true while parse_frame data
60
- data.string.clear
61
60
  end
62
61
 
63
62
  def send_response response
@@ -67,12 +66,10 @@ module Iodine
67
66
  return body && body.close unless send_headers response, request
68
67
  return log_finished(response) && body && body.close if request.head?
69
68
  if body
70
- buffer = String.new
71
69
  until body.eof?
72
- response.bytes_written += emit_payload(body.read(@settings[SETTINGS_MAX_FRAME_SIZE], buffer), request[:sid], 0, (body.eof? ? 1 : 0))
70
+ response.bytes_written += emit_payload(body.read(@settings[SETTINGS_MAX_FRAME_SIZE], Thread.current[:write_buffer]), request[:sid], 0, (body.eof? ? 1 : 0))
73
71
  end
74
72
  body.close
75
- buffer.clear
76
73
  else
77
74
  emit_payload(''.freeze, request[:sid], 0, 1)
78
75
  end
@@ -85,11 +82,9 @@ module Iodine
85
82
  send_headers response, request
86
83
  return body && body.close if request.head?
87
84
  if body
88
- buffer = String.new
89
85
  until body.eof?
90
- response.bytes_written += emit_payload(body.read(@settings[SETTINGS_MAX_FRAME_SIZE], buffer), request[:sid], 0, ((finish && body.eof?) ? 1 : 0))
86
+ response.bytes_written += emit_payload(body.read(@settings[SETTINGS_MAX_FRAME_SIZE], Thread.current[:write_buffer]), request[:sid], 0, ((finish && body.eof?) ? 1 : 0))
91
87
  end
92
- buffer.clear
93
88
  body.close
94
89
  elsif finish
95
90
  emit_payload(''.freeze, request[:sid], 0, 1)
@@ -146,7 +141,9 @@ module Iodine
146
141
  request = response.request
147
142
  return if Iodine.logger.nil? || request[:no_log]
148
143
  t_n = Time.now
149
- 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
144
+ (Thread.current[:log_buffer] ||= String.new).clear
145
+ 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"
146
+ Iodine.log Thread.current[:log_buffer]
150
147
  end
151
148
 
152
149
  def send_headers response, request
@@ -155,7 +152,10 @@ module Iodine
155
152
  # headers[:status] = response.status.to_s
156
153
  headers['set-cookie'] = response.extract_cookies
157
154
  headers.freeze
158
- emit_payload (@hpack.encode(status: response.status.to_s) + @hpack.encode(headers)), request[:sid], 1, (request.head? ? 1 : 0)
155
+ (out = (Thread.current[:headers_buffer] ||= String.new)).clear
156
+ out << @hpack.encode(headers)
157
+ emit_payload (out), request[:sid], 1, (request.head? ? 1 : 0)
158
+ out.clear
159
159
  return true
160
160
  end
161
161
 
@@ -16,7 +16,7 @@ module Iodine
16
16
  end
17
17
  # handle broadcasts.
18
18
  def on_broadcast data
19
- @locker.synchronize { @handler.on_broadcast(data) if @handler.respond_to? :on_broadcast }
19
+ @locker.synchronize { @handler.on_broadcast(data) } if @handler.respond_to? :on_broadcast
20
20
  end
21
21
  # cleanup after closing.
22
22
  def on_close
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = "0.1.15"
2
+ VERSION = "0.1.16"
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.15
4
+ version: 0.1.16
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-11-14 00:00:00.000000000 Z
11
+ date: 2015-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler