ev_core: avoid needless String#dup
[rainbows.git] / lib / rainbows / ev_core.rb
blob3d02b8a4c5104bab7da9e3e78c229f1d535d8e0a
1 # -*- encoding: binary -*-
3 module Rainbows
5   # base module for evented models like Rev and EventMachine
6   module EvCore
7     include Unicorn
8     include Rainbows::Const
9     G = Rainbows::G
11     # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
12     ASYNC_CALLBACK = "async.callback".freeze
14     ASYNC_CLOSE = "async.close".freeze
16     def post_init
17       @remote_addr = ::TCPSocket === @_io ? @_io.peeraddr.last : LOCALHOST
18       @env = {}
19       @hp = HttpParser.new
20       @state = :headers # [ :body [ :trailers ] ] :app_call :close
21       @buf = ""
22     end
24     # graceful exit, like SIGQUIT
25     def quit
26       @state = :close
27     end
29     def handle_error(e)
30       msg = Error.response(e) and write(msg)
31       ensure
32         quit
33     end
35     # TeeInput doesn't map too well to this right now...
36     def on_read(data)
37       case @state
38       when :headers
39         @hp.headers(@env, @buf << data) or return
40         @state = :body
41         len = @hp.content_length
42         if len == 0
43           @input = HttpRequest::NULL_IO
44           app_call # common case
45         else # nil or len > 0
46           # since we don't do streaming input, we have no choice but
47           # to take over 100-continue handling from the Rack application
48           if @env[HTTP_EXPECT] =~ /\A100-continue\z/i
49             write(EXPECT_100_RESPONSE)
50             @env.delete(HTTP_EXPECT)
51           end
52           @input = len && len <= MAX_BODY ? StringIO.new("") : Util.tmpio
53           @hp.filter_body(@buf2 = "", @buf)
54           @input << @buf2
55           on_read("")
56         end
57       when :body
58         if @hp.body_eof?
59           @state = :trailers
60           on_read(data)
61         elsif data.size > 0
62           @hp.filter_body(@buf2, @buf << data)
63           @input << @buf2
64           on_read("")
65         end
66       when :trailers
67         if @hp.trailers(@env, @buf << data)
68           @input.rewind
69           app_call
70         end
71       end
72       rescue => e
73         handle_error(e)
74     end
76   end
77 end