Class: Rainbows::MaxBody

Inherits:
Object
  • Object
show all
Defined in:
lib/rainbows/max_body.rb

Overview

Middleware used to enforce client_max_body_size for TeeInput users.

There is no need to configure this middleware manually, it will automatically be configured for you based on the client_max_body_size setting.

For more fine-grained control, you may also define it per-endpoint in your Rack config.ru like this:

   map "/limit_1M" do
     use Rainbows::MaxBody, 1024*1024
     run MyApp
   end
   map "/limit_10M" do
     use Rainbows::MaxBody, 1024*1024*10
     run MyApp
   end

This is only compatible with concurrency models that expose a streaming "rack.input" to the Rack application. Thus it is NOT compatible with any of the following as they fully buffer the request body before the application dispatch:

  • :Coolio
  • :CoolioThreadPool
  • :CoolioThreadSpawn
  • :Epoll
  • :EventMachine
  • :NeverBlock
  • :Rev
  • :RevThreadPool
  • :RevThreadSpawn
  • :XEpoll

However, the global Rainbows::Configurator#client_max_body_size is compatible with all concurrency models Rainbows! supports.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, limit = nil) ⇒ MaxBody

This is automatically called when used with Rack::Builder#use



42
43
44
45
46
47
48
49
# File 'lib/rainbows/max_body.rb', line 42

def initialize(app, limit = nil)
  case limit
  when Integer, nil
  else
    raise ArgumentError, "limit not an Integer"
  end
  @app, @limit = app, limit
end

Class Method Details

.setup ⇒ Object

this is called after forking, so it won't ever affect the master if it's reconfigured



67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rainbows/max_body.rb', line 67

def self.setup # :nodoc:
  Rainbows.server.client_max_body_size or return
  case Rainbows.server.use
  when :Rev, :Coolio, :EventMachine, :NeverBlock,
       :RevThreadSpawn, :RevThreadPool,
       :CoolioThreadSpawn, :CoolioThreadPool,
       :Epoll, :XEpoll
    return
  end

  # force ourselves to the outermost middleware layer
  Rainbows.server.app = self.new(Rainbows.server.app)
end

Instance Method Details

#call(env) ⇒ Object

our main Rack middleware endpoint



52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rainbows/max_body.rb', line 52

def call(env)
  @limit = Rainbows.server.client_max_body_size if nil == @limit
  catch(:rainbows_EFBIG) do
    len = env['CONTENT_LENGTH']
    if len && len.to_i > @limit
      return err
    elsif /\Achunked\z/i =~ env['HTTP_TRANSFER_ENCODING']
      limit_input!(env)
    end
    @app.call(env)
  end || err
end

#err ⇒ Object

Rack response returned when there's an error



82
83
84
# File 'lib/rainbows/max_body.rb', line 82

def err # :nodoc:
  [ 413, { 'Content-Length' => '0', 'Content-Type' => 'text/plain' }, [] ]
end

#limit_input!(env) ⇒ Object



86
87
88
89
90
# File 'lib/rainbows/max_body.rb', line 86

def limit_input!(env)
  input = env['rack.input']
  klass = input.respond_to?(:rewind) ? RewindableWrapper : Wrapper
  env['rack.input'] = klass.new(input, @limit)
end