about summary refs log tree commit homepage
path: root/lib/rainbows/epoll
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-02-08 22:45:20 +0000
committerEric Wong <normalperson@yhbt.net>2013-02-11 01:57:05 +0000
commite166cfe5e8d648b544b1291ec157bd234a425e21 (patch)
tree8ac56aadc51d81d4d250cfec696446f19ffd1d64 /lib/rainbows/epoll
parente6faf9e26bcb172026a4984ecadbaa8b6789bcb7 (diff)
downloadrainbows-e166cfe5e8d648b544b1291ec157bd234a425e21.tar.gz
This requires Rack 1.5.x and unicorn 4.6.0 for hijacking
support.  Older versions of Rack continue to work fine,
but we must use unicorn 4.6.0 features to support this.
Diffstat (limited to 'lib/rainbows/epoll')
-rw-r--r--lib/rainbows/epoll/client.rb20
1 files changed, 17 insertions, 3 deletions
diff --git a/lib/rainbows/epoll/client.rb b/lib/rainbows/epoll/client.rb
index d72696b..f6af6fa 100644
--- a/lib/rainbows/epoll/client.rb
+++ b/lib/rainbows/epoll/client.rb
@@ -52,6 +52,7 @@ module Rainbows::Epoll::Client
     when String
       on_read(rv)
       return if @wr_queue[0] || closed?
+      return hijacked if @hp.hijacked?
     when :wait_readable
       KATO[self] = @@last_expire if :headers == @state
       return EP.set(self, IN)
@@ -67,7 +68,9 @@ module Rainbows::Epoll::Client
   def app_call input # called by on_read()
     @env[RACK_INPUT] = input
     @env[REMOTE_ADDR] = kgio_addr
+    @hp.hijack_setup(@env, self)
     status, headers, body = APP.call(@env.merge!(RACK_DEFAULTS))
+    return hijacked if @hp.hijacked?
     ev_write_response(status, headers, body, @hp.next?)
   end
 
@@ -78,7 +81,8 @@ module Rainbows::Epoll::Client
     if st.file?
       defer_file(status, headers, body, alive, io, st)
     elsif st.socket? || st.pipe?
-      chunk = stream_response_headers(status, headers, alive)
+      chunk = stream_response_headers(status, headers, alive, body)
+      return hijacked if nil == chunk
       stream_response_body(body, io, chunk)
     else
       # char or block device... WTF?
@@ -102,10 +106,18 @@ module Rainbows::Epoll::Client
     else
       write_response(status, headers, body, alive)
     end
+    return hijacked if @hp.hijacked?
     # try to read more if we didn't have to buffer writes
     next_request if alive && 0 == @wr_queue.size
   end
 
+  def hijacked
+    KATO.delete(self)
+    Server.decr # no other place to do this
+    EP.delete(self)
+    nil
+  end
+
   def next_request
     if 0 == @buf.size
       want_more
@@ -113,6 +125,7 @@ module Rainbows::Epoll::Client
       # pipelined request (already in buffer)
       on_read(Z)
       return if @wr_queue[0] || closed?
+      return hijacked if @hp.hijacked?
       close if :close == @state
     end
   end
@@ -197,13 +210,14 @@ module Rainbows::Epoll::Client
     true
   end
 
+  # Rack apps should not hijack here, but they may...
   def defer_file(status, headers, body, alive, io, st)
     if r = sendfile_range(status, headers)
       status, headers, range = r
-      write_headers(status, headers, alive)
+      write_headers(status, headers, alive, body) or return hijacked
       range and defer_file_stream(range[0], range[1], io, body)
     else
-      write_headers(status, headers, alive)
+      write_headers(status, headers, alive, body) or return hijacked
       defer_file_stream(0, st.size, io, body)
     end
   end