5 # Rack::Response provides a convenient interface to create a Rack
8 # It allows setting of headers and cookies, and provides useful
9 # defaults (a OK response containing HTML).
11 # You can use Response#write to iteratively generate your response,
12 # but note that this is buffered by Rack::Response until you call
13 # +finish+. +finish+ however can take a block inside which calls to
14 # +write+ are syncronous with the Rack response.
16 # Your application's +call+ should end returning Response#finish.
21 def initialize(body
=[], status
=200, header
={}, &block
)
23 @header = Utils
::HeaderHash.new({"Content-Type" => "text/html"}.
26 @writer = lambda
{ |x
| @body << x
}
32 if body
.respond_to
? :to_str
34 elsif body
.respond_to
?(:each)
39 raise TypeError
, "stringable or iterable required"
42 yield self if block_given
?
46 attr_accessor
:status, :body
56 def set_cookie(key
, value
)
59 domain
= "; domain=" + value
[:domain] if value
[:domain]
60 path
= "; path=" + value
[:path] if value
[:path]
61 # According to RFC 2109, we need dashes here.
62 # N.B.: cgi.rb uses spaces...
63 expires
= "; expires=" + value
[:expires].clone
.gmtime
.
64 strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value
[:expires]
65 secure
= "; secure" if value
[:secure]
66 httponly
= "; HttpOnly" if value
[:httponly]
69 value
= [value
] unless Array
=== value
70 cookie
= Utils
.escape(key
) + "=" +
71 value
.map
{ |v
| Utils
.escape v
}.join("&") +
72 "#{domain}#{path}#{expires}#{secure}#{httponly}"
74 case self["Set-Cookie"]
76 self["Set-Cookie"] << cookie
78 self["Set-Cookie"] = [self["Set-Cookie"], cookie
]
80 self["Set-Cookie"] = cookie
84 def delete_cookie(key
, value
={})
85 unless Array
=== self["Set-Cookie"]
86 self["Set-Cookie"] = [self["Set-Cookie"]].compact
89 self["Set-Cookie"].reject
! { |cookie
|
90 cookie
=~
/\A#{Utils.escape(key)}=/
94 {:value => '', :path => nil, :domain => nil,
95 :expires => Time
.at(0) }.merge(value
))
102 if [204, 304].include?(status
.to_i
)
103 header
.delete
"Content-Type"
104 [status
.to_i
, header
.to_hash
, []]
106 [status
.to_i
, header
.to_hash
, self]
109 alias to_a finish
# For *response
112 @body.each(&callback
)
114 @block.call(self) if @block
117 # Append to body and update Content-Length.
119 # NOTE: Do not mix #write and direct #body access!
126 header
["Content-Length"] = @length.to_s
131 body
.close
if body
.respond_to
?(:close)
135 @block == nil && @body.empty
?
141 def invalid
?; @status < 100 || @status >= 600; end
143 def informational
?; @status >= 100 && @status < 200; end
144 def successful
?; @status >= 200 && @status < 300; end
145 def redirection
?; @status >= 300 && @status < 400; end
146 def client_error
?; @status >= 400 && @status < 500; end
147 def server_error
?; @status >= 500 && @status < 600; end
149 def ok
?; @status == 200; end
150 def forbidden
?; @status == 403; end
151 def not_found
?; @status == 404; end
153 def redirect
?; [301, 302, 303, 307].include? @status; end
154 def empty
?; [201, 204, 304].include? @status; end
157 attr_reader
:headers, :original_headers
164 headers
["Content-Type"]
168 cl
= headers
["Content-Length"]