From 96fbc5e91017c4912169629abc7dbb56cda9082c Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 30 Dec 2009 01:27:15 -0800 Subject: EventMachine: support deferrables in responses Some async apps rely on more than just "async.callback" and make full use of Deferrables provided by the EM::Deferrable module. Thanks to James Tucker for bringing this to our attention. --- lib/rainbows/ev_core.rb | 2 ++ lib/rainbows/event_machine.rb | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'lib/rainbows') diff --git a/lib/rainbows/ev_core.rb b/lib/rainbows/ev_core.rb index 0d3c079..a9c5bfc 100644 --- a/lib/rainbows/ev_core.rb +++ b/lib/rainbows/ev_core.rb @@ -11,6 +11,8 @@ module Rainbows # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ] ASYNC_CALLBACK = "async.callback".freeze + ASYNC_CLOSE = "async.close".freeze + def post_init @remote_addr = ::TCPSocket === @_io ? @_io.peeraddr.last : LOCALHOST @env = {} diff --git a/lib/rainbows/event_machine.rb b/lib/rainbows/event_machine.rb index bcc0240..aacdfb5 100644 --- a/lib/rainbows/event_machine.rb +++ b/lib/rainbows/event_machine.rb @@ -37,6 +37,7 @@ module Rainbows def initialize(io) @_io = io + @body = nil end alias write send_data @@ -54,6 +55,9 @@ module Rainbows @env[REMOTE_ADDR] = @remote_addr @env[ASYNC_CALLBACK] = method(:response_write) + # we're not sure if anybody uses this, but Thin sets it, too + @env[ASYNC_CLOSE] = EM::DefaultDeferrable.new + response = catch(:async) { APP.call(@env.update(RACK_DEFAULTS)) } # too tricky to support pipelining with :async since the @@ -77,9 +81,14 @@ module Rainbows end while true end - def response_write(response, out = [], alive = false) - body = response.last - unless body.respond_to?(:to_path) + def response_write(response, out = [ CONN_CLOSE ], alive = false) + @body = body = response.last + if body.respond_to?(:errback) && body.respond_to?(:callback) + body.callback { quit } + body.errback { quit } + HttpResponse.write(self, response, out) + return + elsif ! body.respond_to?(:to_path) HttpResponse.write(self, response, out) quit unless alive return @@ -120,6 +129,8 @@ module Rainbows end def unbind + async_close = @env[ASYNC_CLOSE] and async_close.succeed + @body.respond_to?(:fail) and @body.fail @_io.close end end -- cgit v1.2.3-24-ge0c7