module Rack::Utils

def self.key_space_limit

def self.key_space_limit
  default_query_parser.key_space_limit
end

def self.key_space_limit=(v)

def self.key_space_limit=(v)
  self.default_query_parser = self.default_query_parser.new_space_limit(v)
end

def self.param_depth_limit

def self.param_depth_limit
  default_query_parser.param_depth_limit
end

def self.param_depth_limit=(v)

def self.param_depth_limit=(v)
  self.default_query_parser = self.default_query_parser.new_depth_limit(v)
end

def add_cookie_to_header(header, key, value)

def add_cookie_to_header(header, key, value)
  case value
  when Hash
    domain  = "; domain=#{value[:domain]}"   if value[:domain]
    path    = "; path=#{value[:path]}"       if value[:path]
    max_age = "; max-age=#{value[:max_age]}" if value[:max_age]
    expires = "; expires=#{value[:expires].httpdate}" if value[:expires]
    secure = "; secure"  if value[:secure]
    httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only])
    same_site =
      case value[:same_site]
      when false, nil
        nil
      when :none, 'None', :None
        '; SameSite=None'
      when :lax, 'Lax', :Lax
        '; SameSite=Lax'
      when true, :strict, 'Strict', :Strict
        '; SameSite=Strict'
      else
        raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}"
      end
    value = value[:value]
  end
  value = [value] unless Array === value
  cookie = "#{escape(key)}=#{value.map { |v| escape v }.join('&')}#{domain}" \
    "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}"
  case header
  when nil, ''
    cookie
  when String
    [header, cookie].join("\n")
  when Array
    (header + [cookie]).join("\n")
  else
    raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}"
  end
end

def add_remove_cookie_to_header(header, key, value = {})

strange method name.
Adds a cookie that will *remove* a cookie from the client. Hence the
def add_remove_cookie_to_header(header, key, value = {})
  new_header = make_delete_cookie_header(header, key, value)
  add_cookie_to_header(new_header, key,
             { value: '', path: nil, domain: nil,
               max_age: '0',
               expires: Time.at(0) }.merge(value))
end

def best_q_match(q_value_header, available_mimes)

is arbitrary.
matches (same specificity and quality), the value returned
in RFC 2616 Section 14. If there are multiple best
Return best accept value to use, based on the algorithm
def best_q_match(q_value_header, available_mimes)
  values = q_values(q_value_header)
  matches = values.map do |req_mime, quality|
    match = available_mimes.find { |am| Rack::Mime.match?(am, req_mime) }
    next unless match
    [match, quality]
  end.compact.sort_by do |match, quality|
    (match.split('/', 2).count('*') * -10) + quality
  end.last
  matches && matches.first
end

def build_nested_query(value, prefix = nil)

def build_nested_query(value, prefix = nil)
  case value
  when Array
    value.map { |v|
      build_nested_query(v, "#{prefix}[]")
    }.join("&")
  when Hash
    value.map { |k, v|
      build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
    }.delete_if(&:empty?).join('&')
  when nil
    prefix
  else
    raise ArgumentError, "value must be a Hash" if prefix.nil?
    "#{prefix}=#{escape(value)}"
  end
end

def build_query(params)

def build_query(params)
  params.map { |k, v|
    if v.class == Array
      build_query(v.map { |x| [k, x] })
    else
      v.nil? ? escape(k) : "#{escape(k)}=#{escape(v)}"
    end
  }.join("&")
end

def byte_ranges(env, size, max_ranges: 100)

Returns an empty array if none of the ranges are satisfiable.
Returns nil if the header is missing or syntactically invalid.
Parses the "Range:" header, if present, into an array of Range objects.
def byte_ranges(env, size, max_ranges: 100)
  get_byte_ranges env['HTTP_RANGE'], size, max_ranges: max_ranges
end

def clean_path_info(path_info)

def clean_path_info(path_info)
  parts = path_info.split PATH_SEPS
  clean = []
  parts.each do |part|
    next if part.empty? || part == '.'
    part == '..' ? clean.pop : clean << part
  end
  clean_path = clean.join(::File::SEPARATOR)
  clean_path.prepend("/") if parts.empty? || parts.first.empty?
  clean_path
end

def clock_time

def clock_time
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
end

def clock_time

:nocov:
def clock_time
  Time.now.to_f
end

def delete_cookie_header!(header, key, value = {})

def delete_cookie_header!(header, key, value = {})
  header[SET_COOKIE] = add_remove_cookie_to_header(header[SET_COOKIE], key, value)
  nil
end

def escape(s)

URI escapes. (CGI style space to +)
def escape(s)
  URI.encode_www_form_component(s)
end

def escape_html(string)

Escape ampersands, brackets and quotes to their HTML/XML entities.
def escape_html(string)
  string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
end

def escape_path(s)

true URI escaping.
Like URI escaping, but with %20 instead of +. Strictly speaking this is
def escape_path(s)
  RFC2396_PARSER.escape s
end

def get_byte_ranges(http_range, size, max_ranges: 100)

def get_byte_ranges(http_range, size, max_ranges: 100)
  # See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35>
  return nil unless http_range && http_range =~ /bytes=([^;]+)/
  byte_range = $1
  return nil if byte_range.count(',') >= max_ranges
  ranges = []
  byte_range.split(/,[ \t]*/).each do |range_spec|
    return nil unless range_spec.include?('-')
    range = range_spec.split('-')
    r0, r1 = range[0], range[1]
    if r0.nil? || r0.empty?
      return nil if r1.nil?
      # suffix-byte-range-spec, represents trailing suffix of file
      r0 = size - r1.to_i
      r0 = 0  if r0 < 0
      r1 = size - 1
    else
      r0 = r0.to_i
      if r1.nil?
        r1 = size - 1
      else
        r1 = r1.to_i
        return nil  if r1 < r0  # backwards range is syntactically invalid
        r1 = size - 1  if r1 >= size
      end
    end
    ranges << (r0..r1)  if r0 <= r1
  end
  return [] if ranges.map(&:size).inject(0, :+) > size
  ranges
end

def make_delete_cookie_header(header, key, value)

def make_delete_cookie_header(header, key, value)
  case header
  when nil, ''
    cookies = []
  when String
    cookies = header.split("\n")
  when Array
    cookies = header
  end
  key = escape(key)
  domain = value[:domain]
  path = value[:path]
  regexp = if domain
             if path
               /\A#{key}=.*(?:domain=#{domain}(?:;|$).*path=#{path}(?:;|$)|path=#{path}(?:;|$).*domain=#{domain}(?:;|$))/
             else
               /\A#{key}=.*domain=#{domain}(?:;|$)/
             end
           elsif path
             /\A#{key}=.*path=#{path}(?:;|$)/
           else
             /\A#{key}=/
           end
  cookies.reject! { |cookie| regexp.match? cookie }
  cookies.join("\n")
end

def parse_cookies(env)

def parse_cookies(env)
  parse_cookies_header env[HTTP_COOKIE]
end

def parse_cookies_header(header)

def parse_cookies_header(header)
  # According to RFC 6265:
  # The syntax for cookie headers only supports semicolons
  # User Agent -> Server ==
  # Cookie: SID=31d4d96e407aad42; lang=en-US
  return {} unless header
  header.split(/[;] */n).each_with_object({}) do |cookie, cookies|
    next if cookie.empty?
    key, value = cookie.split('=', 2)
    cookies[key] = (unescape(value) rescue value) unless cookies.key?(key)
  end
end

def parse_nested_query(qs, d = nil)

def parse_nested_query(qs, d = nil)
  Rack::Utils.default_query_parser.parse_nested_query(qs, d)
end

def parse_query(qs, d = nil, &unescaper)

def parse_query(qs, d = nil, &unescaper)
  Rack::Utils.default_query_parser.parse_query(qs, d, &unescaper)
end

def q_values(q_value_header)

def q_values(q_value_header)
  q_value_header.to_s.split(',').map do |part|
    value, parameters = part.split(';', 2).map(&:strip)
    quality = 1.0
    if parameters && (md = /\Aq=([\d.]+)/.match(parameters))
      quality = md[1].to_f
    end
    [value, quality]
  end
end

def rfc2109(time)


weekday and month.
Do not use %a and %b from Time.strptime, it would use localized names for
that I'm certain someone implemented only that option.
NOTE: I'm not sure the RFC says it requires GMT, but is ambiguous enough

It assumes that the time is in GMT to comply to the RFC 2109.
of '% %b %Y'.
Modified version of stdlib time.rb Time#rfc2822 to use '%d-%b-%Y' instead
def rfc2109(time)
  wday = RFC2822_DAY_NAME[time.wday]
  mon = RFC2822_MONTH_NAME[time.mon - 1]
  time.strftime("#{wday}, %d-#{mon}-%Y %H:%M:%S GMT")
end

def rfc2822(time)

def rfc2822(time)
  time.rfc2822
end

def secure_compare(a, b)

via timing attacks.
on variable length plaintext strings because it could leak length info
that have already been processed by HMAC. This should not be used
NOTE: the values compared should be of fixed length, such as strings

Constant time string comparison.
def secure_compare(a, b)
  return false unless a.bytesize == b.bytesize
  l = a.unpack("C*")
  r, i = 0, -1
  b.each_byte { |v| r |= v ^ l[i += 1] }
  r == 0
end

def select_best_encoding(available_encodings, accept_encoding)

acceptable encodings are considered.
To reduce denial of service potential, only the first 16

# => "gzip"
[["compress", 0.5], ["gzip", 1.0]])
select_best_encoding(%w(compress gzip identity),

Example:

Request#accept_encoding.
The accept_encoding argument is typically generated by calling

the highest priority.
priority for the encoding, return the available encoding with
is an encoding name and the second element is the numeric
acceptable encodings array is an array where the first element
acceptable encodings for a request, where each element of the
Given an array of available encoding strings, and an array of
def select_best_encoding(available_encodings, accept_encoding)
  # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
  # Only process the first 16 encodings
  accept_encoding = accept_encoding[0...16]
  expanded_accept_encoding = []
  wildcard_seen = false
  accept_encoding.each do |m, q|
    preference = available_encodings.index(m) || available_encodings.size
    if m == "*"
      unless wildcard_seen
        (available_encodings - accept_encoding.map(&:first)).each do |m2|
          expanded_accept_encoding << [m2, q, preference]
        end
        wildcard_seen = true
      end
    else
      expanded_accept_encoding << [m, q, preference]
    end
  end
  encoding_candidates = expanded_accept_encoding
    .sort do |(_, q1, p1), (_, q2, p2)|
      if r = (q1 <=> q2).nonzero?
        -r
      else
        (p1 <=> p2).nonzero? || 0
      end
    end
    .map!(&:first)
  unless encoding_candidates.include?("identity")
    encoding_candidates.push("identity")
  end
  expanded_accept_encoding.each do |m, q|
    encoding_candidates.delete(m) if q == 0.0
  end
  (encoding_candidates & available_encodings)[0]
end

def set_cookie_header!(header, key, value)

def set_cookie_header!(header, key, value)
  header[SET_COOKIE] = add_cookie_to_header(header[SET_COOKIE], key, value)
  nil
end

def status_code(status)

def status_code(status)
  if status.is_a?(Symbol)
    SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" }
  else
    status.to_i
  end
end

def unescape(s, encoding = Encoding::UTF_8)

target encoding of the string returned, and it defaults to UTF-8
Unescapes a URI escaped string with +encoding+. +encoding+ will be the
def unescape(s, encoding = Encoding::UTF_8)
  URI.decode_www_form_component(s, encoding)
end

def unescape_path(s)

unescaping query parameters or form components.
Unescapes the **path** component of a URI. See Rack::Utils.unescape for
def unescape_path(s)
  RFC2396_PARSER.unescape s
end

def valid_path?(path)

def valid_path?(path)
  path.valid_encoding? && !path.include?(NULL_BYTE)
end