aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller/response.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_controller/response.rb')
-rw-r--r--actionpack/lib/action_controller/response.rb95
1 files changed, 61 insertions, 34 deletions
diff --git a/actionpack/lib/action_controller/response.rb b/actionpack/lib/action_controller/response.rb
index f89861e5a5..866616bac3 100644
--- a/actionpack/lib/action_controller/response.rb
+++ b/actionpack/lib/action_controller/response.rb
@@ -1,24 +1,25 @@
require 'digest/md5'
module ActionController # :nodoc:
- # Represents an HTTP response generated by a controller action. One can use an
- # ActionController::AbstractResponse object to retrieve the current state of the
- # response, or customize the response. An AbstractResponse object can either
- # represent a "real" HTTP response (i.e. one that is meant to be sent back to the
- # web browser) or a test response (i.e. one that is generated from integration
- # tests). See CgiResponse and TestResponse, respectively.
+ # Represents an HTTP response generated by a controller action. One can use
+ # an ActionController::Response object to retrieve the current state
+ # of the response, or customize the response. An Response object can
+ # either represent a "real" HTTP response (i.e. one that is meant to be sent
+ # back to the web browser) or a test response (i.e. one that is generated
+ # from integration tests). See CgiResponse and TestResponse, respectively.
#
- # AbstractResponse is mostly a Ruby on Rails framework implement detail, and should
- # never be used directly in controllers. Controllers should use the methods defined
- # in ActionController::Base instead. For example, if you want to set the HTTP
- # response's content MIME type, then use ActionControllerBase#headers instead of
- # AbstractResponse#headers.
+ # Response is mostly a Ruby on Rails framework implement detail, and
+ # should never be used directly in controllers. Controllers should use the
+ # methods defined in ActionController::Base instead. For example, if you want
+ # to set the HTTP response's content MIME type, then use
+ # ActionControllerBase#headers instead of Response#headers.
#
- # Nevertheless, integration tests may want to inspect controller responses in more
- # detail, and that's when AbstractResponse can be useful for application developers.
- # Integration test methods such as ActionController::Integration::Session#get and
- # ActionController::Integration::Session#post return objects of type TestResponse
- # (which are of course also of type AbstractResponse).
+ # Nevertheless, integration tests may want to inspect controller responses in
+ # more detail, and that's when Response can be useful for application
+ # developers. Integration test methods such as
+ # ActionController::Integration::Session#get and
+ # ActionController::Integration::Session#post return objects of type
+ # TestResponse (which are of course also of type Response).
#
# For example, the following demo integration "test" prints the body of the
# controller response to the console:
@@ -29,22 +30,24 @@ module ActionController # :nodoc:
# puts @response.body
# end
# end
- class AbstractResponse
+ class Response < Rack::Response
DEFAULT_HEADERS = { "Cache-Control" => "no-cache" }
attr_accessor :request
- attr_accessor :status
- # The body content (e.g. HTML) of the response, as a String.
- attr_accessor :body
- # The headers of the response, as a Hash. It maps header names to header values.
- attr_accessor :headers
attr_accessor :session, :cookies, :assigns, :template, :layout
attr_accessor :redirected_to, :redirected_to_method_params
delegate :default_charset, :to => 'ActionController::Base'
def initialize
- @body, @headers, @session, @assigns = "", DEFAULT_HEADERS.merge("cookie" => []), [], []
+ @status = 200
+ @header = DEFAULT_HEADERS.merge("cookie" => [])
+
+ @writer = lambda { |x| @body << x }
+ @block = nil
+
+ @body = "",
+ @session, @assigns = [], []
end
def location; headers['Location'] end
@@ -140,9 +143,31 @@ module ActionController # :nodoc:
handle_conditional_get!
set_content_length!
convert_content_type!
+
+ convert_language!
+ convert_expires!
set_cookies!
end
+ def each(&callback)
+ if @body.respond_to?(:call)
+ @writer = lambda { |x| callback.call(x) }
+ @body.call(self, self)
+ elsif @body.is_a?(String)
+ @body.each_line(&callback)
+ else
+ @body.each(&callback)
+ end
+
+ @writer = callback
+ @block.call(self) if @block
+ end
+
+ def write(str)
+ @writer.call str.to_s
+ str
+ end
+
private
def handle_conditional_get!
if etag? || last_modified?
@@ -171,23 +196,25 @@ module ActionController # :nodoc:
end
def convert_content_type!
- if content_type = headers.delete("Content-Type")
- self.headers["type"] = content_type
- end
- if content_type = headers.delete("Content-type")
- self.headers["type"] = content_type
- end
- if content_type = headers.delete("content-type")
- self.headers["type"] = content_type
- end
+ headers['Content-Type'] ||= "text/html"
+ headers['Content-Type'] += "; charset=" + headers.delete('charset') if headers['charset']
end
- # Don't set the Content-Length for block-based bodies as that would mean reading it all into memory. Not nice
- # for, say, a 2GB streaming file.
+ # Don't set the Content-Length for block-based bodies as that would mean
+ # reading it all into memory. Not nice for, say, a 2GB streaming file.
def set_content_length!
unless body.respond_to?(:call) || (status && status.to_s[0..2] == '304')
self.headers["Content-Length"] ||= body.size
end
+ headers["Content-Length"] = headers["Content-Length"].to_s if headers["Content-Length"]
+ end
+
+ def convert_language!
+ headers["Content-Language"] = headers.delete("language") if headers["language"]
+ end
+
+ def convert_expires!
+ headers["Expires"] = headers.delete("") if headers["expires"]
end
def set_cookies!