Class: ActionDispatch::Request

Inherits:
Object
  • Object
show all
Includes:
ContentSecurityPolicy::Request, Flash::RequestMethods, Http::Cache::Request, Http::FilterParameters, Http::MimeNegotiation, Http::Parameters, Http::URL, PermissionsPolicy::Request, Rack::Request::Env, Rack::Request::Helpers
Defined in:
lib/action_dispatch/http/request.rb,
lib/action_dispatch/request/utils.rb,
lib/action_dispatch/request/session.rb,
lib/action_dispatch/middleware/flash.rb

Direct Known Subclasses

TestRequest

Defined Under Namespace

Classes: Session, Utils

Constant Summary collapse

LOCALHOST =
Regexp.union [/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/]
ENV_METHODS =
%w[ AUTH_TYPE GATEWAY_INTERFACE
PATH_TRANSLATED REMOTE_HOST
REMOTE_IDENT REMOTE_USER REMOTE_ADDR
SERVER_NAME SERVER_PROTOCOL
ORIGINAL_SCRIPT_NAME

HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
HTTP_NEGOTIATE HTTP_PRAGMA HTTP_CLIENT_IP
HTTP_X_FORWARDED_FOR HTTP_ORIGIN HTTP_VERSION
HTTP_X_CSRF_TOKEN HTTP_X_REQUEST_ID HTTP_X_FORWARDED_HOST
].freeze
TRANSFER_ENCODING =

:nodoc:

"HTTP_TRANSFER_ENCODING"
PASS_NOT_FOUND =

:nodoc:

Class.new { # :nodoc:
  def self.action(_); self; end
  def self.call(_); [404, { Constants::X_CASCADE => "pass" }, []]; end
  def self.action_encoding_template(action); false; end
}
RFC2616 =

HTTP methods from [RFC 2616: Hypertext Transfer Protocol – HTTP/1.1](www.ietf.org/rfc/rfc2616.txt)

%w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
RFC2518 =

HTTP methods from [RFC 2518: HTTP Extensions for Distributed Authoring – WEBDAV](www.ietf.org/rfc/rfc2518.txt)

%w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
RFC3253 =

HTTP methods from [RFC 3253: Versioning Extensions to WebDAV](www.ietf.org/rfc/rfc3253.txt)

%w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
RFC3648 =

HTTP methods from [RFC 3648: WebDAV Ordered Collections Protocol](www.ietf.org/rfc/rfc3648.txt)

%w(ORDERPATCH)
RFC3744 =

HTTP methods from [RFC 3744: WebDAV Access Control Protocol](www.ietf.org/rfc/rfc3744.txt)

%w(ACL)
RFC5323 =

HTTP methods from [RFC 5323: WebDAV SEARCH](www.ietf.org/rfc/rfc5323.txt)

%w(SEARCH)
RFC4791 =

HTTP methods from [RFC 4791: Calendaring Extensions to WebDAV](www.ietf.org/rfc/rfc4791.txt)

%w(MKCALENDAR)
RFC5789 =

HTTP methods from [RFC 5789: PATCH Method for HTTP](www.ietf.org/rfc/rfc5789.txt)

%w(PATCH)
HTTP_METHODS =
RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
HTTP_METHOD_LOOKUP =
{}
ACTION_DISPATCH_REQUEST_ID =

:nodoc:

"action_dispatch.request_id"

Constants included from PermissionsPolicy::Request

PermissionsPolicy::Request::POLICY

Constants included from ContentSecurityPolicy::Request

ContentSecurityPolicy::Request::NONCE, ContentSecurityPolicy::Request::NONCE_DIRECTIVES, ContentSecurityPolicy::Request::NONCE_GENERATOR, ContentSecurityPolicy::Request::POLICY, ContentSecurityPolicy::Request::POLICY_REPORT_ONLY

Constants included from Http::URL

Http::URL::HOST_REGEXP, Http::URL::IP_HOST_REGEXP, Http::URL::PROTOCOL_REGEXP

Constants included from Http::FilterParameters

Http::FilterParameters::ENV_MATCH, Http::FilterParameters::NULL_ENV_FILTER, Http::FilterParameters::NULL_PARAM_FILTER

Constants included from Http::Parameters

Http::Parameters::DEFAULT_PARSERS, Http::Parameters::PARAMETERS_KEY

Constants included from Http::MimeNegotiation

Http::MimeNegotiation::RESCUABLE_MIME_FORMAT_ERRORS

Constants included from Http::Cache::Request

Http::Cache::Request::HTTP_IF_MODIFIED_SINCE, Http::Cache::Request::HTTP_IF_NONE_MATCH

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from PermissionsPolicy::Request

#permissions_policy, #permissions_policy=

Methods included from ContentSecurityPolicy::Request

#content_security_policy, #content_security_policy=, #content_security_policy_nonce, #content_security_policy_nonce_directives, #content_security_policy_nonce_directives=, #content_security_policy_nonce_generator, #content_security_policy_nonce_generator=, #content_security_policy_report_only, #content_security_policy_report_only=

Methods included from Http::URL

#domain, extract_domain, extract_subdomain, extract_subdomains, full_url_for, #host, #host_with_port, #optional_port, path_for, #port, #port_string, #protocol, #raw_host_with_port, #server_port, #standard_port, #standard_port?, #subdomain, #subdomains, #url, url_for

Methods included from Http::FilterParameters

#filtered_env, #filtered_parameters, #filtered_path, #parameter_filter

Methods included from Http::Parameters

#parameters, #path_parameters, #path_parameters=

Methods included from Http::MimeNegotiation

#accepts, #content_mime_type, #format, #format=, #formats, #formats=, #has_content_type?, #negotiate_mime, #should_apply_vary_header?, #variant, #variant=

Methods included from Http::Cache::Request

#etag_matches?, #fresh?, #if_modified_since, #if_none_match, #if_none_match_etags, #not_modified?

Methods included from Flash::RequestMethods

#flash, #flash=, #flash_hash

Constructor Details

#initialize(env) ⇒ Request

Returns a new instance of Request.



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/action_dispatch/http/request.rb', line 64

def initialize(env)
  super

  @rack_request = Rack::Request.new(env)

  @method            = nil
  @request_method    = nil
  @remote_ip         = nil
  @original_fullpath = nil
  @fullpath          = nil
  @ip                = nil
end

Instance Attribute Details

#rack_requestObject (readonly)

Returns the value of attribute rack_request.



77
78
79
# File 'lib/action_dispatch/http/request.rb', line 77

def rack_request
  @rack_request
end

Class Method Details

.emptyObject



60
61
62
# File 'lib/action_dispatch/http/request.rb', line 60

def self.empty
  new({})
end

Instance Method Details

#authorizationObject

Returns the authorization header regardless of whether it was specified directly or through one of the proxy alternatives.



459
460
461
462
463
464
# File 'lib/action_dispatch/http/request.rb', line 459

def authorization
  get_header("HTTP_AUTHORIZATION")   ||
  get_header("X-HTTP_AUTHORIZATION") ||
  get_header("X_HTTP_AUTHORIZATION") ||
  get_header("REDIRECT_X_HTTP_AUTHORIZATION")
end

#bodyObject

The request body is an IO input stream. If the RAW_POST_DATA environment variable is already set, wrap it in a StringIO.



356
357
358
359
360
361
362
363
# File 'lib/action_dispatch/http/request.rb', line 356

def body
  if raw_post = get_header("RAW_POST_DATA")
    raw_post = (+raw_post).force_encoding(Encoding::BINARY)
    StringIO.new(raw_post)
  else
    body_stream
  end
end

#body_streamObject

:nodoc:



376
377
378
# File 'lib/action_dispatch/http/request.rb', line 376

def body_stream # :nodoc:
  get_header("rack.input")
end

:nodoc:



79
80
# File 'lib/action_dispatch/http/request.rb', line 79

def commit_cookie_jar! # :nodoc:
end

#commit_csrf_tokenObject



491
492
493
# File 'lib/action_dispatch/http/request.rb', line 491

def commit_csrf_token
  controller_instance.commit_csrf_token(self) if controller_instance.respond_to?(:commit_csrf_token)
end

#commit_flashObject



480
481
# File 'lib/action_dispatch/http/request.rb', line 480

def commit_flash
end

#content_lengthObject

Returns the content length of the request as an integer.



291
292
293
294
# File 'lib/action_dispatch/http/request.rb', line 291

def content_length
  return raw_post.bytesize if has_header?(TRANSFER_ENCODING)
  super.to_i
end

#controller_classObject



88
89
90
91
92
# File 'lib/action_dispatch/http/request.rb', line 88

def controller_class
  params = path_parameters
  params[:action] ||= "index"
  controller_class_for(params[:controller])
end

#controller_class_for(name) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/action_dispatch/http/request.rb', line 94

def controller_class_for(name)
  if name
    controller_param = name.underscore
    const_name = controller_param.camelize << "Controller"
    begin
      const_name.constantize
    rescue NameError => error
      if error.missing_name == const_name || const_name.start_with?("#{error.missing_name}::")
        raise MissingController.new(error.message, error.name)
      else
        raise
      end
    end
  else
    PASS_NOT_FOUND
  end
end

#controller_instanceObject

:nodoc:



190
191
192
# File 'lib/action_dispatch/http/request.rb', line 190

def controller_instance # :nodoc:
  get_header("action_controller.instance")
end

#controller_instance=(controller) ⇒ Object

:nodoc:



194
195
196
# File 'lib/action_dispatch/http/request.rb', line 194

def controller_instance=(controller) # :nodoc:
  set_header("action_controller.instance", controller)
end

#engine_script_name(_routes) ⇒ Object

:nodoc:



176
177
178
# File 'lib/action_dispatch/http/request.rb', line 176

def engine_script_name(_routes) # :nodoc:
  get_header(_routes.env_key)
end

#engine_script_name=(name) ⇒ Object

:nodoc:



180
181
182
# File 'lib/action_dispatch/http/request.rb', line 180

def engine_script_name=(name) # :nodoc:
  set_header(routes.env_key, name.dup)
end

#form_data?Boolean

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 not assumed to contain form-data when no ‘Content-Type` header is provided and the request_method is POST.

Returns:

  • (Boolean)


372
373
374
# File 'lib/action_dispatch/http/request.rb', line 372

def form_data?
  FORM_DATA_MEDIA_TYPES.include?(media_type)
end

#fullpathObject

Returns the ‘String` full path including params of the last URL requested.

# get "/articles"
request.fullpath # => "/articles"

# get "/articles?page=2"
request.fullpath # => "/articles?page=2"


270
271
272
# File 'lib/action_dispatch/http/request.rb', line 270

def fullpath
  @fullpath ||= super
end

#GETObject Also known as: query_parameters

Override Rack’s GET method to support indifferent access.



394
395
396
397
398
399
400
401
402
403
# File 'lib/action_dispatch/http/request.rb', line 394

def GET
  fetch_header("action_dispatch.request.query_parameters") do |k|
    encoding_template = Request::Utils::CustomParamEncoder.action_encoding_template(self, path_parameters[:controller], path_parameters[:action])
    rack_query_params = ActionDispatch::ParamBuilder.from_query_string(rack_request.query_string, encoding_template: encoding_template)

    set_header k, rack_query_params
  end
rescue ActionDispatch::ParamError => e
  raise ActionController::BadRequest.new("Invalid query parameters: #{e.message}")
end

#headersObject

Provides access to the request’s HTTP headers, for example:

request.headers["Content-Type"] # => "text/plain"


232
233
234
# File 'lib/action_dispatch/http/request.rb', line 232

def headers
  @headers ||= Http::Headers.new(self)
end

#http_auth_saltObject



198
199
200
# File 'lib/action_dispatch/http/request.rb', line 198

def http_auth_salt
  get_header "action_dispatch.http_auth_salt"
end

#inspectObject

:nodoc:



483
484
485
# File 'lib/action_dispatch/http/request.rb', line 483

def inspect # :nodoc:
  "#<#{self.class.name} #{method} #{original_url.dump} for #{remote_ip}>"
end

#ipObject

Returns the IP address of client as a ‘String`.



305
306
307
# File 'lib/action_dispatch/http/request.rb', line 305

def ip
  @ip ||= super
end

#key?(key) ⇒ Boolean

Returns true if the request has a header matching the given key parameter.

request.key? :ip_spoofing_check # => true

Returns:

  • (Boolean)


115
116
117
# File 'lib/action_dispatch/http/request.rb', line 115

def key?(key)
  has_header? key
end

#local?Boolean

True if the request came from localhost, 127.0.0.1, or ::1.

Returns:

  • (Boolean)


467
468
469
# File 'lib/action_dispatch/http/request.rb', line 467

def local?
  LOCALHOST.match?(remote_addr) && LOCALHOST.match?(remote_ip)
end

#loggerObject



476
477
478
# File 'lib/action_dispatch/http/request.rb', line 476

def logger
  get_header("action_dispatch.logger")
end

#media_typeObject

The ‘String` MIME type of the request.

# get "/articles"
request.media_type # => "application/x-www-form-urlencoded"


286
287
288
# File 'lib/action_dispatch/http/request.rb', line 286

def media_type
  content_mime_type&.to_s
end

#method(*args) ⇒ Object

Returns the original value of the environment’s REQUEST_METHOD, even if it was overridden by middleware. See #request_method for more information.

For debugging purposes, when called with arguments this method will fall back to Object#method



212
213
214
215
216
217
218
219
220
221
# File 'lib/action_dispatch/http/request.rb', line 212

def method(*args)
  if args.empty?
    @method ||= check_method(
      get_header("rack.methodoverride.original_method") ||
      get_header("REQUEST_METHOD")
    )
  else
    super
  end
end

#method_symbolObject

Returns a symbol form of the #method.



225
226
227
# File 'lib/action_dispatch/http/request.rb', line 225

def method_symbol
  HTTP_METHOD_LOOKUP[method]
end

#original_fullpathObject

Returns a ‘String` with the last requested path including their params.

# get '/foo'
request.original_fullpath # => '/foo'

# get '/foo?bar'
request.original_fullpath # => '/foo?bar'


259
260
261
# File 'lib/action_dispatch/http/request.rb', line 259

def original_fullpath
  @original_fullpath ||= (get_header("ORIGINAL_FULLPATH") || fullpath)
end

#original_urlObject

Returns the original request URL as a ‘String`.

# get "/articles?page=2"
request.original_url # => "http://www.example.com/articles?page=2"


278
279
280
# File 'lib/action_dispatch/http/request.rb', line 278

def original_url
  base_url + original_fullpath
end

#POSTObject Also known as: request_parameters

Override Rack’s POST method to support indifferent access.



407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
# File 'lib/action_dispatch/http/request.rb', line 407

def POST
  fetch_header("action_dispatch.request.request_parameters") do
    encoding_template = Request::Utils::CustomParamEncoder.action_encoding_template(self, path_parameters[:controller], path_parameters[:action])

    param_list = nil
    pr = parse_formatted_parameters(params_parsers) do
      if param_list = request_parameters_list
        ActionDispatch::ParamBuilder.from_pairs(param_list, encoding_template: encoding_template)
      else
        # We're not using a version of Rack that provides raw form
        # pairs; we must use its hash (and thus post-process it below).
        fallback_request_parameters
      end
    end

    # If the request body was parsed by a custom parser like JSON
    # (and thus the above block was not run), we need to
    # post-process the result hash.
    if param_list.nil?
      pr = ActionDispatch::ParamBuilder.from_hash(pr, encoding_template: encoding_template)
    end

    self.request_parameters = pr
  end
rescue ActionDispatch::ParamError, EOFError => e
  raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
end

#raw_postObject

Read the request body. This is useful for web services that need to work with raw requests directly.



347
348
349
350
351
352
# File 'lib/action_dispatch/http/request.rb', line 347

def raw_post
  unless has_header? "RAW_POST_DATA"
    set_header("RAW_POST_DATA", read_body_stream)
  end
  get_header "RAW_POST_DATA"
end

#raw_request_methodObject

:nodoc:



145
# File 'lib/action_dispatch/http/request.rb', line 145

alias raw_request_method request_method

#remote_ipObject

Returns the IP address of client as a ‘String`, usually set by the RemoteIp middleware.



311
312
313
# File 'lib/action_dispatch/http/request.rb', line 311

def remote_ip
  @remote_ip ||= (get_header("action_dispatch.remote_ip") || ip).to_s
end

#remote_ip=(remote_ip) ⇒ Object



315
316
317
318
# File 'lib/action_dispatch/http/request.rb', line 315

def remote_ip=(remote_ip)
  @remote_ip = nil
  set_header "action_dispatch.remote_ip", remote_ip
end

#request_idObject Also known as: uuid

Returns the unique request id, which is based on either the ‘X-Request-Id` header that can be generated by a firewall, load balancer, or web server, or by the RequestId middleware (which sets the `action_dispatch.request_id` environment variable).

This unique ID is useful for tracing a request from end-to-end as part of logging or debugging. This relies on the Rack variable set by the ActionDispatch::RequestId middleware.



330
331
332
# File 'lib/action_dispatch/http/request.rb', line 330

def request_id
  get_header ACTION_DISPATCH_REQUEST_ID
end

#request_id=(id) ⇒ Object

:nodoc:



334
335
336
# File 'lib/action_dispatch/http/request.rb', line 334

def request_id=(id) # :nodoc:
  set_header ACTION_DISPATCH_REQUEST_ID, id
end

#request_methodObject

Returns the HTTP method that the application should see. In the case where the method was overridden by a middleware (for instance, if a HEAD request was converted to a GET, or if a _method parameter was used to determine the method the application should use), this method returns the overridden value, not the original.



152
153
154
# File 'lib/action_dispatch/http/request.rb', line 152

def request_method
  @request_method ||= check_method(super)
end

#request_method=(request_method) ⇒ Object

:nodoc:



184
185
186
187
188
# File 'lib/action_dispatch/http/request.rb', line 184

def request_method=(request_method) # :nodoc:
  if check_method(request_method)
    @request_method = set_header("REQUEST_METHOD", request_method)
  end
end

#request_method_symbolObject

Returns a symbol form of the #request_method.



203
204
205
# File 'lib/action_dispatch/http/request.rb', line 203

def request_method_symbol
  HTTP_METHOD_LOOKUP[request_method]
end

#request_parameters=(params) ⇒ Object



471
472
473
474
# File 'lib/action_dispatch/http/request.rb', line 471

def request_parameters=(params)
  raise if params.nil?
  set_header("action_dispatch.request.request_parameters", params)
end

#request_parameters_listObject



436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
# File 'lib/action_dispatch/http/request.rb', line 436

def request_parameters_list
  # We don't use Rack's parse result, but we must call it so Rack
  # can populate the rack.request.* keys we need.
  rack_post = rack_request.POST

  if form_pairs = get_header("rack.request.form_pairs")
    # Multipart
    form_pairs
  elsif form_vars = get_header("rack.request.form_vars")
    # URL-encoded
    ActionDispatch::QueryParser.each_pair(form_vars)
  elsif rack_post && !rack_post.empty?
    # It was multipart, but Rack did not preserve a pair list
    # (probably too old). Flat parameter list is not available.
    nil
  else
    # No request body, or not a format Rack knows
    []
  end
end

#reset_csrf_tokenObject



487
488
489
# File 'lib/action_dispatch/http/request.rb', line 487

def reset_csrf_token
  controller_instance.reset_csrf_token(self) if controller_instance.respond_to?(:reset_csrf_token)
end

#reset_sessionObject



380
381
382
383
# File 'lib/action_dispatch/http/request.rb', line 380

def reset_session
  session.destroy
  reset_csrf_token
end

#route_uri_patternObject

Returns the URI pattern of the matched route for the request, using the same format as ‘bin/rails routes`:

request.route_uri_pattern # => "/:controller(/:action(/:id))(.:format)"


160
161
162
# File 'lib/action_dispatch/http/request.rb', line 160

def route_uri_pattern
  get_header("action_dispatch.route_uri_pattern")
end

#route_uri_pattern=(pattern) ⇒ Object

:nodoc:



164
165
166
# File 'lib/action_dispatch/http/request.rb', line 164

def route_uri_pattern=(pattern) # :nodoc:
  set_header("action_dispatch.route_uri_pattern", pattern)
end

#routesObject

:nodoc:



168
169
170
# File 'lib/action_dispatch/http/request.rb', line 168

def routes # :nodoc:
  get_header("action_dispatch.routes")
end

#routes=(routes) ⇒ Object

:nodoc:



172
173
174
# File 'lib/action_dispatch/http/request.rb', line 172

def routes=(routes) # :nodoc:
  set_header("action_dispatch.routes", routes)
end

#send_early_hints(links) ⇒ Object

Early Hints is an HTTP/2 status code that indicates hints to help a client start making preparations for processing the final response.

If the env contains ‘rack.early_hints` then the server accepts HTTP2 push for link headers.

The ‘send_early_hints` method accepts a hash of links as follows:

send_early_hints("link" => "</style.css>; rel=preload; as=style,</script.js>; rel=preload")

If you are using ‘javascript_include_tag` or `stylesheet_link_tag` the Early Hints headers are included by default if supported.



248
249
250
# File 'lib/action_dispatch/http/request.rb', line 248

def send_early_hints(links)
  env["rack.early_hints"]&.call(links)
end

#server_softwareObject

Returns the lowercase name of the HTTP server software.



341
342
343
# File 'lib/action_dispatch/http/request.rb', line 341

def server_software
  (get_header("SERVER_SOFTWARE") && /^([a-zA-Z]+)/ =~ get_header("SERVER_SOFTWARE")) ? $1.downcase : nil
end

#session=(session) ⇒ Object

:nodoc:



385
386
387
# File 'lib/action_dispatch/http/request.rb', line 385

def session=(session) # :nodoc:
  Session.set self, session
end

#session_options=(options) ⇒ Object



389
390
391
# File 'lib/action_dispatch/http/request.rb', line 389

def session_options=(options)
  Session::Options.set self, options
end

#xml_http_request?Boolean Also known as: xhr?

Returns true if the ‘X-Requested-With` header contains “XMLHttpRequest” (case-insensitive), which may need to be manually added depending on the choice of JavaScript libraries and frameworks.

Returns:

  • (Boolean)


299
300
301
# File 'lib/action_dispatch/http/request.rb', line 299

def xml_http_request?
  /XMLHttpRequest/i.match?(get_header("HTTP_X_REQUESTED_WITH"))
end