1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
| | # -*- encoding: binary -*-
# 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 conrol, 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
class Rainbows::MaxBody
# :call-seq:
# # in config.ru:
# use Rainbows::MaxBody, 4096
# run YourApplication.new
def initialize(app, limit = Rainbows.max_bytes)
Integer === limit or raise ArgumentError, "limit not an Integer"
@app, @limit = app, limit
end
# :stopdoc:
RACK_INPUT = "rack.input".freeze
CONTENT_LENGTH = "CONTENT_LENGTH"
HTTP_TRANSFER_ENCODING = "HTTP_TRANSFER_ENCODING"
# our main Rack middleware endpoint
def call(env)
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
# this is called after forking, so it won't ever affect the master
# if it's reconfigured
def self.setup # :nodoc:
Rainbows.max_bytes 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
# Rack response returned when there's an error
def err # :nodoc:
[ 413, { 'Content-Length' => '0', 'Content-Type' => 'text/plain' }, [] ]
end
def limit_input!(env)
input = env[RACK_INPUT]
klass = input.respond_to?(:rewind) ? RewindableWrapper : Wrapper
env[RACK_INPUT] = klass.new(input, @limit)
end
# :startdoc:
end
require 'rainbows/max_body/wrapper'
require 'rainbows/max_body/rewindable_wrapper'
|