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
Modules: URIParser 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.8"
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')
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 208 209 210 |
# File 'lib/http/cookie.rb', line 133 def initialize(*args) @name = @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.
551 552 553 |
# File 'lib/http/cookie.rb', line 551 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.
548 549 550 |
# File 'lib/http/cookie.rb', line 548 def created_at @created_at end |
#domain ⇒ Object
Returns the value of attribute domain.
386 387 388 |
# File 'lib/http/cookie.rb', line 386 def domain @domain end |
#domain_name ⇒ Object (readonly)
Returns the domain attribute value as a DomainName object.
434 435 436 |
# File 'lib/http/cookie.rb', line 434 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.
441 442 443 |
# File 'lib/http/cookie.rb', line 441 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.
479 480 481 |
# File 'lib/http/cookie.rb', line 479 def httponly @httponly end |
#max_age ⇒ Object
Returns the value of attribute max_age.
509 510 511 |
# File 'lib/http/cookie.rb', line 509 def max_age @max_age end |
#name ⇒ Object
Returns the value of attribute name.
350 351 352 |
# File 'lib/http/cookie.rb', line 350 def name @name end |
#origin ⇒ Object
Returns the value of attribute origin.
453 454 455 |
# File 'lib/http/cookie.rb', line 453 def origin @origin end |
#path ⇒ Object
Returns the value of attribute path.
444 445 446 |
# File 'lib/http/cookie.rb', line 444 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.
473 474 475 |
# File 'lib/http/cookie.rb', line 473 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.
485 486 487 |
# File 'lib/http/cookie.rb', line 485 def session @session end |
#value ⇒ Object
Returns the value of attribute value.
367 368 369 |
# File 'lib/http/cookie.rb', line 367 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”.
334 335 336 |
# File 'lib/http/cookie.rb', line 334 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.
341 342 343 344 345 346 347 |
# File 'lib/http/cookie.rb', line 341 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.
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 328 329 330 |
# File 'lib/http/cookie.rb', line 276 def parse(, origin, = nil, &block) if logger = [:logger] created_at = [:created_at] end origin = HTTP::Cookie::URIParser.parse(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
232 233 234 235 236 237 238 239 240 241 |
# File 'lib/http/cookie.rb', line 232 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.
648 649 650 651 652 653 654 655 |
# File 'lib/http/cookie.rb', line 648 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.
574 575 576 577 578 579 580 581 582 583 584 585 |
# File 'lib/http/cookie.rb', line 574 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`.
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 |
# File 'lib/http/cookie.rb', line 555 def acceptable_from_uri?(uri) uri = HTTP::Cookie::URIParser.parse(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”`.
601 602 603 |
# File 'lib/http/cookie.rb', line 601 def +"#{@name}=#{Scanner.quote(@value)}" end |
#dot_domain ⇒ Object
Returns the domain, with a dot prefixed only if the domain flag is on.
429 430 431 |
# File 'lib/http/cookie.rb', line 429 def dot_domain @for_domain ? (+'.') << @domain : @domain end |
#encode_with(coder) ⇒ Object
YAML serialization helper for Psych.
664 665 666 667 668 |
# File 'lib/http/cookie.rb', line 664 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.
541 542 543 544 |
# File 'lib/http/cookie.rb', line 541 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.
531 532 533 534 535 536 537 |
# File 'lib/http/cookie.rb', line 531 def expired?(time = Time.now) if expires = self.expires expires <= time else false end end |
#expires ⇒ Object Also known as: expires_at
488 489 490 |
# File 'lib/http/cookie.rb', line 488 def expires @expires or @created_at && @max_age ? @created_at + @max_age : nil end |
#expires=(t) ⇒ Object Also known as: expires_at=
See #expires.
493 494 495 496 497 498 499 500 501 502 503 504 |
# File 'lib/http/cookie.rb', line 493 def expires= t case t when nil, Time when DateTime t = t.to_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.
671 672 673 |
# File 'lib/http/cookie.rb', line 671 def init_with(coder) yaml_initialize(coder.tag, coder.map) end |
#inspect ⇒ Object
640 641 642 643 644 |
# File 'lib/http/cookie.rb', line 640 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.
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
# File 'lib/http/cookie.rb', line 610 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.
659 660 661 |
# File 'lib/http/cookie.rb', line 659 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.
589 590 591 592 593 594 595 596 597 |
# File 'lib/http/cookie.rb', line 589 def valid_for_uri?(uri) if @domain.nil? raise "cannot tell if this cookie is valid because the domain is unknown" end uri = HTTP::Cookie::URIParser.parse(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.
676 677 678 679 680 681 682 683 684 685 686 687 688 689 |
# File 'lib/http/cookie.rb', line 676 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 |