Class: FastSend
- Inherits:
-
Object
- Object
- FastSend
- Defined in:
- lib/fast_send.rb,
lib/fast_send/version.rb
Overview
A Rack middleware that sends the response using file buffers. If the response body returned by the upstream application supports “each_file”, then the middleware will call this method, grab each yielded file in succession and use the fastest possible way to send it to the client (using a response wrapper or Rack hijacking). If sendfile support is available on the client socket, sendfile() will be used to stream the file via the OS.
A sample response body object will look like this:
class Files
def each_file
File.open('data1.bin','r') {|f| yield(f) }
File.open('data2.bin','r') {|f| yield(f) }
end
end
# and then in your Rack app
return [200, {'Content-Type' => 'binary/octet-stream'}, Files.new]
Note that the receiver of ‘each_file` is responsbble for closing and deallocating the file if necessary.
You can also supply the following response headers that will be used as callbacks during the response send on the way out.
`fast_send.started' => ->(zero_bytes) { } # When the response is started
`fast_send.bytes_sent' => ->(sent_this_time, sent_total) { } # Called on each sent chunk
`fast_send.complete' => ->(sent_total) { } # When response completes without exceptions
`fast_send.aborted' => ->(exception) { } # When the response is not sent completely, both for exceptions and client closes
`fast_send.error' => ->(exception) { } # the response is not sent completely due to an error in the application
`fast_send.cleanup' => ->(sent_total) { } # Called at the end of the response, in an ensure block
Defined Under Namespace
Classes: NaiveEach, SocketHandler
Constant Summary collapse
- CLIENT_DISCONNECTS =
All exceptions that get raised when the client closes a connection before receiving the entire response
[Errno::EPIPE, Errno::ECONNRESET, Errno::ENOTCONN, Errno::EPROTOTYPE]
- UnknownCallback =
Gets raised if a fast_send.something is mentioned in the response headers but is not supported as a callback (the dangers of hashmaps as datastructures is that you can sometimes mistype keys)
Class.new(StandardError)
- VERSION =
"1.1.3"- CALLBACK_HEADER_NAMES =
%w( fast_send.started fast_send.aborted fast_send.error fast_send.complete fast_send.bytes_sent fast_send.cleanup ).freeze
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#initialize(with_rack_app) ⇒ FastSend
constructor
A new instance of FastSend.
Constructor Details
#initialize(with_rack_app) ⇒ FastSend
Returns a new instance of FastSend.
101 102 103 |
# File 'lib/fast_send.rb', line 101 def initialize(with_rack_app) @app = with_rack_app end |
Instance Method Details
#call(env) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/fast_send.rb', line 105 def call(env) s, h, b = @app.call(env) return [s, h, b] unless b.respond_to?(:each_file) @logger = env.fetch(C_rack_logger) { NullLogger } server = env[C_SERVER_SOFTWARE] if has_robust_hijack_support?(env) @logger.debug { 'Server (%s) allows partial hijack, setting up Connection: close' % server } h[C_Connection] = C_close h[C_dispatch] = C_hijack response_via_hijack(s, h, b) else @logger.warn { msg = 'Server (%s) has no hijack support or hijacking is broken. Unwanted buffering possible.' msg % server } h[C_dispatch] = C_naive response_via_naive_each(s, h, b) end end |