lib/reel/response.rb in reel-0.0.2 vs lib/reel/response.rb in reel-0.1.0
- old
+ new
@@ -4,30 +4,46 @@
STATUS_CODES = Http::Response::STATUS_CODES
SYMBOL_TO_STATUS_CODE = Http::Response::SYMBOL_TO_STATUS_CODE
CRLF = "\r\n"
attr_reader :status # Status has a special setter to coerce symbol names
- attr_accessor :reason
+ attr_accessor :reason # Reason can be set explicitly if desired
+ attr_reader :headers, :body
def initialize(status, body_or_headers = nil, body = nil)
self.status = status
- if body_or_headers and not body
- @body = body_or_headers
- @headers = {}
- else
+ if body_or_headers.is_a?(Hash)
+ headers = body_or_headers
@body = body
- @headers = body_or_headers
+ else
+ headers = {}
+ @body = body_or_headers
end
+ @headers = {}
+ headers.each do |name, value|
+ name = name.to_s
+ key = name[Http::CANONICAL_HEADER]
+ key ||= canonicalize_header(name)
+ @headers[key] = value.to_s
+ end
+
case @body
when String
@headers['Content-Length'] ||= @body.bytesize
when IO
@headers['Content-Length'] ||= @body.stat.size
+ when Enumerable
+ @headers['Transfer-Encoding'] ||= 'chunked'
+ when NilClass
+ else raise ArgumentError, "can't render #{@body.class} as a response body"
end
+ # Prevent modification through the accessor
+ @headers.freeze
+
# FIXME: real HTTP versioning
@version = "HTTP/1.1"
end
# Set the status
@@ -57,10 +73,18 @@
when IO
# TODO: IO.copy_stream when it works cross-platform
while data = @body.read(4096)
socket << data
end
+ when Enumerable
+ @body.each do |chunk|
+ chunk_header = chunk.bytesize.to_s(16) + CRLF
+ socket << chunk_header
+ socket << chunk
+ end
+
+ socket << "0" << CRLF * 2
end
end
# Convert headers into a string
# FIXME: this should probably be factored elsewhere, SRP and all
@@ -74,7 +98,13 @@
end
response_header << CRLF
end
private :render_header
+
+ # Transform to canonical HTTP header capitalization
+ def canonicalize_header(header)
+ header.to_s.split(/[\-_]/).map(&:capitalize).join('-')
+ end
+ private :canonicalize_header
end
end