max_body: rdoc updates
[rainbows.git] / lib / rainbows / max_body.rb
blob33ba572c0c27cb5cad856a1c90e242f116352b56
1 # -*- encoding: binary -*-
3 # Middleware used to enforce client_max_body_size for TeeInput users.
5 # There is no need to configure this middleware manually, it will
6 # automatically be configured for you based on the client_max_body_size
7 # setting.
9 # For more fine-grained control, you may also define it per-endpoint in
10 # your Rack config.ru like this:
12 #        map "/limit_1M" do
13 #          use Rainbows::MaxBody, 1024*1024
14 #          run MyApp
15 #        end
16 #        map "/limit_10M" do
17 #          use Rainbows::MaxBody, 1024*1024*10
18 #          run MyApp
19 #        end
21 class Rainbows::MaxBody
23   # This is automatically called when used with Rack::Builder#use
24   def initialize(app, limit = Rainbows.client_max_body_size)
25     Integer === limit or raise ArgumentError, "limit not an Integer"
26     @app, @limit = app, limit
27   end
29   # :stopdoc:
30   RACK_INPUT = "rack.input".freeze
31   CONTENT_LENGTH = "CONTENT_LENGTH"
32   HTTP_TRANSFER_ENCODING = "HTTP_TRANSFER_ENCODING"
34   # our main Rack middleware endpoint
35   def call(env)
36     catch(:rainbows_EFBIG) do
37       len = env[CONTENT_LENGTH]
38       if len && len.to_i > @limit
39         return err
40       elsif /\Achunked\z/i =~ env[HTTP_TRANSFER_ENCODING]
41         limit_input!(env)
42       end
43       @app.call(env)
44     end || err
45   end
47   # this is called after forking, so it won't ever affect the master
48   # if it's reconfigured
49   def self.setup # :nodoc:
50     Rainbows.client_max_body_size or return
51     case Rainbows.server.use
52     when :Rev, :Coolio, :EventMachine, :NeverBlock,
53          :RevThreadSpawn, :RevThreadPool,
54          :CoolioThreadSpawn, :CoolioThreadPool,
55          :Epoll, :XEpoll
56       return
57     end
59     # force ourselves to the outermost middleware layer
60     Rainbows.server.app = self.new(Rainbows.server.app)
61   end
63   # Rack response returned when there's an error
64   def err # :nodoc:
65     [ 413, { 'Content-Length' => '0', 'Content-Type' => 'text/plain' }, [] ]
66   end
68   def limit_input!(env)
69     input = env[RACK_INPUT]
70     klass = input.respond_to?(:rewind) ? RewindableWrapper : Wrapper
71     env[RACK_INPUT] = klass.new(input, @limit)
72   end
74   # :startdoc:
75 end
76 require 'rainbows/max_body/wrapper'
77 require 'rainbows/max_body/rewindable_wrapper'