diff --git a/README.md b/README.md index b287de3..aec8d99 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,10 @@ Or install it yourself as: ## Usage + ######################## + # Client side example + ######################## + # Initialize a cookie jar jar = HTTP::CookieJar.new @@ -30,15 +34,30 @@ Or install it yourself as: jar.load(filename) if File.exist?(filename) # Store received cookies - HTTP::Cookie.parse(set_cookie_header_value, :origin => uri) { |cookie| + HTTP::Cookie.parse(set_cookie_header_value, origin: uri) { |cookie| jar << cookie } - # Extract cookies to send - cookie_value_to_send = jar.cookies(uri).join(', ') + # Get the value for the Cookie field of a request header + cookie_header_value = jar.cookies(uri).join(', ') # Save to a file - jar.save_as(filename) + jar.save(filename) + + + ######################## + # Server side example + ######################## + + # Generate a cookie + cookies = HTTP::Cookie.new("uid", "a12345", domain: 'example.org', + for_domain: true, + path: '/', + max_age: 7*86400) + + # Get the value for the Set-Cookie field of a response header + set_cookie_header_value = cookies.set_cookie_value(my_url) + ## To-Do list diff --git a/lib/http/cookie.rb b/lib/http/cookie.rb index a4129ba..8a388c2 100644 --- a/lib/http/cookie.rb +++ b/lib/http/cookie.rb @@ -385,21 +385,12 @@ class HTTP::Cookie acceptable_from_uri?(uri) && normalize_path(uri.path).start_with?(@path) end - def to_s + # Returns a string for use in a Cookie header value, + # i.e. "name=value". + def cookie_value "#{@name}=#{@value}" end - - # Compares the cookie with another. When there are many cookies with - # the same name for a URL, the value of the smallest must be used. - def <=>(other) - # RFC 6265 5.4 - # Precedence: 1. longer path 2. older creation - (@name <=> other.name).nonzero? || - (other.path.length <=> @path.length).nonzero? || - (@created_at <=> other.created_at).nonzero? || - @value <=> other.value - end - include Comparable + alias to_s cookie_value # Serializes the cookie into a cookies.txt line. def to_cookiestxt_line(linefeed = "\n") @@ -414,6 +405,50 @@ class HTTP::Cookie ].join("\t") << linefeed end + # Returns a string for use in a Set-Cookie header value. If the + # cookie does not have an origin set, one must be given from the + # argument. + # + # This method does not check if this cookie will be accepted from + # the origin. + def set_cookie_value(origin = nil) + origin = origin ? URI(origin) : @origin or + raise "origin must be specified to produce a value for Set-Cookie" + + string = cookie_value + if @for_domain || @domain != DomainName.new(origin.host).hostname + string << "; domain=#{@domain}" + end + if (normalize_uri_path(origin) + './').path != @path + string << "; path=#{@path}" + end + if expires = @expires + string << "; expires=#{@expires.httpdate}" + end + if comment = @comment + string << "; comment=#{@comment}" + end + if httponly? + string << "; HttpOnly" + end + if secure? + string << "; secure" + end + string + end + + # Compares the cookie with another. When there are many cookies with + # the same name for a URL, the value of the smallest must be used. + def <=>(other) + # RFC 6265 5.4 + # Precedence: 1. longer path 2. older creation + (@name <=> other.name).nonzero? || + (other.path.length <=> @path.length).nonzero? || + (@created_at <=> other.created_at).nonzero? || + @value <=> other.value + end + include Comparable + # YAML serialization helper for Syck. def to_yaml_properties PERSISTENT_PROPERTIES.map { |name| "@#{name}" } diff --git a/test/test_http_cookie.rb b/test/test_http_cookie.rb index 9cbf874..62bbd82 100644 --- a/test/test_http_cookie.rb +++ b/test/test_http_cookie.rb @@ -369,6 +369,27 @@ class TestHTTPCookie < Test::Unit::TestCase end end + def test_set_cookie_value + url = URI.parse('http://rubyforge.org/') + cookie_params = @cookie_params.merge('secure' => 'secure') + cookie_value = 'foo=bar' + + cookie_params.keys.combine.each do |keys| + cookie_text = [cookie_value, *keys.map { |key| cookie_params[key] }].join('; ') + cookie, = HTTP::Cookie.parse(cookie_text, :origin => url) + cookie2, = HTTP::Cookie.parse(cookie.set_cookie_value, :origin => url) + + assert_equal(cookie.name, cookie2.name) + assert_equal(cookie.value, cookie2.value) + assert_equal(cookie.domain, cookie2.domain) + assert_equal(cookie.for_domain?, cookie2.for_domain?) + assert_equal(cookie.path, cookie2.path) + assert_equal(cookie.expires, cookie2.expires) + assert_equal(cookie.secure?, cookie2.secure?) + assert_equal(cookie.httponly?, cookie2.httponly?) + end + end + def test_parse_cookie_no_spaces url = URI.parse('http://rubyforge.org/') cookie_params = @cookie_params