1 # -*- encoding: binary -*-
2 require 'thread' # for Queue
3 require 'rainbows/ev_core'
7 # base module for mixed Thread + evented models like RevThreadSpawn
17 # we pass ourselves off as a Socket to Unicorn::TeeInput and this
18 # is the only method Unicorn::TeeInput requires from the socket
19 def readpartial(length, buf = "")
20 # we must modify the original buffer if there was one
21 length == 0 and return buf.replace("")
23 # wait on the main loop to feed us
25 @tbuf.write(@state.pop)
28 buf.replace(@tbuf.read(length))
33 @thread.nil? or @thread.join # only one thread per connection
35 alive, headers = @hp.keepalive?, @hp.headers?
36 @thread = Thread.new(self) do |client|
38 env[REMOTE_ADDR] = @remote_addr
39 env[RACK_INPUT] = input || TeeInput.new(client, env, @hp, @buf)
40 response = APP.call(env.update(RACK_DEFAULTS))
41 if 100 == response.first.to_i
42 write(EXPECT_100_RESPONSE)
43 env.delete(HTTP_EXPECT)
44 response = APP.call(env)
48 out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if headers
49 response_write(response, out)
51 handle_error(e) rescue nil
54 if alive # in case we pipeline
56 redo if @hp.headers(@env.clear, @buf)
64 @hp.headers(@env, @buf << data) or return
65 if 0 == @hp.content_length
66 app_spawn(HttpRequest::NULL_IO) # common case
68 @state, @tbuf = Queue.new, ::IO::Buffer.new