landline/lib/hyde/response.rb

102 lines
2.6 KiB
Ruby

# frozen_string_literal: true
module Hyde
# Rack protocol response wrapper.
class Response
@chunk_size = 1024
self.class.attr_accessor :chunk_size
# @param response [Array(Integer, Hash, Array), nil]
def initialize(response = nil)
if response
@status = response[0]
@headers = response[1]
@body = response[2]
else
@status = 404
@headers = {}
@body = []
end
end
# Return internal representation of Rack response
# @return [Array(Integer,Hash,Array)]
def finalize
[@status, @headers, @body]
end
# Make internal representation conformant
def validate
if [204, 304].include?(@status) or (100..199).include?(@status)
@headers.delete "content-length"
@headers.delete "content-type"
@body = []
elsif @headers.empty?
length = @body.is_a?(String) ? @body.length : @body.join.length
@headers = {
"content-length" => length,
"content-type" => "text/html"
}
end
@body = self.class.chunk_body(@body) if @body.is_a? String
self
end
# Add a header to the headers hash
# @param key [String] header name
# @param value [String] header value
def add_header(key, value)
if @headers[key].is_a? String
@headers[key] = [@headers[key], value]
elsif @headers[key].is_a? Array
@headers[key].append(value)
else
@headers[key] = value
end
end
# Delete a header value from the headers hash
# If no value is provided, deletes all key entries
# @param key [String] header name
# @param value [String, nil] header value
def delete_header(key, value = nil)
if value and @response[key]
@response[key].delete(value)
else
@response.delete(key)
end
end
attr_accessor :status, :headers, :body
# Ensure response correctness
# @param obj [String, Array, Hyde::Response]
# @return Response
def self.convert(obj)
case obj
when Response
obj.validate
when Array
Response.new(obj).validate
when String, File, IO
Response.new([200,
{
"content-type" => "text/html",
"content-length" => obj.length
},
chunk_body(obj)])
end
end
# Turn body into array of chunks
def self.chunk_body(text)
if text.is_a? String
text.chars.each_slice(@chunk_size).map(&:join)
elsif text.is_a? Array
text
end
end
end
end