diff --git a/ChangeLog b/ChangeLog index 91ef2d4206..f1235e4f9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Fri May 15 08:24:28 2015 Takeyuki FUJIOKA + + * lib/cgi/cookie.rb: Implement HttpOnly flag for cookies. + [fix GH-887] Patch by @martinpovolny + Fri May 15 06:54:19 2015 Aaron Patterson * variable.c: Change autoload to call `require` through Ruby rather diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb index f74ba13764..eb100be1c2 100644 --- a/lib/cgi/cookie.rb +++ b/lib/cgi/cookie.rb @@ -10,29 +10,32 @@ class CGI # == Examples of use # cookie1 = CGI::Cookie.new("name", "value1", "value2", ...) # cookie1 = CGI::Cookie.new("name" => "name", "value" => "value") - # cookie1 = CGI::Cookie.new('name' => 'name', - # 'value' => ['value1', 'value2', ...], - # 'path' => 'path', # optional - # 'domain' => 'domain', # optional - # 'expires' => Time.now, # optional - # 'secure' => true, # optional + # cookie1 = CGI::Cookie.new('name' => 'name', + # 'value' => ['value1', 'value2', ...], + # 'path' => 'path', # optional + # 'domain' => 'domain', # optional + # 'expires' => Time.now, # optional + # 'secure' => true, # optional + # 'httponly' => true # optional # ) # # cgi.out("cookie" => [cookie1, cookie2]) { "string" } # - # name = cookie1.name - # values = cookie1.value - # path = cookie1.path - # domain = cookie1.domain - # expires = cookie1.expires - # secure = cookie1.secure + # name = cookie1.name + # values = cookie1.value + # path = cookie1.path + # domain = cookie1.domain + # expires = cookie1.expires + # secure = cookie1.secure + # httponly = cookie1.httponly # - # cookie1.name = 'name' - # cookie1.value = ['value1', 'value2', ...] - # cookie1.path = 'path' - # cookie1.domain = 'domain' - # cookie1.expires = Time.now + 30 - # cookie1.secure = true + # cookie1.name = 'name' + # cookie1.value = ['value1', 'value2', ...] + # cookie1.path = 'path' + # cookie1.domain = 'domain' + # cookie1.expires = Time.now + 30 + # cookie1.secure = true + # cookie1.httponly = true class Cookie < Array @@accept_charset="UTF-8" unless defined?(@@accept_charset) @@ -60,6 +63,8 @@ class CGI # secure:: whether this cookie is a secure cookie or not (default to # false). Secure cookies are only transmitted to HTTPS # servers. + # httponly:: whether this cookie is a HttpOnly cookie or not (default to + # false). HttpOnly cookies are not available to javascript. # # These keywords correspond to attributes of the cookie object. def initialize(name = "", *value) @@ -70,6 +75,7 @@ class CGI %r|^(.*/)|.match(ENV["SCRIPT_NAME"]) @path = ($1 or "") @secure = false + @httponly = false return super(value) end @@ -89,7 +95,8 @@ class CGI end @domain = options["domain"] @expires = options["expires"] - @secure = options["secure"] == true ? true : false + @secure = options["secure"] == true + @httponly = options["httponly"] == true super(value) end @@ -103,7 +110,9 @@ class CGI # Time at which this cookie expires, as a +Time+ attr_accessor :expires # True if this cookie is secure; false otherwise - attr_reader("secure") + attr_reader :secure + # True if this cookie is httponly; false otherwise + attr_reader :httponly # Returns the value or list of values for this cookie. def value @@ -119,8 +128,14 @@ class CGI # # +val+ must be a boolean. def secure=(val) - @secure = val if val == true or val == false - @secure + @secure = !!val + end + + # Set whether the Cookie is a httponly cookie or not. + # + # +val+ must be a boolean. + def httponly=(val) + @httponly = !!val end # Convert the Cookie to its string representation. @@ -130,7 +145,8 @@ class CGI buf << "; domain=#{@domain}" if @domain buf << "; path=#{@path}" if @path buf << "; expires=#{CGI::rfc1123_date(@expires)}" if @expires - buf << "; secure" if @secure == true + buf << "; secure" if @secure + buf << "; HttpOnly" if @httponly buf end diff --git a/test/cgi/test_cgi_cookie.rb b/test/cgi/test_cgi_cookie.rb index 8f0fb70827..eee6215fac 100644 --- a/test/cgi/test_cgi_cookie.rb +++ b/test/cgi/test_cgi_cookie.rb @@ -31,6 +31,7 @@ class CGICookieTest < Test::Unit::TestCase assert_nil(cookie.expires) assert_equal('', cookie.path) assert_equal(false, cookie.secure) + assert_equal(false, cookie.httponly) assert_equal("name1=val1&%26%3C%3E%22&%E3%82%86%E3%82%93%E3%82%86%E3%82%93; path=", cookie.to_s) end @@ -45,6 +46,7 @@ class CGICookieTest < Test::Unit::TestCase 'domain'=>'www.example.com', 'expires'=>t, 'secure'=>true, + 'httponly'=>true ) assert_equal('name1', cookie.name) assert_equal(value, cookie.value) @@ -52,7 +54,8 @@ class CGICookieTest < Test::Unit::TestCase assert_equal(t, cookie.expires) assert_equal('/cgi-bin/myapp/', cookie.path) assert_equal(true, cookie.secure) - assert_equal('name1=val1&%26%3C%3E%22&%A5%E0%A5%B9%A5%AB; domain=www.example.com; path=/cgi-bin/myapp/; expires=Tue, 31 Dec 2030 23:59:59 GMT; secure', cookie.to_s) + assert_equal(true, cookie.httponly) + assert_equal('name1=val1&%26%3C%3E%22&%A5%E0%A5%B9%A5%AB; domain=www.example.com; path=/cgi-bin/myapp/; expires=Tue, 31 Dec 2030 23:59:59 GMT; secure; HttpOnly', cookie.to_s) end