module Body
The Body module provides functionality for handling Rack response bodies. It includes methods for wrapping different types of response bodies and handling completion callbacks.
Nested
Definitions
CONTENT_LENGTH = "content-length"
The content-length
header key.
def self.no_content?(status)
Check if the given status code indicates no content should be returned. Status codes 204 (No Content), 205 (Reset Content), and 304 (Not Modified) should not include a response body.
Signature
-
parameter
status
Integer
The HTTP status code.
-
returns
Boolean
True if the status code indicates no content.
Implementation
def self.no_content?(status)
status == 204 or status == 205 or status == 304
end
def self.wrap(env, status, headers, body, input = nil)
Wrap a Rack response body into a Protocol::HTTP::Body
instance.
Handles different types of response bodies:
Protocol::HTTP::Body::Readable
instances are returned as-is.- Bodies that respond to
to_path
are wrapped inProtocol::HTTP::Body::File
. - Enumerable bodies are wrapped in
class Protocol::Rack::Body::Enumerable
. - Other bodies are wrapped in
Streaming = ::Protocol::HTTP::Body::Streamable::ResponseBody
.
Signature
-
parameter
env
Hash
The Rack environment.
-
parameter
status
Integer
The HTTP status code.
-
parameter
headers
Hash
The response headers.
-
parameter
body
Object
The response body to wrap.
-
parameter
input
Object
Optional input for streaming bodies.
-
returns
Protocol::HTTP::Body
The wrapped response body.
Implementation
def self.wrap(env, status, headers, body, input = nil)
# In no circumstance do we want this header propagating out:
if length = headers.delete(CONTENT_LENGTH)
# We don't really trust the user to provide the right length to the transport.
length = Integer(length)
end
# If we have an Async::HTTP body, we return it directly:
if body.is_a?(::Protocol::HTTP::Body::Readable)
# Ignore.
elsif status == 200 and body.respond_to?(:to_path)
begin
# Don't mangle partial responses (206)
body = ::Protocol::HTTP::Body::File.open(body.to_path).tap do
body.close if body.respond_to?(:close) # Close the original body.
end
rescue Errno::ENOENT
# If the file is not available, ignore.
end
elsif body.respond_to?(:each)
body = Body::Enumerable.wrap(body, length)
elsif body
body = Body::Streaming.new(body, input)
else
Console.warn(self, "Rack response body was nil, ignoring!")
end
if body and no_content?(status)
unless body.empty?
Console.warn(self, "Rack response body was not empty, and status code indicates no content!", body: body, status: status)
end
body.close
body = nil
end
response_finished = env[RACK_RESPONSE_FINISHED]
if response_finished&.any?
if body
body = ::Protocol::HTTP::Body::Completable.new(body, completion_callback(response_finished, env, status, headers))
else
completion_callback(response_finished, env, status, headers).call(nil)
end
end
return body
end
def self.completion_callback(response_finished, env, status, headers)
Create a completion callback for response finished handlers. The callback is called with any error that occurred during response processing.
Signature
-
parameter
response_finished
Array
Array of response finished callbacks.
-
parameter
env
Hash
The Rack environment.
-
parameter
status
Integer
The HTTP status code.
-
parameter
headers
Hash
The response headers.
-
returns
Proc
A callback that calls all response finished handlers.
Implementation
def self.completion_callback(response_finished, env, status, headers)
proc do |error|
response_finished.each do |callback|
callback.call(env, status, headers, error)
end
end
end