lib/hanami/action/rack.rb in hanami-controller-1.0.0.beta1 vs lib/hanami/action/rack.rb in hanami-controller-1.0.0.beta2

- old
+ new

@@ -8,16 +8,40 @@ module Action # Rack integration API # # @since 0.1.0 module Rack + # Rack SPEC response code + # + # @since 1.0.0.beta2 + # @api private + RESPONSE_CODE = 0 + + # Rack SPEC response headers + # + # @since 1.0.0.beta2 + # @api private + RESPONSE_HEADERS = 1 + + # Rack SPEC response body + # + # @since 1.0.0.beta2 + # @api private + RESPONSE_BODY = 2 + # The default HTTP response code # # @since 0.1.0 # @api private DEFAULT_RESPONSE_CODE = 200 + # Not Found + # + # @since 1.0.0.beta2 + # @api private + NOT_FOUND = 404 + # The default Rack response body # # @since 0.1.0 # @api private DEFAULT_RESPONSE_BODY = [] @@ -34,10 +58,23 @@ # # @since 0.3.2 # @api private REQUEST_METHOD = 'REQUEST_METHOD'.freeze + # The Content-Length HTTP header + # + # @since 1.0.0.beta2 + # @api private + CONTENT_LENGTH = 'Content-Length'.freeze + + # The non-standard HTTP header to pass the control over when a resource + # cannot be found by the current endpoint + # + # @since 1.0.0.beta2 + # @api private + X_CASCADE = 'X-Cascade'.freeze + # HEAD request # # @since 0.3.2 # @api private HEAD = 'HEAD'.freeze @@ -255,10 +292,11 @@ body = Array(body) unless body.respond_to?(:each) @_body = body end # Send a file as response. + # <tt>This method only sends files from the public directory</tt> # # It automatically handle the following cases: # # * <tt>Content-Type</tt> and <tt>Content-Length</tt> # * File Not found (returns a 404) @@ -280,15 +318,43 @@ # # ... # send_file Pathname.new('path/to/file') # end # end def send_file(path) - result = File.new(path, self.class.configuration.public_directory).call(@_env) - headers.merge!(result[1]) - halt result[0], result[2] + _send_file( + File.new(path, self.class.configuration.public_directory).call(@_env) + ) end + # Send a file as response from anywhere in the file system. + # + # @see Hanami::Action::Rack#send_file + # + # @param path [String, Pathname] path to the file to be sent + # @return [void] + # + # @since 1.0.0.beta2 + # + # @example + # require 'hanami/controller' + # + # class Show + # include Hanami::Action + # + # def call(params) + # # ... + # unsafe_send_file Pathname.new('/tmp/path/to/file') + # end + # end + def unsafe_send_file(path) + directory = self.class.configuration.root_directory if Pathname.new(path).relative? + + _send_file( + File.new(path, directory).call(@_env) + ) + end + # Check if the current request is a HEAD # # @return [TrueClass,FalseClass] the result of the check # # @since 0.3.2 @@ -300,9 +366,23 @@ # # @api private # @since 0.4.4 def request_method @_env[REQUEST_METHOD] + end + + # @since 1.0.0.beta2 + # @api private + def _send_file(response) + headers.merge!(response[RESPONSE_HEADERS]) + + if response[RESPONSE_CODE] == NOT_FOUND + headers.delete(X_CASCADE) + headers.delete(CONTENT_LENGTH) + halt NOT_FOUND + else + halt response[RESPONSE_CODE], response[RESPONSE_BODY] + end end end end end