Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve quotes when parsing server cookie #11 #15

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions lib/http/cookie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class HTTP::Cookie
UNIX_EPOCH = Time.at(0)

PERSISTENT_PROPERTIES = %w[
name value
name value raw_value
domain for_domain path
secure httponly
expires max_age
Expand Down Expand Up @@ -139,6 +139,7 @@ def initialize(*args)
args.pop
else
self.name, self.value = args # value is set to nil
adjust_raw_value
return
end
when 2..3
Expand All @@ -149,6 +150,7 @@ def initialize(*args)
argc == 2 or
raise ArgumentError, "wrong number of arguments (#{argc} for 1-3)"
self.name, self.value = args
adjust_raw_value
return
end
else
Expand Down Expand Up @@ -204,6 +206,7 @@ def initialize(*args)
self.origin = origin if origin
self.max_age = max_age if max_age
self.value = value.nil? && (@expires || @max_age) ? '' : value
adjust_raw_value
end

autoload :Scanner, 'http/cookie/scanner'
Expand Down Expand Up @@ -380,6 +383,17 @@ def value= value
@value = value
end

def adjust_raw_value
if m = @value.match(/^"(.*)"$/)
@raw_value = @value
@value = m[1]
else
@raw_value = nil
end
end

attr_accessor :raw_value

attr_reader :domain

# See #domain.
Expand Down Expand Up @@ -594,7 +608,8 @@ def valid_for_uri?(uri)
# Returns a string for use in the Cookie header, i.e. `name=value`
# or `name="value"`.
def cookie_value
"#{@name}=#{Scanner.quote(@value)}"
v = ( @raw_value.nil? ? Scanner.quote(@value) : @raw_value )
"#{@name}=#{v}"
end
alias to_s cookie_value

Expand Down
12 changes: 8 additions & 4 deletions lib/http/cookie/scanner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,14 @@ def scan_value
case
when scan(/[^,;"]+/)
s << matched
when skip(/"/)
# RFC 6265 2.2
# A cookie-value may be DQUOTE'd.
s << scan_dquoted
when scan(/"/)
if s.length == 0
# RFC 6265 2.2
# A cookie-value may be DQUOTE'd.
s << '"' << scan_dquoted << '"'
else
s << matched
end
when check(/;|#{RE_COOKIE_COMMA}/o)
break
else
Expand Down
31 changes: 30 additions & 1 deletion test/test_http_cookie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def test_parse_no_space
assert_equal 1, HTTP::Cookie.parse(cookie_str, uri) { |cookie|
assert_equal 'foo', cookie.name
assert_equal 'bar', cookie.value
assert_equal nil, cookie.raw_value
assert_equal '/', cookie.path
assert_equal Time.at(1320539286), cookie.expires
}.size
Expand Down Expand Up @@ -111,6 +112,8 @@ def test_parse_quoted
assert_equal 1, HTTP::Cookie.parse(cookie_str, uri) { |cookie|
assert_equal 'quoted', cookie.name
assert_equal 'value', cookie.value
assert_equal '"value"', cookie.raw_value
assert_equal 'quoted="value"', cookie.cookie_value
}.size
end

Expand Down Expand Up @@ -430,7 +433,10 @@ def test_cookie_with_secure
def test_cookie_value
[
['foo="bar baz"', 'bar baz'],
['foo="bar baz"', '"bar baz"'],
['foo="bar\"; \"baz"', 'bar"; "baz'],
['foo="bar\"; \"baz"', '"bar\"; \"baz"'],
['foo="ba\"r baz"', '"ba\"r baz"'],
].each { |cookie_value, value|
cookie = HTTP::Cookie.new('foo', value)
assert_equal(cookie_value, cookie.cookie_value)
Expand All @@ -453,8 +459,14 @@ def test_cookie_value

assert_equal 3, hash.size

parsed_pairs = [
['Foo', 'value1'],
['Bar', '"value 2"'],
['Baz', 'value3'],
]

hash.each_pair { |name, value|
_, pvalue = pairs.assoc(name)
_, pvalue = parsed_pairs.assoc(name)
assert_equal pvalue, value
}
end
Expand Down Expand Up @@ -1062,6 +1074,23 @@ def test_valid_for_uri?
}
end

def test_yaml_quotes
require 'yaml'
uri = URI.parse('http://localhost/')
cookie_str = 'foo="bar"; Path=/'
assert_equal 1, HTTP::Cookie.parse(cookie_str, uri) { |cookie|
assert_equal 'foo', cookie.name
assert_equal 'bar', cookie.value
assert_equal '"bar"', cookie.raw_value

ycookie = YAML.load(cookie.to_yaml)
assert_equal 'bar', ycookie.value
assert_equal '"bar"', ycookie.raw_value
assert_equal cookie_str, ycookie.set_cookie_value

}.size
end

def test_yaml_expires
require 'yaml'
cookie = HTTP::Cookie.new(cookie_values)
Expand Down