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"] }, [""] ] })