rainbows 4.7.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +5 -0
  3. data/GIT-VERSION-GEN +1 -1
  4. data/README +5 -9
  5. data/bin/rainbows +3 -3
  6. data/lib/rainbows.rb +18 -6
  7. data/lib/rainbows/configurator.rb +8 -8
  8. data/lib/rainbows/const.rb +0 -3
  9. data/lib/rainbows/coolio.rb +2 -7
  10. data/lib/rainbows/coolio/client.rb +6 -6
  11. data/lib/rainbows/coolio/heartbeat.rb +2 -2
  12. data/lib/rainbows/coolio/thread_client.rb +3 -3
  13. data/lib/rainbows/dev_fd_response.rb +8 -14
  14. data/lib/rainbows/epoll/client.rb +9 -10
  15. data/lib/rainbows/error.rb +2 -2
  16. data/lib/rainbows/ev_core.rb +11 -17
  17. data/lib/rainbows/event_machine/client.rb +7 -7
  18. data/lib/rainbows/event_machine/try_defer.rb +1 -4
  19. data/lib/rainbows/fiber.rb +1 -1
  20. data/lib/rainbows/fiber/base.rb +3 -3
  21. data/lib/rainbows/fiber/coolio/heartbeat.rb +1 -1
  22. data/lib/rainbows/fiber/io.rb +1 -1
  23. data/lib/rainbows/http_parser.rb +24 -0
  24. data/lib/rainbows/http_server.rb +5 -4
  25. data/lib/rainbows/join_threads.rb +2 -2
  26. data/lib/rainbows/max_body.rb +4 -9
  27. data/lib/rainbows/process_client.rb +11 -12
  28. data/lib/rainbows/response.rb +20 -37
  29. data/lib/rainbows/revactor.rb +0 -1
  30. data/lib/rainbows/revactor/client.rb +2 -3
  31. data/lib/rainbows/revactor/proxy.rb +1 -1
  32. data/lib/rainbows/reverse_proxy.rb +9 -19
  33. data/lib/rainbows/reverse_proxy/coolio.rb +3 -3
  34. data/lib/rainbows/reverse_proxy/ev_client.rb +2 -5
  35. data/lib/rainbows/reverse_proxy/event_machine.rb +1 -1
  36. data/lib/rainbows/sendfile.rb +3 -9
  37. data/lib/rainbows/server_token.rb +1 -6
  38. data/lib/rainbows/stream_response_epoll.rb +8 -9
  39. data/lib/rainbows/thread_timeout.rb +4 -4
  40. data/lib/rainbows/writer_thread_pool.rb +2 -2
  41. data/lib/rainbows/xepoll_thread_pool/client.rb +3 -4
  42. data/lib/rainbows/xepoll_thread_spawn/client.rb +3 -4
  43. data/rainbows.gemspec +1 -1
  44. data/t/t0105-rack-input-limit-bigger.sh +10 -2
  45. data/t/test_isolate.rb +1 -1
  46. metadata +5 -4
@@ -10,9 +10,6 @@
10
10
  # See http://brainspl.at/articles/2008/04/18/deferred-requests-with-merb-ebb-and-thin
11
11
  # for more information.
12
12
  class Rainbows::EventMachine::TryDefer
13
- # shortcuts
14
- ASYNC_CALLBACK = Rainbows::EvCore::ASYNC_CALLBACK # :nodoc:
15
-
16
13
  def initialize(app) # :nodoc:
17
14
  # the entire app becomes multithreaded, even the root (non-deferred)
18
15
  # thread since any thread can share processes with others
@@ -22,7 +19,7 @@ def initialize(app) # :nodoc:
22
19
 
23
20
  def call(env) # :nodoc:
24
21
  if @app.deferred?(env)
25
- EM.defer(proc { catch(:async) { @app.call(env) } }, env[ASYNC_CALLBACK])
22
+ EM.defer(proc { catch(:async) { @app.call(env) } }, env['async.callback'])
26
23
  # all of the async/deferred stuff breaks Rack::Lint :<
27
24
  nil
28
25
  else
@@ -29,7 +29,7 @@ module Rainbows::Fiber
29
29
  # right?). Calling this directly is deprecated, use
30
30
  # Rainbows.sleep(seconds) instead.
31
31
  def self.sleep(seconds)
32
- ZZ[Fiber.current] = Time.now + seconds
32
+ ZZ[Fiber.current] = Rainbows.now + seconds
33
33
  Fiber.yield
34
34
  end
35
35
 
@@ -40,7 +40,7 @@ def schedule
40
40
  # woken and returns an interval to IO.select on
41
41
  def schedule_sleepers
42
42
  max = nil
43
- now = Time.now
43
+ now = Rainbows.now
44
44
  fibs = []
45
45
  ZZ.delete_if { |fib, time|
46
46
  if now >= time
@@ -50,11 +50,11 @@ def schedule_sleepers
50
50
  false
51
51
  end
52
52
  }
53
- fibs.each { |fib| fib.resume }
53
+ fibs.each(&:resume)
54
54
 
55
55
  max_sleep = 1.0 # wake up semi-frequently to prevent SIGKILL from master
56
56
  if max
57
- max -= Time.now
57
+ max -= Rainbows.now
58
58
  return 0 if max < 0.0
59
59
  return max_sleep if max > max_sleep
60
60
  max
@@ -5,7 +5,7 @@ class Rainbows::Fiber::Coolio::Heartbeat < Coolio::TimerWatcher
5
5
  ZZ = Rainbows::Fiber::ZZ
6
6
  def on_timer
7
7
  exit if (! Rainbows.tick && Rainbows.cur <= 0)
8
- now = Time.now
8
+ now = Rainbows.now
9
9
  fibs = []
10
10
  ZZ.delete_if { |fib, time| now >= time ? fibs << fib : ! fib.alive? }
11
11
  fibs.each { |fib| fib.resume if fib.alive? }
@@ -63,7 +63,7 @@ def timed_read(buf)
63
63
  expire = nil
64
64
  case rv = Kgio.tryread(@to_io, 16384, buf)
65
65
  when :wait_readable
66
- return if expire && expire < Time.now
66
+ return if expire && expire < Rainbows.now
67
67
  expire ||= read_expire
68
68
  kgio_wait_readable
69
69
  else
@@ -2,6 +2,30 @@
2
2
  # :enddoc:
3
3
  # avoid modifying Unicorn::HttpParser
4
4
  class Rainbows::HttpParser < Unicorn::HttpParser
5
+ @keepalive_requests = 100
6
+ class << self
7
+ attr_accessor :keepalive_requests
8
+ end
9
+
10
+ def initialize(*args)
11
+ @keepalive_requests = self.class.keepalive_requests
12
+ super
13
+ end
14
+
15
+ def next?
16
+ return false if (@keepalive_requests -= 1) <= 0
17
+ super
18
+ end
19
+
20
+ def hijack_setup(io)
21
+ @hijack_io = io
22
+ env['rack.hijack'] = self # avoid allocating a new proc this way
23
+ end
24
+
25
+ def call # for rack.hijack
26
+ env['rack.hijack_io'] = @hijack_io
27
+ end
28
+
5
29
  def self.quit
6
30
  alias_method :next?, :never!
7
31
  end
@@ -8,6 +8,7 @@ class Rainbows::HttpServer < Unicorn::HttpServer
8
8
  attr_accessor :client_header_buffer_size
9
9
  attr_accessor :client_max_body_size
10
10
  attr_reader :use
11
+ attr_reader :master_pid
11
12
 
12
13
  def self.setup(block)
13
14
  Rainbows.server.instance_eval(&block)
@@ -81,10 +82,10 @@ def svc
81
82
  end
82
83
 
83
84
  def use=(mod)
84
- @use = mod.to_s.split(/::/)[-1].to_sym
85
+ @use = mod.to_s.split('::')[-1].to_sym
85
86
  new_defaults = {
86
87
  'rainbows.model' => @use,
87
- 'rack.multithread' => !!(mod.to_s =~ /Thread/),
88
+ 'rack.multithread' => mod.to_s.include?('Thread'),
88
89
  'rainbows.autochunk' => [:Coolio,:Rev,:Epoll,:XEpoll,
89
90
  :EventMachine,:NeverBlock].include?(@use),
90
91
  }
@@ -92,11 +93,11 @@ def use=(mod)
92
93
  end
93
94
 
94
95
  def keepalive_requests=(nr)
95
- Unicorn::HttpRequest.keepalive_requests = nr
96
+ Rainbows::HttpParser.keepalive_requests = nr
96
97
  end
97
98
 
98
99
  def keepalive_requests
99
- Unicorn::HttpRequest.keepalive_requests
100
+ Rainbows::HttpParser.keepalive_requests
100
101
  end
101
102
 
102
103
  def client_max_header_size=(bytes)
@@ -5,12 +5,12 @@ module Rainbows::JoinThreads
5
5
 
6
6
  # blocking acceptor threads must be forced to run
7
7
  def self.acceptors(threads)
8
- expire = Time.now + Rainbows.server.timeout
8
+ expire = Rainbows.now + Rainbows.server.timeout
9
9
  threads.delete_if do |thr|
10
10
  Rainbows.tick
11
11
  begin
12
12
  # blocking accept() may not wake up properly
13
- thr.raise(Errno::EINTR) if Time.now > expire && thr.stop?
13
+ thr.raise(Errno::EINTR) if Rainbows.now > expire && thr.stop?
14
14
 
15
15
  thr.run
16
16
  thr.join(0.01)
@@ -48,19 +48,14 @@ def initialize(app, limit = nil)
48
48
  @app, @limit = app, limit
49
49
  end
50
50
 
51
- # :stopdoc:
52
- RACK_INPUT = "rack.input".freeze
53
- CONTENT_LENGTH = "CONTENT_LENGTH"
54
- HTTP_TRANSFER_ENCODING = "HTTP_TRANSFER_ENCODING"
55
-
56
51
  # our main Rack middleware endpoint
57
52
  def call(env)
58
53
  @limit = Rainbows.server.client_max_body_size if nil == @limit
59
54
  catch(:rainbows_EFBIG) do
60
- len = env[CONTENT_LENGTH]
55
+ len = env['CONTENT_LENGTH']
61
56
  if len && len.to_i > @limit
62
57
  return err
63
- elsif /\Achunked\z/i =~ env[HTTP_TRANSFER_ENCODING]
58
+ elsif /\Achunked\z/i =~ env['HTTP_TRANSFER_ENCODING']
64
59
  limit_input!(env)
65
60
  end
66
61
  @app.call(env)
@@ -89,9 +84,9 @@ def err # :nodoc:
89
84
  end
90
85
 
91
86
  def limit_input!(env)
92
- input = env[RACK_INPUT]
87
+ input = env['rack.input']
93
88
  klass = input.respond_to?(:rewind) ? RewindableWrapper : Wrapper
94
- env[RACK_INPUT] = klass.new(input, @limit)
89
+ env['rack.input'] = klass.new(input, @limit)
95
90
  end
96
91
 
97
92
  # :startdoc:
@@ -5,12 +5,11 @@ module Rainbows::ProcessClient
5
5
  include Rainbows::Const
6
6
 
7
7
  NULL_IO = Unicorn::HttpRequest::NULL_IO
8
- RACK_INPUT = Unicorn::HttpRequest::RACK_INPUT
9
8
  IC = Unicorn::HttpRequest.input_class
10
9
  Rainbows.config!(self, :client_header_buffer_size, :keepalive_timeout)
11
10
 
12
11
  def read_expire
13
- Time.now + KEEPALIVE_TIMEOUT
12
+ Rainbows.now + KEEPALIVE_TIMEOUT
14
13
  end
15
14
 
16
15
  # used for reading headers (respecting keepalive_timeout)
@@ -19,7 +18,7 @@ def timed_read(buf)
19
18
  begin
20
19
  case rv = kgio_tryread(CLIENT_HEADER_BUFFER_SIZE, buf)
21
20
  when :wait_readable
22
- return if expire && expire < Time.now
21
+ return if expire && expire < Rainbows.now
23
22
  expire ||= read_expire
24
23
  kgio_wait_readable(KEEPALIVE_TIMEOUT)
25
24
  else
@@ -39,13 +38,13 @@ def process_loop
39
38
  end
40
39
 
41
40
  set_input(env, hp)
42
- env[REMOTE_ADDR] = kgio_addr
43
- hp.hijack_setup(env, to_io)
41
+ env['REMOTE_ADDR'] = kgio_addr
42
+ hp.hijack_setup(to_io)
44
43
  status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
45
44
 
46
45
  if 100 == status.to_i
47
- write(EXPECT_100_RESPONSE)
48
- env.delete(HTTP_EXPECT)
46
+ write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
47
+ env.delete('HTTP_EXPECT'.freeze)
49
48
  status, headers, body = APP.call(env)
50
49
  end
51
50
  return if hp.hijacked?
@@ -66,18 +65,18 @@ def handle_error(e)
66
65
  end
67
66
 
68
67
  def set_input(env, hp)
69
- env[RACK_INPUT] = 0 == hp.content_length ? NULL_IO : IC.new(self, hp)
68
+ env['rack.input'] = 0 == hp.content_length ? NULL_IO : IC.new(self, hp)
70
69
  end
71
70
 
72
71
  def process_pipeline(env, hp)
73
72
  begin
74
73
  set_input(env, hp)
75
- env[REMOTE_ADDR] = kgio_addr
76
- hp.hijack_setup(env, to_io)
74
+ env['REMOTE_ADDR'] = kgio_addr
75
+ hp.hijack_setup(to_io)
77
76
  status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
78
77
  if 100 == status.to_i
79
- write(EXPECT_100_RESPONSE)
80
- env.delete(HTTP_EXPECT)
78
+ write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
79
+ env.delete('HTTP_EXPECT'.freeze)
81
80
  status, headers, body = APP.call(env)
82
81
  end
83
82
  return if hp.hijacked?
@@ -2,10 +2,6 @@
2
2
  # :enddoc:
3
3
  module Rainbows::Response
4
4
  include Unicorn::HttpResponse
5
- Close = "close"
6
- KeepAlive = "keep-alive"
7
- Content_Length = "Content-Length".freeze
8
- Transfer_Encoding = "Transfer-Encoding".freeze
9
5
  Rainbows.config!(self, :copy_stream)
10
6
 
11
7
  # private file class for IO objects opened by Rainbows! itself (and not
@@ -19,20 +15,8 @@ def self.setup
19
15
  Rainbows::HttpParser.keepalive_requests = 0
20
16
  end
21
17
 
22
- # Rack 1.5.0 (protocol version 1.2) adds response hijacking support
23
- if ((Rack::VERSION[0] << 8) | Rack::VERSION[1]) >= 0x0102
24
- RACK_HIJACK = "rack.hijack"
25
-
26
- def hijack_prepare(value)
27
- value
28
- end
29
-
30
- def hijack_socket
31
- @hp.env[RACK_HIJACK].call
32
- end
33
- else
34
- def hijack_prepare(_)
35
- end
18
+ def hijack_socket
19
+ @hp.env['rack.hijack'].call
36
20
  end
37
21
 
38
22
  # returns the original body on success
@@ -40,29 +24,30 @@ def hijack_prepare(_)
40
24
  def write_headers(status, headers, alive, body)
41
25
  @hp.headers? or return body
42
26
  hijack = nil
43
- status = CODES[status.to_i] || status
44
- buf = "HTTP/1.1 #{status}\r\n" \
45
- "Date: #{httpdate}\r\n" \
46
- "Status: #{status}\r\n"
27
+ code = status.to_i
28
+ msg = Rack::Utils::HTTP_STATUS_CODES[code]
29
+ buf = "HTTP/1.1 #{msg ? %Q(#{code} #{msg}) : status}\r\n" \
30
+ "Date: #{httpdate}\r\n"
47
31
  headers.each do |key, value|
48
32
  case key
49
- when %r{\A(?:Date\z|Connection\z)}i
33
+ when %r{\A(?:Date|Connection)\z}i
50
34
  next
51
35
  when "rack.hijack"
52
36
  # this was an illegal key in Rack < 1.5, so it should be
53
37
  # OK to silently discard it for those older versions
54
- hijack = hijack_prepare(value)
38
+ hijack = value
55
39
  alive = false # No persistent connections for hijacking
56
40
  else
57
41
  if /\n/ =~ value
58
42
  # avoiding blank, key-only cookies with /\n+/
59
- buf << value.split(/\n+/).map! { |v| "#{key}: #{v}\r\n" }.join
43
+ value.split(/\n+/).each { |v| buf << "#{key}: #{v}\r\n" }
60
44
  else
61
45
  buf << "#{key}: #{value}\r\n"
62
46
  end
63
47
  end
64
48
  end
65
- write(buf << "Connection: #{alive ? KeepAlive : Close}\r\n\r\n")
49
+ write(buf << (alive ? "Connection: keep-alive\r\n\r\n".freeze
50
+ : "Connection: close\r\n\r\n".freeze))
66
51
 
67
52
  if hijack
68
53
  body = nil # ensure caller does not close body
@@ -152,30 +137,27 @@ def write_body_stream(body)
152
137
  end # ! COPY_STREAM
153
138
 
154
139
  if IO.method_defined?(:trysendfile) || COPY_STREAM
155
- HTTP_RANGE = 'HTTP_RANGE'
156
- Content_Range = 'Content-Range'.freeze
157
-
158
140
  # This does not support multipart responses (does anybody actually
159
141
  # use those?)
160
142
  def sendfile_range(status, headers)
161
143
  status = status.to_i
162
144
  if 206 == status
163
- if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ headers[Content_Range]
145
+ if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ headers['Content-Range'.freeze]
164
146
  a, b = $1.to_i, $2.to_i
165
147
  return 206, headers, [ a, b - a + 1 ]
166
148
  end
167
149
  return # wtf...
168
150
  end
169
151
  200 == status &&
170
- /\Abytes=(\d+-\d*|\d*-\d+)\z/ =~ @hp.env[HTTP_RANGE] or
152
+ /\Abytes=(\d+-\d*|\d*-\d+)\z/ =~ @hp.env['HTTP_RANGE'] or
171
153
  return
172
- a, b = $1.split(/-/)
154
+ a, b = $1.split('-'.freeze)
173
155
 
174
156
  # HeaderHash is quite expensive, and Rack::File currently
175
157
  # uses a regular Ruby Hash with properly-cased headers the
176
158
  # same way they're presented in rfc2616.
177
159
  headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
178
- clen = headers[Content_Length] or return
160
+ clen = headers['Content-Length'.freeze] or return
179
161
  size = clen.to_i
180
162
 
181
163
  if b.nil? # bytes=M-
@@ -190,13 +172,14 @@ def sendfile_range(status, headers)
190
172
  end
191
173
 
192
174
  if 0 > count || offset >= size
193
- headers[Content_Length] = "0"
194
- headers[Content_Range] = "bytes */#{clen}"
175
+ headers['Content-Length'.freeze] = "0"
176
+ headers['Content-Range'.freeze] = "bytes */#{clen}"
195
177
  return 416, headers, nil
196
178
  else
197
179
  count = size if count > size
198
- headers[Content_Length] = count.to_s
199
- headers[Content_Range] = "bytes #{offset}-#{offset+count-1}/#{clen}"
180
+ headers['Content-Length'.freeze] = count.to_s
181
+ headers['Content-Range'.freeze] =
182
+ "bytes #{offset}-#{offset+count-1}/#{clen}"
200
183
  return 206, headers, [ offset, count ]
201
184
  end
202
185
  end
@@ -1,6 +1,5 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'revactor'
3
- require 'fcntl'
4
3
  Revactor::VERSION >= '0.1.5' or abort 'revactor 0.1.5 is required'
5
4
 
6
5
  # Enables use of the Actor model through {Revactor}[http://revactor.org]
@@ -1,6 +1,5 @@
1
1
  # -*- encoding: binary -*-
2
2
  # :enddoc:
3
- require 'fcntl'
4
3
  class Rainbows::Revactor::Client
5
4
  autoload :TeeSocket, 'rainbows/revactor/client/tee_socket'
6
5
  RD_ARGS = {}
@@ -11,7 +10,7 @@ class Rainbows::Revactor::Client
11
10
  def initialize(client)
12
11
  @client, @rd_args, @ts = client, [ nil ], nil
13
12
  io = client.instance_variable_get(:@_io)
14
- io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
13
+ io.close_on_exec = true
15
14
  @kgio_addr = if Revactor::TCP::Socket === client
16
15
  @rd_args << RD_ARGS
17
16
  client.remote_addr
@@ -33,7 +32,7 @@ def timed_read(buf2)
33
32
  end
34
33
 
35
34
  def set_input(env, hp)
36
- env[RACK_INPUT] = 0 == hp.content_length ?
35
+ env['rack.input'] = 0 == hp.content_length ?
37
36
  NULL_IO : IC.new(@ts = TeeSocket.new(@client), hp)
38
37
  end
39
38
 
@@ -22,7 +22,7 @@ def each
22
22
  # (instead of Errno::EPIPE), so we need to limit the rescue
23
23
  # to just readpartial and let EOFErrors during yield bubble up
24
24
  begin
25
- buf = readpartial(INPUT_SIZE)
25
+ buf = readpartial(16384)
26
26
  rescue EOFError
27
27
  break
28
28
  end while yield(buf) || true
@@ -47,15 +47,6 @@ class Rainbows::ReverseProxy
47
47
  autoload :EventMachine, 'rainbows/reverse_proxy/event_machine'
48
48
  autoload :EvClient, 'rainbows/reverse_proxy/ev_client'
49
49
 
50
- HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
51
- REMOTE_ADDR = "REMOTE_ADDR"
52
- REQUEST_METHOD = "REQUEST_METHOD"
53
- REQUEST_URI = "REQUEST_URI"
54
- CRLF = "\r\n"
55
- TR = %w(_ -)
56
- CONTENT_LENGTH = "CONTENT_LENGTH"
57
- HTTP_TRANSFER_ENCODING = "HTTP_TRANSFER_ENCODING"
58
- RackInput = "rack.input"
59
50
  E502 = [ 502, [ %w(Content-Length 0), %w(Content-Type text/plain) ], [] ]
60
51
 
61
52
  def initialize(opts)
@@ -113,24 +104,23 @@ def call(env)
113
104
 
114
105
  # returns request headers for sending to the upstream as a string
115
106
  def build_headers(env, input)
116
- remote_addr = env[REMOTE_ADDR]
117
- xff = env[HTTP_X_FORWARDED_FOR]
107
+ remote_addr = env['REMOTE_ADDR']
108
+ xff = env['HTTP_X_FORWARDED_FOR']
118
109
  xff = xff ? "#{xff},#{remote_addr}" : remote_addr
119
- req = "#{env[REQUEST_METHOD]} #{env[REQUEST_URI]} HTTP/1.0\r\n" \
110
+ req = "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']} HTTP/1.0\r\n" \
120
111
  "Connection: close\r\n" \
121
112
  "X-Forwarded-For: #{xff}\r\n"
122
- uscore, dash = *TR
123
113
  env.each do |key, value|
124
114
  %r{\AHTTP_(\w+)\z} =~ key or next
125
115
  key = $1
126
116
  next if %r{\A(?:VERSION|CONNECTION|KEEP_ALIVE|X_FORWARDED_FOR)\z}x =~ key
127
- key.tr!(uscore, dash)
117
+ key.tr!('_'.freeze, '-'.freeze)
128
118
  req << "#{key}: #{value}\r\n"
129
119
  end
130
120
  input and req << (input.respond_to?(:size) ?
131
121
  "Content-Length: #{input.size}\r\n" :
132
- "Transfer-Encoding: chunked\r\n")
133
- req << CRLF
122
+ "Transfer-Encoding: chunked\r\n".freeze)
123
+ req << "\r\n".freeze
134
124
  end
135
125
 
136
126
  def pick_upstream(env) # +env+ is reserved for future expansion
@@ -139,16 +129,16 @@ def pick_upstream(env) # +env+ is reserved for future expansion
139
129
  end
140
130
 
141
131
  def prepare_input!(env)
142
- if cl = env[CONTENT_LENGTH]
132
+ if cl = env['CONTENT_LENGTH']
143
133
  size = cl.to_i
144
134
  size > 0 or return
145
- elsif %r{\Achunked\z}i =~ env.delete(HTTP_TRANSFER_ENCODING)
135
+ elsif %r{\Achunked\z}i =~ env.delete('HTTP_TRANSFER_ENCODING')
146
136
  # do people use multiple transfer-encodings?
147
137
  else
148
138
  return
149
139
  end
150
140
 
151
- input = env[RackInput]
141
+ input = env['rack.input']
152
142
  if input.respond_to?(:rewind)
153
143
  if input.respond_to?(:size)
154
144
  input.size # TeeInput-specific behavior