Class: HTTP::Cookie
- Inherits:
-
Object
- Object
- HTTP::Cookie
- Includes:
- Comparable
- Defined in:
- lib/http/cookie.rb,
lib/http/cookie/version.rb
Overview
This class is used to represent an HTTP Cookie.
Defined Under Namespace
Classes: Scanner
Constant Summary collapse
- MAX_LENGTH =
Maximum number of bytes per cookie (RFC 6265 6.1 requires 4096 at least)
4096
- MAX_COOKIES_PER_DOMAIN =
Maximum number of cookies per domain (RFC 6265 6.1 requires 50 at least)
50
- MAX_COOKIES_TOTAL =
Maximum number of cookies total (RFC 6265 6.1 requires 3000 at least)
3000
- UNIX_EPOCH =
:stopdoc:
Time.at(0)
- PERSISTENT_PROPERTIES =
%w[ name value domain for_domain path secure httponly expires max_age created_at accessed_at ]
- VERSION =
"1.0.3"
Instance Attribute Summary collapse
-
#accessed_at ⇒ Object
The time this cookie was last accessed at.
-
#created_at ⇒ Object
The time this cookie was created at.
-
#domain ⇒ Object
Returns the value of attribute domain.
-
#domain_name ⇒ Object
readonly
Returns the domain attribute value as a DomainName object.
-
#for_domain ⇒ Object
(also: #for_domain?)
The domain flag.
-
#httponly ⇒ Object
(also: #httponly?)
The HttpOnly flag.
-
#max_age ⇒ Object
Returns the value of attribute max_age.
-
#name ⇒ Object
Returns the value of attribute name.
-
#origin ⇒ Object
Returns the value of attribute origin.
-
#path ⇒ Object
Returns the value of attribute path.
-
#secure ⇒ Object
(also: #secure?)
The secure flag.
-
#session ⇒ Object
(also: #session?)
readonly
The session flag.
-
#value ⇒ Object
Returns the value of attribute value.
Class Method Summary collapse
-
.cookie_value(cookies) ⇒ Object
Takes an array of cookies and returns a string for use in the Cookie header, like “name1=value2; name2=value2”.
-
.cookie_value_to_hash(cookie_value) ⇒ Object
Parses a Cookie header value into a hash of name-value string pairs.
-
.parse(set_cookie, origin, options = nil, &block) ⇒ Object
Parses a Set-Cookie header value ‘set_cookie` assuming that it is sent from a source URI/URL `origin`, and returns an array of Cookie objects.
-
.path_match?(base_path, target_path) ⇒ Boolean
Tests if
target_path
is underbase_path
as described in RFC 6265 5.1.4.
Instance Method Summary collapse
-
#<=>(other) ⇒ Object
Compares the cookie with another.
-
#acceptable? ⇒ Boolean
Tests if it is OK to accept this cookie considering its origin.
-
#acceptable_from_uri?(uri) ⇒ Boolean
Tests if it is OK to accept this cookie if it is sent from a given URI/URL, ‘uri`.
-
#cookie_value ⇒ Object
(also: #to_s)
Returns a string for use in the Cookie header, i.e.
-
#dot_domain ⇒ Object
Returns the domain, with a dot prefixed only if the domain flag is on.
-
#encode_with(coder) ⇒ Object
YAML serialization helper for Psych.
-
#expire! ⇒ Object
Expires this cookie by setting the expires attribute value to a past date.
-
#expired?(time = Time.now) ⇒ Boolean
Tests if this cookie is expired by now, or by a given time.
- #expires ⇒ Object (also: #expires_at)
-
#expires=(t) ⇒ Object
(also: #expires_at=)
See #expires.
-
#init_with(coder) ⇒ Object
YAML deserialization helper for Syck.
-
#initialize(*args) ⇒ Cookie
constructor
:call-seq: new(name, value = nil) new(name, value = nil, **attr_hash) new(**attr_hash).
- #inspect ⇒ Object
-
#set_cookie_value ⇒ Object
Returns a string for use in the Set-Cookie header.
-
#to_yaml_properties ⇒ Object
YAML serialization helper for Syck.
-
#valid_for_uri?(uri) ⇒ Boolean
Tests if it is OK to send this cookie to a given ‘uri`.
-
#yaml_initialize(tag, map) ⇒ Object
YAML deserialization helper for Psych.
Constructor Details
#initialize(*args) ⇒ Cookie
:call-seq:
new(name, value = nil)
new(name, value = nil, **attr_hash)
new(**attr_hash)
Creates a cookie object. For each key of ‘attr_hash`, the setter is called if defined and any error (typically ArgumentError or TypeError) that is raised will be passed through. Each key can be either a downcased symbol or a string that may be mixed case. Support for the latter may, however, be obsoleted in future when Ruby 2.0’s keyword syntax is adopted.
If ‘value` is omitted or it is nil, an expiration cookie is created unless `max_age` or `expires` (`expires_at`) is given.
e.g.
new("uid", "a12345")
new("uid", "a12345", :domain => 'example.org',
:for_domain => true, :expired => Time.now + 7*86400)
new("name" => "uid", "value" => "a12345", "Domain" => 'www.example.org')
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# File 'lib/http/cookie.rb', line 130 def initialize(*args) @origin = @domain = @path = @expires = @max_age = nil @for_domain = @secure = @httponly = false @session = true @created_at = @accessed_at = Time.now case argc = args.size when 1 if attr_hash = Hash.try_convert(args.last) args.pop else self.name, self.value = args # value is set to nil return end when 2..3 if attr_hash = Hash.try_convert(args.last) args.pop self.name, value = args else argc == 2 or raise ArgumentError, "wrong number of arguments (#{argc} for 1-3)" self.name, self.value = args return end else raise ArgumentError, "wrong number of arguments (#{argc} for 1-3)" end for_domain = false domain = max_age = origin = nil attr_hash.each_pair { |okey, val| case key ||= okey when :name self.name = val when :value value = val when :domain domain = val when :path self.path = val when :origin origin = val when :for_domain, :for_domain? for_domain = val when :max_age # Let max_age take precedence over expires max_age = val when :expires, :expires_at self.expires = val unless max_age when :httponly, :httponly? @httponly = val when :secure, :secure? @secure = val when Symbol setter = :"#{key}=" if respond_to?(setter) __send__(setter, val) else warn "unknown attribute name: #{okey.inspect}" if $VERBOSE next end when String warn "use downcased symbol for keyword: #{okey.inspect}" if $VERBOSE key = key.downcase.to_sym redo else warn "invalid keyword ignored: #{okey.inspect}" if $VERBOSE next end } if @name.nil? raise ArgumentError, "name must be specified" end @for_domain = for_domain self.domain = domain if domain self.origin = origin if origin self.max_age = max_age if max_age self.value = value.nil? && (@expires || @max_age) ? '' : value end |
Instance Attribute Details
#accessed_at ⇒ Object
The time this cookie was last accessed at.
546 547 548 |
# File 'lib/http/cookie.rb', line 546 def accessed_at @accessed_at end |
#created_at ⇒ Object
The time this cookie was created at. This value is used as a base date for interpreting the Max-Age attribute value. See #expires.
543 544 545 |
# File 'lib/http/cookie.rb', line 543 def created_at @created_at end |
#domain ⇒ Object
Returns the value of attribute domain.
383 384 385 |
# File 'lib/http/cookie.rb', line 383 def domain @domain end |
#domain_name ⇒ Object (readonly)
Returns the domain attribute value as a DomainName object.
431 432 433 |
# File 'lib/http/cookie.rb', line 431 def domain_name @domain_name end |
#for_domain ⇒ Object Also known as: for_domain?
The domain flag. (the opposite of host-only-flag)
If this flag is true, this cookie will be sent to any host in the #domain, including the host domain itself. If it is false, this cookie will be sent only to the host indicated by the #domain.
438 439 440 |
# File 'lib/http/cookie.rb', line 438 def for_domain @for_domain end |
#httponly ⇒ Object Also known as: httponly?
The HttpOnly flag. (http-only-flag)
A cookie with this flag on should be hidden from a client script.
476 477 478 |
# File 'lib/http/cookie.rb', line 476 def httponly @httponly end |
#max_age ⇒ Object
Returns the value of attribute max_age.
504 505 506 |
# File 'lib/http/cookie.rb', line 504 def max_age @max_age end |
#name ⇒ Object
Returns the value of attribute name.
347 348 349 |
# File 'lib/http/cookie.rb', line 347 def name @name end |
#origin ⇒ Object
Returns the value of attribute origin.
450 451 452 |
# File 'lib/http/cookie.rb', line 450 def origin @origin end |
#path ⇒ Object
Returns the value of attribute path.
441 442 443 |
# File 'lib/http/cookie.rb', line 441 def path @path end |
#secure ⇒ Object Also known as: secure?
The secure flag. (secure-only-flag)
A cookie with this flag on should only be sent via a secure protocol like HTTPS.
470 471 472 |
# File 'lib/http/cookie.rb', line 470 def secure @secure end |
#session ⇒ Object (readonly) Also known as: session?
The session flag. (the opposite of persistent-flag)
A cookie with this flag on should be hidden from a client script.
482 483 484 |
# File 'lib/http/cookie.rb', line 482 def session @session end |
#value ⇒ Object
Returns the value of attribute value.
364 365 366 |
# File 'lib/http/cookie.rb', line 364 def value @value end |
Class Method Details
.cookie_value(cookies) ⇒ Object
Takes an array of cookies and returns a string for use in the Cookie header, like “name1=value2; name2=value2”.
331 332 333 |
# File 'lib/http/cookie.rb', line 331 def () .join('; ') end |
.cookie_value_to_hash(cookie_value) ⇒ Object
Parses a Cookie header value into a hash of name-value string pairs. The first appearance takes precedence if multiple pairs with the same name occur.
338 339 340 341 342 343 344 |
# File 'lib/http/cookie.rb', line 338 def () {}.tap { |hash| Scanner.new(). { |name, value| hash[name] ||= value } } end |
.parse(set_cookie, origin, options = nil, &block) ⇒ Object
Parses a Set-Cookie header value ‘set_cookie` assuming that it is sent from a source URI/URL `origin`, and returns an array of Cookie objects. Parts (separated by commas) that are malformed or considered unacceptable are silently ignored.
If a block is given, each cookie object is passed to the block.
Available option keywords are below:
:created_at : The creation time of the cookies parsed.
:logger : Logger object useful for debugging
### Compatibility Note for Mechanize::Cookie users
-
Order of parameters changed in HTTP::Cookie.parse:
Mechanize::Cookie.parse(uri, set_cookie[, log]) HTTP::Cookie.parse(set_cookie, uri[, :logger => # log])
-
HTTP::Cookie.parse does not accept nil for ‘set_cookie`.
-
HTTP::Cookie.parse does not yield nil nor include nil in an returned array. It simply ignores unparsable parts.
-
HTTP::Cookie.parse is made to follow RFC 6265 to the extent not terribly breaking interoperability with broken implementations. In particular, it is capable of parsing cookie definitions containing double-quotes just as naturally expected.
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/http/cookie.rb', line 273 def parse(, origin, = nil, &block) if logger = [:logger] created_at = [:created_at] end origin = URI(origin) [].tap { || Scanner.new(, logger). { |name, value, attrs| break if name.nil? || name.empty? begin = new(name, value) rescue => e logger.warn("Invalid name or value: #{e}") if logger next end .created_at = created_at if created_at attrs.each { |aname, avalue| begin case aname when 'domain' .for_domain = true # The following may negate @for_domain if the value is # an eTLD or IP address, hence this order. .domain = avalue when 'path' .path = avalue when 'expires' # RFC 6265 4.1.2.2 # The Max-Age attribute has precedence over the Expires # attribute. .expires = avalue unless .max_age when 'max-age' .max_age = avalue when 'secure' .secure = avalue when 'httponly' .httponly = avalue end rescue => e logger.warn("Couldn't parse #{aname} '#{avalue}': #{e}") if logger end } .origin = origin .acceptable? or next yield if block_given? << } } end |
.path_match?(base_path, target_path) ⇒ Boolean
Tests if target_path
is under base_path
as described in RFC 6265 5.1.4. base_path
must be an absolute path. target_path
may be empty, in which case it is treated as the root path.
e.g.
path_match?('/admin/', '/admin/index') == true
path_match?('/admin/', '/Admin/index') == false
path_match?('/admin/', '/admin/') == true
path_match?('/admin/', '/admin') == false
path_match?('/admin', '/admin') == true
path_match?('/admin', '/Admin') == false
path_match?('/admin', '/admins') == false
path_match?('/admin', '/admin/') == true
path_match?('/admin', '/admin/index') == true
229 230 231 232 233 234 235 236 237 238 |
# File 'lib/http/cookie.rb', line 229 def path_match?(base_path, target_path) base_path.start_with?('/') or return false # RFC 6265 5.1.4 bsize = base_path.size tsize = target_path.size return bsize == 1 if tsize == 0 # treat empty target_path as "/" return false unless target_path.start_with?(base_path) return true if bsize == tsize || base_path.end_with?('/') target_path[bsize] == ?/ end |
Instance Method Details
#<=>(other) ⇒ Object
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.
643 644 645 646 647 648 649 650 |
# File 'lib/http/cookie.rb', line 643 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 |
#acceptable? ⇒ Boolean
Tests if it is OK to accept this cookie considering its origin. If either domain or path is missing, raises ArgumentError. If origin is missing, returns true.
569 570 571 572 573 574 575 576 577 578 579 580 |
# File 'lib/http/cookie.rb', line 569 def acceptable? case when @domain.nil? raise "domain is missing" when @path.nil? raise "path is missing" when @origin.nil? true else acceptable_from_uri?(@origin) end end |
#acceptable_from_uri?(uri) ⇒ Boolean
Tests if it is OK to accept this cookie if it is sent from a given URI/URL, ‘uri`.
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 |
# File 'lib/http/cookie.rb', line 550 def acceptable_from_uri?(uri) uri = URI(uri) return false unless URI::HTTP === uri && uri.host host = DomainName.new(uri.host) # RFC 6265 5.3 case when host.hostname == @domain true when @for_domain # !host-only-flag host.(@domain_name) else @domain.nil? end end |
#cookie_value ⇒ Object Also known as: to_s
Returns a string for use in the Cookie header, i.e. ‘name=value` or `name=“value”`.
596 597 598 |
# File 'lib/http/cookie.rb', line 596 def "#{@name}=#{Scanner.quote(@value)}" end |
#dot_domain ⇒ Object
Returns the domain, with a dot prefixed only if the domain flag is on.
426 427 428 |
# File 'lib/http/cookie.rb', line 426 def dot_domain @for_domain ? '.' << @domain : @domain end |
#encode_with(coder) ⇒ Object
YAML serialization helper for Psych.
659 660 661 662 663 |
# File 'lib/http/cookie.rb', line 659 def encode_with(coder) PERSISTENT_PROPERTIES.each { |key| coder[key.to_s] = instance_variable_get(:"@#{key}") } end |
#expire! ⇒ Object
Expires this cookie by setting the expires attribute value to a past date.
536 537 538 539 |
# File 'lib/http/cookie.rb', line 536 def expire! self.expires = UNIX_EPOCH self end |
#expired?(time = Time.now) ⇒ Boolean
Tests if this cookie is expired by now, or by a given time.
526 527 528 529 530 531 532 |
# File 'lib/http/cookie.rb', line 526 def expired?(time = Time.now) if expires = self.expires expires <= time else false end end |
#expires ⇒ Object Also known as: expires_at
485 486 487 |
# File 'lib/http/cookie.rb', line 485 def expires @expires or @created_at && @max_age ? @created_at + @max_age : nil end |
#expires=(t) ⇒ Object Also known as: expires_at=
See #expires.
490 491 492 493 494 495 496 497 498 499 |
# File 'lib/http/cookie.rb', line 490 def expires= t case t when nil, Time else t = Time.parse(t) end @max_age = nil @session = t.nil? @expires = t end |
#init_with(coder) ⇒ Object
YAML deserialization helper for Syck.
666 667 668 |
# File 'lib/http/cookie.rb', line 666 def init_with(coder) yaml_initialize(coder.tag, coder.map) end |
#inspect ⇒ Object
635 636 637 638 639 |
# File 'lib/http/cookie.rb', line 635 def inspect '#<%s:' % self.class << PERSISTENT_PROPERTIES.map { |key| '%s=%s' % [key, instance_variable_get(:"@#{key}").inspect] }.join(', ') << ' origin=%s>' % [@origin ? @origin.to_s : 'nil'] end |
#set_cookie_value ⇒ Object
Returns a string for use in the Set-Cookie header. If necessary information like a path or domain (when ‘for_domain` is set) is missing, RuntimeError is raised. It is always the best to set an origin before calling this method.
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 |
# File 'lib/http/cookie.rb', line 605 def string = if @for_domain if @domain string << "; Domain=#{@domain}" else raise "for_domain is specified but domain is unknown" end end if @path if !@origin || (@origin + './').path != @path string << "; Path=#{@path}" end else raise "path is unknown" end if @max_age string << "; Max-Age=#{@max_age}" elsif @expires string << "; Expires=#{@expires.httpdate}" end if @httponly string << "; HttpOnly" end if @secure string << "; Secure" end string end |
#to_yaml_properties ⇒ Object
YAML serialization helper for Syck.
654 655 656 |
# File 'lib/http/cookie.rb', line 654 def to_yaml_properties PERSISTENT_PROPERTIES.map { |name| "@#{name}" } end |
#valid_for_uri?(uri) ⇒ Boolean
Tests if it is OK to send this cookie to a given ‘uri`. A RuntimeError is raised if the cookie’s domain is unknown.
584 585 586 587 588 589 590 591 592 |
# File 'lib/http/cookie.rb', line 584 def valid_for_uri?(uri) if @domain.nil? raise "cannot tell if this cookie is valid because the domain is unknown" end uri = URI(uri) # RFC 6265 5.4 return false if secure? && !(URI::HTTPS === uri) acceptable_from_uri?(uri) && HTTP::Cookie.path_match?(@path, uri.path) end |
#yaml_initialize(tag, map) ⇒ Object
YAML deserialization helper for Psych.
671 672 673 674 675 676 677 678 679 680 681 682 683 684 |
# File 'lib/http/cookie.rb', line 671 def yaml_initialize(tag, map) expires = nil @origin = nil map.each { |key, value| case key when 'expires' # avoid clobbering max_age expires = value when *PERSISTENT_PROPERTIES __send__(:"#{key}=", value) end } self.expires = expires if self.max_age.nil? end |