Protocol::RackSourceProtocolRackBody

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:

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