/
response.rb
99 lines (83 loc) · 2.59 KB
/
response.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
module Thin
# A response sent to the client.
class Response
CONNECTION = 'Connection'.freeze
CLOSE = 'close'.freeze
KEEP_ALIVE = 'keep-alive'.freeze
SERVER = 'Server'.freeze
CONTENT_LENGTH = 'Content-Length'.freeze
# Status code
attr_accessor :status
# Response body, must respond to +each+.
attr_accessor :body
# Headers key-value hash
attr_reader :headers
def initialize
@headers = Headers.new
@status = 200
@persistent = false
end
# String representation of the headers
# to be sent in the response.
def headers_output
# Set default headers
@headers[CONNECTION] = persistent? ? KEEP_ALIVE : CLOSE
@headers[SERVER] = Thin::SERVER
@headers.to_s
end
# Top header of the response,
# containing the status code and response headers.
def head
"HTTP/1.1 #{@status} #{HTTP_STATUS_CODES[@status.to_i]}\r\n#{headers_output}\r\n"
end
if Thin.ruby_18?
# Ruby 1.8 implementation.
# Respects Rack specs.
#
# See http://rack.rubyforge.org/doc/files/SPEC.html
def headers=(key_value_pairs)
key_value_pairs.each do |k, vs|
vs.each { |v| @headers[k] = v.chomp } if vs
end if key_value_pairs
end
else
# Ruby 1.9 doesn't have a String#each anymore.
# Rack spec doesn't take care of that yet, for now we just use
# +each+ but fallback to +each_line+ on strings.
# I wish we could remove that condition.
# To be reviewed when a new Rack spec comes out.
def headers=(key_value_pairs)
key_value_pairs.each do |k, vs|
next unless vs
if vs.is_a?(String)
vs.each_line { |v| @headers[k] = v.chomp }
else
vs.each { |v| @headers[k] = v.chomp }
end
end if key_value_pairs
end
end
# Close any resource used by the response
def close
@body.close if @body.respond_to?(:close)
end
# Yields each chunk of the response.
# To control the size of each chunk
# define your own +each+ method on +body+.
def each
yield head
@body.each do |chunk|
yield chunk
end
end
# Tell the client the connection should stay open
def persistent!
@persistent = true
end
# Persistent connection must be requested as keep-alive
# from the server and have a Content-Length.
def persistent?
@persistent && @headers.has_key?(CONTENT_LENGTH)
end
end
end