diff --git a/lib/http/cookie.rb b/lib/http/cookie.rb index 23493e5..08d685e 100644 --- a/lib/http/cookie.rb +++ b/lib/http/cookie.rb @@ -53,8 +53,8 @@ class HTTP::Cookie private :check_string_type end - attr_reader :name, :domain, :path, :origin - attr_accessor :secure, :httponly, :value, :version + attr_reader :name, :value, :domain, :path, :origin + attr_accessor :secure, :httponly, :version attr_reader :domain_name, :expires, :max_age attr_accessor :comment @@ -287,14 +287,31 @@ class HTTP::Cookie # Sets the cookie name. def name=(name) - if name.nil? || name.empty? + name = check_string_type(name) or + raise TypeError, "#{name.class} is not a String" + if name.empty? raise ArgumentError, "cookie name cannot be empty" - elsif name.match(/[\x00-\x1F=\x7F]/) - raise ArgumentError, "cookie name cannot contain a control character or an equal sign" + elsif name.match(/[\x00-\x20\x7F,;\\"=]/) + raise ArgumentError, "invalid cookie name" end + # RFC 6265 4.1.1 + # cookie-name may not match: + # /[\x00-\x20\x7F()<>@,;:\\"\/\[\]?={}]/ @name = name end + def value=(value) + value = check_string_type(value) or + raise TypeError, "#{value.class} is not a String" + if value.match(/[\x00-\x1F\x7F]/) + raise ArgumentError, "invalid cookie value" + end + # RFC 6265 4.1.1 + # cookie-name may not match: + # /[^\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]/ + @value = value + end + # Sets the domain attribute. A leading dot in +domain+ implies # turning the +for_domain?+ flag on. def domain=(domain) diff --git a/test/test_http_cookie.rb b/test/test_http_cookie.rb index ad5866d..93b3cee 100644 --- a/test/test_http_cookie.rb +++ b/test/test_http_cookie.rb @@ -462,6 +462,37 @@ class TestHTTPCookie < Test::Unit::TestCase }.merge(options) end + def test_bad_name + [ + "a\tb", "a\vb", "a\rb", "a\nb", 'a b', + "a\\b", 'a"b', # 'a:b', 'a/b', 'a[b]', + 'a=b', 'a,b', 'a;b', + ].each { |name| + assert_raises(ArgumentError) { + HTTP::Cookie.new(cookie_values(:name => name)) + } + cookie = HTTP::Cookie.new(cookie_values) + assert_raises(ArgumentError) { + cookie.name = name + } + } + end + + def test_bad_value + [ + "a\tb", "a\vb", "a\rb", "a\nb", + "a\\b", 'a"b', # 'a:b', 'a/b', 'a[b]', + ].each { |name| + assert_raises(ArgumentError) { + HTTP::Cookie.new(cookie_values(:name => name)) + } + cookie = HTTP::Cookie.new(cookie_values) + assert_raises(ArgumentError) { + cookie.name = name + } + } + end + def test_compare time = Time.now cookies = [