module Rack::Request::Helpers

Constants

AUTHORITY
DEFAULT_PORTS

Default ports depending on scheme. Used to decide whether or not to include the port in a generated URI.

FORM_DATA_MEDIA_TYPES

The set of form-data media-types. Requests that do not indicate one of the media types present in this list will not be eligible for form-data / param parsing.

FORWARDED_SCHEME_HEADERS
HTTP_FORWARDED
HTTP_X_FORWARDED_FOR

The address of the client which connected to the proxy.

HTTP_X_FORWARDED_HOST

The contents of the host/:authority header sent to the proxy.

HTTP_X_FORWARDED_PORT

The port used to connect to the proxy.

HTTP_X_FORWARDED_PROTO

The protocol used to connect to the proxy.

HTTP_X_FORWARDED_SCHEME

The value of the scheme sent to the proxy.

HTTP_X_FORWARDED_SSL

Another way for specifying https scheme was used.

PARSEABLE_DATA_MEDIA_TYPES

The set of media-types. Requests that do not indicate one of the media types present in this list will not be eligible for param parsing like soap attachments or generic multiparts

Public Instance Methods

GET() click to toggle source

Returns the data received in the query string.

# File lib/rack/request.rb, line 484
def GET
  if get_header(RACK_REQUEST_QUERY_STRING) == query_string
    get_header(RACK_REQUEST_QUERY_HASH)
  else
    query_hash = parse_query(query_string, '&')
    set_header(RACK_REQUEST_QUERY_STRING, query_string)
    set_header(RACK_REQUEST_QUERY_HASH, query_hash)
  end
end
POST() click to toggle source

Returns the data received in the request body.

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

# File lib/rack/request.rb, line 498
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)
      # And it was memoized from the same input:
      if get_header(RACK_REQUEST_FORM_INPUT).equal?(rack_input)
        return form_hash
      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?
      unless set_header(RACK_REQUEST_FORM_HASH, parse_multipart)
        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
[](key) click to toggle source

shortcut for request.params[key]

# File lib/rack/request.rb, line 609
def [](key)
  warn("Request#[] is deprecated and will be removed in a future version of Rack. Please use request.params[] instead", uplevel: 1)

  params[key.to_s]
end
[]=(key, value) click to toggle source

shortcut for request.params[key] = value

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

# File lib/rack/request.rb, line 618
def []=(key, value)
  warn("Request#[]= is deprecated and will be removed in a future version of Rack. Please use request.params[]= instead", uplevel: 1)

  params[key.to_s] = value
end
accept_encoding() click to toggle source
# File lib/rack/request.rb, line 596
def accept_encoding
  parse_http_accept_header(get_header("HTTP_ACCEPT_ENCODING"))
end
accept_language() click to toggle source
# File lib/rack/request.rb, line 600
def accept_language
  parse_http_accept_header(get_header("HTTP_ACCEPT_LANGUAGE"))
end
authority() click to toggle source

The authority of the incoming request as defined by RFC3976. tools.ietf.org/html/rfc3986#section-3.2

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

# File lib/rack/request.rb, line 266
def authority
  forwarded_authority || host_authority || server_authority
end
base_url() click to toggle source
# File lib/rack/request.rb, line 579
def base_url
  "#{scheme}://#{host_with_port}"
end
body() click to toggle source
# File lib/rack/request.rb, line 190
def body;            get_header(RACK_INPUT)                         end
content_charset() click to toggle source

The character set of the request body if a “charset” media type parameter was given, or nil if no “charset” was specified. Note that, per RFC2616, text/* media types that specify no explicit charset are to be considered ISO-8859-1.

# File lib/rack/request.rb, line 458
def content_charset
  media_type_params['charset']
end
content_length() click to toggle source
# File lib/rack/request.rb, line 199
def content_length;  get_header('CONTENT_LENGTH')                   end
content_type() click to toggle source
# File lib/rack/request.rb, line 308
def content_type
  content_type = get_header('CONTENT_TYPE')
  content_type.nil? || content_type.empty? ? nil : content_type
end
cookies() click to toggle source
# File lib/rack/request.rb, line 293
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
delete?() click to toggle source

Checks the HTTP request method (or verb) to see if it was of type DELETE

# File lib/rack/request.rb, line 220
def delete?;  request_method == DELETE  end
delete_param(k) click to toggle source

Destructively delete a parameter, whether it’s in GET or POST. Returns the value of the deleted parameter.

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

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

# File lib/rack/request.rb, line 574
def delete_param(k)
  post_value, get_value = self.POST.delete(k), self.GET.delete(k)
  post_value || get_value
end
form_data?() click to toggle source

Determine whether the request body contains form-data by checking the request content-type for one of the media-types: “application/x-www-form-urlencoded” or “multipart/form-data”. The list of form-data media types can be modified through the FORM_DATA_MEDIA_TYPES array.

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

# File lib/rack/request.rb, line 470
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
forwarded_authority() click to toggle source
# File lib/rack/request.rb, line 393
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
forwarded_for() click to toggle source
# File lib/rack/request.rb, line 353
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
forwarded_port() click to toggle source
# File lib/rack/request.rb, line 374
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
fullpath() click to toggle source
# File lib/rack/request.rb, line 592
def fullpath
  query_string.empty? ? path : "#{path}?#{query_string}"
end
get?() click to toggle source

Checks the HTTP request method (or verb) to see if it was of type GET

# File lib/rack/request.rb, line 223
def get?;     request_method == GET     end
head?() click to toggle source

Checks the HTTP request method (or verb) to see if it was of type HEAD

# File lib/rack/request.rb, line 226
def head?;    request_method == HEAD    end
host() click to toggle source

Returns a formatted host, suitable for being used in a URI.

# File lib/rack/request.rb, line 333
def host
  split_authority(self.authority)[0]
end
host_authority() click to toggle source

The ‘HTTP_HOST` header.

# File lib/rack/request.rb, line 318
def host_authority
  get_header(HTTP_HOST)
end
host_with_port(authority = self.authority) click to toggle source
# File lib/rack/request.rb, line 322
def host_with_port(authority = self.authority)
  host, _, port = split_authority(authority)

  if port == DEFAULT_PORTS[self.scheme]
    host
  else
    authority
  end
end
hostname() click to toggle source

Returns an address suitable for being to resolve to an address. In the case of a domain name or IPv4 address, the result is the same as host. In the case of IPv6 or future address formats, the square brackets are removed.

# File lib/rack/request.rb, line 341
def hostname
  split_authority(self.authority)[1]
end
ip() click to toggle source
# File lib/rack/request.rb, line 414
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
logger() click to toggle source
# File lib/rack/request.rb, line 200
def logger;          get_header(RACK_LOGGER)                        end
media_type() click to toggle source

The media type (type/subtype) portion of the CONTENT_TYPE header without any media type parameters. e.g., when CONTENT_TYPE is “text/plain;charset=utf-8”, the media-type is “text/plain”.

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

# File lib/rack/request.rb, line 441
def media_type
  MediaType.type(content_type)
end
media_type_params() click to toggle source

The media type parameters provided in CONTENT_TYPE as a Hash, or an empty Hash if no CONTENT_TYPE or media-type parameters were provided. e.g., when the CONTENT_TYPE is “text/plain;charset=utf-8”, this method responds with the following Hash:

{ 'charset' => 'utf-8' }
# File lib/rack/request.rb, line 450
def media_type_params
  MediaType.params(content_type)
end
options?() click to toggle source

Checks the HTTP request method (or verb) to see if it was of type OPTIONS

# File lib/rack/request.rb, line 229
def options?; request_method == OPTIONS end
params() click to toggle source

The union of GET and POST data.

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

# File lib/rack/request.rb, line 545
def params
  self.GET.merge(self.POST)
end
parseable_data?() click to toggle source

Determine whether the request body contains data by checking the request media_type against registered parse-data media-types

# File lib/rack/request.rb, line 479
def parseable_data?
  PARSEABLE_DATA_MEDIA_TYPES.include?(media_type)
end
patch?() click to toggle source

Checks the HTTP request method (or verb) to see if it was of type PATCH

# File lib/rack/request.rb, line 235
def patch?;   request_method == PATCH   end
path() click to toggle source
# File lib/rack/request.rb, line 588
def path
  script_name + path_info
end
path_info() click to toggle source
# File lib/rack/request.rb, line 194
def path_info;       get_header(PATH_INFO).to_s                     end
path_info=(s) click to toggle source
# File lib/rack/request.rb, line 195
def path_info=(s);   set_header(PATH_INFO, s.to_s)                  end
port() click to toggle source
# File lib/rack/request.rb, line 345
def port
  if authority = self.authority
    _, _, port = split_authority(authority)
  end

  port || forwarded_port&.last || DEFAULT_PORTS[scheme] || server_port
end
post?() click to toggle source

Checks the HTTP request method (or verb) to see if it was of type POST

# File lib/rack/request.rb, line 238
def post?;    request_method == POST    end
put?() click to toggle source

Checks the HTTP request method (or verb) to see if it was of type PUT

# File lib/rack/request.rb, line 241
def put?;     request_method == PUT     end
query_string() click to toggle source
# File lib/rack/request.rb, line 198
def query_string;    get_header(QUERY_STRING).to_s                  end
referer() click to toggle source

the referer of the client

# File lib/rack/request.rb, line 204
def referer;         get_header('HTTP_REFERER')                     end
Also aliased as: referrer
referrer()
Alias for: referer
request_method() click to toggle source
# File lib/rack/request.rb, line 197
def request_method;  get_header(REQUEST_METHOD)                     end
scheme() click to toggle source
# File lib/rack/request.rb, line 249
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
script_name() click to toggle source
# File lib/rack/request.rb, line 191
def script_name;     get_header(SCRIPT_NAME).to_s                   end
script_name=(s) click to toggle source
# File lib/rack/request.rb, line 192
def script_name=(s); set_header(SCRIPT_NAME, s.to_s)                end
server_authority() click to toggle source

The authority as defined by the ‘SERVER_NAME` and `SERVER_PORT` variables.

# File lib/rack/request.rb, line 272
def server_authority
  host = self.server_name
  port = self.server_port

  if host
    if port
      "#{host}:#{port}"
    else
      host
    end
  end
end
server_name() click to toggle source
# File lib/rack/request.rb, line 285
def server_name
  get_header(SERVER_NAME)
end
server_port() click to toggle source
# File lib/rack/request.rb, line 289
def server_port
  get_header(SERVER_PORT)
end
session() click to toggle source
# File lib/rack/request.rb, line 207
def session
  fetch_header(RACK_SESSION) do |k|
    set_header RACK_SESSION, default_session
  end
end
session_options() click to toggle source
# File lib/rack/request.rb, line 213
def session_options
  fetch_header(RACK_SESSION_OPTIONS) do |k|
    set_header RACK_SESSION_OPTIONS, {}
  end
end
ssl?() click to toggle source
# File lib/rack/request.rb, line 410
def ssl?
  scheme == 'https' || scheme == 'wss'
end
trace?() click to toggle source

Checks the HTTP request method (or verb) to see if it was of type TRACE

# File lib/rack/request.rb, line 244
def trace?;   request_method == TRACE   end
trusted_proxy?(ip) click to toggle source
# File lib/rack/request.rb, line 604
def trusted_proxy?(ip)
  Rack::Request.ip_filter.call(ip)
end
update_param(k, v) click to toggle source

Destructively update a parameter, whether it’s in GET and/or POST. Returns nil.

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.

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

# File lib/rack/request.rb, line 554
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
url() click to toggle source

Tries to return a remake of the original request URL as a string.

# File lib/rack/request.rb, line 584
def url
  base_url + fullpath
end
user_agent() click to toggle source
# File lib/rack/request.rb, line 201
def user_agent;      get_header('HTTP_USER_AGENT')                  end
values_at(*keys) click to toggle source

like Hash#values_at

# File lib/rack/request.rb, line 625
def values_at(*keys)
  keys.map { |key| params[key] }
end
xhr?() click to toggle source
# File lib/rack/request.rb, line 313
def xhr?
  get_header("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest"
end

Private Instance Methods

allowed_scheme(header) click to toggle source
# File lib/rack/request.rb, line 757
def allowed_scheme(header)
  header if ALLOWED_SCHEMES.include?(header)
end
default_session() click to toggle source
# File lib/rack/request.rb, line 631
def default_session; {}; end
forwarded_priority() click to toggle source
# File lib/rack/request.rb, line 761
def forwarded_priority
  Request.forwarded_priority
end
forwarded_scheme() click to toggle source
# File lib/rack/request.rb, line 733
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
get_http_forwarded(token) click to toggle source

Get an array of values set in the RFC 7239 ‘Forwarded` request header.

# File lib/rack/request.rb, line 659
def get_http_forwarded(token)
  Utils.forwarded_values(get_header(HTTP_FORWARDED))&.[](token)
end
parse_http_accept_header(header) click to toggle source
# File lib/rack/request.rb, line 647
def parse_http_accept_header(header)
  header.to_s.split(",").each(&:strip!).map do |part|
    attribute, parameters = part.split(";", 2).each(&:strip!)
    quality = 1.0
    if parameters and /\Aq=([\d.]+)/ =~ parameters
      quality = $1.to_f
    end
    [attribute, quality]
  end
end
parse_multipart() click to toggle source
# File lib/rack/request.rb, line 671
def parse_multipart
  Rack::Multipart.extract_multipart(self, query_parser)
end
parse_query(qs, d = '&') click to toggle source
# File lib/rack/request.rb, line 667
def parse_query(qs, d = '&')
  query_parser.parse_nested_query(qs, d)
end
query_parser() click to toggle source
# File lib/rack/request.rb, line 663
def query_parser
  Utils.default_query_parser
end
reject_trusted_ip_addresses(ip_addresses) click to toggle source
# File lib/rack/request.rb, line 724
def reject_trusted_ip_addresses(ip_addresses)
  ip_addresses.reject { |ip| trusted_proxy?(ip) }
end
split_authority(authority) click to toggle source
# File lib/rack/request.rb, line 718
def split_authority(authority)
  return [] if authority.nil?
  return [] unless match = AUTHORITY.match(authority)
  return match[:host], match[:address], match[:port]&.to_i
end
split_header(value) click to toggle source
# File lib/rack/request.rb, line 675
def split_header(value)
  value ? value.strip.split(/[,\s]+/) : []
end
wrap_ipv6(host) click to toggle source

Assist with compatibility when processing ‘X-Forwarded-For`.

# File lib/rack/request.rb, line 634
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
x_forwarded_proto_priority() click to toggle source
# File lib/rack/request.rb, line 765
def x_forwarded_proto_priority
  Request.x_forwarded_proto_priority
end