1 # -*- encoding: binary -*-
4 RUBY_VERSION =~ %r{\A1\.8} && ::Rev::VERSION < "0.3.2" and
5 warn "Rainbows::RevThreadSpawn + Rev (< 0.3.2)" \
6 " does not work well under Ruby 1.8"
10 # A combination of the Rev and ThreadSpawn models. This allows Ruby
11 # Thread-based concurrency for application processing. It DOES NOT
12 # expose a streamable "rack.input" for upload processing within the
13 # app. DevFdResponse should be used with this class to proxy
14 # asynchronous responses. All network I/O between the client and
15 # server are handled by the main thread and outside of the core
16 # application dispatch.
18 # WARNING: this model does not currently perform well under 1.8. See the
19 # {rev-talk mailing list}[http://rubyforge.org/mailman/listinfo/rev-talk]
20 # for ongoing performance work that will hopefully make it into the
21 # next release of {Rev}[http://rev.rubyforge.org/].
25 class Master < ::Rev::AsyncWatcher
38 client, response = @queue.pop
39 client.response_write(response)
43 class Client < Rainbows::Rev::Client
44 DR = Rainbows::Rev::DeferredResponse
45 KATO = Rainbows::Rev::KATO
47 def response_write(response)
49 alive = @hp.keepalive? && G.alive
50 out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if @hp.headers?
51 DR.write(self, response, out)
52 return quit unless alive && G.alive
57 # keepalive requests are always body-less, so @input is unchanged
58 if @hp.headers(@env, @buf)
59 @input = HttpRequest::NULL_IO
66 # fails-safe application dispatch, we absolutely cannot
67 # afford to fail or raise an exception (killing the thread)
68 # here because that could cause a deadlock and we'd leak FDs
71 @env[REMOTE_ADDR] = @remote_addr
72 APP.call(@env.update(RACK_DEFAULTS))
74 Error.app(e) # we guarantee this does not raise
80 KATO.delete(client = self)
82 @env[RACK_INPUT] = @input
83 @input = nil # not sure why, @input seems to get closed otherwise...
84 Thread.new { MASTER << [ client, app_response ] }
88 include Rainbows::Rev::Core
90 def init_worker_process(worker)
92 Client.const_set(:MASTER, Master.new.attach(::Rev::Loop.default))