refactor response sendfile body handling for easier debugging
[rainbows.git] / lib / rainbows / revactor / body.rb
blob9820df34d4126df3eb37e37fe19c4eb4c8565876
1 # -*- encoding: binary -*-
2 # :enddoc:
3 module Rainbows::Revactor::Body
4   # TODO non-blocking splice(2) under Linux
5   ALIASES = {
6     :write_body_stream => :write_body_each
7   }
9   if IO.method_defined?(:sendfile_nonblock)
10     def write_body_file_sendfile_revactor(client, body, range)
11       body = body_to_io(body)
12       sock = client.instance_variable_get(:@_io)
13       pfx = Revactor::TCP::Socket === client ? :tcp : :unix
14       write_complete = T[:"#{pfx}_write_complete", client]
15       closed = T[:"#{pfx}_closed", client]
16       offset, count = range ? range : [ 0, body.stat.size ]
17       begin
18         offset += (n = sock.sendfile_nonblock(body, offset, count))
19       rescue Errno::EAGAIN
20         # The @_write_buffer is empty at this point, trigger the
21         # on_readable method which in turn triggers on_write_complete
22         # even though nothing was written
23         client.controller = Actor.current
24         client.__send__(:enable_write_watcher)
25         Actor.receive do |filter|
26           filter.when(write_complete) {}
27           filter.when(closed) { raise Errno::EPIPE }
28         end
29         retry
30       rescue EOFError
31         break
32       end while (count -= n) > 0
33       ensure
34         close_if_private(body)
35     end
36     ALIASES[:write_body_file] = :write_body_file_sendfile_revactor
37   else
38     ALIASES[:write_body] = :write_body_each
39   end
41   def self.included(klass)
42     ALIASES.each do |new_method, orig_method|
43       klass.__send__(:alias_method, new_method, orig_method)
44     end
45   end
46 end