1 # -*- encoding: binary -*-
5 # base module for evented models like Rev and EventMachine
8 include Rainbows::Const
10 NULL_IO = Unicorn::HttpRequest::NULL_IO
12 # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
13 ASYNC_CALLBACK = "async.callback".freeze
15 ASYNC_CLOSE = "async.close".freeze
18 @remote_addr = Rainbows.addr(@_io)
21 @state = :headers # [ :body [ :trailers ] ] :app_call :close
25 # graceful exit, like SIGQUIT
31 msg = Error.response(e) and write(msg)
36 # TeeInput doesn't map too well to this right now...
40 @hp.headers(@env, @buf << data) or return
42 len = @hp.content_length
45 app_call # common case
47 # since we don't do streaming input, we have no choice but
48 # to take over 100-continue handling from the Rack application
49 if @env[HTTP_EXPECT] =~ /\A100-continue\z/i
50 write(EXPECT_100_RESPONSE)
51 @env.delete(HTTP_EXPECT)
53 @input = CapInput.new(len, self)
54 @hp.filter_body(@buf2 = "", @buf)
63 @hp.filter_body(@buf2, @buf << data)
68 if @hp.trailers(@env, @buf << data)
77 class CapInput < Struct.new(:io, :client, :bytes_left)
78 MAX_BODY = Unicorn::Const::MAX_BODY
81 def self.err(client, msg)
82 client.write(Const::ERROR_413_RESPONSE)
85 # zip back up the stack
86 raise IOError, msg, []
89 def self.new(len, client)
90 max = Rainbows.max_bytes
93 err(client, "Content-Length too big: #{len} > #{max}")
95 len <= MAX_BODY ? StringIO.new("") : Util.tmpio
97 max ? super(Util.tmpio, client, max) : Util.tmpio
102 if (self.bytes_left -= buf.size) < 0
104 CapInput.err(client, "chunked request body too big")
109 def gets; io.gets; end
110 def each(&block); io.each(&block); end
111 def size; io.size; end
112 def rewind; io.rewind; end
113 def read(*args); io.read(*args); end