process_client: fix attempted keepalive on HTTP 0.9
[rainbows.git] / lib / rainbows / process_client.rb
blobd2c9d0edf2b2385213cc2f72c799b79556978a81
1 # -*- encoding: binary -*-
2 # :enddoc:
3 module Rainbows::ProcessClient
4   G = Rainbows::G
5   include Rainbows::Response
6   HttpParser = Unicorn::HttpParser
7   NULL_IO = Unicorn::HttpRequest::NULL_IO
8   RACK_INPUT = Unicorn::HttpRequest::RACK_INPUT
9   TeeInput = Rainbows::TeeInput
10   include Rainbows::Const
12   def wait_headers_readable(client)
13     IO.select([client], nil, nil, G.kato)
14   end
16   # once a client is accepted, it is processed in its entirety here
17   # in 3 easy steps: read request, call app, write app response
18   # this is used by synchronous concurrency models
19   #   Base, ThreadSpawn, ThreadPool
20   def process_client(client) # :nodoc:
21     hp = HttpParser.new
22     client.kgio_read!(16384, buf = hp.buf)
23     remote_addr = client.kgio_addr
24     alive = false
26     begin # loop
27       until env = hp.parse
28         wait_headers_readable(client) or return
29         buf << client.kgio_read!(16384)
30       end
32       env[CLIENT_IO] = client
33       env[RACK_INPUT] = 0 == hp.content_length ?
34                         NULL_IO : TeeInput.new(client, hp)
35       env[REMOTE_ADDR] = remote_addr
36       status, headers, body = APP.call(env.update(RACK_DEFAULTS))
38       if 100 == status.to_i
39         client.write(EXPECT_100_RESPONSE)
40         env.delete(HTTP_EXPECT)
41         status, headers, body = APP.call(env)
42       end
44       if hp.headers?
45         headers = HH.new(headers)
46         range = make_range!(env, status, headers) and status = range.shift
47         alive = hp.keepalive? && G.alive
48         headers[CONNECTION] = alive ? KEEP_ALIVE : CLOSE
49         client.write(response_header(status, headers))
50       end
51       write_body(client, body, range)
52     end while alive && hp.reset.nil?
53   # if we get any error, try to write something back to the client
54   # assuming we haven't closed the socket, but don't get hung up
55   # if the socket is already closed or broken.  We'll always ensure
56   # the socket is closed at the end of this function
57   rescue => e
58     Rainbows::Error.write(client, e)
59   ensure
60     client.close unless client.closed?
61   end
62 end