module Rack::Request::Helpers

def GET

Returns the data received in the query string.
def GET
  rr_query_string = get_header(RACK_REQUEST_QUERY_STRING)
  query_string = self.query_string
  if rr_query_string == query_string
    get_header(RACK_REQUEST_QUERY_HASH)
  else
    if rr_query_string
      warn "query string used for GET parsing different from current query string. Starting in Rack 3.2, Rack will used the cached GET value instead of parsing the current query string.", uplevel: 1
    end
    query_hash = parse_query(query_string, '&')
    set_header(RACK_REQUEST_QUERY_STRING, query_string)
    set_header(RACK_REQUEST_QUERY_HASH, query_hash)
  end
end

def POST

multipart/form-data.
This method support both application/x-www-form-urlencoded and

Returns the data received in the request body.
def POST
  if error = get_header(RACK_REQUEST_FORM_ERROR)
    raise error.class, error.message, cause: error.cause
  end
  begin
    rack_input = get_header(RACK_INPUT)
    # If the form hash was already memoized:
    if form_hash = get_header(RACK_REQUEST_FORM_HASH)
      form_input = get_header(RACK_REQUEST_FORM_INPUT)
      # And it was memoized from the same input:
      if form_input.equal?(rack_input)
        return form_hash
      elsif form_input
        warn "input stream used for POST parsing different from current input stream. Starting in Rack 3.2, Rack will used the cached POST value instead of parsing the current input stream.", uplevel: 1
      end
    end
    # Otherwise, figure out how to parse the input:
    if rack_input.nil?
      set_header RACK_REQUEST_FORM_INPUT, nil
      set_header(RACK_REQUEST_FORM_HASH, {})
    elsif form_data? || parseable_data?
      if pairs = Rack::Multipart.parse_multipart(env, Rack::Multipart::ParamList)
        set_header RACK_REQUEST_FORM_PAIRS, pairs
        set_header RACK_REQUEST_FORM_HASH, expand_param_pairs(pairs)
      else
        form_vars = get_header(RACK_INPUT).read
        # Fix for Safari Ajax postings that always append \0
        # form_vars.sub!(/\0\z/, '') # performance replacement:
        form_vars.slice!(-1) if form_vars.end_with?("\0")
        set_header RACK_REQUEST_FORM_VARS, form_vars
        set_header RACK_REQUEST_FORM_HASH, parse_query(form_vars, '&')
      end
      set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT)
      get_header RACK_REQUEST_FORM_HASH
    else
      set_header RACK_REQUEST_FORM_INPUT, get_header(RACK_INPUT)
      set_header(RACK_REQUEST_FORM_HASH, {})
    end
  rescue => error
    set_header(RACK_REQUEST_FORM_ERROR, error)
    raise
  end
end

def accept_encoding

def accept_encoding
  parse_http_accept_header(get_header("HTTP_ACCEPT_ENCODING"))
end

def accept_language

def accept_language
  parse_http_accept_header(get_header("HTTP_ACCEPT_LANGUAGE"))
end

def allowed_scheme(header)

def allowed_scheme(header)
  header if ALLOWED_SCHEMES.include?(header)
end

def authority

In HTTP/2, this is the `:authority` pseudo-header.
In HTTP/1, this is the `host` header.

https://tools.ietf.org/html/rfc3986#section-3.2
The authority of the incoming request as defined by RFC3976.
def authority
  forwarded_authority || host_authority || server_authority
end

def base_url

def base_url
  "#{scheme}://#{host_with_port}"
end

def body; get_header(RACK_INPUT) end

def body;            get_header(RACK_INPUT)                         end

def content_charset

charset are to be considered ISO-8859-1.
that, per RFC2616, text/* media types that specify no explicit
parameter was given, or nil if no "charset" was specified. Note
The character set of the request body if a "charset" media type
def content_charset
  media_type_params['charset']
end

def content_length; get_header('CONTENT_LENGTH') end

def content_length;  get_header('CONTENT_LENGTH')                   end

def content_type

def content_type
  content_type = get_header('CONTENT_TYPE')
  content_type.nil? || content_type.empty? ? nil : content_type
end

def cookies

def cookies
  hash = fetch_header(RACK_REQUEST_COOKIE_HASH) do |key|
    set_header(key, {})
  end
  string = get_header(HTTP_COOKIE)
  unless string == get_header(RACK_REQUEST_COOKIE_STRING)
    hash.replace Utils.parse_cookies_header(string)
    set_header(RACK_REQUEST_COOKIE_STRING, string)
  end
  hash
end

def default_session; {}; end

def default_session; {}; end

def delete?; request_method == DELETE end

Checks the HTTP request method (or verb) to see if it was of type DELETE
def delete?;  request_method == DELETE  end

def delete_param(k)

env['rack.input'] is not touched.

If the parameter is in both GET and POST, the POST value takes precedence since that's how #params works.

Destructively delete a parameter, whether it's in GET or POST. Returns the value of the deleted parameter.
def delete_param(k)
  post_value, get_value = self.POST.delete(k), self.GET.delete(k)
  post_value || get_value
end

def expand_param_pairs(pairs, query_parser = query_parser())

def expand_param_pairs(pairs, query_parser = query_parser())
  params = query_parser.make_params
  pairs.each do |k, v|
    query_parser.normalize_params(params, k, v)
  end
  params.to_params_hash
end

def form_data?

content-type header is provided and the request_method is POST.
A request body is also assumed to contain form-data when no

+FORM_DATA_MEDIA_TYPES+ array.
list of form-data media types can be modified through the
"application/x-www-form-urlencoded" or "multipart/form-data". The
the request content-type for one of the media-types:
Determine whether the request body contains form-data by checking
def form_data?
  type = media_type
  meth = get_header(RACK_METHODOVERRIDE_ORIGINAL_METHOD) || get_header(REQUEST_METHOD)
  (meth == POST && type.nil?) || FORM_DATA_MEDIA_TYPES.include?(type)
end

def forwarded_authority

def forwarded_authority
  forwarded_priority.each do |type|
    case type
    when :forwarded
      if forwarded = get_http_forwarded(:host)
        return forwarded.last
      end
    when :x_forwarded
      if value = get_header(HTTP_X_FORWARDED_HOST)
        return wrap_ipv6(split_header(value).last)
      end
    end
  end
  nil
end

def forwarded_for

def forwarded_for
  forwarded_priority.each do |type|
    case type
    when :forwarded
      if forwarded_for = get_http_forwarded(:for)
        return(forwarded_for.map! do |authority|
          split_authority(authority)[1]
        end)
      end
    when :x_forwarded
      if value = get_header(HTTP_X_FORWARDED_FOR)
        return(split_header(value).map do |authority|
          split_authority(wrap_ipv6(authority))[1]
        end)
      end
    end
  end
  nil
end

def forwarded_port

def forwarded_port
  forwarded_priority.each do |type|
    case type
    when :forwarded
      if forwarded = get_http_forwarded(:for)
        return(forwarded.map do |authority|
          split_authority(authority)[2]
        end.compact)
      end
    when :x_forwarded
      if value = get_header(HTTP_X_FORWARDED_PORT)
        return split_header(value).map(&:to_i)
      end
    end
  end
  nil
end

def forwarded_priority

def forwarded_priority
  Request.forwarded_priority
end

def forwarded_scheme

def forwarded_scheme
  forwarded_priority.each do |type|
    case type
    when :forwarded
      if (forwarded_proto = get_http_forwarded(:proto)) &&
         (scheme = allowed_scheme(forwarded_proto.last))
        return scheme
      end
    when :x_forwarded
      x_forwarded_proto_priority.each do |x_type|
        if header = FORWARDED_SCHEME_HEADERS[x_type]
          split_header(get_header(header)).reverse_each do |scheme|
            if allowed_scheme(scheme)
              return scheme
            end
          end
        end
      end
    end
  end
  nil
end

def fullpath

def fullpath
  query_string.empty? ? path : "#{path}?#{query_string}"
end

def get?; request_method == GET end

Checks the HTTP request method (or verb) to see if it was of type GET
def get?;     request_method == GET     end

def get_http_forwarded(token)

Get an array of values set in the RFC 7239 `Forwarded` request header.
def get_http_forwarded(token)
  Utils.forwarded_values(get_header(HTTP_FORWARDED))&.[](token)
end

def head?; request_method == HEAD end

Checks the HTTP request method (or verb) to see if it was of type HEAD
def head?;    request_method == HEAD    end

def host

Returns a formatted host, suitable for being used in a URI.
def host
  split_authority(self.authority)[0]
end

def host_authority

The `HTTP_HOST` header.
def host_authority
  get_header(HTTP_HOST)
end

def host_with_port(authority = self.authority)

def host_with_port(authority = self.authority)
  host, _, port = split_authority(authority)
  if port == DEFAULT_PORTS[self.scheme]
    host
  else
    authority
  end
end

def hostname

brackets are removed.
as +host+. In the case of IPv6 or future address formats, the square
In the case of a domain name or IPv4 address, the result is the same
Returns an address suitable for being to resolve to an address.
def hostname
  split_authority(self.authority)[1]
end

def ip

def ip
  remote_addresses = split_header(get_header('REMOTE_ADDR'))
  external_addresses = reject_trusted_ip_addresses(remote_addresses)
  unless external_addresses.empty?
    return external_addresses.last
  end
  if (forwarded_for = self.forwarded_for) && !forwarded_for.empty?
    # The forwarded for addresses are ordered: client, proxy1, proxy2.
    # So we reject all the trusted addresses (proxy*) and return the
    # last client. Or if we trust everyone, we just return the first
    # address.
    return reject_trusted_ip_addresses(forwarded_for).last || forwarded_for.first
  end
  # If all the addresses are trusted, and we aren't forwarded, just return
  # the first remote address, which represents the source of the request.
  remote_addresses.first
end

def link?; request_method == LINK end

Checks the HTTP request method (or verb) to see if it was of type LINK
def link?;    request_method == LINK    end

def logger; get_header(RACK_LOGGER) end

def logger;          get_header(RACK_LOGGER)                        end

def media_type

http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
For more information on the use of media types in HTTP, see:

"text/plain;charset=utf-8", the media-type is "text/plain".
without any media type parameters. e.g., when CONTENT_TYPE is
The media type (type/subtype) portion of the CONTENT_TYPE header
def media_type
  MediaType.type(content_type)
end

def media_type_params

{ 'charset' => 'utf-8' }
this method responds with the following Hash:
provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8",
an empty Hash if no CONTENT_TYPE or media-type parameters were
The media type parameters provided in CONTENT_TYPE as a Hash, or
def media_type_params
  MediaType.params(content_type)
end

def options?; request_method == OPTIONS end

Checks the HTTP request method (or verb) to see if it was of type OPTIONS
def options?; request_method == OPTIONS end

def params

Note that modifications will not be persisted in the env. Use update_param or delete_param if you want to destructively modify params.

The union of GET and POST data.
def params
  self.GET.merge(self.POST)
end

def parse_http_accept_header(header)

def parse_http_accept_header(header)
  # It would be nice to use filter_map here, but it's Ruby 2.7+
  parts = header.to_s.split(',')
  parts.map! do |part|
    part.strip!
    next if part.empty?
    attribute, parameters = part.split(';', 2)
    attribute.strip!
    parameters&.strip!
    quality = 1.0
    if parameters and /\Aq=([\d.]+)/ =~ parameters
      quality = $1.to_f
    end
    [attribute, quality]
  end
  parts.compact!
  parts
end

def parse_multipart

def parse_multipart
  Rack::Multipart.extract_multipart(self, query_parser)
end

def parse_query(qs, d = '&')

def parse_query(qs, d = '&')
  query_parser.parse_nested_query(qs, d)
end

def parseable_data?

the request media_type against registered parse-data media-types
Determine whether the request body contains data by checking
def parseable_data?
  PARSEABLE_DATA_MEDIA_TYPES.include?(media_type)
end

def patch?; request_method == PATCH end

Checks the HTTP request method (or verb) to see if it was of type PATCH
def patch?;   request_method == PATCH   end

def path

def path
  script_name + path_info
end

def path_info; get_header(PATH_INFO).to_s end

def path_info;       get_header(PATH_INFO).to_s                     end

def path_info=(s); set_header(PATH_INFO, s.to_s) end

def path_info=(s);   set_header(PATH_INFO, s.to_s)                  end

def port

def port
  if authority = self.authority
    _, _, port = split_authority(authority)
  end
  port || forwarded_port&.last || DEFAULT_PORTS[scheme] || server_port
end

def post?; request_method == POST end

Checks the HTTP request method (or verb) to see if it was of type POST
def post?;    request_method == POST    end

def put?; request_method == PUT end

Checks the HTTP request method (or verb) to see if it was of type PUT
def put?;     request_method == PUT     end

def query_parser

def query_parser
  Utils.default_query_parser
end

def query_string; get_header(QUERY_STRING).to_s end

def query_string;    get_header(QUERY_STRING).to_s                  end

def referer; get_header('HTTP_REFERER') end

the referer of the client
def referer;         get_header('HTTP_REFERER')                     end

def reject_trusted_ip_addresses(ip_addresses)

def reject_trusted_ip_addresses(ip_addresses)
  ip_addresses.reject { |ip| trusted_proxy?(ip) }
end

def request_method; get_header(REQUEST_METHOD) end

def request_method;  get_header(REQUEST_METHOD)                     end

def scheme

def scheme
  if get_header(HTTPS) == 'on'
    'https'
  elsif get_header(HTTP_X_FORWARDED_SSL) == 'on'
    'https'
  elsif forwarded_scheme
    forwarded_scheme
  else
    get_header(RACK_URL_SCHEME)
  end
end

def script_name; get_header(SCRIPT_NAME).to_s end

def script_name;     get_header(SCRIPT_NAME).to_s                   end

def script_name=(s); set_header(SCRIPT_NAME, s.to_s) end

def script_name=(s); set_header(SCRIPT_NAME, s.to_s)                end

def server_authority

variables.
The authority as defined by the `SERVER_NAME` and `SERVER_PORT`
def server_authority
  host = self.server_name
  port = self.server_port
  if host
    if port
      "#{host}:#{port}"
    else
      host
    end
  end
end

def server_name

def server_name
  get_header(SERVER_NAME)
end

def server_port

def server_port
  get_header(SERVER_PORT)
end

def session

def session
  fetch_header(RACK_SESSION) do |k|
    set_header RACK_SESSION, default_session
  end
end

def session_options

def session_options
  fetch_header(RACK_SESSION_OPTIONS) do |k|
    set_header RACK_SESSION_OPTIONS, {}
  end
end

def split_authority(authority)

def split_authority(authority)
  return [] if authority.nil?
  return [] unless match = AUTHORITY.match(authority)
  return match[:host], match[:address], match[:port]&.to_i
end

def split_header(value)

def split_header(value)
  value ? value.strip.split(/[,\s]+/) : []
end

def ssl?

def ssl?
  scheme == 'https' || scheme == 'wss'
end

def trace?; request_method == TRACE end

Checks the HTTP request method (or verb) to see if it was of type TRACE
def trace?;   request_method == TRACE   end

def trusted_proxy?(ip)

def trusted_proxy?(ip)
  Rack::Request.ip_filter.call(ip)
end

def unlink?; request_method == UNLINK end

Checks the HTTP request method (or verb) to see if it was of type UNLINK
def unlink?;  request_method == UNLINK  end

def update_param(k, v)

env['rack.input'] is not touched.

The parameter is updated wherever it was previous defined, so GET, POST, or both. If it wasn't previously defined, it's inserted into GET.

Destructively update a parameter, whether it's in GET and/or POST. Returns nil.
def update_param(k, v)
  found = false
  if self.GET.has_key?(k)
    found = true
    self.GET[k] = v
  end
  if self.POST.has_key?(k)
    found = true
    self.POST[k] = v
  end
  unless found
    self.GET[k] = v
  end
end

def url

Tries to return a remake of the original request URL as a string.
def url
  base_url + fullpath
end

def user_agent; get_header('HTTP_USER_AGENT') end

def user_agent;      get_header('HTTP_USER_AGENT')                  end

def values_at(*keys)

like Hash#values_at
def values_at(*keys)
  warn("Request#values_at is deprecated and will be removed in a future version of Rack. Please use request.params.values_at instead", uplevel: 1)
  
  keys.map { |key| params[key] }
end

def wrap_ipv6(host)

Assist with compatibility when processing `X-Forwarded-For`.
def wrap_ipv6(host)
  # Even thought IPv6 addresses should be wrapped in square brackets,
  # sometimes this is not done in various legacy/underspecified headers.
  # So we try to fix this situation for compatibility reasons.
  # Try to detect IPv6 addresses which aren't escaped yet:
  if !host.start_with?('[') && host.count(':') > 1
    "[#{host}]"
  else
    host
  end
end

def x_forwarded_proto_priority

def x_forwarded_proto_priority
  Request.x_forwarded_proto_priority
end

def xhr?

def xhr?
  get_header("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest"
end