class Rack::Response

Your application’s call should end returning Response#finish.
write are synchronous with the Rack response.
finish. finish however can take a block inside which calls to
but note that this is buffered by Rack::Response until you call
You can use Response#write to iteratively generate your response,
defaults (an OK response with empty headers and body).
It allows setting of headers and cookies, and provides useful
response.
Rack::Response provides a convenient interface to create a Rack

def self.[](status, headers, body)

def self.[](status, headers, body)
  self.new(body, status, headers)
end

def chunked?

def chunked?
  CHUNKED == get_header(TRANSFER_ENCODING)
end

def close

def close
  @body.close if @body.respond_to?(:close)
end

def delete_header(key)

def delete_header(key)
  raise ArgumentError unless key.is_a?(String)
  @headers.delete key
end

def each(&callback)

def each(&callback)
  @body.each(&callback)
  @buffered = true
  if @block
    @writer = callback
    @block.call(self)
  end
end

def empty?

def empty?
  @block == nil && @body.empty?
end

def finish(&block)

Returns:
  • (Array) - a 3-tuple suitable of `[status, headers, body]`
def finish(&block)
  if no_entity_body?
    delete_header CONTENT_TYPE
    delete_header CONTENT_LENGTH
    close
    return [@status, @headers, []]
  else
    if block_given?
      # We don't add the content-length here as the user has provided a block that can #write additional chunks to the body.
      @block = block
      return [@status, @headers, self]
    else
      # If we know the length of the body, set the content-length header... except if we are chunked? which is a legacy special case where the body might already be encoded and thus the actual encoded body length and the content-length are likely to be different.
      if @length && !chunked?
        @headers[CONTENT_LENGTH] = @length.to_s
      end
      return [@status, @headers, @body]
    end
  end
end

def get_header(key)

def get_header(key)
  raise ArgumentError unless key.is_a?(String)
  @headers[key]
end

def has_header?(key)

def has_header?(key)
  raise ArgumentError unless key.is_a?(String)
  @headers.key?(key)
end

def initialize(body = nil, status = 200, headers = {})

instance and the value can be either a +String+ or +Array+ instance.
the Rack specification for response headers. The key must be a +String+
The +headers+ must be a +Hash+ of key-value header pairs which conform to

can provide any other valid status code.
The +status+ defaults to +200+ which is the "OK" HTTP status code. You

body) or +call+ (streaming body).
Rack response body, typically implementing one of +each+ (enumerable
Otherwise it is expected +body+ conforms to the normal requirements of a

initial contents of the buffer.
construct a buffered response object containing using that string as the
If the +body+ responds to +to_str+, assume it's a string-like object and

buffering.
If the +body+ is +nil+, construct an empty response object with internal

and +headers+.
Initialize the response object with the specified +body+, +status+
def initialize(body = nil, status = 200, headers = {})
  @status = status.to_i
  unless headers.is_a?(Hash)
    raise ArgumentError, "Headers must be a Hash!"
  end
  @headers = Headers.new
  # Convert headers input to a plain hash with lowercase keys.
  headers.each do |k, v|
    @headers[k] = v
  end
  @writer = self.method(:append)
  @block = nil
  # Keep track of whether we have expanded the user supplied body.
  if body.nil?
    @body = []
    @buffered = true
    # Body is unspecified - it may be a buffered response, or it may be a HEAD response.
    @length = nil
  elsif body.respond_to?(:to_str)
    @body = [body]
    @buffered = true
    @length = body.to_str.bytesize
  else
    @body = body
    @buffered = nil # undetermined as of yet.
    @length = nil
  end
  yield self if block_given?
end

def no_entity_body?

def no_entity_body?
  # The response body is an enumerable body and it is not allowed to have an entity body.
  @body.respond_to?(:each) && STATUS_WITH_NO_ENTITY_BODY[@status]
end

def redirect(target, status = 302)

def redirect(target, status = 302)
  self.status = status
  self.location = target
end

def set_header(key, value)

def set_header(key, value)
  raise ArgumentError unless key.is_a?(String)
  @headers[key] = value
end

def write(chunk)


NOTE: Do not mix #write and direct #body access!

Converts the response into a buffered response if it wasn't already.

Append a chunk to the response body.
def write(chunk)
  buffered_body!
  @writer.call(chunk.to_s)
end