rainbows 3.2.0 → 3.3.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 (70) hide show
  1. data/.document +1 -0
  2. data/COPYING +617 -282
  3. data/Documentation/comparison.haml +81 -24
  4. data/FAQ +3 -0
  5. data/GIT-VERSION-GEN +1 -1
  6. data/LICENSE +14 -5
  7. data/README +10 -9
  8. data/Sandbox +25 -0
  9. data/TODO +2 -22
  10. data/lib/rainbows.rb +50 -49
  11. data/lib/rainbows/client.rb +6 -5
  12. data/lib/rainbows/configurator.rb +191 -37
  13. data/lib/rainbows/const.rb +1 -1
  14. data/lib/rainbows/coolio.rb +4 -1
  15. data/lib/rainbows/coolio/client.rb +2 -2
  16. data/lib/rainbows/coolio/heartbeat.rb +2 -1
  17. data/lib/rainbows/coolio_fiber_spawn.rb +12 -7
  18. data/lib/rainbows/coolio_thread_pool.rb +19 -10
  19. data/lib/rainbows/coolio_thread_spawn.rb +3 -0
  20. data/lib/rainbows/epoll.rb +27 -5
  21. data/lib/rainbows/epoll/client.rb +3 -3
  22. data/lib/rainbows/ev_core.rb +2 -1
  23. data/lib/rainbows/event_machine.rb +4 -0
  24. data/lib/rainbows/event_machine/client.rb +2 -1
  25. data/lib/rainbows/fiber.rb +5 -0
  26. data/lib/rainbows/fiber/base.rb +1 -0
  27. data/lib/rainbows/fiber/coolio/methods.rb +0 -1
  28. data/lib/rainbows/fiber/io.rb +10 -6
  29. data/lib/rainbows/fiber/io/pipe.rb +6 -1
  30. data/lib/rainbows/fiber/io/socket.rb +6 -1
  31. data/lib/rainbows/fiber_pool.rb +12 -7
  32. data/lib/rainbows/fiber_spawn.rb +11 -6
  33. data/lib/rainbows/http_server.rb +55 -59
  34. data/lib/rainbows/join_threads.rb +4 -0
  35. data/lib/rainbows/max_body.rb +29 -10
  36. data/lib/rainbows/never_block.rb +7 -10
  37. data/lib/rainbows/pool_size.rb +14 -0
  38. data/lib/rainbows/process_client.rb +23 -1
  39. data/lib/rainbows/queue_pool.rb +8 -6
  40. data/lib/rainbows/response.rb +12 -11
  41. data/lib/rainbows/revactor.rb +14 -7
  42. data/lib/rainbows/revactor/client.rb +2 -2
  43. data/lib/rainbows/stream_file.rb +11 -4
  44. data/lib/rainbows/thread_pool.rb +12 -28
  45. data/lib/rainbows/thread_spawn.rb +14 -13
  46. data/lib/rainbows/thread_timeout.rb +118 -30
  47. data/lib/rainbows/writer_thread_pool/client.rb +1 -1
  48. data/lib/rainbows/writer_thread_spawn/client.rb +2 -2
  49. data/lib/rainbows/xepoll.rb +13 -5
  50. data/lib/rainbows/xepoll/client.rb +19 -17
  51. data/lib/rainbows/xepoll_thread_pool.rb +82 -0
  52. data/lib/rainbows/xepoll_thread_pool/client.rb +129 -0
  53. data/lib/rainbows/xepoll_thread_spawn.rb +58 -0
  54. data/lib/rainbows/xepoll_thread_spawn/client.rb +121 -0
  55. data/pkg.mk +4 -0
  56. data/rainbows.gemspec +4 -1
  57. data/t/GNUmakefile +5 -1
  58. data/t/client_header_buffer_size.ru +5 -0
  59. data/t/simple-http_XEpollThreadPool.ru +10 -0
  60. data/t/simple-http_XEpollThreadSpawn.ru +10 -0
  61. data/t/t0022-copy_stream-byte-range.sh +1 -15
  62. data/t/t0026-splice-copy_stream-byte-range.sh +25 -0
  63. data/t/t0027-nil-copy_stream.sh +60 -0
  64. data/t/t0041-optional-pool-size.sh +2 -2
  65. data/t/t0042-client_header_buffer_size.sh +65 -0
  66. data/t/t9100-thread-timeout.sh +1 -6
  67. data/t/t9101-thread-timeout-threshold.sh +1 -6
  68. data/t/test-lib.sh +58 -0
  69. data/t/test_isolate.rb +9 -3
  70. metadata +47 -16
@@ -10,7 +10,7 @@ module Rainbows::Epoll::Client
10
10
  OUT = SleepyPenguin::Epoll::OUT | SleepyPenguin::Epoll::ET
11
11
  KATO = {}
12
12
  KATO.compare_by_identity if KATO.respond_to?(:compare_by_identity)
13
- KEEPALIVE_TIMEOUT = Rainbows.keepalive_timeout
13
+ Rainbows.config!(self, :keepalive_timeout)
14
14
  EP = Rainbows::Epoll::EP
15
15
  @@last_expire = Time.now
16
16
 
@@ -33,7 +33,7 @@ module Rainbows::Epoll::Client
33
33
  end
34
34
 
35
35
  def on_readable
36
- case rv = kgio_tryread(16384, RBUF)
36
+ case rv = kgio_tryread(CLIENT_HEADER_BUFFER_SIZE, RBUF)
37
37
  when String
38
38
  on_read(rv)
39
39
  return if @wr_queue[0] || closed?
@@ -226,7 +226,7 @@ module Rainbows::Epoll::Client
226
226
  else # nil => EOF
227
227
  return pipe.close # nil
228
228
  end while true
229
- rescue => e
229
+ rescue
230
230
  pipe.close
231
231
  raise
232
232
  end
@@ -9,6 +9,7 @@ module Rainbows::EvCore
9
9
  autoload :CapInput, 'rainbows/ev_core/cap_input'
10
10
  RBUF = ""
11
11
  Z = "".freeze
12
+ Rainbows.config!(self, :client_header_buffer_size)
12
13
 
13
14
  # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
14
15
  ASYNC_CALLBACK = "async.callback".freeze
@@ -132,7 +133,7 @@ module Rainbows::EvCore
132
133
  end
133
134
 
134
135
  def mkinput
135
- max = Rainbows.max_bytes
136
+ max = Rainbows.server.client_max_body_size
136
137
  len = @hp.content_length
137
138
  if len
138
139
  if max && (len > max)
@@ -40,6 +40,10 @@ EM::VERSION >= '0.12.10' or abort 'eventmachine 0.12.10 is required'
40
40
  # the Rack application to process data as it arrives. This means
41
41
  # "rack.input" will be fully buffered in memory or to a temporary file
42
42
  # before the application is entered.
43
+ #
44
+ # === RubyGem Requirements
45
+ #
46
+ # * event_machine 0.12.10
43
47
  module Rainbows::EventMachine
44
48
  autoload :ResponsePipe, 'rainbows/event_machine/response_pipe'
45
49
  autoload :ResponseChunkPipe, 'rainbows/event_machine/response_chunk_pipe'
@@ -2,6 +2,7 @@
2
2
  # :enddoc:
3
3
  class Rainbows::EventMachine::Client < EM::Connection
4
4
  include Rainbows::EvCore
5
+ Rainbows.config!(self, :keepalive_timeout)
5
6
 
6
7
  def initialize(io)
7
8
  @_io = io
@@ -87,7 +88,7 @@ class Rainbows::EventMachine::Client < EM::Connection
87
88
  if alive
88
89
  if @deferred.nil?
89
90
  if @buf.empty?
90
- set_comm_inactivity_timeout(Rainbows.keepalive_timeout)
91
+ set_comm_inactivity_timeout(KEEPALIVE_TIMEOUT)
91
92
  else
92
93
  EM.next_tick { receive_data(nil) }
93
94
  end
@@ -8,6 +8,11 @@ end
8
8
  # :startdoc:
9
9
 
10
10
  # core namespace for all things that use Fibers in \Rainbows!
11
+ #
12
+ # It's generally not recommended to use any of this in your applications
13
+ # unless you're willing to accept breakage. Most of this is very
14
+ # difficult-to-use, fragile and we don't have much time to devote to
15
+ # supporting these in the future.
11
16
  module Rainbows::Fiber
12
17
 
13
18
  # :stopdoc:
@@ -64,6 +64,7 @@ module Rainbows::Fiber::Base
64
64
  end
65
65
 
66
66
  def self.setup(klass, app)
67
+ Rainbows::Client.__send__(:include, Rainbows::Fiber::IO::Methods)
67
68
  require 'rainbows/fiber/body'
68
69
  Rainbows::Client.__send__(:include, Rainbows::Fiber::Body)
69
70
  self.const_set(:APP, app)
@@ -38,7 +38,6 @@ end
38
38
 
39
39
  [
40
40
  Rainbows::Fiber::IO,
41
- Rainbows::Client,
42
41
  # the next two trigger autoload, ugh, oh well...
43
42
  Rainbows::Fiber::IO::Socket,
44
43
  Rainbows::Fiber::IO::Pipe
@@ -1,13 +1,18 @@
1
1
  # -*- encoding: binary -*-
2
2
 
3
- # A Fiber-aware IO class, gives users the illusion of a synchronous
4
- # interface that yields away from the current Fiber whenever
3
+ # A \Fiber-aware IO class, gives users the illusion of a synchronous
4
+ # interface that yields away from the current \Fiber whenever
5
5
  # the underlying descriptor is blocked on reads or write
6
6
  #
7
+ # It's not recommended to use any of this in your applications
8
+ # unless you're willing to accept breakage. Most of this is very
9
+ # difficult-to-use, fragile and we don't have much time to devote to
10
+ # supporting these in the future.
11
+ #
7
12
  # This is a stable, legacy interface and should be preserved for all
8
13
  # future versions of Rainbows! However, new apps should use
9
- # Rainbows::Fiber::IO::Socket or Rainbows::Fiber::IO::Pipe instead.
10
-
14
+ # Rainbows::Fiber::IO::Socket or Rainbows::Fiber::IO::Pipe instead
15
+ # (or better yet, avoid any of the Rainbows::Fiber* stuff).
11
16
  class Rainbows::Fiber::IO
12
17
  attr_accessor :to_io
13
18
 
@@ -45,7 +50,7 @@ class Rainbows::Fiber::IO
45
50
  end
46
51
 
47
52
  def write(buf)
48
- case rv = Kgio.trywrite(buf)
53
+ case rv = Kgio.trywrite(@to_io, buf)
49
54
  when String
50
55
  buf = rv
51
56
  when :wait_writable
@@ -96,7 +101,6 @@ end
96
101
  # :stopdoc:
97
102
  require 'rainbows/fiber/io/methods'
98
103
  require 'rainbows/fiber/io/compat'
99
- Rainbows::Client.__send__(:include, Rainbows::Fiber::IO::Methods)
100
104
  class Rainbows::Fiber::IO
101
105
  include Rainbows::Fiber::IO::Compat
102
106
  include Rainbows::Fiber::IO::Methods
@@ -1,7 +1,12 @@
1
1
  # -*- encoding: binary -*-
2
2
  # A Fiber-aware Pipe class, gives users the illusion of a synchronous
3
3
  # interface that yields away from the current Fiber whenever
4
- # the underlying descriptor is blocked on reads or write
4
+ # the underlying descriptor is blocked on reads or write.
5
+ #
6
+ # It's not recommended to use any of this in your applications
7
+ # unless you're willing to accept breakage. Most of this is very
8
+ # difficult-to-use, fragile and we don't have much time to devote to
9
+ # supporting these in the future.
5
10
  class Rainbows::Fiber::IO::Pipe < Kgio::Pipe
6
11
  include Rainbows::Fiber::IO::Methods
7
12
  end
@@ -1,7 +1,12 @@
1
1
  # -*- encoding: binary -*-
2
2
  # A Fiber-aware Socket class, gives users the illusion of a synchronous
3
3
  # interface that yields away from the current Fiber whenever
4
- # the underlying descriptor is blocked on reads or write
4
+ # the underlying descriptor is blocked on reads or write.
5
+ #
6
+ # It's not recommended to use any of this in your applications
7
+ # unless you're willing to accept breakage. Most of this is very
8
+ # difficult-to-use, fragile and we don't have much time to devote to
9
+ # supporting these in the future.
5
10
  class Rainbows::Fiber::IO::Socket < Kgio::Socket
6
11
  include Rainbows::Fiber::IO::Methods
7
12
  end
@@ -3,13 +3,18 @@ require 'rainbows/fiber'
3
3
 
4
4
  # A Fiber-based concurrency model for Ruby 1.9. This uses a pool of
5
5
  # Fibers to handle client IO to run the application and the root Fiber
6
- # for scheduling and connection acceptance. The pool size is equal to
7
- # the number of +worker_connections+. Compared to the ThreadPool
8
- # model, Fibers are very cheap in terms of memory usage so you can
9
- # have more active connections. This model supports a streaming
10
- # "rack.input" with lightweight concurrency. Applications are
11
- # strongly advised to wrap all slow IO objects (sockets, pipes) using
12
- # the Rainbows::Fiber::IO class whenever possible.
6
+ # for scheduling and connection acceptance.
7
+ #
8
+ # This concurrency model is difficult to use with existing applications,
9
+ # lacks third-party support, and is thus NOT recommended.
10
+ #
11
+ # The pool size is equal to the number of +worker_connections+.
12
+ # Compared to the ThreadPool model, Fibers are very cheap in terms of
13
+ # memory usage so you can have more active connections. This model
14
+ # supports a streaming "rack.input" with lightweight concurrency.
15
+ # Applications are strongly advised to wrap all slow IO objects
16
+ # (sockets, pipes) using the Rainbows::Fiber::IO class whenever
17
+ # possible.
13
18
  module Rainbows::FiberPool
14
19
  include Rainbows::Fiber::Base
15
20
 
@@ -1,12 +1,17 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'rainbows/fiber'
3
3
 
4
- # Simple Fiber-based concurrency model for 1.9. This spawns a new
5
- # Fiber for every incoming client connection and the root Fiber for
6
- # scheduling and connection acceptance. This exports a streaming
7
- # "rack.input" with lightweight concurrency. Applications are
8
- # strongly advised to wrap all slow IO objects (sockets, pipes) using
9
- # the Rainbows::Fiber::IO class whenever possible.
4
+ # Simple Fiber-based concurrency model for 1.9. This spawns a new Fiber
5
+ # for every incoming client connection and the root Fiber for scheduling
6
+ # and connection acceptance.
7
+ #
8
+ # This concurrency model is difficult to use with existing applications,
9
+ # lacks third-party support, and is thus NOT recommended.
10
+ #
11
+ # This exports a streaming "rack.input" with lightweight concurrency.
12
+ # Applications are strongly advised to wrap all slow IO objects
13
+ # (sockets, pipes) using the Rainbows::Fiber::IO class whenever
14
+ # possible.
10
15
  module Rainbows::FiberSpawn
11
16
  include Rainbows::Fiber::Base
12
17
 
@@ -2,6 +2,13 @@
2
2
  # :enddoc:
3
3
 
4
4
  class Rainbows::HttpServer < Unicorn::HttpServer
5
+ attr_accessor :copy_stream
6
+ attr_accessor :worker_connections
7
+ attr_accessor :keepalive_timeout
8
+ attr_accessor :client_header_buffer_size
9
+ attr_accessor :client_max_body_size
10
+ attr_reader :use
11
+
5
12
  def self.setup(block)
6
13
  Rainbows.server.instance_eval(&block)
7
14
  end
@@ -9,9 +16,9 @@ class Rainbows::HttpServer < Unicorn::HttpServer
9
16
  def initialize(app, options)
10
17
  Rainbows.server = self
11
18
  @logger = Unicorn::Configurator::DEFAULTS[:logger]
12
- rv = super(app, options)
13
- defined?(@use) or use(:Base)
14
- @worker_connections ||= Rainbows::MODEL_WORKER_CONNECTIONS[@use]
19
+ super(app, options)
20
+ defined?(@use) or self.use = Rainbows::Base
21
+ @worker_connections ||= @use == :Base ? 1 : 50
15
22
  end
16
23
 
17
24
  def reopen_worker_logs(worker_nr)
@@ -33,80 +40,69 @@ class Rainbows::HttpServer < Unicorn::HttpServer
33
40
  end
34
41
 
35
42
  def load_config!
36
- use :Base
37
- Rainbows.keepalive_timeout = 5
38
- Rainbows.max_bytes = 1024 * 1024
39
- @worker_connections = nil
40
43
  super
41
- @worker_connections ||= Rainbows::MODEL_WORKER_CONNECTIONS[@use]
44
+ @worker_connections = 1 if @use == :Base
45
+ end
46
+
47
+ def worker_loop(worker)
48
+ Rainbows.forked = true
49
+ orig = method(:worker_loop)
50
+ extend(Rainbows.const_get(@use))
51
+ m = method(:worker_loop)
52
+ orig == m ? super(worker) : worker_loop(worker)
42
53
  end
43
54
 
44
- def ready_pipe=(v)
45
- # hacky hook got force Rainbows! to load modules only in workers
46
- if defined?(@master_pid) && @master_pid == Process.ppid
47
- extend(Rainbows.const_get(@use))
55
+ def spawn_missing_workers
56
+ # 5: std{in,out,err} + heartbeat FD + per-process listener
57
+ nofile = 5 + @worker_connections + LISTENERS.size
58
+ trysetrlimit(:RLIMIT_NOFILE, nofile)
59
+
60
+ case @use
61
+ when :ThreadSpawn, :ThreadPool, :ActorSpawn,
62
+ :CoolioThreadSpawn, :RevThreadSpawn,
63
+ :XEpollThreadSpawn, :WriterThreadPool, :WriterThreadSpawn
64
+ trysetrlimit(:RLIMIT_NPROC, @worker_connections + LISTENERS.size + 1)
65
+ when :XEpollThreadPool, :CoolioThreadPool
66
+ trysetrlimit(:RLIMIT_NPROC, Rainbows::O[:pool_size] + LISTENERS.size + 1)
48
67
  end
49
68
  super
50
69
  end
51
70
 
52
- def use(*args)
53
- model = args.shift or return @use
54
- mod = begin
55
- Rainbows.const_get(model)
56
- rescue NameError => e
57
- logger.error "error loading #{model.inspect}: #{e}"
58
- e.backtrace.each { |l| logger.error l }
59
- raise ArgumentError, "concurrency model #{model.inspect} not supported"
71
+ def trysetrlimit(resource, want)
72
+ var = Process.const_get(resource)
73
+ cur, max = Process.getrlimit(var)
74
+ cur <= want and Process.setrlimit(var, cur = max > want ? max : want)
75
+ if cur == want
76
+ @logger.warn "#{resource} rlim_cur=#{cur} is barely enough"
77
+ @logger.warn "#{svc} may monopolize resources dictated by #{resource}" \
78
+ " and leave none for your app"
60
79
  end
80
+ rescue => e
81
+ @logger.error e.message
82
+ @logger.error "#{resource} needs to be increased to >=#{want} before" \
83
+ " starting #{svc}"
84
+ end
61
85
 
62
- Module === mod or
63
- raise ArgumentError, "concurrency model #{model.inspect} not supported"
64
- args.each do |opt|
65
- case opt
66
- when Hash; Rainbows::O.update(opt)
67
- when Symbol; Rainbows::O[opt] = true
68
- else; raise ArgumentError, "can't handle option: #{opt.inspect}"
69
- end
70
- end
71
- mod.setup if mod.respond_to?(:setup)
86
+ def svc
87
+ File.basename($0)
88
+ end
89
+
90
+ def use=(mod)
91
+ @use = mod.to_s.split(/::/)[-1].to_sym
72
92
  new_defaults = {
73
- 'rainbows.model' => (@use = model.to_sym),
74
- 'rack.multithread' => !!(model.to_s =~ /Thread/),
93
+ 'rainbows.model' => @use,
94
+ 'rack.multithread' => !!(mod.to_s =~ /Thread/),
75
95
  'rainbows.autochunk' => [:Coolio,:Rev,:Epoll,:XEpoll,
76
96
  :EventMachine,:NeverBlock].include?(@use),
77
97
  }
78
98
  Rainbows::Const::RACK_DEFAULTS.update(new_defaults)
79
99
  end
80
100
 
81
- def worker_connections(*args)
82
- return @worker_connections if args.empty?
83
- nr = args[0]
84
- (Integer === nr && nr > 0) or
85
- raise ArgumentError, "worker_connections must be a positive Integer"
86
- @worker_connections = nr
87
- end
88
-
89
- def keepalive_timeout(nr)
90
- (Integer === nr && nr >= 0) or
91
- raise ArgumentError, "keepalive_timeout must be a non-negative Integer"
92
- Rainbows.keepalive_timeout = nr
93
- end
94
-
95
- def keepalive_requests(nr)
96
- Integer === nr or
97
- raise ArgumentError, "keepalive_requests must be a non-negative Integer"
101
+ def keepalive_requests=(nr)
98
102
  Unicorn::HttpRequest.keepalive_requests = nr
99
103
  end
100
104
 
101
- def client_max_body_size(nr)
102
- err = "client_max_body_size must be nil or a non-negative Integer"
103
- case nr
104
- when nil
105
- when Integer
106
- nr >= 0 or raise ArgumentError, err
107
- else
108
- raise ArgumentError, err
109
- end
110
- Rainbows.max_bytes = nr
105
+ def keepalive_requests
106
+ Unicorn::HttpRequest.keepalive_requests
111
107
  end
112
108
  end
@@ -5,9 +5,13 @@ 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
9
  threads.delete_if do |thr|
9
10
  Rainbows.tick
10
11
  begin
12
+ # blocking accept() may not wake up properly
13
+ thr.raise(Errno::EINTR) if Time.now > expire && thr.stop?
14
+
11
15
  thr.run
12
16
  thr.join(0.01)
13
17
  rescue
@@ -6,7 +6,7 @@
6
6
  # automatically be configured for you based on the client_max_body_size
7
7
  # setting.
8
8
  #
9
- # For more fine-grained conrol, you may also define it per-endpoint in
9
+ # For more fine-grained control, you may also define it per-endpoint in
10
10
  # your Rack config.ru like this:
11
11
  #
12
12
  # map "/limit_1M" do
@@ -17,16 +17,34 @@
17
17
  # use Rainbows::MaxBody, 1024*1024*10
18
18
  # run MyApp
19
19
  # end
20
-
20
+ #
21
+ # This is only compatible with concurrency models that expose a streaming
22
+ # "rack.input" to the Rack application. Thus it is NOT compatible with
23
+ # any of the following as they fully buffer the request body before
24
+ # the application dispatch:
25
+ #
26
+ # * :Coolio
27
+ # * :CoolioThreadPool
28
+ # * :CoolioThreadSpawn
29
+ # * :Epoll
30
+ # * :EventMachine
31
+ # * :NeverBlock
32
+ # * :Rev
33
+ # * :RevThreadPool
34
+ # * :RevThreadSpawn
35
+ # * :XEpoll
36
+ #
37
+ # However, the global Rainbows::Configurator#client_max_body_size is compatible
38
+ # with all concurrency models \Rainbows! supports.
21
39
  class Rainbows::MaxBody
22
40
 
23
-
24
- # :call-seq:
25
- # # in config.ru:
26
- # use Rainbows::MaxBody, 4096
27
- # run YourApplication.new
28
- def initialize(app, limit = Rainbows.max_bytes)
29
- Integer === limit or raise ArgumentError, "limit not an Integer"
41
+ # This is automatically called when used with Rack::Builder#use
42
+ def initialize(app, limit = nil)
43
+ case limit
44
+ when Integer, nil
45
+ else
46
+ raise ArgumentError, "limit not an Integer"
47
+ end
30
48
  @app, @limit = app, limit
31
49
  end
32
50
 
@@ -37,6 +55,7 @@ class Rainbows::MaxBody
37
55
 
38
56
  # our main Rack middleware endpoint
39
57
  def call(env)
58
+ @limit = Rainbows.server.client_max_body_size if nil == @limit
40
59
  catch(:rainbows_EFBIG) do
41
60
  len = env[CONTENT_LENGTH]
42
61
  if len && len.to_i > @limit
@@ -51,7 +70,7 @@ class Rainbows::MaxBody
51
70
  # this is called after forking, so it won't ever affect the master
52
71
  # if it's reconfigured
53
72
  def self.setup # :nodoc:
54
- Rainbows.max_bytes or return
73
+ Rainbows.server.client_max_body_size or return
55
74
  case Rainbows.server.use
56
75
  when :Rev, :Coolio, :EventMachine, :NeverBlock,
57
76
  :RevThreadSpawn, :RevThreadPool,