rainbows 4.7.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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