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.0"
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 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.
538 539 540 |
# File 'lib/http/cookie.rb', line 538 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.
535 536 537 |
# File 'lib/http/cookie.rb', line 535 def created_at @created_at end |
#domain ⇒ Object
Returns the value of attribute domain.
376 377 378 |
# File 'lib/http/cookie.rb', line 376 def domain @domain end |
#domain_name ⇒ Object (readonly)
Returns the domain attribute value as a DomainName object.
424 425 426 |
# File 'lib/http/cookie.rb', line 424 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.
431 432 433 |
# File 'lib/http/cookie.rb', line 431 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.
468 469 470 |
# File 'lib/http/cookie.rb', line 468 def httponly @httponly end |
#max_age ⇒ Object
Returns the value of attribute max_age.
496 497 498 |
# File 'lib/http/cookie.rb', line 496 def max_age @max_age end |
#name ⇒ Object
Returns the value of attribute name.
340 341 342 |
# File 'lib/http/cookie.rb', line 340 def name @name end |
#origin ⇒ Object
Returns the value of attribute origin.
443 444 445 |
# File 'lib/http/cookie.rb', line 443 def origin @origin end |
#path ⇒ Object
Returns the value of attribute path.
434 435 436 |
# File 'lib/http/cookie.rb', line 434 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.
462 463 464 |
# File 'lib/http/cookie.rb', line 462 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.
474 475 476 |
# File 'lib/http/cookie.rb', line 474 def session @session end |
#value ⇒ Object
Returns the value of attribute value.
357 358 359 |
# File 'lib/http/cookie.rb', line 357 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”.
324 325 326 |
# File 'lib/http/cookie.rb', line 324 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.
331 332 333 334 335 336 337 |
# File 'lib/http/cookie.rb', line 331 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 |
# 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? = new(name, value) .created_at = created_at if created_at attrs.each { |aname, avalue| begin case aname when 'domain' .for_domain = true .domain = avalue # This may negate @for_domain 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.
635 636 637 638 639 640 641 642 |
# File 'lib/http/cookie.rb', line 635 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.
561 562 563 564 565 566 567 568 569 570 571 572 |
# File 'lib/http/cookie.rb', line 561 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`.
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 |
# File 'lib/http/cookie.rb', line 542 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”`.
588 589 590 |
# File 'lib/http/cookie.rb', line 588 def "#{@name}=#{Scanner.quote(@value)}" end |
#dot_domain ⇒ Object
Returns the domain, with a dot prefixed only if the domain flag is on.
419 420 421 |
# File 'lib/http/cookie.rb', line 419 def dot_domain @for_domain ? '.' << @domain : @domain end |
#encode_with(coder) ⇒ Object
YAML serialization helper for Psych.
651 652 653 654 655 |
# File 'lib/http/cookie.rb', line 651 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.
528 529 530 531 |
# File 'lib/http/cookie.rb', line 528 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.
518 519 520 521 522 523 524 |
# File 'lib/http/cookie.rb', line 518 def expired?(time = Time.now) if expires = self.expires expires <= time else false end end |
#expires ⇒ Object Also known as: expires_at
477 478 479 |
# File 'lib/http/cookie.rb', line 477 def expires @expires or @created_at && @max_age ? @created_at + @max_age : nil end |
#expires=(t) ⇒ Object Also known as: expires_at=
See #expires.
482 483 484 485 486 487 488 489 490 491 |
# File 'lib/http/cookie.rb', line 482 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.
658 659 660 |
# File 'lib/http/cookie.rb', line 658 def init_with(coder) yaml_initialize(coder.tag, coder.map) end |
#inspect ⇒ Object
627 628 629 630 631 |
# File 'lib/http/cookie.rb', line 627 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.
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 |
# File 'lib/http/cookie.rb', line 597 def string = if @for_domain if @domain string << "; Domain=#{@domain}" else raise "for_domain is specified but domain is known" end end if @path if !@origin || (@origin + './').path != @path string << "; Path=#{@path}" end else raise "path is known" 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.
646 647 648 |
# File 'lib/http/cookie.rb', line 646 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.
576 577 578 579 580 581 582 583 584 |
# File 'lib/http/cookie.rb', line 576 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.
663 664 665 666 667 668 669 670 671 672 673 674 675 676 |
# File 'lib/http/cookie.rb', line 663 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 |