diff --git a/SPEC.rdoc b/SPEC.rdoc
index 76389d833..5d89e09fc 100644
--- a/SPEC.rdoc
+++ b/SPEC.rdoc
@@ -258,10 +258,9 @@ The header must not contain a +Status+ key.
Header keys must conform to RFC7230 token specification, i.e. cannot
contain non-printable ASCII, DQUOTE or "(),/:;<=>?@[\]{}".
Header keys must not contain uppercase ASCII characters (A-Z).
-The values of the header must be Strings,
-consisting of lines (for multiple header values, e.g. multiple
-Set-Cookie values) separated by "\\n".
-The lines must not contain characters below 037.
+Header values must be either a String instance,
+or an Array of String instances,
+such that each String instance must not contain characters below 037.
=== The content-type
diff --git a/lib/rack/handler/webrick.rb b/lib/rack/handler/webrick.rb
index 47cc2cc03..9044ab781 100644
--- a/lib/rack/handler/webrick.rb
+++ b/lib/rack/handler/webrick.rb
@@ -95,15 +95,15 @@ def service(req, res)
begin
res.status = status.to_i
io_lambda = nil
- headers.each { |k, vs|
- if k == RACK_HIJACK
- io_lambda = vs
- elsif k == "set-cookie"
- res.cookies.concat vs.split("\n")
+ headers.each { |key, value|
+ if key == RACK_HIJACK
+ io_lambda = value
+ elsif key == "set-cookie"
+ res.cookies.concat(Array(value))
else
# Since WEBrick won't accept repeated headers,
# merge the values per RFC 1945 section 4.2.
- res[k] = vs.split("\n").join(", ")
+ res[key] = Array(value).join(", ")
end
}
diff --git a/lib/rack/lint.rb b/lib/rack/lint.rb
index d6ec46c96..0f67f2965 100755
--- a/lib/rack/lint.rb
+++ b/lib/rack/lint.rb
@@ -655,7 +655,7 @@ def check_headers(headers)
raise LintError, "headers object should not be frozen, but is"
end
- headers.each { |key, value|
+ headers.each do |key, value|
## The header keys must be Strings.
unless key.kind_of? String
raise LintError, "header key must be a string, was #{key.class}"
@@ -663,7 +663,7 @@ def check_headers(headers)
## Special headers starting "rack." are for communicating with the
## server, and must not be sent back to the client.
- next if key =~ /^rack\..+$/
+ next if key.start_with?("rack.")
## The header must not contain a +Status+ key.
raise LintError, "header must not contain status" if key == "status"
@@ -673,19 +673,23 @@ def check_headers(headers)
## Header keys must not contain uppercase ASCII characters (A-Z).
raise LintError, "uppercase character in header name: #{key}" if key =~ /[A-Z]/
- ## The values of the header must be Strings,
- unless value.kind_of? String
- raise LintError, "a header value must be a String, but the value of '#{key}' is a #{value.class}"
- end
- ## consisting of lines (for multiple header values, e.g. multiple
- ## Set-Cookie values) separated by "\\n".
- value.split("\n").each { |item|
- ## The lines must not contain characters below 037.
- if item =~ /[\000-\037]/
- raise LintError, "invalid header value #{key}: #{item.inspect}"
- end
- }
- }
+ ## Header values must be either a String instance,
+ if value.kind_of?(String)
+ check_header_value(key, value)
+ elsif value.kind_of?(Array)
+ ## or an Array of String instances,
+ value.each{|value| check_header_value(key, value)}
+ else
+ raise LintError, "a header value must be a String or Array of Strings, but the value of '#{key}' is a #{value.class}"
+ end
+ end
+ end
+
+ def check_header_value(key, value)
+ ## such that each String instance must not contain characters below 037.
+ if value =~ /[\000-\037]/
+ raise LintError, "invalid header value #{key}: #{value.inspect}"
+ end
end
##
diff --git a/lib/rack/response.rb b/lib/rack/response.rb
index 6c43156e4..55abb8d3f 100644
--- a/lib/rack/response.rb
+++ b/lib/rack/response.rb
@@ -143,19 +143,19 @@ def empty?
def has_header?(key)
raise ArgumentError unless key.is_a?(String)
- headers.key? key
+ @headers.key?(key)
end
def get_header(key)
raise ArgumentError unless key.is_a?(String)
- headers[key]
+ @headers[key]
end
- def set_header(key, v)
+ def set_header(key, value)
raise ArgumentError unless key.is_a?(String)
- headers[key] = v
+ @headers[key] = value
end
def delete_header(key)
raise ArgumentError unless key.is_a?(String)
- headers.delete key
+ @headers.delete key
end
alias :[] :get_header
@@ -186,7 +186,7 @@ def unprocessable?; status == 422; end
def redirect?; [301, 302, 303, 307, 308].include? status; end
def include?(header)
- has_header? header
+ has_header?(header)
end
# Add a header that may have multiple values.
@@ -198,15 +198,23 @@ def include?(header)
# assert_equal 'Accept-Encoding,Cookie', response.get_header('Vary')
#
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
- def add_header(key, v)
+ def add_header(key, value)
raise ArgumentError unless key.is_a?(String)
- if v.nil?
- get_header key
- elsif has_header? key
- set_header key, "#{get_header key},#{v}"
+ if value.nil?
+ return get_header(key)
+ end
+
+ value = value.to_s
+
+ if header = get_header(key)
+ if header.is_a?(Array)
+ header << value
+ else
+ set_header(key, [header, value])
+ end
else
- set_header key, v
+ set_header(key, value)
end
end
@@ -242,28 +250,31 @@ def location=(location)
end
def set_cookie(key, value)
- cookie_header = get_header SET_COOKIE
- set_header SET_COOKIE, ::Rack::Utils.add_cookie_to_header(cookie_header, key, value)
+ add_header SET_COOKIE, Utils.set_cookie_header(key, value)
end
def delete_cookie(key, value = {})
- set_header SET_COOKIE, ::Rack::Utils.add_remove_cookie_to_header(get_header(SET_COOKIE), key, value)
+ set_header(SET_COOKIE,
+ Utils.delete_set_cookie_header!(
+ get_header(SET_COOKIE), key, value
+ )
+ )
end
def set_cookie_header
get_header SET_COOKIE
end
- def set_cookie_header=(v)
- set_header SET_COOKIE, v
+ def set_cookie_header=(value)
+ set_header SET_COOKIE, value
end
def cache_control
get_header CACHE_CONTROL
end
- def cache_control=(v)
- set_header CACHE_CONTROL, v
+ def cache_control=(value)
+ set_header CACHE_CONTROL, value
end
# Specifies that the content shouldn't be cached. Overrides `cache!` if already called.
@@ -286,8 +297,8 @@ def etag
get_header ETAG
end
- def etag=(v)
- set_header ETAG, v
+ def etag=(value)
+ set_header ETAG, value
end
protected
@@ -345,10 +356,21 @@ def initialize(status, headers)
@headers = headers
end
- def has_header?(key); headers.key? key; end
- def get_header(key); headers[key]; end
- def set_header(key, v); headers[key] = v; end
- def delete_header(key); headers.delete key; end
+ def has_header?(key)
+ headers.key?(key)
+ end
+
+ def get_header(key)
+ headers[key]
+ end
+
+ def set_header(key, value)
+ headers[key] = value
+ end
+
+ def delete_header(key)
+ headers.delete(key)
+ end
end
end
end
diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb
index 69e22d8a6..cd9f0aad3 100644
--- a/lib/rack/utils.rb
+++ b/lib/rack/utils.rb
@@ -222,7 +222,7 @@ def parse_cookies_header(header)
end
end
- def add_cookie_to_header(header, key, value)
+ def set_cookie_header(key, value)
case value
when Hash
domain = "; domain=#{value[:domain]}" if value[:domain]
@@ -248,71 +248,59 @@ def add_cookie_to_header(header, key, value)
end
value = [value] unless Array === value
- cookie = "#{escape(key)}=#{value.map { |v| escape v }.join('&')}#{domain}" \
+ return "#{escape(key)}=#{value.map { |v| escape v }.join('&')}#{domain}" \
"#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}"
+ end
- case header
- when nil, ''
- cookie
- when String
- [header, cookie].join("\n")
- when Array
- (header + [cookie]).join("\n")
+ def set_cookie_header!(headers, key, value)
+ if header = headers[SET_COOKIE]
+ if header.is_a?(Array)
+ header << set_cookie_header(key, value)
+ else
+ headers[SET_COOKIE] = [header, set_cookie_header(key, value)]
+ end
else
- raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}"
+ headers[SET_COOKIE] = set_cookie_header(key, value)
end
end
- def set_cookie_header!(header, key, value)
- header[SET_COOKIE] = add_cookie_to_header(header[SET_COOKIE], key, value)
- nil
- end
-
- def make_delete_cookie_header(header, key, value)
- case header
- when nil, ''
- cookies = []
- when String
- cookies = header.split("\n")
- when Array
- cookies = header
- end
-
- key = escape(key)
- domain = value[:domain]
- path = value[:path]
- regexp = if domain
- if path
- /\A#{key}=.*(?:domain=#{domain}(?:;|$).*path=#{path}(?:;|$)|path=#{path}(?:;|$).*domain=#{domain}(?:;|$))/
+ # Adds a cookie that will *remove* a cookie from the client. Hence the
+ # strange method name.
+ def delete_set_cookie_header(key, value = {})
+ set_cookie_header(key, {
+ value: '', path: nil, domain: nil,
+ max_age: '0',
+ expires: Time.at(0)
+ }.merge(value))
+ end
+
+ def delete_set_cookie_header!(header, key, value = {})
+ if header
+ header = Array(header)
+
+ key = escape(key)
+ domain = value[:domain]
+ path = value[:path]
+ regexp = if domain
+ if path
+ /\A#{key}=.*(?:domain=#{domain}(?:;|$).*path=#{path}(?:;|$)|path=#{path}(?:;|$).*domain=#{domain}(?:;|$))/
+ else
+ /\A#{key}=.*domain=#{domain}(?:;|$)/
+ end
+ elsif path
+ /\A#{key}=.*path=#{path}(?:;|$)/
else
- /\A#{key}=.*domain=#{domain}(?:;|$)/
+ /\A#{key}=/
end
- elsif path
- /\A#{key}=.*path=#{path}(?:;|$)/
- else
- /\A#{key}=/
- end
-
- cookies.reject! { |cookie| regexp.match? cookie }
-
- cookies.join("\n")
- end
-
- def delete_cookie_header!(header, key, value = {})
- header[SET_COOKIE] = add_remove_cookie_to_header(header[SET_COOKIE], key, value)
- nil
- end
- # Adds a cookie that will *remove* a cookie from the client. Hence the
- # strange method name.
- def add_remove_cookie_to_header(header, key, value = {})
- new_header = make_delete_cookie_header(header, key, value)
+ header.reject! { |cookie| regexp.match? cookie }
- add_cookie_to_header(new_header, key,
- { value: '', path: nil, domain: nil,
- max_age: '0',
- expires: Time.at(0) }.merge(value))
+ header << delete_set_cookie_header(key, value)
+ else
+ header = delete_set_cookie_header(key, value)
+ end
+ return header
end
def rfc2822(time)
diff --git a/test/spec_lint.rb b/test/spec_lint.rb
index 974ed2622..0b87b188a 100755
--- a/test/spec_lint.rb
+++ b/test/spec_lint.rb
@@ -365,15 +365,7 @@ def obj.each; end
[200, { "foo" => Object.new }, []]
}).call(env({}))
}.must_raise(Rack::Lint::LintError).
- message.must_equal "a header value must be a String, but the value of 'foo' is a Object"
-
- lambda {
- Rack::Lint.new(lambda { |env|
- [200, { "foo" => [1, 2, 3] }, []]
- }).call(env({}))
- }.must_raise(Rack::Lint::LintError).
- message.must_equal "a header value must be a String, but the value of 'foo' is a Array"
-
+ message.must_equal "a header value must be a String or Array of Strings, but the value of 'foo' is a Object"
lambda {
Rack::Lint.new(lambda { |env|
@@ -382,11 +374,6 @@ def obj.each; end
}.must_raise(Rack::Lint::LintError).
message.must_match(/invalid header/)
- # line ends (010).must_be :allowed in header values.?
- Rack::Lint.new(lambda { |env|
- [200, { "foo-bar" => "one\ntwo\nthree", "content-length" => "0", "content-type" => "text/plain" }, []]
- }).call(env({})).first.must_equal 200
-
lambda {
Rack::Lint.new(lambda { |env|
[200, [%w(content-type text/plain), %w(content-length 0)], []]
diff --git a/test/spec_mock.rb b/test/spec_mock.rb
index 0c50d6d6e..70a7c6f2e 100644
--- a/test/spec_mock.rb
+++ b/test/spec_mock.rb
@@ -466,21 +466,21 @@
lambda { @res.add_header nil, '1' }.must_raise ArgumentError
# Sets header on first addition
- @res.add_header('FOO', '1').must_equal '1,1'
- @res.get_header('FOO').must_equal '1,1'
+ @res.add_header('FOO', '1').must_equal ['1', '1']
+ @res.get_header('FOO').must_equal ['1', '1']
# Ignores nil additions
- @res.add_header('FOO', nil).must_equal '1,1'
- @res.get_header('FOO').must_equal '1,1'
+ @res.add_header('FOO', nil).must_equal ['1', '1']
+ @res.get_header('FOO').must_equal ['1', '1']
# Converts additions to strings
- @res.add_header('FOO', 2).must_equal '1,1,2'
- @res.get_header('FOO').must_equal '1,1,2'
+ @res.add_header('FOO', 2).must_equal ['1', '1', '2']
+ @res.get_header('FOO').must_equal ['1', '1', '2']
# Respects underlying case-sensitivity
- @res.add_header('Foo', 'yep').must_equal '1,1,2,yep'
- @res.get_header('Foo').must_equal '1,1,2,yep'
- @res.get_header('FOO').must_equal '1,1,2,yep'
+ @res.add_header('Foo', 'yep').must_equal ['1', '1', '2', 'yep']
+ @res.get_header('Foo').must_equal ['1', '1', '2', 'yep']
+ @res.get_header('FOO').must_equal ['1', '1', '2', 'yep']
end
it 'delete_header' do
diff --git a/test/spec_response.rb b/test/spec_response.rb
index 91cdfbb4e..d30d8abd9 100644
--- a/test/spec_response.rb
+++ b/test/spec_response.rb
@@ -103,16 +103,16 @@
response.set_cookie "foo", "bar"
response["Set-Cookie"].must_equal "foo=bar"
response.set_cookie "foo2", "bar2"
- response["Set-Cookie"].must_equal ["foo=bar", "foo2=bar2"].join("\n")
+ response["Set-Cookie"].must_equal ["foo=bar", "foo2=bar2"]
response.set_cookie "foo3", "bar3"
- response["Set-Cookie"].must_equal ["foo=bar", "foo2=bar2", "foo3=bar3"].join("\n")
+ response["Set-Cookie"].must_equal ["foo=bar", "foo2=bar2", "foo3=bar3"]
end
it "can set cookies with the same name for multiple domains" do
response = Rack::Response.new
response.set_cookie "foo", { value: "bar", domain: "sample.example.com" }
response.set_cookie "foo", { value: "bar", domain: ".example.com" }
- response["Set-Cookie"].must_equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
+ response["Set-Cookie"].must_equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"]
end
it "formats the Cookie expiration date accordingly to RFC 6265" do
@@ -237,31 +237,35 @@
response["Set-Cookie"].must_equal [
"foo2=bar2",
"foo=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"
- ].join("\n")
+ ]
end
it "can delete cookies with the same name from multiple domains" do
response = Rack::Response.new
response.set_cookie "foo", { value: "bar", domain: "sample.example.com" }
response.set_cookie "foo", { value: "bar", domain: ".example.com" }
- response["Set-Cookie"].must_equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
+ response["Set-Cookie"].must_equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"]
response.delete_cookie "foo", domain: ".example.com"
- response["Set-Cookie"].must_equal ["foo=bar; domain=sample.example.com", "foo=; domain=.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"].join("\n")
+ response["Set-Cookie"].must_equal ["foo=bar; domain=sample.example.com", "foo=; domain=.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"]
response.delete_cookie "foo", domain: "sample.example.com"
- response["Set-Cookie"].must_equal ["foo=; domain=.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT",
- "foo=; domain=sample.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"].join("\n")
+ response["Set-Cookie"].must_equal [
+ "foo=; domain=.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT",
+ "foo=; domain=sample.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"
+ ]
end
it "only deletes cookies for the domain specified" do
response = Rack::Response.new
response.set_cookie "foo", { value: "bar", domain: "example.com.example.com" }
response.set_cookie "foo", { value: "bar", domain: "example.com" }
- response["Set-Cookie"].must_equal ["foo=bar; domain=example.com.example.com", "foo=bar; domain=example.com"].join("\n")
- response.delete_cookie "foo", domain: "example.com"
- response["Set-Cookie"].must_equal ["foo=bar; domain=example.com.example.com", "foo=; domain=example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"].join("\n")
- response.delete_cookie "foo", domain: "example.com.example.com"
- response["Set-Cookie"].must_equal ["foo=; domain=example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT",
- "foo=; domain=example.com.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"].join("\n")
+ response["Set-Cookie"].must_equal ["foo=bar; domain=example.com.example.com", "foo=bar; domain=example.com"]
+ response.delete_cookie "foo", { domain: "example.com" }
+ response["Set-Cookie"].must_equal ["foo=bar; domain=example.com.example.com", "foo=; domain=example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"]
+ response.delete_cookie "foo", { domain: "example.com.example.com" }
+ response["Set-Cookie"].must_equal [
+ "foo=; domain=example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT",
+ "foo=; domain=example.com.example.com; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"
+ ]
end
it "can delete cookies with the same name with different paths" do
@@ -269,11 +273,11 @@
response.set_cookie "foo", { value: "bar", path: "/" }
response.set_cookie "foo", { value: "bar", path: "/path" }
response["Set-Cookie"].must_equal ["foo=bar; path=/",
- "foo=bar; path=/path"].join("\n")
+ "foo=bar; path=/path"]
response.delete_cookie "foo", path: "/path"
response["Set-Cookie"].must_equal ["foo=bar; path=/",
- "foo=; path=/path; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"].join("\n")
+ "foo=; path=/path; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"]
end
it "only delete cookies with the path specified" do
@@ -283,12 +287,12 @@
response.set_cookie "foo", value: "bar", path: "/a/b"
response["Set-Cookie"].must_equal ["foo=bar; path=/",
"foo=bar; path=/a",
- "foo=bar; path=/a/b"].join("\n")
+ "foo=bar; path=/a/b"]
response.delete_cookie "foo", path: "/a"
response["Set-Cookie"].must_equal ["foo=bar; path=/",
"foo=bar; path=/a/b",
- "foo=; path=/a; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"].join("\n")
+ "foo=; path=/a; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"]
end
it "only delete cookies with the domain and path specified" do
@@ -312,7 +316,7 @@
"foo=bar; domain=example.com; path=/",
"foo=bar; domain=example.com; path=/a",
"foo=bar; domain=example.com; path=/a/b",
- ].join("\n")
+ ]
response.delete_cookie "foo", path: "/a", domain: "example.com"
response["Set-Cookie"].must_equal [
@@ -325,7 +329,7 @@
"foo=bar; domain=example.com; path=/",
"foo=bar; domain=example.com; path=/a/b",
"foo=; domain=example.com; path=/a; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT",
- ].join("\n")
+ ]
response.delete_cookie "foo", path: "/a/b", domain: "example.com"
response["Set-Cookie"].must_equal [
@@ -338,7 +342,7 @@
"foo=bar; domain=example.com; path=/",
"foo=; domain=example.com; path=/a; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT",
"foo=; domain=example.com; path=/a/b; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT",
- ].join("\n")
+ ]
end
it "can do redirects" do
@@ -683,12 +687,12 @@ def obj.each
lambda { @response.add_header nil, '1' }.must_raise ArgumentError
# Add a value to an existing header
- @response.add_header('Foo', '2').must_equal '1,2'
- @response.get_header('Foo').must_equal '1,2'
+ @response.add_header('Foo', '2').must_equal ["1", "2"]
+ @response.get_header('Foo').must_equal ["1", "2"]
# Add nil to an existing header
- @response.add_header('Foo', nil).must_equal '1,2'
- @response.get_header('Foo').must_equal '1,2'
+ @response.add_header('Foo', nil).must_equal ["1", "2"]
+ @response.get_header('Foo').must_equal ["1", "2"]
# Add nil to a nonexistent header
@response.add_header('Bar', nil).must_be_nil
diff --git a/test/spec_utils.rb b/test/spec_utils.rb
index 2e2bbb517..44a2a44d9 100644
--- a/test/spec_utils.rb
+++ b/test/spec_utils.rb
@@ -557,55 +557,27 @@ def initialize(*)
cookies.must_equal({ "%66oo" => "baz", "foo" => "bar" })
end
- it "adds new cookies to nil header" do
- Rack::Utils.add_cookie_to_header(nil, 'name', 'value').must_equal 'name=value'
- end
-
- it "adds new cookies to blank header" do
- header = ''
- Rack::Utils.add_cookie_to_header(header, 'name', 'value').must_equal 'name=value'
- header.must_equal ''
- end
-
- it "adds new cookies to string header" do
- header = 'existing-cookie'
- Rack::Utils.add_cookie_to_header(header, 'name', 'value').must_equal "existing-cookie\nname=value"
- header.must_equal 'existing-cookie'
- end
-
- it "adds new cookies to array header" do
- header = %w[ existing-cookie ]
- Rack::Utils.add_cookie_to_header(header, 'name', 'value').must_equal "existing-cookie\nname=value"
- header.must_equal %w[ existing-cookie ]
- end
-
- it "adds new cookies to an unrecognized header" do
- lambda {
- Rack::Utils.add_cookie_to_header(Object.new, 'name', 'value')
- }.must_raise ArgumentError
+ it "generates appropriate cookie header value" do
+ Rack::Utils.set_cookie_header('name', 'value').must_equal 'name=value'
end
it "sets and deletes cookies in header hash" do
- header = { 'set-cookie' => '' }
- Rack::Utils.set_cookie_header!(header, 'name', 'value').must_be_nil
- header['set-cookie'].must_equal 'name=value'
- Rack::Utils.set_cookie_header!(header, 'name2', 'value2').must_be_nil
- header['set-cookie'].must_equal "name=value\nname2=value2"
- Rack::Utils.set_cookie_header!(header, 'name2', 'value3').must_be_nil
- header['set-cookie'].must_equal "name=value\nname2=value2\nname2=value3"
-
- Rack::Utils.delete_cookie_header!(header, 'name2').must_be_nil
- header['set-cookie'].must_equal "name=value\nname2=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"
- Rack::Utils.delete_cookie_header!(header, 'name').must_be_nil
- header['set-cookie'].must_equal "name2=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT\nname=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"
-
- header = { 'set-cookie' => nil }
- Rack::Utils.delete_cookie_header!(header, 'name').must_be_nil
- header['set-cookie'].must_equal "name=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"
-
- header = { 'set-cookie' => [] }
- Rack::Utils.delete_cookie_header!(header, 'name').must_be_nil
- header['set-cookie'].must_equal "name=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"
+ headers = {}
+ Rack::Utils.set_cookie_header!(headers, 'name', 'value')
+ headers['set-cookie'].must_equal 'name=value'
+ Rack::Utils.set_cookie_header!(headers, 'name2', 'value2')
+ headers['set-cookie'].must_equal ['name=value', 'name2=value2']
+ Rack::Utils.set_cookie_header!(headers, 'name2', 'value3')
+ headers['set-cookie'].must_equal ['name=value', 'name2=value2', 'name2=value3']
+ end
+
+ it "deletes cookies in header field" do
+ header = []
+
+ Rack::Utils.delete_set_cookie_header!(header, 'name2')
+ header.must_equal ["name2=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"]
+ Rack::Utils.delete_set_cookie_header!(header, 'name')
+ header.must_equal ["name2=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT", "name=; max-age=0; expires=Thu, 01 Jan 1970 00:00:00 GMT"]
end
end
diff --git a/test/spec_webrick.rb b/test/spec_webrick.rb
index 3d689474a..948f69f8f 100644
--- a/test/spec_webrick.rb
+++ b/test/spec_webrick.rb
@@ -158,7 +158,7 @@ def is_running?
[
401,
{ "content-type" => "text/plain",
- "www-authenticate" => "Bar realm=X\nBaz realm=Y" },
+ "www-authenticate" => ["Bar realm=X", "Baz realm=Y"] },
[""]
]
})