Class: ActionDispatch::Response
| Relationships & Source Files | |
| Namespace Children | |
|
Classes:
| |
| Extension / Inclusion / Inheritance Descendants | |
|
Subclasses:
|
|
| Super Chains via Extension / Inclusion / Inheritance | |
|
Instance Chain:
self,
MonitorMixin,
Http::Cache::Response,
Http::FilterRedirect,
Rack::Response::Helpers
|
|
| Inherits: | Object |
| Defined in: | actionpack/lib/action_dispatch/http/response.rb |
Overview
Represents an HTTP response generated by a controller action. Use it to
retrieve the current state of the response, or customize the response. It can
either represent a real HTTP response (i.e. one that is meant to be sent back
to the web browser) or a TestResponse (i.e. one that is generated from
integration tests).
The Response object for the current request is exposed on controllers as
ActionController::Metal#response. ::ActionController::Metal also provides a few
additional methods that delegate to attributes of the Response such as
ActionController::Metal#headers.
Integration tests will likely also want to inspect responses in more detail.
Methods such as Integration::RequestHelpers#get and
Integration::RequestHelpers#post return instances of TestResponse (which
inherits from Response) for this purpose.
For example, the following demo integration test prints the body of the controller response to the console:
class DemoControllerTest < ActionDispatch::IntegrationTest
def test_print_root_path_to_console
get('/')
puts response.body
end
end
Constant Summary
-
AMBIGUOUS_CONTENT_TYPE_PART =
private
# File 'actionpack/lib/action_dispatch/http/response.rb', line 531
Parts of a Content-Type header that the parser could read differently than they were given: parameters, whitespace, quoting.
/[;\s"]/ -
CONTENT_TYPE =
# File 'actionpack/lib/action_dispatch/http/response.rb', line 96"Content-Type" -
CONTENT_TYPE_PARSER =
Internal use only
# File 'actionpack/lib/action_dispatch/http/response.rb', line 488/ \A (?<mime_type>[^;\s]\s*(?:;\s*(?:(?!charset)[^;\s]))*)? (?:;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)? /x -
Header =
# File 'actionpack/lib/action_dispatch/http/response.rb', line 62
To be deprecated:
Headers -
NO_CONTENT_CODES =
# File 'actionpack/lib/action_dispatch/http/response.rb', line 98[100, 101, 102, 103, 204, 205, 304].freeze
-
NullContentTypeHeader =
# File 'actionpack/lib/action_dispatch/http/response.rb', line 486ContentTypeHeader.new(nil, nil).freeze
-
SET_COOKIE =
# File 'actionpack/lib/action_dispatch/http/response.rb', line 97"Set-Cookie"
Http::FilterRedirect - Included
Http::Cache::Response - Included
DATE, DEFAULT_CACHE_CONTROL, IMMUTABLE, LAST_MODIFIED, MUST_REVALIDATE, MUST_UNDERSTAND, NO_CACHE, NO_STORE, PRIVATE, PUBLIC, SPECIAL_KEYS
Class Attribute Summary
Class Method Summary
- .create(status = 200, headers = {}, body = [], default_headers: self.default_headers)
- .merge_default_headers(original, default)
- .new(status = 200, headers = nil, body = []) {|_self| ... } ⇒ Response constructor
-
.rack_status_code(status)
Internal use only
See additional method definition at line 49.
Instance Attribute Summary
-
#body
rw
Returns the content of the response as a string.
-
#body=(body)
rw
Allows you to manually set or override the response body.
-
#charset
rw
The charset of the response.
-
#charset=(charset)
rw
Sets the HTTP character set.
- #committed? ⇒ Boolean readonly
-
#content_type
rw
Content type of response.
-
#content_type=(content_type)
rw
Sets the HTTP response's content MIME type.
-
#header
readonly
Alias for #headers.
-
#headers
(also: #header)
readonly
The headers for the response.
-
#request
rw
The request that the response is responding to.
- #sending? ⇒ Boolean readonly
- #sending_file=(v) writeonly
- #sent? ⇒ Boolean readonly
-
#status
rw
The HTTP status code.
-
#status=(status)
rw
Sets the HTTP status code.
-
#stream
readonly
The underlying body, as a streamable object.
Http::Cache::Response - Included
| #cache_control, #date, #date=, #date?, | |
| #etag= | This method sets a weak ETag validator on the response so browsers and proxies may cache the response, keyed on the ETag. |
| #etag?, #last_modified, #last_modified=, #last_modified?, #strong_etag=, | |
| #strong_etag? | True if an ETag is set, and it isn't a weak validator (not preceded with |
| #weak_etag=, | |
| #weak_etag? | True if an ETag is set, and it's a weak validator (preceded with |
Http::FilterRedirect - Included
Instance Method Summary
- #[]
- #[]=
-
#_cache_control
Aliasing these off because
AD::Http::Cache::Responsedefines them. - #_cache_control=
- #abort
- #await_commit
- #await_sent
- #body_parts
- #close
-
#code
Returns a string to ensure compatibility with
Net::HTTPResponse. - #commit!
-
#cookies
Returns the response cookies, converted to a
::Hashof (name => value) pairs. - #delete_header(key)
- #each(&block)
- #get_header(key)
- #handle_no_content!
- #has_header?(key) ⇒ Boolean
-
#location
(also: #redirect_url)
Location of the response.
-
#location=(location)
Sets the location of the response.
-
#media_type
Media type of response.
-
#message
(also: #status_message)
Returns the corresponding message for the current HTTP status code:
-
#prepare!
Alias for #to_a.
- #rack_response(status, headers)
-
#redirect_url
Alias for #location.
- #reset_body!
-
#response_code
The response code of the request.
-
#send_file(path)
Send the file stored at
pathas the response body. - #sending!
- #sent!
- #set_header(key, v)
-
#status_message
Alias for #message.
-
#to_a
(also: #prepare!)
Turns the
Responseinto a Rack-compatible array of the status, headers, and body. - #write(string)
- #assign_default_content_type_and_charset! private
- #before_committed private
- #before_sending private
- #build_buffer(response, body) private
-
#parsed_content_type_header
private
Small internal convenience method to get the parsed version of the current content type header.
- #set_content_type(content_type, charset) private
- #parse_content_type(content_type) private Internal use only
Http::Cache::Response - Included
| #cache_control_headers, #cache_control_segments, #generate_strong_etag, #generate_weak_etag, #handle_conditional_get!, #merge_and_normalize_cache_control!, #prepare_cache_control! |
Http::FilterRedirect - Included
Constructor Details
.new(status = 200, headers = nil, body = []) {|_self| ... } ⇒ Response
# File 'actionpack/lib/action_dispatch/http/response.rb', line 196
def initialize(status = 200, headers = nil, body = []) super() @headers = Headers.new headers&.each do |key, value| @headers[key] = value end self.body, self.status = body, status @cv = new_cond @committed = false @sending = false @sent = false @parsed_content_type = nil @parsed_content_type_raw = nil prepare_cache_control! yield self if block_given? end
Class Attribute Details
.default_charset (rw)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 100
class_attribute :default_charset, default: "utf-8", instance_accessor: false
.default_charset? ⇒ Boolean (rw)
[ GitHub ]
# File 'actionpack/lib/action_dispatch/http/response.rb', line 100
class_attribute :default_charset, default: "utf-8", instance_accessor: false
.default_headers (rw)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 101
class_attribute :default_headers, instance_accessor: false
.default_headers? ⇒ Boolean (rw)
[ GitHub ]
# File 'actionpack/lib/action_dispatch/http/response.rb', line 101
class_attribute :default_headers, instance_accessor: false
Class Method Details
.create(status = 200, headers = {}, body = [], default_headers: self.default_headers)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 184
def self.create(status = 200, headers = {}, body = [], default_headers: self.default_headers) headers = merge_default_headers(headers, default_headers) new status, headers, body end
.merge_default_headers(original, default)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 189
def self.merge_default_headers(original, default) default.respond_to?(:merge) ? default.merge(original) : original end
.rack_status_code(status)
See additional method definition at line 49.
Instance Attribute Details
#body (rw)
Returns the content of the response as a string. This contains the contents of
any calls to render.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 370
def body if @stream.respond_to?(:to_ary) @stream.to_ary.join elsif @stream.respond_to?(:body) @stream.body else @stream end end
#body=(body) (rw)
Allows you to manually set or override the response body.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 385
def body=(body) # Prevent ActionController::Metal::Live::Response from committing the response prematurely. synchronize do if body.respond_to?(:to_str) @stream = build_buffer(self, [body]) elsif body.respond_to?(:to_path) @stream = body elsif body.respond_to?(:to_ary) @stream = build_buffer(self, body) else @stream = body end end end
#charset (rw)
The charset of the response. HTML wants to know the encoding of the content you're giving them, so we need to send that along.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 340
def charset header_info = parsed_content_type_header header_info.charset&.dup || self.class.default_charset end
#charset=(charset) (rw)
Sets the HTTP character set. In case of nil parameter it sets the charset to
.default_charset.
response.charset = 'utf-16' # => 'utf-16'
response.charset = nil # => 'utf-8'
# File 'actionpack/lib/action_dispatch/http/response.rb', line 329
def charset=(charset) content_type = parsed_content_type_header.mime_type&.dup if false == charset set_content_type content_type, nil else set_content_type content_type, charset || self.class.default_charset end end
#committed? ⇒ Boolean (readonly)
[ GitHub ]
# File 'actionpack/lib/action_dispatch/http/response.rb', line 258
def committed?; synchronize { @committed }; end
#content_type (rw)
Content type of response.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 309
def content_type super.presence end
#content_type=(content_type) (rw)
Sets the HTTP response's content MIME type. For example, in the controller you could write this:
response.content_type = "text/html"
This method also accepts a symbol with the extension of the MIME type:
response.content_type = :html
If a character set has been defined for this response (see #charset=) then the character set information will also be included in the content type information.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 290
def content_type=(content_type) case content_type when NilClass return when Symbol mime_type = Mime[content_type] raise ArgumentError, "Unknown MIME type #{content_type}" unless mime_type new_header_info = ContentTypeHeader.new(mime_type.to_s) else new_header_info = parse_content_type(content_type.to_s) end prev_header_info = parsed_content_type_header charset = new_header_info.charset || prev_header_info.charset charset ||= self.class.default_charset unless prev_header_info.mime_type set_content_type new_header_info.mime_type, charset end
#header (readonly)
Alias for #headers.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 85
alias_method :header, :headers
#headers (readonly) Also known as: #header
The headers for the response.
header["Content-Type"] # => "text/plain"
header["Content-Type"] = "application/json"
header["Content-Type"] # => "application/json"
Also aliased as headers.
headers["Content-Type"] # => "text/plain"
headers["Content-Type"] = "application/json"
headers["Content-Type"] # => "application/json"
Also aliased as #header for compatibility.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 83
attr_reader :headers
#request (rw)
The request that the response is responding to.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 65
attr_accessor :request
#sending? ⇒ Boolean (readonly)
[ GitHub ]
# File 'actionpack/lib/action_dispatch/http/response.rb', line 257
def sending?; synchronize { @sending }; end
#sending_file=(v) (writeonly)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 318
def sending_file=(v) if true == v self.charset = false end end
#sent? ⇒ Boolean (readonly)
[ GitHub ]
# File 'actionpack/lib/action_dispatch/http/response.rb', line 259
def sent?; synchronize { @sent }; end
#status (rw)
The HTTP status code.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 68
attr_reader :status
#status=(status) (rw)
Sets the HTTP status code.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 274
def status=(status) @status = Response.rack_status_code(status) end
#stream (readonly)
The underlying body, as a streamable object.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 194
attr_reader :stream
Instance Method Details
#[]
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 87
delegate :[], :[]=, to: :@headers
#[]=
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 87
delegate :[], :[]=, to: :@headers
#_cache_control
Aliasing these off because AD::Http::Cache::Response defines them.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 105
alias :_cache_control :cache_control
#_cache_control=
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 106
alias :_cache_control= :cache_control=
#abort
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 447
def abort if stream.respond_to?(:abort) stream.abort elsif stream.respond_to?(:close) # `stream.close` should really be reserved for a close from the other direction, # but we must fall back to it for compatibility. stream.close end end
#assign_default_content_type_and_charset! (private)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 578
def assign_default_content_type_and_charset! ct = parsed_content_type_header return if ct.mime_type set_content_type(Mime[:html].to_s, ct.charset || self.class.default_charset) end
#await_commit
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 224
def await_commit synchronize do @cv.wait_until { @committed } end end
#await_sent
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 230
def await_sent synchronize { @cv.wait_until { @sent } } end
#before_committed (private)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 556
def before_committed return if committed? assign_default_content_type_and_charset! merge_and_normalize_cache_control!(@cache_control) handle_conditional_get! handle_no_content! end
#before_sending (private)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 564
def before_sending # Normally we've already committed by now, but it's possible (e.g., if the # controller action tries to read back its own response) to get here before # that. In that case, we must force an "early" commit: we're about to freeze the # headers, so this is our last chance. commit! unless committed? @request. unless committed? end
#body_parts
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 434
def body_parts parts = [] @stream.each { |x| parts << x } parts end
#build_buffer(response, body) (private)
[ GitHub ]#close
[ GitHub ]#code
Returns a string to ensure compatibility with Net::HTTPResponse.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 351
def code @status.to_s end
#commit!
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 234
def commit! synchronize do before_committed @committed = true @cv.broadcast end end
#cookies
Returns the response cookies, converted to a ::Hash of (name => value) pairs
assert_equal 'AuthorOfNewPage', r.['author']
# File 'actionpack/lib/action_dispatch/http/response.rb', line 470
def = {} if header = get_header(SET_COOKIE) header = header.split("\n") if header.respond_to?(:to_str) header.each do || if pair = .split(";").first key, value = pair.split("=").map { |v| Rack::Utils.unescape(v) } [key] = value end end end end
#delete_header(key)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 222
def delete_header(key); @headers.delete key; end
#each(&block)
[ GitHub ]#get_header(key)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 220
def get_header(key); @headers[key]; end
#handle_no_content!
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 630
def handle_no_content! if NO_CONTENT_CODES.include?(@status) @headers.delete CONTENT_TYPE @headers.delete "Content-Length" end end
#has_header?(key) ⇒ Boolean
# File 'actionpack/lib/action_dispatch/http/response.rb', line 219
def has_header?(key); @headers.key? key; end
#location Also known as: #redirect_url
Location of the response.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 262
rdoc_method :method: location
#location=(location)
Sets the location of the response
# File 'actionpack/lib/action_dispatch/http/response.rb', line 267
rdoc_method :method: location=
#media_type
Media type of response.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 314
def media_type parsed_content_type_header.mime_type&.dup end
#message Also known as: #status_message
# File 'actionpack/lib/action_dispatch/http/response.rb', line 363
def Rack::Utils::HTTP_STATUS_CODES[@status] end
#parse_content_type(content_type) (private)
# File 'actionpack/lib/action_dispatch/http/response.rb', line 494
def parse_content_type(content_type) # Without parameters or whitespace, the whole value is the media type, which # is what CONTENT_TYPE_PARSER would return. if String === content_type && !content_type.empty? && !content_type.match?(/[;\s]/) ContentTypeHeader.new(String.new(content_type), nil) elsif content_type && match = CONTENT_TYPE_PARSER.match(content_type) ContentTypeHeader.new(match[:mime_type], match[:charset]) else NullContentTypeHeader end end
#parsed_content_type_header (private)
Small internal convenience method to get the parsed version of the current content type header. The result is memoized per raw header value, since the header is read several times per request (content negotiation, charset, committing the response) and parsing allocates a MatchData and its captures each time. A missing header is not memoized: it parses to a shared null object without allocating.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 512
def parsed_content_type_header raw = get_header(CONTENT_TYPE) return NullContentTypeHeader unless raw # The memo key is a frozen copy, so changing the header in place misses it. # It is stored only once parsing succeeds, and the encoding is compared # because == ignores it for ASCII-only strings. memoized_raw = @parsed_content_type_raw if raw == memoized_raw && raw.encoding == memoized_raw.encoding @parsed_content_type else @parsed_content_type = parse_content_type(raw) @parsed_content_type_raw = -raw @parsed_content_type end end
#prepare!
Alias for #to_a.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 465
alias prepare! to_a
#rack_response(status, headers)
[ GitHub ]#redirect_url
Alias for #location.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 441
alias_method :redirect_url, :location
#reset_body!
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 430
def reset_body! @stream = build_buffer(self, []) end
#response_code
The response code of the request.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 346
def response_code @status end
#send_file(path)
Send the file stored at path as the response body.
#sending!
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 242
def sending! synchronize do before_sending @sending = true @cv.broadcast end end
#sent!
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 250
def sent! synchronize do @sent = true @cv.broadcast end end
#set_content_type(content_type, charset) (private)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 534
def set_content_type(content_type, charset) type = content_type || "" if charset charset = charset.to_s.downcase type = "#{type}; charset=#{charset}" else charset = nil end set_header CONTENT_TYPE, type # We serialized the parts ourselves, so prime the parsed-header memo # instead of letting the reader regexp-parse our own output back apart. # Parts the parser could read differently, or that aren't in the encoding # of the header it would read them from, go through the parser. mime_type = content_type.presence unless mime_type&.match?(AMBIGUOUS_CONTENT_TYPE_PART) || charset&.match?(AMBIGUOUS_CONTENT_TYPE_PART) || charset == "" || (mime_type && mime_type.encoding != type.encoding) || (charset && charset.encoding != type.encoding) @parsed_content_type_raw = -type @parsed_content_type = ContentTypeHeader.new(mime_type, charset) end end
#set_header(key, v)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 221
def set_header(key, v); @headers[key] = v; end
#status_message
Alias for #message.
# File 'actionpack/lib/action_dispatch/http/response.rb', line 366
alias_method :, :
#to_a Also known as: #prepare!
# File 'actionpack/lib/action_dispatch/http/response.rb', line 461
def to_a commit! rack_response @status, @headers.to_hash end
#write(string)
[ GitHub ]# File 'actionpack/lib/action_dispatch/http/response.rb', line 380
def write(string) @stream.write string end