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 status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
46 write(EXPECT_100_RESPONSE)
47 env.delete(HTTP_EXPECT)
48 status, headers, body = APP.call(env)
50 write_response(status, headers, body, alive = @hp.next?)
52 # if we get any error, try to write something back to the client
53 # assuming we haven't closed the socket, but don't get hung up
54 # if the socket is already closed or broken. We'll always ensure
55 # the socket is closed at the end of this function
63 Rainbows::Error.write(self, e)
66 def set_input(env, hp)
67 env[RACK_INPUT] = 0 == hp.content_length ? NULL_IO : IC.new(self, hp)
70 def process_pipeline(env, hp)
73 env[REMOTE_ADDR] = kgio_addr
74 status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
76 write(EXPECT_100_RESPONSE)
77 env.delete(HTTP_EXPECT)
78 status, headers, body = APP.call(env)
80 write_response(status, headers, body, alive = hp.next?)
81 end while alive && pipeline_ready(hp)
87 # override this in subclass/module
88 def pipeline_ready(hp)