1 # -*- encoding: binary -*-
3 module Rainbows::ProcessClient
4 include Rainbows::Response
5 include Rainbows::Const
7 NULL_IO = Unicorn::HttpRequest::NULL_IO
8 RACK_INPUT = Unicorn::HttpRequest::RACK_INPUT
9 IC = Unicorn::HttpRequest.input_class
10 Rainbows.config!(self, :client_header_buffer_size, :keepalive_timeout)
13 Time.now + KEEPALIVE_TIMEOUT
16 # used for reading headers (respecting keepalive_timeout)
20 case rv = kgio_tryread(CLIENT_HEADER_BUFFER_SIZE, buf)
22 return if expire && expire < Time.now
23 expire ||= read_expire
24 kgio_wait_readable(KEEPALIVE_TIMEOUT)
32 @hp = hp = Rainbows::HttpParser.new
33 kgio_read!(CLIENT_HEADER_BUFFER_SIZE, buf = hp.buf) or return
37 timed_read(buf2 ||= "") or return
42 env[REMOTE_ADDR] = kgio_addr
43 hp.hijack_setup(env, to_io)
44 status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
47 write(EXPECT_100_RESPONSE)
48 env.delete(HTTP_EXPECT)
49 status, headers, body = APP.call(env)
51 return if hp.hijacked?
52 write_response(status, headers, body, alive = hp.next?) or return
54 # if we get any error, try to write something back to the client
55 # assuming we haven't closed the socket, but don't get hung up
56 # if the socket is already closed or broken. We'll always ensure
57 # the socket is closed at the end of this function
61 close unless closed? || hp.hijacked?
65 Rainbows::Error.write(self, e)
68 def set_input(env, hp)
69 env[RACK_INPUT] = 0 == hp.content_length ? NULL_IO : IC.new(self, hp)
72 def process_pipeline(env, hp)
75 env[REMOTE_ADDR] = kgio_addr
76 hp.hijack_setup(env, to_io)
77 status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
79 write(EXPECT_100_RESPONSE)
80 env.delete(HTTP_EXPECT)
81 status, headers, body = APP.call(env)
83 return if hp.hijacked?
84 write_response(status, headers, body, alive = hp.next?) or return
85 end while alive && pipeline_ready(hp)
91 # override this in subclass/module
92 def pipeline_ready(hp)