module CookieJar::CookieValidation

Contains logic to parse and validate cookie headers

Constants

BASE_HOSTNAME
BASE_PATH
HDN
IPADDR
PARAM1
PARAM2
TOKEN

Public Class Methods

compute_search_domains(request_uri) click to toggle source

Given a URI, compute the relevant search domains for pre-existing cookies. This includes all the valid dotted forms for a named or IP domains.

@param [String, URI] request_uri requested uri @return [Array<String>] all cookie domain values which would match the

requested uri
# File lib/cookiejar/cookie_validation.rb, line 148
def self.compute_search_domains(request_uri)
  uri = to_uri request_uri
  return nil unless uri.is_a? URI::HTTP
  host = uri.host
  compute_search_domains_for_host host
end
compute_search_domains_for_host(host) click to toggle source

Given a host, compute the relevant search domains for pre-existing cookies

@param [String] host host being requested @return [Array<String>] all cookie domain values which would match the

requested uri
# File lib/cookiejar/cookie_validation.rb, line 161
def self.compute_search_domains_for_host(host)
  host = effective_host host
  result = [host]
  unless host =~ IPADDR
    result << ".#{host}"
    base = hostname_reach host
    result << ".#{base}" if base
  end
  result
end
decode_value(value) click to toggle source

Attempt to decipher a partially decoded version of text cookie values

# File lib/cookiejar/cookie_validation.rb, line 344
def self.decode_value(value)
  if /\A"(.*)"\Z/ =~ value
    value_to_string value
  else
    CGI.unescape value
  end
end
domains_match(tested_domain, base_domain) click to toggle source

Compare a tested domain against the base domain to see if they match, or if the base domain is reachable.

@param [String] tested_domain domain to be tested against @param [String] base_domain new domain being tested @return [String,nil] matching domain on success, nil on failure

# File lib/cookiejar/cookie_validation.rb, line 93
def self.domains_match(tested_domain, base_domain)
  base = effective_host base_domain
  search_domains = compute_search_domains_for_host base
  search_domains.find do |domain|
    domain == tested_domain
  end
end
effective_host(host_or_uri) click to toggle source

Compute the effective host (RFC 2965, section 1)

Has the added additional logic of searching for interior dots specifically, and matches colons to prevent .local being suffixed on IPv6 addresses

@param [String, URI] host_or_uridomain name, or absolute URI @return [String] effective host per RFC rules

# File lib/cookiejar/cookie_validation.rb, line 209
def self.effective_host(host_or_uri)
  hostname = to_domain host_or_uri
  hostname = hostname.downcase

  if /.[\.:]./.match(hostname) || hostname == '.local'
    hostname
  else
    hostname + '.local'
  end
end
hostname_reach(hostname) click to toggle source

Compute the reach of a hostname (RFC 2965, section 1) Determines the next highest superdomain

@param [String,URI,Cookie] hostname hostname, or object holding hostname @return [String,nil] next highest hostname, or nil if none

# File lib/cookiejar/cookie_validation.rb, line 106
def self.hostname_reach(hostname)
  host = to_domain hostname
  host = host.downcase
  match = BASE_HOSTNAME.match host
  match[1] if match
end
parse_set_cookie2(set_cookie_value) click to toggle source

Break apart a RFC 2965 cookie value into its core components. This does not do any validation, or defaulting of values based on requested URI

@param [String] set_cookie_value a Set-Cookie2 header formatted cookie

definition

@return [Hash] Contains the parsed values of the cookie

# File lib/cookiejar/cookie_validation.rb, line 359
def self.parse_set_cookie2(set_cookie_value)
  args = {}
  first = true
  index = 0
  begin
    md = PARAM2.match set_cookie_value[index..-1]
    if md.nil? || md.offset(0).first != 0
      fail InvalidCookieError,
           "Invalid Set-Cookie2 header '#{set_cookie_value}'"
    end
    index += md.offset(0)[1]

    key = md[1].downcase.to_sym
    keyvalue = md[2] || md[3]
    if first
      args[:name] = md[1]
      args[:value] = keyvalue
      first = false
    else
      keyvalue = value_to_string keyvalue
      case key
      when :comment, :commenturl, :domain, :path
        args[key] = keyvalue
      when :discard, :secure
        args[key] = true
      when :httponly
        args[:http_only] = true
      when :"max-age"
        args[:max_age] = keyvalue.to_i
      when :version
        args[:version] = keyvalue.to_i
      when :port
        # must be in format '"port,port"'
        ports = keyvalue.split(/,\s*/)
        args[:ports] = ports.map(&:to_i)
      else
        fail InvalidCookieError, "Unknown cookie parameter '#{key}'"
      end
    end
  end until md.post_match.empty?
  # if our last match in the scan failed
  if args[:version] != 1
    fail InvalidCookieError,
         'Set-Cookie2 declares a non RFC2965 version cookie'
  end

  args
end
to_domain(uri_or_domain) click to toggle source

Converts an input cookie or uri to a string representing the domain. Assume strings are already domains. Value may not be an effective host.

@param [String, URI, Cookie] object containing the domain @return [String] domain information.

# File lib/cookiejar/cookie_validation.rb, line 77
def self.to_domain(uri_or_domain)
  if uri_or_domain.is_a? URI
    uri_or_domain.host
  elsif uri_or_domain.is_a? Cookie
    uri_or_domain.domain
  else
    uri_or_domain
  end
end
to_path(uri_or_path) click to toggle source

Converts an input cookie or uri to a string representing the path. Assume strings are already paths

@param [String, URI, Cookie] object containing the path @return [String] path information

# File lib/cookiejar/cookie_validation.rb, line 64
def self.to_path(uri_or_path)
  if (uri_or_path.is_a? URI) || (uri_or_path.is_a? Cookie)
    uri_or_path.path
  else
    uri_or_path
  end
end
to_uri(request_uri) click to toggle source

Converts the input object to a URI (if not already a URI)

@param [String, URI] request_uri URI we are normalizing @param [URI] URI representation of input string, or original URI

# File lib/cookiejar/cookie_validation.rb, line 55
def self.to_uri(request_uri)
  (request_uri.is_a? URI) ? request_uri : (URI.parse request_uri)
end
value_to_string(value) click to toggle source

Parse a RFC 2965 value and convert to a literal string

# File lib/cookiejar/cookie_validation.rb, line 334
def self.value_to_string(value)
  if /\A"(.*)"\Z/ =~ value
    value = Regexp.last_match(1)
    value.gsub(/\\(.)/, '\1')
  else
    value
  end
end