123456789_123456789_123456789_123456789_123456789_

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

Http::FilterRedirect - Included

FILTERED

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

Instance Attribute Summary

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 W/).

#weak_etag=,
#weak_etag?

True if an ETag is set, and it's a weak validator (preceded with W/).

Http::FilterRedirect - Included

Instance Method Summary

Http::Cache::Response - Included

Http::FilterRedirect - Included

Constructor Details

.new(status = 200, headers = nil, body = []) {|_self| ... } ⇒ Response

Yields:

  • (_self)

Yield Parameters:

  • _self (Response) —

    the object that the method was called on

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 198

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 102

class_attribute :default_charset, default: "utf-8", instance_accessor: false

.default_charset? ⇒ Boolean (rw)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 102

class_attribute :default_charset, default: "utf-8", instance_accessor: false

.default_headers (rw)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 103

class_attribute :default_headers, instance_accessor: false

.default_headers? ⇒ Boolean (rw)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 103

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 186

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 191

def self.merge_default_headers(original, default)
  default.respond_to?(:merge) ? default.merge(original) : original
end

.rack_status_code(status)

This method is for internal use only.

See additional method definition at line 51.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 56

def rack_status_code(status) # :nodoc:
  status = :unprocessable_content if status == :unprocessable_entity
  Rack::Utils.status_code(status)
end

Instance Attribute Details

#body (rw)

Returns the content of the response as a string. This contains the contents of any calls to render.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 372

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.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 387

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.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 342

def charset
  header_info = parsed_content_type_header
  header_info.charset || 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'
[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 331

def charset=(charset)
  content_type = parsed_content_type_header.mime_type
  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 260

def committed?; synchronize { @committed }; end

#content_type (rw)

Content type of response.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 311

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.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 292

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.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 87

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.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 85

attr_reader :headers

#request (rw)

The request that the response is responding to.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 67

attr_accessor :request

#sending? ⇒ Boolean (readonly)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 259

def sending?;   synchronize { @sending };   end

#sending_file=(v) (writeonly)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 320

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 261

def sent?;      synchronize { @sent };      end

#status (rw)

The HTTP status code.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 70

attr_reader :status

#status=(status) (rw)

Sets the HTTP status code.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 276

def status=(status)
  @status = Response.rack_status_code(status)
end

#stream (readonly)

The underlying body, as a streamable object.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 196

attr_reader :stream

Instance Method Details

#[]

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 89

delegate :[], :[]=, to: :@headers

#[]=

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 89

delegate :[], :[]=, to: :@headers

#_cache_control

Aliasing these off because AD::Http::Cache::Response defines them.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 107

alias :_cache_control :cache_control

#_cache_control=

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 108

alias :_cache_control= :cache_control=

#abort

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 449

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 569

def assign_default_content_type_and_charset!
  return if media_type

  ct = parsed_content_type_header
  set_content_type(ct.mime_type || Mime[:html].to_s,
                   ct.charset || self.class.default_charset)
end

#await_commit

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 226

def await_commit
  synchronize do
    @cv.wait_until { @committed }
  end
end

#await_sent

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 232

def await_sent
  synchronize { @cv.wait_until { @sent } }
end

#before_committed (private)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 547

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 555

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.commit_cookie_jar! unless committed?
end

#body_parts

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 436

def body_parts
  parts = []
  @stream.each { |x| parts << x }
  parts
end

#build_buffer(response, body) (private)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 565

def build_buffer(response, body)
  Buffer.new response, body
end

#close

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 445

def close
  stream.close if stream.respond_to?(:close)
end

#code

Returns a string to ensure compatibility with Net::HTTPResponse.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 353

def code
  @status.to_s
end

#commit!

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 236

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.cookies['author']
[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 472

def cookies
  cookies = {}
  if header = get_header(SET_COOKIE)
    header = header.split("\n") if header.respond_to?(:to_str)
    header.each do |cookie|
      if pair = cookie.split(";").first
        key, value = pair.split("=").map { |v| Rack::Utils.unescape(v) }
        cookies[key] = value
      end
    end
  end
  cookies
end

#delete_header(key)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 224

def delete_header(key); @headers.delete key; end

#each(&block)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 91

def each(&block)
  sending!
  x = @stream.each(&block)
  sent!
  x
end

#get_header(key)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 222

def get_header(key);    @headers[key];       end

#handle_no_content!

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 621

def handle_no_content!
  if NO_CONTENT_CODES.include?(@status)
    @headers.delete CONTENT_TYPE
    @headers.delete "Content-Length"
  end
end

#has_header?(key) ⇒ Boolean

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 221

def has_header?(key);   @headers.key? key;   end

#location Also known as: #redirect_url

Location of the response.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 264

rdoc_method :method: location

#location=(location)

Sets the location of the response

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 269

rdoc_method :method: location=

#media_type

Media type of response.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 316

def media_type
  parsed_content_type_header.mime_type
end

#message Also known as: #status_message

Returns the corresponding message for the current HTTP status code:

response.status = 200
response.message # => "OK"

response.status = 404
response.message # => "Not Found"
[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 365

def message
  Rack::Utils::HTTP_STATUS_CODES[@status]
end

#parse_content_type(content_type) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 496

def parse_content_type(content_type)
  if 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.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 510

def parsed_content_type_header
  raw = get_header(CONTENT_TYPE)
  return NullContentTypeHeader unless raw

  if raw == @parsed_content_type_raw
    @parsed_content_type
  else
    @parsed_content_type_raw = raw
    @parsed_content_type = parse_content_type(raw)
  end
end

#prepare!

Alias for #to_a.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 467

alias prepare! to_a

#rack_response(status, headers)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 628

def rack_response(status, headers)
  if NO_CONTENT_CODES.include?(status)
    [status, headers, []]
  else
    [status, headers, RackBody.new(self)]
  end
end

#redirect_url

Alias for #location.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 443

alias_method :redirect_url, :location

#reset_body!

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 432

def reset_body!
  @stream = build_buffer(self, [])
end

#response_code

The response code of the request.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 348

def response_code
  @status
end

#send_file(path)

Send the file stored at path as the response body.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 427

def send_file(path)
  commit!
  @stream = FileBody.new(path)
end

#sending!

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 244

def sending!
  synchronize do
    before_sending
    @sending = true
    @cv.broadcast
  end
end

#sent!

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 252

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 527

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 go through the parser.
  mime_type = content_type.presence
  unless mime_type&.match?(AMBIGUOUS_CONTENT_TYPE_PART) || charset&.match?(AMBIGUOUS_CONTENT_TYPE_PART) || charset == ""
    @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 223

def set_header(key, v); @headers[key] = v;   end

#status_message

Alias for #message.

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 368

alias_method :status_message, :message

#to_a Also known as: #prepare!

Turns the Response into a Rack-compatible array of the status, headers, and body. Allows explicit splatting:

status, headers, body = *response
[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 463

def to_a
  commit!
  rack_response @status, @headers.to_hash
end

#write(string)

[ GitHub ]

  
# File 'actionpack/lib/action_dispatch/http/response.rb', line 382

def write(string)
  @stream.write string
end