2017-07-24 16:20:53 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
require "abstract_unit"
|
|
|
|
require "timeout"
|
|
|
|
require "rack/content_length"
|
2009-04-26 11:26:53 -04:00
|
|
|
|
|
|
|
class ResponseTest < ActiveSupport::TestCase
|
|
|
|
def setup
|
2015-09-23 17:39:45 -04:00
|
|
|
@response = ActionDispatch::Response.create
|
2015-12-01 14:28:01 -05:00
|
|
|
@response.request = ActionDispatch::Request.empty
|
2009-04-26 11:26:53 -04:00
|
|
|
end
|
|
|
|
|
2012-07-27 18:54:11 -04:00
|
|
|
def test_can_wait_until_commit
|
|
|
|
t = Thread.new {
|
2012-07-28 12:12:35 -04:00
|
|
|
@response.await_commit
|
2012-07-27 18:54:11 -04:00
|
|
|
}
|
|
|
|
@response.commit!
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response, :committed?
|
2012-07-28 12:12:35 -04:00
|
|
|
assert t.join(0.5)
|
2012-07-27 18:54:11 -04:00
|
|
|
end
|
|
|
|
|
2012-07-29 18:51:21 -04:00
|
|
|
def test_stream_close
|
|
|
|
@response.stream.close
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.stream, :closed?
|
2012-07-29 18:51:21 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_stream_write
|
|
|
|
@response.stream.write "foo"
|
|
|
|
@response.stream.close
|
|
|
|
assert_equal "foo", @response.body
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_write_after_close
|
|
|
|
@response.stream.close
|
|
|
|
|
|
|
|
e = assert_raises(IOError) do
|
|
|
|
@response.stream.write "omg"
|
|
|
|
end
|
|
|
|
assert_equal "closed stream", e.message
|
|
|
|
end
|
|
|
|
|
2016-03-03 01:43:18 -05:00
|
|
|
def test_each_isnt_called_if_str_body_is_written
|
|
|
|
# Controller writes and reads response body
|
|
|
|
each_counter = 0
|
2018-12-20 11:39:18 -05:00
|
|
|
@response.body = Object.new.tap { |o| o.singleton_class.define_method(:each) { |&block| each_counter += 1; block.call "foo" } }
|
2016-08-06 12:54:50 -04:00
|
|
|
@response["X-Foo"] = @response.body
|
2016-03-03 01:43:18 -05:00
|
|
|
|
|
|
|
assert_equal 1, each_counter, "#each was not called once"
|
|
|
|
|
|
|
|
# Build response
|
|
|
|
status, headers, body = @response.to_a
|
|
|
|
|
|
|
|
assert_equal 200, status
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "foo", headers["X-Foo"]
|
2016-03-03 01:43:18 -05:00
|
|
|
assert_equal "foo", body.each.to_a.join
|
|
|
|
|
|
|
|
# Show that #each was not called twice
|
|
|
|
assert_equal 1, each_counter, "#each was not called once"
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_set_header_after_read_body_during_action
|
|
|
|
@response.body
|
|
|
|
|
|
|
|
# set header after the action reads back @response.body
|
2016-08-06 12:54:50 -04:00
|
|
|
@response["x-header"] = "Best of all possible worlds."
|
2016-03-03 01:43:18 -05:00
|
|
|
|
|
|
|
# the response can be built.
|
|
|
|
status, headers, body = @response.to_a
|
|
|
|
assert_equal 200, status
|
|
|
|
assert_equal "", body.body
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "Best of all possible worlds.", headers["x-header"]
|
2016-03-03 01:43:18 -05:00
|
|
|
end
|
|
|
|
|
2016-01-05 21:13:40 -05:00
|
|
|
def test_read_body_during_action
|
|
|
|
@response.body = "Hello, World!"
|
|
|
|
|
|
|
|
# even though there's no explicitly set content-type,
|
2016-12-24 12:29:52 -05:00
|
|
|
assert_nil @response.content_type
|
2016-01-05 21:13:40 -05:00
|
|
|
|
|
|
|
# after the action reads back @response.body,
|
|
|
|
assert_equal "Hello, World!", @response.body
|
|
|
|
|
|
|
|
# the response can be built.
|
|
|
|
status, headers, body = @response.to_a
|
|
|
|
assert_equal 200, status
|
|
|
|
assert_equal({
|
|
|
|
"Content-Type" => "text/html; charset=utf-8"
|
|
|
|
}, headers)
|
|
|
|
|
|
|
|
parts = []
|
|
|
|
body.each { |part| parts << part }
|
|
|
|
assert_equal ["Hello, World!"], parts
|
|
|
|
end
|
|
|
|
|
2011-12-12 22:45:16 -05:00
|
|
|
def test_response_body_encoding
|
2013-01-28 02:59:50 -05:00
|
|
|
body = ["hello".encode(Encoding::UTF_8)]
|
2011-12-12 22:45:16 -05:00
|
|
|
response = ActionDispatch::Response.new 200, {}, body
|
2015-12-01 14:28:01 -05:00
|
|
|
response.request = ActionDispatch::Request.empty
|
2011-12-12 22:45:16 -05:00
|
|
|
assert_equal Encoding::UTF_8, response.body.encoding
|
|
|
|
end
|
|
|
|
|
2015-06-16 17:58:50 -04:00
|
|
|
def test_response_charset_writer
|
2016-08-06 12:54:50 -04:00
|
|
|
@response.charset = "utf-16"
|
|
|
|
assert_equal "utf-16", @response.charset
|
2015-06-16 17:58:50 -04:00
|
|
|
@response.charset = nil
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "utf-8", @response.charset
|
2015-06-16 17:58:50 -04:00
|
|
|
end
|
|
|
|
|
2015-09-08 19:13:54 -04:00
|
|
|
def test_setting_content_type_header_impacts_content_type_method
|
2016-08-06 12:54:50 -04:00
|
|
|
@response.headers["Content-Type"] = "application/aaron"
|
|
|
|
assert_equal "application/aaron", @response.content_type
|
2015-09-08 19:13:54 -04:00
|
|
|
end
|
|
|
|
|
2016-12-09 14:29:06 -05:00
|
|
|
def test_empty_content_type_returns_nil
|
2016-12-28 21:53:51 -05:00
|
|
|
@response.headers["Content-Type"] = ""
|
2016-12-24 12:29:52 -05:00
|
|
|
assert_nil @response.content_type
|
2016-12-09 14:29:06 -05:00
|
|
|
end
|
|
|
|
|
2009-04-26 11:26:53 -04:00
|
|
|
test "simple output" do
|
|
|
|
@response.body = "Hello, World!"
|
|
|
|
|
|
|
|
status, headers, body = @response.to_a
|
|
|
|
assert_equal 200, status
|
|
|
|
assert_equal({
|
2010-09-22 15:40:14 -04:00
|
|
|
"Content-Type" => "text/html; charset=utf-8"
|
2009-04-26 11:26:53 -04:00
|
|
|
}, headers)
|
|
|
|
|
|
|
|
parts = []
|
|
|
|
body.each { |part| parts << part }
|
|
|
|
assert_equal ["Hello, World!"], parts
|
|
|
|
end
|
2011-02-07 19:44:27 -05:00
|
|
|
|
2010-10-18 15:00:48 -04:00
|
|
|
test "status handled properly in initialize" do
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal 200, ActionDispatch::Response.new("200 OK").status
|
2010-10-18 15:00:48 -04:00
|
|
|
end
|
2009-04-26 11:26:53 -04:00
|
|
|
|
2015-09-08 18:37:33 -04:00
|
|
|
def test_only_set_charset_still_defaults_to_text_html
|
|
|
|
response = ActionDispatch::Response.new
|
|
|
|
response.charset = "utf-16"
|
2016-10-28 23:05:58 -04:00
|
|
|
_, headers, _ = response.to_a
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "text/html; charset=utf-16", headers["Content-Type"]
|
2015-09-08 18:37:33 -04:00
|
|
|
end
|
|
|
|
|
2009-04-26 11:26:53 -04:00
|
|
|
test "utf8 output" do
|
|
|
|
@response.body = [1090, 1077, 1089, 1090].pack("U*")
|
|
|
|
|
2011-02-07 19:44:27 -05:00
|
|
|
status, headers, _ = @response.to_a
|
2009-04-26 11:26:53 -04:00
|
|
|
assert_equal 200, status
|
|
|
|
assert_equal({
|
2010-09-22 15:40:14 -04:00
|
|
|
"Content-Type" => "text/html; charset=utf-8"
|
2009-04-26 11:26:53 -04:00
|
|
|
}, headers)
|
|
|
|
end
|
|
|
|
|
2016-07-09 06:24:01 -04:00
|
|
|
test "content length" do
|
2020-05-20 19:26:55 -04:00
|
|
|
[100, 101, 102, 103, 204].each do |c|
|
2016-07-09 06:24:01 -04:00
|
|
|
@response = ActionDispatch::Response.new
|
|
|
|
@response.status = c.to_s
|
|
|
|
@response.set_header "Content-Length", "0"
|
|
|
|
_, headers, _ = @response.to_a
|
2018-05-12 22:26:10 -04:00
|
|
|
assert_not headers.has_key?("Content-Length"), "#{c} must not have a Content-Length header field"
|
2016-07-09 06:24:01 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
test "does not contain a message-body" do
|
2020-05-20 19:26:55 -04:00
|
|
|
[100, 101, 102, 103, 204, 304].each do |c|
|
2016-07-09 06:24:01 -04:00
|
|
|
@response = ActionDispatch::Response.new
|
|
|
|
@response.status = c.to_s
|
|
|
|
@response.body = "Body must not be included"
|
|
|
|
_, _, body = @response.to_a
|
|
|
|
assert_empty body, "#{c} must not have a message-body but actually contains #{body}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-04-26 11:26:53 -04:00
|
|
|
test "content type" do
|
|
|
|
[204, 304].each do |c|
|
2015-06-15 20:54:08 -04:00
|
|
|
@response = ActionDispatch::Response.new
|
2009-04-26 11:26:53 -04:00
|
|
|
@response.status = c.to_s
|
2011-02-07 19:44:27 -05:00
|
|
|
_, headers, _ = @response.to_a
|
2018-05-12 22:26:10 -04:00
|
|
|
assert_not headers.has_key?("Content-Type"), "#{c} should not have Content-Type header"
|
2009-04-26 11:26:53 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
[200, 302, 404, 500].each do |c|
|
2015-06-15 20:54:08 -04:00
|
|
|
@response = ActionDispatch::Response.new
|
2009-04-26 11:26:53 -04:00
|
|
|
@response.status = c.to_s
|
2011-02-07 19:44:27 -05:00
|
|
|
_, headers, _ = @response.to_a
|
2009-04-26 11:26:53 -04:00
|
|
|
assert headers.has_key?("Content-Type"), "#{c} did not have Content-Type header"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
test "does not include Status header" do
|
|
|
|
@response.status = "200 OK"
|
2011-02-07 19:44:27 -05:00
|
|
|
_, headers, _ = @response.to_a
|
2018-04-17 18:21:34 -04:00
|
|
|
assert_not headers.has_key?("Status")
|
2009-04-26 11:26:53 -04:00
|
|
|
end
|
2009-04-26 12:12:33 -04:00
|
|
|
|
|
|
|
test "response code" do
|
|
|
|
@response.status = "200 OK"
|
|
|
|
assert_equal 200, @response.response_code
|
|
|
|
|
|
|
|
@response.status = "200"
|
|
|
|
assert_equal 200, @response.response_code
|
|
|
|
|
|
|
|
@response.status = 200
|
|
|
|
assert_equal 200, @response.response_code
|
|
|
|
end
|
|
|
|
|
|
|
|
test "code" do
|
|
|
|
@response.status = "200 OK"
|
|
|
|
assert_equal "200", @response.code
|
|
|
|
|
|
|
|
@response.status = "200"
|
|
|
|
assert_equal "200", @response.code
|
|
|
|
|
|
|
|
@response.status = 200
|
|
|
|
assert_equal "200", @response.code
|
|
|
|
end
|
|
|
|
|
|
|
|
test "message" do
|
|
|
|
@response.status = "200 OK"
|
|
|
|
assert_equal "OK", @response.message
|
|
|
|
|
|
|
|
@response.status = "200"
|
|
|
|
assert_equal "OK", @response.message
|
|
|
|
|
|
|
|
@response.status = 200
|
|
|
|
assert_equal "OK", @response.message
|
|
|
|
end
|
|
|
|
|
|
|
|
test "cookies" do
|
2016-08-06 13:35:13 -04:00
|
|
|
@response.set_cookie("user_name", value: "david", path: "/")
|
2015-10-03 02:50:52 -04:00
|
|
|
_status, headers, _body = @response.to_a
|
2009-04-26 12:12:33 -04:00
|
|
|
assert_equal "user_name=david; path=/", headers["Set-Cookie"]
|
2016-08-16 03:30:11 -04:00
|
|
|
assert_equal({ "user_name" => "david" }, @response.cookies)
|
2015-09-23 14:25:33 -04:00
|
|
|
end
|
2009-04-26 12:12:33 -04:00
|
|
|
|
2015-09-23 14:25:33 -04:00
|
|
|
test "multiple cookies" do
|
2016-08-06 13:35:13 -04:00
|
|
|
@response.set_cookie("user_name", value: "david", path: "/")
|
2016-10-28 23:05:58 -04:00
|
|
|
@response.set_cookie("login", value: "foo&bar", path: "/", expires: Time.utc(2005, 10, 10, 5))
|
2015-10-03 02:50:52 -04:00
|
|
|
_status, headers, _body = @response.to_a
|
2020-01-10 17:23:10 -05:00
|
|
|
assert_equal "user_name=david; path=/\nlogin=foo%26bar; path=/; expires=Mon, 10 Oct 2005 05:00:00 GMT", headers["Set-Cookie"]
|
2016-08-16 03:30:11 -04:00
|
|
|
assert_equal({ "login" => "foo&bar", "user_name" => "david" }, @response.cookies)
|
2015-09-23 14:25:33 -04:00
|
|
|
end
|
2010-05-17 19:42:35 -04:00
|
|
|
|
2015-09-23 14:25:33 -04:00
|
|
|
test "delete cookies" do
|
2016-08-06 13:35:13 -04:00
|
|
|
@response.set_cookie("user_name", value: "david", path: "/")
|
2016-10-28 23:05:58 -04:00
|
|
|
@response.set_cookie("login", value: "foo&bar", path: "/", expires: Time.utc(2005, 10, 10, 5))
|
2010-05-17 19:42:35 -04:00
|
|
|
@response.delete_cookie("login")
|
2016-08-16 03:30:11 -04:00
|
|
|
assert_equal({ "user_name" => "david", "login" => nil }, @response.cookies)
|
2009-04-26 12:12:33 -04:00
|
|
|
end
|
2009-12-17 23:10:06 -05:00
|
|
|
|
2016-03-31 20:47:00 -04:00
|
|
|
test "read ETag and Cache-Control" do
|
2010-09-27 14:18:35 -04:00
|
|
|
resp = ActionDispatch::Response.new.tap { |response|
|
|
|
|
response.cache_control[:public] = true
|
2016-08-06 12:54:50 -04:00
|
|
|
response.etag = "123"
|
|
|
|
response.body = "Hello"
|
2009-12-17 23:10:06 -05:00
|
|
|
}
|
|
|
|
resp.to_a
|
|
|
|
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate resp, :etag?
|
|
|
|
assert_predicate resp, :weak_etag?
|
|
|
|
assert_not_predicate resp, :strong_etag?
|
2014-11-10 00:23:31 -05:00
|
|
|
assert_equal('W/"202cb962ac59075b964b07152d234b70"', resp.etag)
|
2016-08-16 03:30:11 -04:00
|
|
|
assert_equal({ public: true }, resp.cache_control)
|
2009-12-17 23:10:06 -05:00
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("public", resp.headers["Cache-Control"])
|
|
|
|
assert_equal('W/"202cb962ac59075b964b07152d234b70"', resp.headers["ETag"])
|
2009-12-17 23:10:06 -05:00
|
|
|
end
|
|
|
|
|
2016-03-31 20:47:00 -04:00
|
|
|
test "read strong ETag" do
|
|
|
|
resp = ActionDispatch::Response.new.tap { |response|
|
|
|
|
response.cache_control[:public] = true
|
2016-08-06 12:54:50 -04:00
|
|
|
response.strong_etag = "123"
|
|
|
|
response.body = "Hello"
|
2016-03-31 20:47:00 -04:00
|
|
|
}
|
|
|
|
resp.to_a
|
|
|
|
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate resp, :etag?
|
|
|
|
assert_not_predicate resp, :weak_etag?
|
|
|
|
assert_predicate resp, :strong_etag?
|
2016-03-31 20:47:00 -04:00
|
|
|
assert_equal('"202cb962ac59075b964b07152d234b70"', resp.etag)
|
|
|
|
end
|
|
|
|
|
2009-12-17 23:10:06 -05:00
|
|
|
test "read charset and content type" do
|
2010-09-27 14:18:35 -04:00
|
|
|
resp = ActionDispatch::Response.new.tap { |response|
|
2016-08-06 12:54:50 -04:00
|
|
|
response.charset = "utf-16"
|
2015-10-05 01:14:04 -04:00
|
|
|
response.content_type = Mime[:xml]
|
2016-08-06 12:54:50 -04:00
|
|
|
response.body = "Hello"
|
2009-12-17 23:10:06 -05:00
|
|
|
}
|
|
|
|
resp.to_a
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("utf-16", resp.charset)
|
2019-04-17 02:37:16 -04:00
|
|
|
assert_equal(Mime[:xml], resp.media_type)
|
|
|
|
assert_equal("application/xml; charset=utf-16", resp.content_type)
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("application/xml; charset=utf-16", resp.headers["Content-Type"])
|
2009-12-17 23:10:06 -05:00
|
|
|
end
|
2011-12-06 11:46:41 -05:00
|
|
|
|
2020-05-28 01:37:43 -04:00
|
|
|
test "respect no-store cache-control" do
|
|
|
|
resp = ActionDispatch::Response.new.tap { |response|
|
|
|
|
response.cache_control[:public] = true
|
|
|
|
response.cache_control[:no_store] = true
|
|
|
|
response.body = "Hello"
|
|
|
|
}
|
|
|
|
resp.to_a
|
|
|
|
|
|
|
|
assert_equal("no-store", resp.headers["Cache-Control"])
|
|
|
|
end
|
|
|
|
|
2015-10-01 15:57:23 -04:00
|
|
|
test "read content type with default charset utf-8" do
|
2017-07-12 12:34:57 -04:00
|
|
|
resp = ActionDispatch::Response.new(200, "Content-Type" => "text/xml")
|
|
|
|
assert_equal("utf-8", resp.charset)
|
2015-10-01 15:57:23 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
test "read content type with charset utf-16" do
|
2011-12-06 11:46:41 -05:00
|
|
|
original = ActionDispatch::Response.default_charset
|
|
|
|
begin
|
2016-08-06 12:54:50 -04:00
|
|
|
ActionDispatch::Response.default_charset = "utf-16"
|
2016-08-06 13:44:11 -04:00
|
|
|
resp = ActionDispatch::Response.new(200, "Content-Type" => "text/xml")
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("utf-16", resp.charset)
|
2011-12-06 11:46:41 -05:00
|
|
|
ensure
|
|
|
|
ActionDispatch::Response.default_charset = original
|
|
|
|
end
|
|
|
|
end
|
2012-08-09 10:12:11 -04:00
|
|
|
|
2018-01-08 22:14:22 -05:00
|
|
|
test "read x_frame_options, x_content_type_options, x_xss_protection, x_download_options and x_permitted_cross_domain_policies, referrer_policy" do
|
2014-06-05 10:52:13 -04:00
|
|
|
original_default_headers = ActionDispatch::Response.default_headers
|
2012-09-08 15:51:22 -04:00
|
|
|
begin
|
|
|
|
ActionDispatch::Response.default_headers = {
|
2016-08-06 12:54:50 -04:00
|
|
|
"X-Frame-Options" => "DENY",
|
|
|
|
"X-Content-Type-Options" => "nosniff",
|
2017-12-09 15:41:55 -05:00
|
|
|
"X-XSS-Protection" => "1;",
|
|
|
|
"X-Download-Options" => "noopen",
|
2018-01-08 22:14:22 -05:00
|
|
|
"X-Permitted-Cross-Domain-Policies" => "none",
|
|
|
|
"Referrer-Policy" => "strict-origin-when-cross-origin"
|
2012-09-08 15:51:22 -04:00
|
|
|
}
|
2015-09-23 17:39:45 -04:00
|
|
|
resp = ActionDispatch::Response.create.tap { |response|
|
2016-08-06 12:54:50 -04:00
|
|
|
response.body = "Hello"
|
2012-09-08 15:51:22 -04:00
|
|
|
}
|
|
|
|
resp.to_a
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("DENY", resp.headers["X-Frame-Options"])
|
|
|
|
assert_equal("nosniff", resp.headers["X-Content-Type-Options"])
|
|
|
|
assert_equal("1;", resp.headers["X-XSS-Protection"])
|
2017-12-09 15:41:55 -05:00
|
|
|
assert_equal("noopen", resp.headers["X-Download-Options"])
|
|
|
|
assert_equal("none", resp.headers["X-Permitted-Cross-Domain-Policies"])
|
2018-01-08 22:14:22 -05:00
|
|
|
assert_equal("strict-origin-when-cross-origin", resp.headers["Referrer-Policy"])
|
2012-09-08 15:51:22 -04:00
|
|
|
ensure
|
2014-06-05 10:52:13 -04:00
|
|
|
ActionDispatch::Response.default_headers = original_default_headers
|
2012-09-08 15:51:22 -04:00
|
|
|
end
|
|
|
|
end
|
2012-08-09 10:12:11 -04:00
|
|
|
|
|
|
|
test "read custom default_header" do
|
2014-06-05 10:52:13 -04:00
|
|
|
original_default_headers = ActionDispatch::Response.default_headers
|
2012-09-08 15:51:22 -04:00
|
|
|
begin
|
|
|
|
ActionDispatch::Response.default_headers = {
|
2016-08-06 12:54:50 -04:00
|
|
|
"X-XX-XXXX" => "Here is my phone number"
|
2012-09-08 15:51:22 -04:00
|
|
|
}
|
2015-09-23 17:39:45 -04:00
|
|
|
resp = ActionDispatch::Response.create.tap { |response|
|
2016-08-06 12:54:50 -04:00
|
|
|
response.body = "Hello"
|
2012-09-08 15:51:22 -04:00
|
|
|
}
|
|
|
|
resp.to_a
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("Here is my phone number", resp.headers["X-XX-XXXX"])
|
2012-09-08 15:51:22 -04:00
|
|
|
ensure
|
2014-06-05 10:52:13 -04:00
|
|
|
ActionDispatch::Response.default_headers = original_default_headers
|
2012-09-08 15:51:22 -04:00
|
|
|
end
|
|
|
|
end
|
2013-08-16 11:22:08 -04:00
|
|
|
|
|
|
|
test "respond_to? accepts include_private" do
|
2018-01-24 21:14:10 -05:00
|
|
|
assert_not_respond_to @response, :method_missing
|
2013-08-16 11:22:08 -04:00
|
|
|
assert @response.respond_to?(:method_missing, true)
|
|
|
|
end
|
2014-02-02 17:55:35 -05:00
|
|
|
|
2014-09-05 16:33:20 -04:00
|
|
|
test "can be explicitly destructured into status, headers and an enumerable body" do
|
2016-08-06 12:54:50 -04:00
|
|
|
response = ActionDispatch::Response.new(404, { "Content-Type" => "text/plain" }, ["Not Found"])
|
2015-12-01 14:28:01 -05:00
|
|
|
response.request = ActionDispatch::Request.empty
|
2014-09-05 16:33:20 -04:00
|
|
|
status, headers, body = *response
|
2014-02-02 17:55:35 -05:00
|
|
|
|
|
|
|
assert_equal 404, status
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal({ "Content-Type" => "text/plain" }, headers)
|
|
|
|
assert_equal ["Not Found"], body.each.to_a
|
2014-02-02 17:55:35 -05:00
|
|
|
end
|
2014-02-08 20:40:08 -05:00
|
|
|
|
2015-01-02 21:25:57 -05:00
|
|
|
test "[response.to_a].flatten does not recurse infinitely" do
|
2014-02-08 20:40:08 -05:00
|
|
|
Timeout.timeout(1) do # use a timeout to prevent it stalling indefinitely
|
2015-01-02 21:25:57 -05:00
|
|
|
status, headers, body = [@response.to_a].flatten
|
2014-02-08 20:40:08 -05:00
|
|
|
assert_equal @response.status, status
|
|
|
|
assert_equal @response.headers, headers
|
|
|
|
assert_equal @response.body, body.each.to_a.join
|
|
|
|
end
|
|
|
|
end
|
2014-09-05 16:33:20 -04:00
|
|
|
|
2014-09-03 11:16:37 -04:00
|
|
|
test "compatibility with Rack::ContentLength" do
|
2016-08-06 12:54:50 -04:00
|
|
|
@response.body = "Hello"
|
2014-09-03 11:16:37 -04:00
|
|
|
app = lambda { |env| @response.to_a }
|
|
|
|
env = Rack::MockRequest.env_for("/")
|
|
|
|
|
2017-09-01 06:15:04 -04:00
|
|
|
_status, headers, _body = app.call(env)
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_nil headers["Content-Length"]
|
2014-09-03 11:16:37 -04:00
|
|
|
|
2017-09-01 06:15:04 -04:00
|
|
|
_status, headers, _body = Rack::ContentLength.new(app).call(env)
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "5", headers["Content-Length"]
|
2014-09-03 11:16:37 -04:00
|
|
|
end
|
2009-12-17 23:10:06 -05:00
|
|
|
end
|
|
|
|
|
2015-10-01 23:42:52 -04:00
|
|
|
class ResponseHeadersTest < ActiveSupport::TestCase
|
|
|
|
def setup
|
|
|
|
@response = ActionDispatch::Response.create
|
2016-08-06 12:54:50 -04:00
|
|
|
@response.set_header "Foo", "1"
|
2015-10-01 23:42:52 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
test "has_header?" do
|
|
|
|
assert @response.has_header? "Foo"
|
|
|
|
assert_not @response.has_header? "foo"
|
2015-10-03 22:14:37 -04:00
|
|
|
assert_not @response.has_header? nil
|
2015-10-01 23:42:52 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
test "get_header" do
|
|
|
|
assert_equal "1", @response.get_header("Foo")
|
|
|
|
assert_nil @response.get_header("foo")
|
2015-10-01 23:42:52 -04:00
|
|
|
assert_nil @response.get_header(nil)
|
|
|
|
end
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
test "set_header" do
|
|
|
|
assert_equal "2", @response.set_header("Foo", "2")
|
|
|
|
assert @response.has_header?("Foo")
|
|
|
|
assert_equal "2", @response.get_header("Foo")
|
2015-10-01 23:42:52 -04:00
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_nil @response.set_header("Foo", nil)
|
|
|
|
assert @response.has_header?("Foo")
|
|
|
|
assert_nil @response.get_header("Foo")
|
2015-10-01 23:42:52 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
test "delete_header" do
|
2015-10-01 23:42:52 -04:00
|
|
|
assert_nil @response.delete_header(nil)
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_nil @response.delete_header("foo")
|
|
|
|
assert @response.has_header?("Foo")
|
2015-10-01 23:42:52 -04:00
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "1", @response.delete_header("Foo")
|
|
|
|
assert_not @response.has_header?("Foo")
|
2015-10-01 23:42:52 -04:00
|
|
|
end
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
test "add_header" do
|
2015-10-01 23:42:52 -04:00
|
|
|
# Add a value to an existing header
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "1,2", @response.add_header("Foo", "2")
|
|
|
|
assert_equal "1,2", @response.get_header("Foo")
|
2015-10-01 23:42:52 -04:00
|
|
|
|
|
|
|
# Add nil to an existing header
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "1,2", @response.add_header("Foo", nil)
|
|
|
|
assert_equal "1,2", @response.get_header("Foo")
|
2015-10-01 23:42:52 -04:00
|
|
|
|
|
|
|
# Add nil to a nonexistent header
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_nil @response.add_header("Bar", nil)
|
|
|
|
assert_not @response.has_header?("Bar")
|
|
|
|
assert_nil @response.get_header("Bar")
|
2015-10-01 23:42:52 -04:00
|
|
|
|
|
|
|
# Add a value to a nonexistent header
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "1", @response.add_header("Bar", "1")
|
|
|
|
assert @response.has_header?("Bar")
|
|
|
|
assert_equal "1", @response.get_header("Bar")
|
2015-10-01 23:42:52 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-12-17 23:10:06 -05:00
|
|
|
class ResponseIntegrationTest < ActionDispatch::IntegrationTest
|
|
|
|
test "response cache control from railsish app" do
|
|
|
|
@app = lambda { |env|
|
|
|
|
ActionDispatch::Response.new.tap { |resp|
|
|
|
|
resp.cache_control[:public] = true
|
2016-08-06 12:54:50 -04:00
|
|
|
resp.etag = "123"
|
|
|
|
resp.body = "Hello"
|
2015-12-01 14:28:01 -05:00
|
|
|
resp.request = ActionDispatch::Request.empty
|
2009-12-17 23:10:06 -05:00
|
|
|
}.to_a
|
|
|
|
}
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
get "/"
|
2009-12-17 23:10:06 -05:00
|
|
|
assert_response :success
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("public", @response.headers["Cache-Control"])
|
|
|
|
assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.headers["ETag"])
|
2009-12-17 23:10:06 -05:00
|
|
|
|
2014-11-10 00:23:31 -05:00
|
|
|
assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.etag)
|
2016-08-16 03:30:11 -04:00
|
|
|
assert_equal({ public: true }, @response.cache_control)
|
2009-12-17 23:10:06 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
test "response cache control from rackish app" do
|
|
|
|
@app = lambda { |env|
|
|
|
|
[200,
|
2016-08-16 03:30:11 -04:00
|
|
|
{ "ETag" => 'W/"202cb962ac59075b964b07152d234b70"',
|
|
|
|
"Cache-Control" => "public" }, ["Hello"]]
|
2009-12-17 23:10:06 -05:00
|
|
|
}
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
get "/"
|
2009-12-17 23:10:06 -05:00
|
|
|
assert_response :success
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("public", @response.headers["Cache-Control"])
|
|
|
|
assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.headers["ETag"])
|
2009-12-17 23:10:06 -05:00
|
|
|
|
2014-11-10 00:23:31 -05:00
|
|
|
assert_equal('W/"202cb962ac59075b964b07152d234b70"', @response.etag)
|
2016-08-16 03:30:11 -04:00
|
|
|
assert_equal({ public: true }, @response.cache_control)
|
2009-12-17 23:10:06 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
test "response charset and content type from railsish app" do
|
|
|
|
@app = lambda { |env|
|
|
|
|
ActionDispatch::Response.new.tap { |resp|
|
2016-08-06 12:54:50 -04:00
|
|
|
resp.charset = "utf-16"
|
2015-10-05 01:14:04 -04:00
|
|
|
resp.content_type = Mime[:xml]
|
2016-08-06 12:54:50 -04:00
|
|
|
resp.body = "Hello"
|
2015-12-01 14:28:01 -05:00
|
|
|
resp.request = ActionDispatch::Request.empty
|
2009-12-17 23:10:06 -05:00
|
|
|
}.to_a
|
|
|
|
}
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
get "/"
|
2009-12-17 23:10:06 -05:00
|
|
|
assert_response :success
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("utf-16", @response.charset)
|
2019-04-17 02:37:16 -04:00
|
|
|
assert_equal(Mime[:xml], @response.media_type)
|
|
|
|
assert_equal("application/xml; charset=utf-16", @response.content_type)
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("application/xml; charset=utf-16", @response.headers["Content-Type"])
|
2009-12-17 23:10:06 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
test "response charset and content type from rackish app" do
|
|
|
|
@app = lambda { |env|
|
|
|
|
[200,
|
2016-08-16 03:30:11 -04:00
|
|
|
{ "Content-Type" => "application/xml; charset=utf-16" },
|
2016-08-06 12:54:50 -04:00
|
|
|
["Hello"]]
|
2009-12-17 23:10:06 -05:00
|
|
|
}
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
get "/"
|
2009-12-17 23:10:06 -05:00
|
|
|
assert_response :success
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("utf-16", @response.charset)
|
2019-04-17 02:37:16 -04:00
|
|
|
assert_equal(Mime[:xml], @response.media_type)
|
|
|
|
assert_equal("application/xml; charset=utf-16", @response.content_type)
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal("application/xml; charset=utf-16", @response.headers["Content-Type"])
|
2009-12-17 23:10:06 -05:00
|
|
|
end
|
2016-02-24 12:46:43 -05:00
|
|
|
|
2016-03-31 20:47:00 -04:00
|
|
|
test "strong ETag validator" do
|
|
|
|
@app = lambda { |env|
|
|
|
|
ActionDispatch::Response.new.tap { |resp|
|
2016-08-06 12:54:50 -04:00
|
|
|
resp.strong_etag = "123"
|
|
|
|
resp.body = "Hello"
|
2016-03-31 20:47:00 -04:00
|
|
|
resp.request = ActionDispatch::Request.empty
|
|
|
|
}.to_a
|
|
|
|
}
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
get "/"
|
2016-03-31 20:47:00 -04:00
|
|
|
assert_response :ok
|
2016-02-24 12:46:43 -05:00
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal('"202cb962ac59075b964b07152d234b70"', @response.headers["ETag"])
|
2016-03-31 20:47:00 -04:00
|
|
|
assert_equal('"202cb962ac59075b964b07152d234b70"', @response.etag)
|
2016-02-24 12:46:43 -05:00
|
|
|
end
|
2019-03-09 01:02:05 -05:00
|
|
|
|
|
|
|
test "response Content-Type with optional parameters" do
|
|
|
|
@app = lambda { |env|
|
|
|
|
[
|
|
|
|
200,
|
|
|
|
{ "Content-Type" => "text/csv; charset=utf-16; header=present" },
|
|
|
|
["Hello"]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
get "/"
|
|
|
|
assert_response :success
|
|
|
|
|
|
|
|
assert_equal("text/csv; charset=utf-16; header=present", @response.headers["Content-Type"])
|
2019-04-17 02:37:16 -04:00
|
|
|
assert_equal("text/csv; charset=utf-16; header=present", @response.content_type)
|
|
|
|
assert_equal("text/csv", @response.media_type)
|
|
|
|
assert_equal("utf-16", @response.charset)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "response Content-Type with optional parameters that set before charset" do
|
|
|
|
@app = lambda { |env|
|
|
|
|
[
|
|
|
|
200,
|
|
|
|
{ "Content-Type" => "text/csv; header=present; charset=utf-16" },
|
|
|
|
["Hello"]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
get "/"
|
|
|
|
assert_response :success
|
|
|
|
|
|
|
|
assert_equal("text/csv; header=present; charset=utf-16", @response.headers["Content-Type"])
|
|
|
|
assert_equal("text/csv; header=present; charset=utf-16", @response.content_type)
|
2019-08-22 14:34:39 -04:00
|
|
|
assert_equal("text/csv; header=present", @response.media_type)
|
2019-03-09 01:02:05 -05:00
|
|
|
assert_equal("utf-16", @response.charset)
|
|
|
|
end
|
|
|
|
|
|
|
|
test "response Content-Type with quoted-string" do
|
|
|
|
@app = lambda { |env|
|
|
|
|
[
|
|
|
|
200,
|
|
|
|
{ "Content-Type" => 'text/csv; header=present; charset="utf-16"' },
|
|
|
|
["Hello"]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
get "/"
|
|
|
|
assert_response :success
|
|
|
|
|
|
|
|
assert_equal('text/csv; header=present; charset="utf-16"', @response.headers["Content-Type"])
|
2019-04-17 02:37:16 -04:00
|
|
|
assert_equal('text/csv; header=present; charset="utf-16"', @response.content_type)
|
2019-08-22 14:34:39 -04:00
|
|
|
assert_equal("text/csv; header=present", @response.media_type)
|
2019-03-09 01:02:05 -05:00
|
|
|
assert_equal("utf-16", @response.charset)
|
|
|
|
end
|
2009-04-26 11:26:53 -04:00
|
|
|
end
|