more consistent logging for errors
[rainbows.git] / lib / rainbows / reverse_proxy / coolio.rb
blob2a977e01f5cfcc7a193ee73993c724cbd37480fd
1 # -*- encoding: binary -*-
2 # :enddoc:
3 # TODO: handle large responses without having it all in memory
4 module Rainbows::ReverseProxy::Coolio
5   LOOP = Cool.io::Loop.default
7   class Backend < Cool.io::IO
8     include Rainbows::ReverseProxy::EvClient
10     def initialize(env, addr, input)
11       @env = env
12       @input = input
13       @junk, @rbuf = "", ""
14       @parser = Kcar::Parser.new
15       @response = @body = nil
16       @headers = Rack::Utils::HeaderHash.new
17       super(UpstreamSocket.start(addr)) # kgio-enabled socket
18     end
20     def on_write_complete
21       if @input
22         buf = @input.read(16384, @junk) and return write(buf)
23         @input = nil
24       end
25     end
27     def on_readable
28       # avoiding IO#read_nonblock since that's expensive in 1.9.2
29       case buf = @_io.kgio_tryread(16384, @junk)
30       when String
31         receive_data(buf)
32       when :wait_readable
33         return
34       when nil
35         @env[AsyncCallback].call(@response)
36         return close
37       end while true # we always read until EAGAIN or EOF
39       rescue => e
40         case e
41         when Errno::ECONNRESET
42           @env[AsyncCallback].call(@response)
43           return close
44         when SystemCallError
45         else
46           Unicorn.log_error(@env["rack.logger"], "on_readable", e)
47         end
48         @env[AsyncCallback].call(Rainbows::ReverseProxy::E502)
49         close
50     end
51   end
53   def call(env)
54     input = prepare_input!(env)
55     sock = Backend.new(env, pick_upstream(env), input).attach(LOOP)
56     sock.write(build_headers(env, input))
57     throw :async
58   end
59 end