iodine 0.1.12 → 0.1.13

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: 0cae62f19555de3237661fc0f47461290f31a47d
4
- data.tar.gz: d4ee6c036d77d5ccc9cc243d2e5407609d39cc16
3
+ metadata.gz: 7fbbba2f03bc0eb7a52c6516a640eda4094230b7
4
+ data.tar.gz: bb2b8b42038b32af81a6fa63b8ee3627fc47ef69
5
5
  SHA512:
6
- metadata.gz: 8ae4692ca663399664b005c9fd8983d151ca14a6ba543455e497d0884eabe760b0719c1bf520ad129584260ca3229f202afe3b80b16ede4c9055077415f77e02
7
- data.tar.gz: 311d1785ec2ff505173d2eb2e34daafd997bcdd038710223d2f69b4348363df587dd4d3ebcedeca8c9fe65f93f86b8efcbbf19796fc4604b77b80c445cdf57cb
6
+ metadata.gz: c8f093d5101e34538a205a2f4aa996781c6bde02838cde091885ae37c6d8bcfd346590824d6ea15ec825194d713eb30cea0b9cf8d1c256dde8c30da372019cd8
7
+ data.tar.gz: e432d26f6af2a463737adff4ffbe8abf54486f61a4d9a475c544ee2c2316c2d8d72fe97fe486a2d701619e73a45afc041c2b2ad2b6bc800901f923192e1a9976
@@ -8,6 +8,18 @@ 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.13
12
+
13
+ **Change**: Session cookie lifetime is now limited to the browser's session. The local data will still persist until the tmp-folder is cleared (when using session file storage).
14
+
15
+ **Fix**: renamed the SSL session token so that the SSL session id isn't lost when a non-secure session is used.
16
+
17
+ **Fix**: The `flash` cookie-jar will now actively prevent Symbol and String keys from overlapping.
18
+
19
+ **Compatibility**: minor fixes and changes in preperation for Ruby 2.3.0.
20
+
21
+ ***
22
+
11
23
  Change log v.0.1.12
12
24
 
13
25
  **Update**: Passing a hash as the cookie value will allow to set cookie parameters using the {Response#set_cookie} options. i.e.: `cookies['key']= {value: "lock", max_age: 20}`.
@@ -62,7 +62,7 @@ module Iodine
62
62
  job = @queue && @queue.pop
63
63
  if job && job[0]
64
64
  begin
65
- job[0].call *job[1]
65
+ job[0].call(*job[1])
66
66
  rescue => e
67
67
  error e
68
68
  end
@@ -55,8 +55,8 @@ module Iodine
55
55
  if @queue.empty?
56
56
  #clear any closed IO objects.
57
57
  @time = Time.now
58
- @ios.keys.each &@status_loop
59
- @ios.values.each &@timeout_proc
58
+ @ios.keys.each(&@status_loop)
59
+ @ios.values.each(&@timeout_proc)
60
60
  until @io_in.empty?
61
61
  n_io = @io_in.pop
62
62
  @ios[n_io[0]] = n_io[1]
@@ -70,7 +70,7 @@ module Iodine
70
70
  begin
71
71
  r = IO.select(@ios.keys, nil, nil, 0.15)
72
72
  r[0].each {|io| @queue << [@ios[io]] } if r
73
- rescue => e
73
+ rescue
74
74
 
75
75
  end
76
76
  unless @stop && @queue.empty?
@@ -66,13 +66,13 @@ module Iodine
66
66
  data = StringIO.new data
67
67
  results = {}
68
68
  while (field = decode_field(data))
69
- name = (field[0].is_a?(String) && field[0][0] == ':') ? field[0][1..-1].to_sym : field[0]
69
+ name = (field[0].is_a?(String) && field[0][0] == ':'.freeze) ? field[0][1..-1].to_sym : field[0]
70
70
  results[name] ? (results[name].is_a?(String) ? (results[name] = [results[name], field[1]]) : (results[name] << field[1]) ) : (results[name] = field[1]) if field[1]
71
71
  end
72
72
  results
73
73
  end
74
74
  def encode headers = {}
75
- buffer = ''.force_encoding(::Encoding::ASCII_8BIT)
75
+ buffer = String.new.force_encoding(::Encoding::ASCII_8BIT)
76
76
  headers.each {|k, v| buffer << encode_field( (k.is_a?(String) ? k : ":#{k.to_s}".freeze) ,v) if v}
77
77
  buffer.force_encoding(::Encoding::ASCII_8BIT)
78
78
  end
@@ -121,10 +121,10 @@ module Iodine
121
121
  if value.is_a?(Array)
122
122
  return (value.map {|v| encode_field name, v} .join)
123
123
  end
124
- raise "Http/2 headers must be LOWERCASE Strings!" if name[0] =~ /[A-Z]/n
124
+ raise "Http/2 headers must be LOWERCASE Strings!" if name[0] =~ /[A-Z]/n.freeze
125
125
  value = value.to_s
126
- if name == 'set-cookie'
127
- buffer = ''.force_encoding ::Encoding::ASCII_8BIT
126
+ if name == 'set-cookie'.freeze
127
+ buffer = String.new.force_encoding ::Encoding::ASCII_8BIT
128
128
  buffer << pack_number( 55, 1, 4)
129
129
  buffer << pack_string(value)
130
130
  return buffer
@@ -132,11 +132,11 @@ module Iodine
132
132
  index = @encoding_list.find(name, value)
133
133
  return pack_number( index, 1, 1) if index
134
134
  index = @encoding_list.find_name name
135
- buffer = ''.force_encoding(::Encoding::ASCII_8BIT)
135
+ buffer = String.new.force_encoding(::Encoding::ASCII_8BIT)
136
136
  if index
137
137
  buffer << pack_number( index, 1, 2)
138
138
  else
139
- raise "Http/2 headers whould be Strings! or allowed Psedo-Header Symbol Only!" if name[0] == ':'
139
+ raise "Http/2 headers whould be Strings! or allowed Psedo-Header Symbol Only!" if name[0] == ':'.freeze
140
140
  buffer << pack_number( 0, 1, 2)
141
141
  buffer << pack_string(name)
142
142
  end
@@ -193,8 +193,8 @@ module Iodine
193
193
  end
194
194
  def inflate data
195
195
  data = StringIO.new data
196
- str = ''
197
- buffer = ''
196
+ str = String.new
197
+ buffer = String.new
198
198
  until data.eof?
199
199
  byte = data.getbyte
200
200
  8.times do |i|
@@ -209,8 +209,8 @@ module Iodine
209
209
  str
210
210
  end
211
211
  def deflate data
212
- str = ''.force_encoding ::Encoding::ASCII_8BIT
213
- buffer = ''.force_encoding ::Encoding::ASCII_8BIT
212
+ str = String.new.force_encoding ::Encoding::ASCII_8BIT
213
+ buffer = String.new.force_encoding ::Encoding::ASCII_8BIT
214
214
  data.bytes.each do |i|
215
215
  buffer << HUFFMAN.key(i)
216
216
  if (buffer.bytesize % 8) == 0
@@ -219,7 +219,7 @@ module Iodine
219
219
  end
220
220
  end
221
221
  unless buffer.empty?
222
- (8-(buffer.bytesize % 8)).times { buffer << '1'} if (buffer.bytesize % 8)
222
+ (8-(buffer.bytesize % 8)).times { buffer << '1'.freeze} if (buffer.bytesize % 8)
223
223
  str << [buffer].pack('B*'.freeze)
224
224
  buffer.clear
225
225
  end
@@ -22,22 +22,22 @@ module Iodine
22
22
  return close
23
23
  end
24
24
  next if l.empty?
25
- request[:method], request[:query], request[:version] = l.split(/[\s]+/, 3)
25
+ request[:method], request[:query], request[:version] = l.split(/[\s]+/.freeze, 3)
26
26
  return (Iodine.warn('Htt1 Protocol Error, closing connection.') && close) unless request[:method] =~ HTTP_METHODS_REGEXP
27
- request[:version] = (request[:version] || '1.1'.freeze).match(/[\d\.]+/)[0]
27
+ request[:version] = (request[:version] || '1.1'.freeze).match(/[\d\.]+/.freeze)[0]
28
28
  request[:time_recieved] = Time.now
29
29
  end
30
30
  until request[:headers_complete] || (l = data.gets).nil?
31
- if l.include? ':'
31
+ if l.include? ':'.freeze
32
32
  # n = l.slice!(0, l.index(':')); l.slice! 0
33
33
  # n.strip! ; n.downcase!; n.freeze
34
34
  # request[n] ? (request[n].is_a?(Array) ? (request[n] << l) : request[n] = [request[n], l ]) : (request[n] = l)
35
35
  request[:headers_size] ||= 0
36
36
  request[:headers_size] += l.bytesize
37
- l = l.strip.split(/:[\s]?/, 2)
37
+ l = l.strip.split(/:[\s]?/.freeze, 2)
38
38
  l[0].strip! ; l[0].downcase!;
39
39
  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])
40
- elsif l =~ /^[\r]?\n/
40
+ elsif l =~ /^[\r]?\n/.freeze
41
41
  request[:headers_complete] = true
42
42
  else
43
43
  #protocol error
@@ -102,10 +102,10 @@ module Iodine
102
102
  headers['content-length'.freeze] ||= body.size if body
103
103
 
104
104
  keep_alive = response.keep_alive
105
- if (request[:version].to_f > 1 && request['connection'.freeze].nil?) || request['connection'.freeze].to_s =~ /ke/i || (headers['connection'.freeze] && headers['connection'.freeze] =~ /^ke/i)
105
+ if (request[:version].to_f > 1 && request['connection'.freeze].nil?) || request['connection'.freeze].to_s =~ /ke/i.freeze || (headers['connection'.freeze] && headers['connection'.freeze] =~ /^ke/i.freeze)
106
106
  keep_alive = true
107
107
  headers['connection'.freeze] ||= 'keep-alive'.freeze
108
- headers['keep-alive'.freeze] ||= "timeout=#{(@timeout ||= 3).to_s}"
108
+ headers['keep-alive'.freeze] ||= "timeout=#{(@timeout ||= 3).to_s}".freeze
109
109
  else
110
110
  headers['connection'.freeze] ||= 'close'.freeze
111
111
  end
@@ -115,7 +115,7 @@ module Iodine
115
115
  buffer = String.new
116
116
  until body.eof?
117
117
  written = write(body.read 65_536, buffer)
118
- return Iodine.warn("Http/1 couldn't send response because connection was lost.") && body.close unless written
118
+ return Iodine.warn("Http/1 couldn't send response because connection was lost.".freeze) && body.close unless written
119
119
  response.bytes_written += written
120
120
  end
121
121
  body.close
@@ -124,9 +124,9 @@ module Iodine
124
124
  log_finished response
125
125
  end
126
126
  def stream_response response, finish = false
127
- timeout = 15
127
+ set_timeout 15
128
128
  unless response.headers.frozen?
129
- response['transfer-encoding'.freeze] = 'chunked'
129
+ response['transfer-encoding'.freeze] = 'chunked'.freeze
130
130
  response.headers['connection'.freeze] = 'close'.freeze
131
131
  send_headers response
132
132
  @refuse_requests = true
@@ -136,11 +136,11 @@ module Iodine
136
136
  buffer = String.new
137
137
  until body.eof?
138
138
  written = stream_data(body.read 65_536, buffer)
139
- return Iodine.warn("Http/1 couldn't send response because connection was lost.") && body.close unless written
139
+ return Iodine.warn("Http/1 couldn't send response because connection was lost.".freeze) && body.close unless written
140
140
  response.bytes_written += written
141
141
  end if body
142
142
  if finish
143
- response.bytes_written += stream_data('')
143
+ response.bytes_written += stream_data(''.freeze)
144
144
  log_finished response
145
145
  close unless response.keep_alive
146
146
  end
@@ -166,7 +166,7 @@ module Iodine
166
166
  when 'OPTIONS'.freeze
167
167
  response = ::Iodine::Http::Response.new request
168
168
  response[:Allow] = 'GET,HEAD,POST,PUT,DELETE,OPTIONS'.freeze
169
- response['access-control-allow-origin'.freeze] = '*'
169
+ response['access-control-allow-origin'.freeze] = '*'.freeze
170
170
  response['content-length'.freeze] = 0
171
171
  send_response response
172
172
  return false
@@ -12,7 +12,7 @@ module Iodine
12
12
  @hpack = ::Iodine::Http::Http2::HPACK.new
13
13
 
14
14
  # the header-stream cache
15
- @header_buffer = ''
15
+ @header_buffer = String.new
16
16
  @header_end_stream = false
17
17
  @header_sid = nil
18
18
  @frame_locker = Mutex.new
@@ -74,7 +74,7 @@ module Iodine
74
74
  body.close
75
75
  buffer.clear
76
76
  else
77
- emit_payload('', request[:sid], 0, 1)
77
+ emit_payload(''.freeze, request[:sid], 0, 1)
78
78
  end
79
79
  log_finished response
80
80
  end
@@ -92,7 +92,7 @@ module Iodine
92
92
  buffer.clear
93
93
  body.close
94
94
  elsif finish
95
- emit_payload('', request[:sid], 0, 1)
95
+ emit_payload(''.freeze, request[:sid], 0, 1)
96
96
  end
97
97
  log_finished response if finish
98
98
  end
@@ -195,7 +195,7 @@ module Iodine
195
195
  return (connection_error(PROTOCOL_ERROR) && Iodine.warn("Preface not given"))
196
196
  end
197
197
  @connected = true
198
- emit_frame '', 0, 0x4
198
+ emit_frame ''.freeze, 0, 0x4
199
199
  true
200
200
  end
201
201
 
@@ -222,14 +222,14 @@ module Iodine
222
222
  frame[:flags] = tmp.ord
223
223
  end
224
224
  unless frame[:sid]
225
- tmp = (frame[:sid_bytes] ||= '')
225
+ tmp = (frame[:sid_bytes] ||= String.new)
226
226
  tmp << data.read(4 - tmp.bytesize).to_s
227
227
  return false if tmp.bytesize < 4
228
228
  tmp = frame.delete(:sid_bytes).unpack('N')[0]
229
229
  frame[:sid] = tmp & 2147483647
230
230
  frame[:R] = tmp & 2147483648
231
231
  end
232
- tmp = (frame[:body] ||= '')
232
+ tmp = (frame[:body] ||= String.new)
233
233
  tmp << data.read(frame[:length] - tmp.bytesize).to_s
234
234
  return false if tmp.bytesize < frame[:length]
235
235
  #TODO: something - Async?
@@ -257,7 +257,7 @@ module Iodine
257
257
  process_ping frame
258
258
  when 7 # GOAWAY
259
259
  go_away NO_ERROR
260
- Iodine.error "Http2 Disconnection with error (#{frame[:flags].to_s}): #{frame[:body].strip}" unless frame[:flags] == 0 && frame[:body] == ''
260
+ Iodine.error "Http2 Disconnection with error (#{frame[:flags].to_s}): #{frame[:body].strip}" unless frame[:flags] == 0 && frame[:body] == ''.freeze
261
261
  when 8 # WINDOW_UPDATE
262
262
  else # Error, frame not recognized
263
263
  end
@@ -402,7 +402,7 @@ module Iodine
402
402
  # Unsupported parameters MUST be ignored
403
403
  end
404
404
  end
405
- emit_frame '', 0, 4, 1
405
+ emit_frame ''.freeze, 0, 4, 1
406
406
  end
407
407
 
408
408
  def process_request request
@@ -8,7 +8,7 @@ module Iodine
8
8
  @app = app
9
9
  Iodine.threads ||= 18
10
10
  Iodine.port = options[:Port]
11
- RACK_DICTIONARY['rack.multiprocess'] = Iodine.processes.to_i > 1
11
+ RACK_DICTIONARY['rack.multiprocess'.freeze] = Iodine.processes.to_i > 1
12
12
  Iodine.protocol ||= Iodine::Http::Http1
13
13
  @pre_rack_handler = Iodine::Http.on_http unless Iodine::Http.on_http == Iodine::Http::NOT_IMPLEMENTED
14
14
  Iodine::Http.on_http self
@@ -27,7 +27,7 @@ module Iodine
27
27
  res[1].each {|k, v| response.headers[k.to_s.downcase] = v }
28
28
  response.body = res[2]
29
29
  response.raw_cookies.clear
30
- response.headers['set-cookie'] = response.headers.delete('set-cookie').split("\n").join("\r\nset-cookie: ") if request[:io].is_a?(Iodine::Http::Http1) && response.headers['set-cookie']
30
+ response.headers['set-cookie'.freeze] = response.headers.delete('set-cookie'.freeze).split("\n".freeze).join("\r\nset-cookie: ".freeze) if request[:io].is_a?(Iodine::Http::Http1) && response.headers['set-cookie'.freeze]
31
31
  response.request[:no_log] = true
32
32
  true
33
33
  end
@@ -41,12 +41,12 @@ module Iodine
41
41
  # env.each {|k, v| env[k] = @request[v] if v.is_a?(Symbol)}
42
42
  RACK_ADDON.each {|k, v| env[k] = (request[v].is_a?(String) ? ( request[v].frozen? ? request[v].dup.force_encoding('ASCII-8BIT') : request[v].force_encoding('ASCII-8BIT') ): request[v])}
43
43
  request.each {|k, v| env["HTTP_#{k.upcase.tr('-', '_')}"] = v if k.is_a?(String) }
44
- env['rack.input'.freeze] ||= request[:body] || StringIO.new(''.force_encoding('ASCII-8BIT'.freeze))
44
+ env['rack.input'.freeze] ||= request[:body] || StringIO.new(''.force_encoding('ASCII-8BIT'.freeze).freeze)
45
45
  env['CONTENT_LENGTH'.freeze] = env.delete 'HTTP_CONTENT_LENGTH'.freeze if env['HTTP_CONTENT_LENGTH'.freeze]
46
46
  env['CONTENT_TYPE'.freeze] = env.delete 'HTTP_CONTENT_TYPE'.freeze if env['HTTP_CONTENT_TYPE'.freeze]
47
- env['HTTP_VERSION'.freeze] = "HTTP/#{request[:version].to_s}"
48
- env['QUERY_STRING'.freeze] ||= ''
49
- env['rack.errors'.freeze] = StringIO.new('')
47
+ env['HTTP_VERSION'.freeze] = "HTTP/#{request[:version].to_s}".freeze
48
+ env['QUERY_STRING'.freeze] ||= ''.freeze
49
+ env['rack.errors'.freeze] = StringIO.new(''.freeze)
50
50
  # should unchain cookies from Array to String
51
51
  env['HTTP_COOKIE'] = env['HTTP_COOKIE'].join '; ' if env['HTTP_COOKIE'].is_a?(Array)
52
52
  env
@@ -68,9 +68,9 @@ module Iodine
68
68
  }
69
69
 
70
70
  RACK_DICTIONARY = {
71
- "GATEWAY_INTERFACE" =>"CGI/1.2",
72
- 'SERVER_SOFTWARE' => "Iodine v. #{Iodine::VERSION}",
73
- 'SCRIPT_NAME' => ''.force_encoding('ASCII-8BIT'),
71
+ "GATEWAY_INTERFACE" =>"CGI/1.2".freeze,
72
+ 'SERVER_SOFTWARE' => "Iodine v. #{Iodine::VERSION}".freeze,
73
+ 'SCRIPT_NAME' => ''.force_encoding('ASCII-8BIT'.freeze).freeze,
74
74
  'rack.logger' => Iodine,
75
75
  'rack.multithread' => true,
76
76
  'rack.multiprocess' => false,
@@ -78,19 +78,19 @@ module Iodine
78
78
  # 'rack.hijack_io' => nil,
79
79
  'rack.run_once' => false
80
80
  }
81
- RACK_DICTIONARY['rack.version'] = ::Rack.version.split('.') if defined?(::Rack)
82
- HASH_SYM_PROC = Proc.new {|h,k| k = (Symbol === k ? k.to_s : k.to_s.to_sym); h.has_key?(k) ? h[k] : (h["gr.#{k.to_s}"] if h.has_key?("gr.#{k.to_s}") ) }
81
+ RACK_DICTIONARY['rack.version'.freeze] = ::Rack.version.split('.'.freeze) if defined?(::Rack)
82
+ HASH_SYM_PROC = Proc.new {|h,k| k = (Symbol === k ? k.to_s : k.to_s.to_sym); h.has_key?(k) ? h[k] : (h["iodine.#{k.to_s}"] if h.has_key?("iodine.#{k.to_s}") ) }
83
83
  end
84
84
  end
85
85
  end
86
86
 
87
- # ENV["RACK_HANDLER"] = 'grhttp'
87
+ # ENV["RACK_HANDLER"] = 'iodine'
88
88
 
89
89
  # make Iodine the default fallback position for Rack.
90
90
  begin
91
91
  require 'rack/handler'
92
92
  Rack::Handler::WEBrick = Rack::Handler.get(:iodine)
93
- rescue Exception => e
93
+ rescue Exception
94
94
 
95
95
  end
96
96
  ::Rack::Handler.register( 'iodine', 'Iodine::Http::Rack') if defined?(::Rack)
@@ -22,7 +22,7 @@ module Iodine
22
22
  end
23
23
  # overrides the []= method to set the cookie for the response (by encoding it and preparing it to be sent), as well as to save the cookie in the combined cookie jar (unencoded and available).
24
24
  def []= key, val
25
- return super unless @response
25
+ return super unless instance_variable_defined?(:@response) && @response
26
26
  if key.is_a?(Symbol) && self.has_key?( key.to_s)
27
27
  key = key.to_s
28
28
  elsif self.has_key?( key.to_s.to_sym)
@@ -98,12 +98,12 @@ module Iodine
98
98
 
99
99
  # the base url ([http/https]://host[:port])
100
100
  def base_url switch_scheme = nil
101
- "#{switch_scheme || self[:scheme]}://#{self[:host_name]}#{self[:port]? ":#{self[:port]}" : ''}"
101
+ "#{switch_scheme || self[:scheme]}://#{self[:host_name]}#{self[:port]? ":#{self[:port]}" : ''.freeze}".freeze
102
102
  end
103
103
 
104
104
  # the request's url, without any GET parameters ([http/https]://host[:port]/path)
105
105
  def request_url switch_scheme = nil
106
- "#{base_url switch_scheme}#{self[:original_path]}"
106
+ "#{base_url switch_scheme}#{self[:original_path]}".freeze
107
107
  end
108
108
 
109
109
  # the protocol's scheme (http/https/ws/wss) managing this request
@@ -213,12 +213,12 @@ module Iodine
213
213
  request[:version] ||= '1'
214
214
 
215
215
  request[:scheme] ||= request['x-forwarded-proto'.freeze] ? request['x-forwarded-proto'.freeze].downcase : ( request[:io].ssl? ? 'https'.freeze : 'http'.freeze)
216
- tmp = (request['host'.freeze] || request[:authority] || ''.freeze).split(':')
216
+ tmp = (request['host'.freeze] || request[:authority] || ''.freeze).split(':'.freeze)
217
217
  request[:host_name] = tmp[0]
218
218
  request[:port] = tmp[1] || nil
219
219
 
220
- tmp = (request[:query] ||= request[:path] ).split('?', 2)
221
- request[:path] = tmp[0].chomp('/')
220
+ tmp = (request[:query] ||= request[:path] ).split('?'.freeze, 2)
221
+ request[:path] = tmp[0].chomp('/'.freeze)
222
222
  request[:original_path] = tmp[0].freeze
223
223
  request[:quary_params] = tmp[1]
224
224
  extract_params tmp[1].split(/[&;]/.freeze), (request[:params] ||= {}) if tmp[1]
@@ -313,7 +313,7 @@ module Iodine
313
313
  end
314
314
  # decode form / uri data (including the '+' sign as a space (%20) replacement).
315
315
  def self.uri_decode! s
316
- s.gsub!('+'.freeze, '%20'.freeze); s.gsub!(/\%[0-9a-f]{2}/i) {|m| m[1..2].to_i(16).chr}; s.gsub!(/&#[0-9]{4};/i) {|m| [m[2..5].to_i].pack 'U'.freeze }; s
316
+ s.gsub!('+'.freeze, '%20'.freeze); s.gsub!(/\%[0-9a-f]{2}/i.freeze) {|m| m[1..2].to_i(16).chr}; s.gsub!(/&#[0-9]{4};/i.freeze) {|m| [m[2..5].to_i].pack 'U'.freeze }; s
317
317
  end
318
318
  # extracts parameters from header data
319
319
  def self.extract_header data, target_hash
@@ -325,7 +325,7 @@ module Iodine
325
325
  end
326
326
  # decode percent-encoded data (excluding the '+' sign for encoding).
327
327
  def self.form_decode! s
328
- s.gsub!(/\%[0-9a-f]{2}/i) {|m| m[1..2].to_i(16).chr}; s.gsub!(/&#[0-9]{4};/i) {|m| [m[2..5].to_i].pack 'U'.freeze }; s
328
+ s.gsub!(/\%[0-9a-f]{2}/i.freeze) {|m| m[1..2].to_i(16).chr}; s.gsub!(/&#[0-9]{4};/i.freeze) {|m| [m[2..5].to_i].pack 'U'.freeze }; s
329
329
  end
330
330
  # Changes String to a Ruby Object, if it's a special string...
331
331
  def self.rubyfy!(string)
@@ -348,32 +348,32 @@ module Iodine
348
348
  # parse content
349
349
  request[:body].rewind
350
350
  case request['content-type'.freeze].to_s
351
- when /x-www-form-urlencoded/
351
+ when /x-www-form-urlencoded/.freeze
352
352
  extract_params request[:body].read.split(/[&;]/), request[:params] #, :form # :uri
353
- when /multipart\/form-data/
353
+ when /multipart\/form-data/.freeze
354
354
  read_multipart request, request
355
- when /text\/xml/
355
+ when /text\/xml/.freeze
356
356
  # to-do support xml?
357
357
  # request[:xml] = make_utf8! request[:body].read
358
358
  nil
359
- when /application\/json/
359
+ when /application\/json/.freeze
360
360
  JSON.parse(make_utf8! request[:body].read).each {|k, v| add_param_to_hash k, v, request[:params]} rescue true
361
361
  end
362
362
  request[:body].rewind if request[:body]
363
363
  end
364
364
 
365
365
  # parse a mime/multipart body or part.
366
- def self.read_multipart request, headers = {}, boundary = [], name_prefix = ''
366
+ def self.read_multipart request, headers = {}, boundary = [], name_prefix = String.new
367
367
  body = request[:body]
368
- return unless headers['content-type'].to_s =~ /multipart/i
368
+ return unless headers['content-type'.freeze].to_s =~ /multipart/i.freeze
369
369
  part_headers = {}
370
- extract_header headers['content-type'].split(/[;,][\s]?/), part_headers
370
+ extract_header headers['content-type'.freeze].split(/[;,][\s]?/.freeze), part_headers
371
371
  boundary << part_headers[:boundary]
372
372
  if part_headers[:name]
373
373
  if name_prefix.empty?
374
374
  name_prefix << part_headers[:name]
375
375
  else
376
- name_prefix << "[#{part_headers[:name]}]"
376
+ name_prefix << "[#{part_headers[:name]}]".freeze
377
377
  end
378
378
  end
379
379
  part_headers.delete :name
@@ -4,6 +4,30 @@ module Iodine
4
4
  #
5
5
  # The response can be sent in stages but should complete within the scope of the connecton's message. Please notice that headers and status cannot be changed once the response started sending data.
6
6
  class Response
7
+ # Makes sure that the `flash` cookie-jar doesn't have Symbols and Strings overlapping.
8
+ class Flash < ::Hash
9
+ # overrides the []= method to set the cookie for the response (by encoding it and preparing it to be sent), as well as to save the cookie in the combined cookie jar (unencoded and available).
10
+ def []= key, val
11
+ if key.is_a?(Symbol) && self.has_key?( key.to_s)
12
+ key = key.to_s
13
+ elsif self.has_key?( key.to_s.to_sym)
14
+ key = key.to_s.to_sym
15
+ end
16
+ super
17
+ end
18
+ # overrides th [] method to allow Symbols and Strings to mix and match
19
+ def [] key
20
+ if key.is_a?(Symbol) && self.has_key?( key.to_s)
21
+ key = key.to_s
22
+ elsif self.has_key?( key.to_s.to_sym)
23
+ key = key.to_s.to_sym
24
+ elsif self.has_key? "magic_flash_#{key.to_s}".freeze.to_sym
25
+ key = "magic_flash_#{key.to_s}".freeze.to_sym
26
+ end
27
+ super
28
+ end
29
+ end
30
+
7
31
  # the response's status code
8
32
  attr_accessor :status
9
33
  # the response's headers
@@ -33,11 +57,9 @@ module Iodine
33
57
  @bytes_written = 0
34
58
  @keep_alive = @http_sblocks_count = false
35
59
  # propegate flash object
36
- @flash = Hash.new do |hs,k|
37
- hs["magic_flash_#{k.to_s}".to_sym] if hs.has_key? "magic_flash_#{k.to_s}".to_sym
38
- end
60
+ @flash = ::Iodine::Http::Response::Flash.new
39
61
  request.cookies.each do |k,v|
40
- @flash[k] = v if k.to_s.start_with? 'magic_flash_'
62
+ @flash[k] = v if k.to_s.start_with? 'magic_flash_'.freeze
41
63
  end
42
64
  end
43
65
 
@@ -83,7 +105,7 @@ module Iodine
83
105
  Iodine.run block, &@stream_proc
84
106
  end
85
107
 
86
- # Creates nested streaming blocks for an Array or another Enumerable object. Once all streaming blocks are done, the response will automatically finish.
108
+ # Creates nested streaming blocks for an Array object (an object answering `#shift`). Once all streaming blocks are done, the response will automatically finish.
87
109
  #
88
110
  # Since streaming blocks might run in parallel, nesting the streaming blocks is important...
89
111
  #
@@ -124,9 +146,15 @@ module Iodine
124
146
  #
125
147
  # @return [Hash like storage] creates and returns the session storage object with all the data from a previous connection.
126
148
  def session
127
- return @session if @session
128
- id = request.cookies[::Iodine::Http.session_token.to_sym] || SecureRandom.uuid
129
- set_cookie ::Iodine::Http.session_token, id, expires: (Time.now+86_400), secure: @request.ssl?, http_only: true
149
+ return @session if instance_variable_defined?(:@session) && @session
150
+ if @request.ssl?
151
+ @@sec_session_token ||= "#{::Iodine::Http.session_token}_enc".freeze
152
+ id = @request.cookies[@@sec_session_token.to_sym] || SecureRandom.uuid
153
+ set_cookie @@sec_session_token, id, expires: :session, secure: true, http_only: true
154
+ else
155
+ id = @request.cookies[::Iodine::Http.session_token.to_sym] || SecureRandom.uuid
156
+ set_cookie ::Iodine::Http.session_token, id, expires: :session, http_only: true
157
+ end
130
158
  @request[:session] = @session = ::Iodine::Http::SessionManager.get(id)
131
159
  end
132
160
 
@@ -177,7 +205,7 @@ module Iodine
177
205
  end
178
206
 
179
207
 
180
- COOKIE_NAME_REGEXP = /[\x00-\x20\(\)\<\>@,;:\\\"\/\[\]\?\=\{\}\s]/
208
+ COOKIE_NAME_REGEXP = /[\x00-\x20\(\)\<\>@,;:\\\"\/\[\]\?\=\{\}\s]/.freeze
181
209
 
182
210
  # Sets/deletes cookies when headers are sent.
183
211
  #
@@ -206,20 +234,20 @@ module Iodine
206
234
  name = name.to_s
207
235
  raise 'Illegal cookie name' if name =~ COOKIE_NAME_REGEXP
208
236
  if value.nil?
209
- params[:expires] = (Time.now - 315360000)
237
+ params[:expires] = (Iodine.time - 315360000)
210
238
  value = 'deleted'.freeze
211
239
  else
212
- params[:expires] ||= (Time.now + 315360000) unless params[:max_age]
240
+ params[:expires] ||= (Iodine.time + 315360000) unless params[:max_age]
213
241
  end
214
242
  params[:path] ||= '/'.freeze
215
243
  value = Iodine::Http::Request.encode_url(value) # this dups the string
216
244
  if params[:max_age]
217
- value << ('; Max-Age=%s' % params[:max_age])
245
+ value << ('; Max-Age=%s'.freeze % params[:max_age])
218
246
  else
219
- value << ('; Expires=%s' % params[:expires].httpdate)
247
+ value << ('; Expires=%s'.freeze % params[:expires].httpdate) if params[:expires].is_a?(::Time)
220
248
  end
221
- value << "; Path=#{params[:path]}"
222
- value << "; Domain=#{params[:domain]}" if params[:domain]
249
+ value << "; Path=#{params[:path]}".freeze
250
+ value << "; Domain=#{params[:domain]}".freeze if params[:domain]
223
251
  value << '; Secure'.freeze if params[:secure]
224
252
  value << '; HttpOnly'.freeze if params[:http_only]
225
253
  @cookies[name.to_sym] = value
@@ -245,7 +273,7 @@ module Iodine
245
273
  request.delete(:body).tap {|f| f.close unless f.respond_to?(:close) && f.closed? rescue false } if request[:body] && @http_sblocks_count.to_i == 0
246
274
  end
247
275
 
248
- # Returns the connection's UUID.
276
+ # Returns the connection's LOCAL UUID.
249
277
  def uuid
250
278
  request[:io].id
251
279
  end
@@ -311,7 +339,7 @@ module Iodine
311
339
  511=>"Network Authentication Required".freeze
312
340
  }
313
341
 
314
- # This will return the Body object as an IO like object, such as StringIO (or File)... And set the body to `nil` (seeing as it was extracted from the response).
342
+ # This will return the Body object as an IO like object, such as StringIO (or File) and set the body to `nil` (seeing as it was extracted from the response).
315
343
  #
316
344
  # This method will also attempts to set headers and update the response status in relation to the body, if applicable. Call this BEFORE getting any final data about the response or sending the headers.
317
345
  def extract_body
@@ -327,7 +355,7 @@ module Iodine
327
355
  elsif @body.is_a?(File) || @body.is_a?(Tempfile) || @body.is_a?(StringIO)
328
356
  @body
329
357
  elsif @body.respond_to? :each
330
- tmp = ''
358
+ tmp = String.new
331
359
  @body.each {|s| tmp << s}
332
360
  @body.close if @body.respond_to? :close
333
361
  @body = nil
@@ -338,7 +366,7 @@ module Iodine
338
366
  body_io.rewind
339
367
 
340
368
  if !(@headers.frozen?) && @request['range'.freeze] && @request.get? && @status == 200 && @headers['content-length'.freeze].nil?
341
- r = @request['range'.freeze].match(/^bytes=([\d]+)\-([\d]+)?$/i)
369
+ r = @request['range'.freeze].match(/^bytes=([\d]+)\-([\d]+)?$/i.freeze)
342
370
  if r
343
371
  old_size = body_io.size
344
372
  start_pos = r[1].to_i
@@ -353,9 +381,9 @@ module Iodine
353
381
  body_io.rewind
354
382
  end
355
383
  @headers['content-range'.freeze] = "bytes #{start_pos}-#{end_pos}/#{old_size}"
356
- @headers['accept-ranges'.freeze] ||= 'bytes'
384
+ @headers['accept-ranges'.freeze] ||= 'bytes'.freeze
357
385
  else
358
- @headers['accept-ranges'.freeze] ||= 'none'
386
+ @headers['accept-ranges'.freeze] ||= 'none'.freeze
359
387
  end
360
388
  end
361
389
 
@@ -374,7 +402,7 @@ module Iodine
374
402
  end
375
403
  #set new flash cookies
376
404
  @flash.each do |k,v|
377
- set_cookie "magic_flash_#{k.to_s}", v
405
+ set_cookie "magic_flash_#{k.to_s}".freeze, v
378
406
  end
379
407
  @cookies.freeze
380
408
  # response.cookies.set_response nil
@@ -133,10 +133,6 @@ module Iodine
133
133
  @request.ssl?
134
134
  end
135
135
 
136
- # return the HTTP's handshake data, including any cookies sent by the server.
137
- def request
138
- @request
139
- end
140
136
  # return a Hash with the HTTP cookies recieved during the HTTP's handshake.
141
137
  def cookies
142
138
  @request.cookies
@@ -154,7 +150,7 @@ module Iodine
154
150
  end
155
151
  byte_size = data.bytesize
156
152
  if byte_size > (::Iodine::Http::Websockets::FRAME_SIZE_LIMIT+2)
157
- sections = byte_size/FRAME_SIZE_LIMIT + (byte_size % ::Iodine::Http::Websockets::FRAME_SIZE_LIMIT ? 1 : 0)
153
+ # sections = byte_size/FRAME_SIZE_LIMIT + (byte_size % ::Iodine::Http::Websockets::FRAME_SIZE_LIMIT ? 1 : 0)
158
154
  ret = write( data.slice!( 0...::Iodine::Http::Websockets::FRAME_SIZE_LIMIT ), op_code, data.empty?, ext) && (ext = op_code = 0) until data.empty?
159
155
  return ret # avoid sending an empty frame.
160
156
  end
@@ -205,20 +201,19 @@ module Iodine
205
201
  ssl.connect
206
202
  end
207
203
  # prep custom headers
208
- custom_headers = ''
204
+ custom_headers = String.new
209
205
  custom_headers = @options[:headers] if @options[:headers].is_a?(String)
210
206
  @options[:headers].each {|k, v| custom_headers << "#{k.to_s}: #{v.to_s}\r\n"} if @options[:headers].is_a?(Hash)
211
- @options[:cookies].each {|k, v| raise 'Illegal cookie name' if k.to_s.match(/[\x00-\x20\(\)<>@,;:\\\"\/\[\]\?\=\{\}\s]/); custom_headers << "Cookie: #{ k }=#{ Iodine::Http::Request.encode_url v }\r\n"} if @options[:cookies].is_a?(Hash)
207
+ @options[:cookies].each {|k, v| raise 'Illegal cookie name' if k.to_s.match(/[\x00-\x20\(\)<>@,;:\\\"\/\[\]\?\=\{\}\s]/.freeze); custom_headers << "Cookie: #{ k }=#{ Iodine::Http::Request.encode_url v }\r\n"} if @options[:cookies].is_a?(Hash)
212
208
 
213
209
  # send protocol upgrade request
214
- websocket_key = [(Array.new(16) {rand 255} .pack 'c*' )].pack('m0*')
215
- (ssl || socket).write "GET #{url.path}#{url.query.to_s.empty? ? '' : ('?' + url.query)} HTTP/1.1\r\nHost: #{url.host}#{url.port ? (':'+url.port.to_s) : ''}\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nOrigin: #{ssl ? 'https' : 'http'}://#{url.host}\r\nSec-WebSocket-Key: #{websocket_key}\r\nSec-WebSocket-Version: 13\r\n#{custom_headers}\r\n"
210
+ websocket_key = [(Array.new(16) {rand 255} .pack 'c*'.freeze )].pack('m0*'.freeze)
211
+ (ssl || socket).write "GET #{url.path}#{url.query.to_s.empty? ? ''.freeze : ("?#{url.query}")} HTTP/1.1\r\nHost: #{url.host}#{url.port ? (":#{url.port.to_s}") : ''.freeze}\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nOrigin: #{ssl ? 'https'.freeze : 'http'.freeze}://#{url.host}\r\nSec-WebSocket-Key: #{websocket_key}\r\nSec-WebSocket-Version: 13\r\n#{custom_headers}\r\n"
216
212
  # wait for answer - make sure we don't over-read
217
213
  # (a websocket message might be sent immidiately after connection is established)
218
- reply = ''
219
- reply.force_encoding(::Encoding::ASCII_8BIT)
214
+ reply = String.new.force_encoding(::Encoding::ASCII_8BIT)
220
215
  stop_time = Time.now + (@options[:timeout] || 5)
221
- stop_reply = "\r\n\r\n"
216
+ stop_reply = "\r\n\r\n".freeze
222
217
  until reply[-4..-1] == stop_reply
223
218
  begin
224
219
  reply << ( ssl ? ssl.read_nonblock(1) : socket.recv_nonblock(1) )
@@ -230,24 +225,24 @@ module Iodine
230
225
  raise "Connection failed" if socket.closed?
231
226
  end
232
227
  # review reply
233
- raise "Connection Refused. Reply was:\r\n #{reply}" unless reply.lines[0].match(/^HTTP\/[\d\.]+ 101/i)
234
- raise 'Websocket Key Authentication failed.' unless reply.match(/^Sec-WebSocket-Accept:[\s]*([^\s]*)/i) && reply.match(/^Sec-WebSocket-Accept:[\s]*([^\s]*)/i)[1] == Digest::SHA1.base64digest(websocket_key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
228
+ raise "Connection Refused. Reply was:\r\n #{reply}" unless reply.lines[0].match(/^HTTP\/[\d\.]+ 101/i.freeze)
229
+ raise 'Websocket Key Authentication failed.' unless reply.match(/^Sec-WebSocket-Accept:[\s]*([^\s]*)/i.freeze) && reply.match(/^Sec-WebSocket-Accept:[\s]*([^\s]*)/i.freeze)[1] == Digest::SHA1.base64digest(websocket_key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
235
230
  # read the body's data and parse any incoming data.
236
231
  @request = Iodine::Http::Request.new
237
- @request[:method] = 'GET'
238
- @request['host'] = "#{url.host}:#{url.port}"
232
+ @request[:method] = 'GET'.freeze
233
+ @request['host'.freeze] = "#{url.host}:#{url.port}"
239
234
  @request[:query] = url.path
240
- @request[:version] = '1.1'
235
+ @request[:version] = '1.1'.freeze
241
236
  reply = StringIO.new reply
242
237
  reply.gets
243
238
 
244
239
  until reply.eof?
245
240
  until @request[:headers_complete] || (l = reply.gets).nil?
246
241
  if l.include? ':'
247
- l = l.strip.split(/:[\s]?/, 2)
242
+ l = l.strip.split(/:[\s]?/.freeze, 2)
248
243
  l[0].strip! ; l[0].downcase!;
249
244
  @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])
250
- elsif l =~ /^[\r]?\n/
245
+ elsif l =~ /^[\r]?\n/.freeze
251
246
  @request[:headers_complete] = true
252
247
  else
253
248
  #protocol error
@@ -6,8 +6,8 @@ module Iodine
6
6
  @handler = @options[:handler]
7
7
  @ws_extentions = @options[:ext]
8
8
  @options[:request][:io] = self
9
- @parser = {body: '', stage: 0, step: 0, mask_key: [], len_bytes: []}
10
- set_timeout = self.class.default_timeout
9
+ @parser = {body: String.new, stage: 0, step: 0, mask_key: [], len_bytes: []}
10
+ set_timeout self.class.default_timeout
11
11
  @handler.on_open if @handler.respond_to? :on_open
12
12
  end
13
13
  # parse and handle messages.
@@ -60,7 +60,7 @@ module Iodine
60
60
  end
61
61
  byte_size = data.bytesize
62
62
  if byte_size > (FRAME_SIZE_LIMIT+2)
63
- sections = byte_size/FRAME_SIZE_LIMIT + (byte_size%FRAME_SIZE_LIMIT ? 1 : 0)
63
+ # sections = byte_size/FRAME_SIZE_LIMIT + (byte_size%FRAME_SIZE_LIMIT ? 1 : 0)
64
64
  send_data( data.slice!( 0...FRAME_SIZE_LIMIT ), op_code, data.empty?, ext) && (ext = op_code = 0) until data.empty?
65
65
  return true # avoid sending an empty frame.
66
66
  end
@@ -149,10 +149,10 @@ module Iodine
149
149
  # and MUST NOT use them unless the server indicates that it wishes to use the extension.
150
150
  ws_extentions = []
151
151
  ext = []
152
- request['sec-websocket-extensions'.freeze].to_s.split(/[\s]*[,][\s]*/).each {|ex| ex = ex.split(/[\s]*;[\s]*/); ( ( tmp = SUPPORTED_EXTENTIONS[ ex[0] ].call(ex[1..-1]) ) && (ws_extentions << tmp) && (ext << tmp.name) ) if SUPPORTED_EXTENTIONS[ ex[0] ] }
152
+ request['sec-websocket-extensions'.freeze].to_s.split(/[\s]*[,][\s]*/.freeze).each {|ex| ex = ex.split(/[\s]*;[\s]*/.freeze); ( ( tmp = SUPPORTED_EXTENTIONS[ ex[0] ].call(ex[1..-1]) ) && (ws_extentions << tmp) && (ext << tmp.name) ) if SUPPORTED_EXTENTIONS[ ex[0] ] }
153
153
  ext.compact!
154
154
  if ext.any?
155
- response['sec-websocket-extensions'.freeze] = ext.join(', ')
155
+ response['sec-websocket-extensions'.freeze] = ext.join(', '.freeze)
156
156
  else
157
157
  ws_extentions = nil
158
158
  end
@@ -200,7 +200,7 @@ module Iodine
200
200
 
201
201
  def self.refuse response
202
202
  response.status = 400
203
- response['sec-websocket-extensions'.freeze] = SUPPORTED_EXTENTIONS.keys.join(', ')
203
+ response['sec-websocket-extensions'.freeze] = SUPPORTED_EXTENTIONS.keys.join(', '.freeze)
204
204
  response['sec-websocket-version'.freeze] = '13'.freeze
205
205
  false
206
206
  end
@@ -298,7 +298,7 @@ module Iodine
298
298
  close
299
299
  parser[:p_op_code] = nil if parser[:p_op_code] == 8
300
300
  else
301
- parser[:message] ? ((parser[:message] << parser[:body]) && parser[:body].clear) : ((parser[:message] = parser[:body]) && parser[:body] = '')
301
+ parser[:message] ? ((parser[:message] << parser[:body]) && parser[:body].clear) : ((parser[:message] = parser[:body]) && parser[:body] = String.new)
302
302
  # handle parser[:op_code] == 0 / fin == false (continue a frame that hasn't ended yet)
303
303
  if parser[:fin]
304
304
  @ws_extentions.each {|ex| ex.parse_message(parser) } if @ws_extentions
@@ -125,7 +125,7 @@ module Iodine
125
125
  touch
126
126
  r
127
127
  end
128
- rescue => e
128
+ rescue # => e
129
129
  # Iodine.info e.message
130
130
  close
131
131
  end
@@ -214,7 +214,7 @@ module Iodine
214
214
  # reads from the IO up to the specified number of bytes (defaults to ~1Mb).
215
215
  def read_ssl size
216
216
  @send_locker.synchronize do
217
- data = ''
217
+ data = String.new
218
218
  begin
219
219
  (data << @io.read_nonblock(size).to_s) until data.bytesize >= size
220
220
  rescue OpenSSL::SSL::SSLErrorWaitReadable, IO::WaitReadable, IO::WaitWritable
@@ -120,7 +120,7 @@ module Iodine
120
120
  def create_cert bits=2048, cn=nil, comment='a self signed certificate for when we only need encryption and no more.'
121
121
  unless cn
122
122
  host_name = Socket::gethostbyname(Socket::gethostname)[0].split('.')
123
- cn = ''
123
+ cn = String.new
124
124
  host_name.each {|n| cn << "/DC=#{n}"}
125
125
  cn << "/CN=Iodine.#{host_name.join('.')}"
126
126
  end
@@ -10,7 +10,7 @@ module Iodine
10
10
  end
11
11
  TIMEOUT = 3 # hardcoded SSL/TLS handshake timeout
12
12
  def on_open
13
- timeout = TIMEOUT
13
+ set_timeout TIMEOUT
14
14
  @ssl_socket = ::OpenSSL::SSL::SSLSocket.new(@io, ::Iodine.ssl_context)
15
15
  @ssl_socket.sync_close = true
16
16
  end
@@ -42,7 +42,7 @@ module Iodine
42
42
  return false unless @next <= @reactor.time
43
43
  return true if @repeat_limit == 0
44
44
  @repeat_limit -= 1 if @repeat_limit.to_i > 0
45
- @reactor.run *@args, &@job
45
+ @reactor.run(*@args, &@job)
46
46
  @next = @reactor.time + @interval
47
47
  @repeat_limit == 0
48
48
  end
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = "0.1.12"
2
+ VERSION = "0.1.13"
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.12
4
+ version: 0.1.13
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-12 00:00:00.000000000 Z
11
+ date: 2015-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler