tests: "wc -c" portability for *BSDs
[rainbows.git] / lib / rainbows / configurator.rb
blob92dacd66c0710fdf18c47f6eaf6124ff14f21590
1 # -*- encoding: binary -*-
3 # This module adds \Rainbows! to the
4 # {Unicorn::Configurator}[http://unicorn.bogomips.org/Unicorn/Configurator.html]
5 # \Rainbows!-specific configuration options must be inside a the Rainbows!
6 # block, otherwise Unicorn::Configurator directives may be used anywhere
7 # in the file.
9 #   Rainbows! do
10 #     use :ThreadSpawn # concurrency model to use
11 #     worker_connections 400
12 #     keepalive_timeout 0 # zero disables keepalives entirely
13 #     client_max_body_size 5*1024*1024 # 5 megabytes
14 #     keepalive_requests 666 # default:100
15 #     client_header_buffer_size 2 * 1024 # 2 kilobytes
16 #   end
18 #   # the rest of the Unicorn configuration...
19 #   worker_processes 8
20 #   stderr_path "/path/to/error.log"
21 #   stdout_path "/path/to/output.log"
22 module Rainbows::Configurator
23   Unicorn::Configurator::DEFAULTS.merge!({
24     :use => Rainbows::Base,
25     :worker_connections => 50,
26     :keepalive_timeout => 5,
27     :keepalive_requests => 100,
28     :client_max_body_size => 1024 * 1024,
29     :client_header_buffer_size => 1024,
30     :client_max_header_size => 112 * 1024,
31     :copy_stream => IO.respond_to?(:copy_stream) ? IO : false,
32   })
34   # Configures \Rainbows! with a given concurrency model to +use+ and
35   # a +worker_connections+ upper-bound.  This method should be called
36   # inside a Unicorn/\Rainbows! configuration file.
37   #
38   # All other methods in Rainbows::Configurator must be called
39   # inside this block.
40   def Rainbows!(&block)
41     block_given? or raise ArgumentError, "Rainbows! requires a block"
42     @block = true
43     instance_eval(&block)
44     ensure
45       @block = false
46   end
48   def check! # :nodoc:
49     @block or abort "must be inside a Rainbows! block"
50   end
52   # This limits the number of connected clients per-process.  The total
53   # number of clients on a server is +worker_processes+ * +worker_connections+.
54   #
55   # This option has no effect with the Base concurrency model, which is
56   # limited to +1+.
57   #
58   # Default: 50
59   def worker_connections(clients)
60     check!
61     set_int(:worker_connections, clients, 1)
62   end
64   # Select a concurrency model for use with \Rainbows!.  You must select
65   # this with a Symbol (prefixed with ":").  Thus if you wish to select
66   # the Rainbows::ThreadSpawn concurrency model, you would use:
67   #
68   #   Rainbows! do
69   #     use :ThreadSpawn
70   #   end
71   #
72   # See the {Summary}[link:Summary.html] document for a summary of
73   # supported concurrency models.  +options+ may be specified for some
74   # concurrency models, but the majority do not support them.
75   #
76   # Default: :Base (no concurrency)
77   def use(model, *options)
78     check!
79     mod = begin
80       Rainbows.const_get(model)
81     rescue NameError => e
82       warn "error loading #{model.inspect}: #{e}"
83       e.backtrace.each { |l| warn l }
84       abort "concurrency model #{model.inspect} not supported"
85     end
86     Module === mod or abort "concurrency model #{model.inspect} not supported"
87     options.each do |opt|
88       case opt
89       when Hash
90         Rainbows::O.merge!(opt)
91       when Symbol
92         Rainbows::O[opt] = true
93       else
94         abort "cannot handle option: #{opt.inspect} in #{options.inspect}"
95       end
96     end
97     mod.setup if mod.respond_to?(:setup)
98     set[:use] = mod
99   end
101   # Sets the value (in seconds) the server will wait for a client in
102   # between requests.  The default value should be enough under most
103   # conditions for browsers to render the page and start retrieving
104   # extra elements.
105   #
106   # Setting this value to +0+ disables keepalive entirely
107   #
108   # Default: 5 seconds
109   def keepalive_timeout(seconds)
110     check!
111     set_int(:keepalive_timeout, seconds, 0)
112   end
114   # This limits the number of requests which can be made over a keep-alive
115   # connection.  This is used to prevent single client from monopolizing
116   # the server and to improve fairness when load-balancing across multiple
117   # machines by forcing a client to reconnect.  This may be helpful
118   # in mitigating some denial-of-service attacks.
119   #
120   # Default: 100 requests
121   def keepalive_requests(count)
122     check!
123     case count
124     when nil, Integer
125       set[:keepalive_requests] = count
126     else
127       abort "not an integer or nil: keepalive_requests=#{count.inspect}"
128     end
129   end
131   # Limits the maximum size of a request body for all requests.
132   # Setting this to +nil+ disables the maximum size check.
133   #
134   # Default: 1 megabyte (1048576 bytes)
135   #
136   # If you want endpoint-specific upload limits and use a
137   # "rack.input"-streaming concurrency model, see the Rainbows::MaxBody
138   def client_max_body_size(bytes)
139     check!
140     err = "client_max_body_size must be nil or a non-negative Integer"
141     case bytes
142     when nil
143     when Integer
144       bytes >= 0 or abort err
145     else
146       abort err
147     end
148     set[:client_max_body_size] = bytes
149   end
151   # Limits the maximum size of a request header for all requests.
152   #
153   # Default: 112 kilobytes (114688 bytes)
154   #
155   # Lowering this will lower worst-case memory usage and mitigate some
156   # denial-of-service attacks.  This should be larger than
157   # client_header_buffer_size.
158   def client_max_header_size(bytes)
159     check!
160     set_int(:client_max_header_size, bytes, 8)
161   end
163   # This governs the amount of memory allocated for an individual read(2) or
164   # recv(2) system call when reading headers.  Applications that make minimal
165   # use of cookies should not increase this from the default.
166   #
167   # Rails applications using session cookies may want to increase this to
168   # 2048 bytes or more depending on expected request sizes.
169   #
170   # Increasing this will increase overall memory usage to your application,
171   # as you will need at least this amount of memory for every connected client.
172   #
173   # Default: 1024 bytes
174   def client_header_buffer_size(bytes)
175     check!
176     set_int(:client_header_buffer_size, bytes, 1)
177   end
179   # Allows overriding the +klass+ where the +copy_stream+ method is
180   # used to do efficient copying of regular files, pipes, and sockets.
181   #
182   # This is only used with multi-threaded concurrency models:
183   #
184   # * ThreadSpawn
185   # * ThreadPool
186   # * WriterThreadSpawn
187   # * WriterThreadPool
188   # * XEpollThreadSpawn
189   # * XEpollThreadPool
190   #
191   # Due to existing {bugs}[http://redmine.ruby-lang.org/search?q=copy_stream]
192   # in the Ruby IO.copy_stream implementation, \Rainbows! uses the
193   # "sendfile" RubyGem that instead of copy_stream to transfer regular files
194   # to clients.  The "sendfile" RubyGem also supports more operating systems,
195   # and works with more concurrency models.
196   #
197   # Recent Linux 2.6 users may override this with "IO::Splice" from the
198   # "io_splice" RubyGem:
199   #
200   #   require "io/splice"
201   #   Rainbows! do
202   #     copy_stream IO::Splice
203   #   end
204   #
205   # Keep in mind that splice(2) itself is a relatively new system call
206   # and has been buggy in many older Linux kernels.  If you're proxying
207   # the output of sockets to the client, be sure to use "io_splice"
208   # 4.1.1 or later to avoid stalling responses.
209   #
210   # Default: IO on Ruby 1.9+, false otherwise
211   def copy_stream(klass)
212     check!
213     if klass && ! klass.respond_to?(:copy_stream)
214       abort "#{klass} must respond to `copy_stream' or be `false'"
215     end
216     set[:copy_stream] = klass
217   end
220 # :enddoc:
221 # inject the Rainbows! method into Unicorn::Configurator
222 Unicorn::Configurator.__send__(:include, Rainbows::Configurator)