1 # -*- encoding: binary -*-
3 # base module for evented models like Rev and EventMachine
4 module Rainbows::EvCore
5 include Rainbows::Const
6 include Rainbows::Response
8 NULL_IO = Unicorn::HttpRequest::NULL_IO
9 HttpParser = Unicorn::HttpParser
11 # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
12 ASYNC_CALLBACK = "async.callback".freeze
14 ASYNC_CLOSE = "async.close".freeze
19 @state = :headers # [ :body [ :trailers ] ] :app_call :close
23 # graceful exit, like SIGQUIT
29 msg = Rainbows::Error.response(e) and write(msg)
34 # returns whether to enable response chunking for autochunk models
35 def stream_response_headers(status, headers)
36 if headers['Content-Length']
39 rv = !!(headers['Transfer-Encoding'] =~ %r{\Achunked\z}i)
40 rv = false if headers.delete('X-Rainbows-Autochunk') == 'no'
42 write(response_header(status, headers))
46 # TeeInput doesn't map too well to this right now...
50 @hp.headers(@env, @buf << data) or return
52 len = @hp.content_length
55 app_call # common case
57 # since we don't do streaming input, we have no choice but
58 # to take over 100-continue handling from the Rack application
59 if @env[HTTP_EXPECT] =~ /\A100-continue\z/i
60 write(EXPECT_100_RESPONSE)
61 @env.delete(HTTP_EXPECT)
63 @input = CapInput.new(len, self)
64 @hp.filter_body(@buf2 = "", @buf)
73 @hp.filter_body(@buf2, @buf << data)
78 if @hp.trailers(@env, @buf << data)
87 class CapInput < Struct.new(:io, :client, :bytes_left)
88 MAX_BODY = Unicorn::Const::MAX_BODY
89 TmpIO = Unicorn::TmpIO
91 def self.err(client, msg)
92 client.write(Rainbows::Const::ERROR_413_RESPONSE)
95 # zip back up the stack
96 raise IOError, msg, []
99 def self.new(len, client)
100 max = Rainbows.max_bytes
102 if max && (len > max)
103 err(client, "Content-Length too big: #{len} > #{max}")
105 len <= MAX_BODY ? StringIO.new("") : TmpIO.new
107 max ? super(TmpIO.new, client, max) : TmpIO.new
112 if (self.bytes_left -= buf.size) < 0
114 CapInput.err(client, "chunked request body too big")
119 def gets; io.gets; end
120 def each(&block); io.each(&block); end
121 def size; io.size; end
122 def rewind; io.rewind; end
123 def read(*args); io.read(*args); end