Class: ActionController::Request

Inherits:
Rack::Request
  • Object
show all
Defined in:
lib/action_controller/request.rb

Direct Known Subclasses

TestRequest

Constant Summary collapse

HTTP_METHODS =
%w(get head put post delete options)
HTTP_METHOD_LOOKUP =
HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
TRUSTED_PROXIES =

Which IP addresses are “trusted proxies” that can be stripped from the right-hand-side of X-Forwarded-For

/^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i

Instance Method Summary collapse

Instance Method Details

#acceptsObject

Returns the accepted MIME type for the request.



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/action_controller/request.rb', line 103

def accepts
  @accepts ||= begin
    header = @env['HTTP_ACCEPT'].to_s.strip

    if header.empty?
      [content_type, Mime::ALL].compact
    else
      Mime::Type.parse(header)
    end
  end
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.



411
412
413
414
415
416
417
418
# File 'lib/action_controller/request.rb', line 411

def body
  if raw_post = @env['RAW_POST_DATA']
    raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
    StringIO.new(raw_post)
  else
    @env['rack.input']
  end
end

#body_streamObject

:nodoc:



436
437
438
# File 'lib/action_controller/request.rb', line 436

def body_stream #:nodoc:
  @env['rack.input']
end

#cache_formatObject



199
200
201
# File 'lib/action_controller/request.rb', line 199

def cache_format
  parameters[:format]
end

#content_lengthObject

Returns the content length of the request as an integer.



80
81
82
# File 'lib/action_controller/request.rb', line 80

def content_length
  super.to_i
end

#content_typeObject

The MIME type of the HTTP request, such as Mime::XML.

For backward compatibility, the post format is extracted from the X-Post-Data-Format HTTP header if present.



88
89
90
91
92
93
94
95
96
# File 'lib/action_controller/request.rb', line 88

def content_type
  @content_type ||= begin
    if @env['CONTENT_TYPE'] =~ /^([^,\;]*)/
      Mime::Type.lookup($1.strip.downcase)
    else
      nil
    end
  end
end

#delete?Boolean

Is this a DELETE request? Equivalent to request.method == :delete.

Returns:

  • (Boolean)


62
63
64
# File 'lib/action_controller/request.rb', line 62

def delete?
  request_method == :delete
end

#domain(tld_length = 1) ⇒ Object

Returns the domain part of a host, such as “rubyonrails.org” in “www.rubyonrails.org”. You can specify a different tld_length, such as 2 to catch rubyonrails.co.uk in “www.rubyonrails.co.uk”.



319
320
321
322
323
# File 'lib/action_controller/request.rb', line 319

def domain(tld_length = 1)
  return nil unless named_host?(host)

  host.split('.').last(1 + tld_length).join('.')
end

#etag_matches?(etag) ⇒ Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/action_controller/request.rb', line 129

def etag_matches?(etag)
  if_none_match && if_none_match == etag
end

#form_data?Boolean

Returns:

  • (Boolean)


420
421
422
# File 'lib/action_controller/request.rb', line 420

def form_data?
  FORM_DATA_MEDIA_TYPES.include?(content_type.to_s)
end

#formatObject

Returns the Mime type for the format used in the request.

GET /posts/5.xml   | request.format => Mime::XML
GET /posts/5.xhtml | request.format => Mime::HTML
GET /posts/5       | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>


154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/action_controller/request.rb', line 154

def format
  @format ||=
    if parameters[:format]
      Mime::Type.lookup_by_extension(parameters[:format])
    elsif ActionController::Base.use_accept_header
      accepts.first
    elsif xhr?
      Mime::Type.lookup_by_extension("js")
    else
      Mime::Type.lookup_by_extension("html")
    end
end

#format=(extension) ⇒ Object

Sets the format by string extension, which can be used to force custom formats that are not controlled by the extension.

class ApplicationController < ActionController::Base
  before_filter :adjust_format_for_iphone

  private
    def adjust_format_for_iphone
      request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
    end
end


179
180
181
182
# File 'lib/action_controller/request.rb', line 179

def format=(extension)
  parameters[:format] = extension.to_s
  @format = Mime::Type.lookup_by_extension(parameters[:format])
end

#fresh?(response) ⇒ Boolean

Check response freshness (Last-Modified and ETag) against request If-Modified-Since and If-None-Match conditions. If both headers are supplied, both must match, or the request is not considered fresh.

Returns:

  • (Boolean)


136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/action_controller/request.rb', line 136

def fresh?(response)
  case
  when if_modified_since && if_none_match
    not_modified?(response.last_modified) && etag_matches?(response.etag)
  when if_modified_since
    not_modified?(response.last_modified)
  when if_none_match
    etag_matches?(response.etag)
  else
    false
  end
end

#GETObject Also known as: query_parameters

Override Rack’s GET method to support indifferent access



425
426
427
# File 'lib/action_controller/request.rb', line 425

def GET
  @env["action_controller.request.query_parameters"] ||= normalize_parameters(super)
end

#get?Boolean

Is this a GET (or HEAD) request? Equivalent to request.method == :get.

Returns:

  • (Boolean)


47
48
49
# File 'lib/action_controller/request.rb', line 47

def get?
  method == :get
end

#head?Boolean

Is this a HEAD request? Since request.method sees HEAD as :get, this method checks the actual HTTP method directly.

Returns:

  • (Boolean)


68
69
70
# File 'lib/action_controller/request.rb', line 68

def head?
  request_method == :head
end

#headersObject

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

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


75
76
77
# File 'lib/action_controller/request.rb', line 75

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

#hostObject

Returns the host for this request, such as example.com.



284
285
286
# File 'lib/action_controller/request.rb', line 284

def host
  raw_host_with_port.sub(/:\d+$/, '')
end

#host_with_portObject

Returns a host:port string for this request, such as “example.com” or “example.com:8080”.



290
291
292
# File 'lib/action_controller/request.rb', line 290

def host_with_port
  "#{host}#{port_string}"
end

#if_modified_sinceObject



115
116
117
118
119
# File 'lib/action_controller/request.rb', line 115

def if_modified_since
  if since = env['HTTP_IF_MODIFIED_SINCE']
    Time.rfc2822(since) rescue nil
  end
end

#if_none_matchObject



121
122
123
# File 'lib/action_controller/request.rb', line 121

def if_none_match
  env['HTTP_IF_NONE_MATCH']
end

#key?(key) ⇒ Boolean

Returns:

  • (Boolean)


24
25
26
# File 'lib/action_controller/request.rb', line 24

def key?(key)
  @env.key?(key)
end

#media_typeObject



98
99
100
# File 'lib/action_controller/request.rb', line 98

def media_type
  content_type.to_s
end

#methodObject

Returns the HTTP request method used for action processing as a lowercase symbol, such as :post. (Unlike #request_method, this method returns :get for a HEAD request because the two are functionally equivalent from the application’s perspective.)



42
43
44
# File 'lib/action_controller/request.rb', line 42

def method
  request_method == :head ? :get : request_method
end

#not_modified?(modified_at) ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/action_controller/request.rb', line 125

def not_modified?(modified_at)
  if_modified_since && modified_at && if_modified_since >= modified_at
end

#parametersObject Also known as: params

Returns both GET and POST parameters in a single hash.



384
385
386
# File 'lib/action_controller/request.rb', line 384

def parameters
  @parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
end

#pathObject

Returns the interpreted path to requested resource after all the installation directory of this application was taken into account.



367
368
369
370
371
# File 'lib/action_controller/request.rb', line 367

def path
  path = request_uri.to_s[/\A[^\?]*/]
  path.sub!(/\A#{ActionController::Base.relative_url_root}/, '')
  path
end

#path_parametersObject

Returns a hash with the parameters used to form the path of the request. Returned hash keys are strings:

{'action' => 'my_action', 'controller' => 'my_controller'}

See symbolized_path_parameters for symbolized keys.



405
406
407
# File 'lib/action_controller/request.rb', line 405

def path_parameters
  @env["action_controller.request.path_parameters"] ||= {}
end

#path_parameters=(parameters) ⇒ Object

:nodoc:



389
390
391
392
# File 'lib/action_controller/request.rb', line 389

def path_parameters=(parameters) #:nodoc:
  @env["action_controller.request.path_parameters"] = parameters
  @symbolized_path_parameters = @parameters = nil
end

#portObject

Returns the port number of this request as an integer.



295
296
297
298
299
300
301
# File 'lib/action_controller/request.rb', line 295

def port
  if raw_host_with_port =~ /:(\d+)$/
    $1.to_i
  else
    standard_port
  end
end

#port_stringObject

Returns a port suffix like “:8080” if the port number of this request is not the default HTTP port 80 or HTTPS port 443.



313
314
315
# File 'lib/action_controller/request.rb', line 313

def port_string
  port == standard_port ? '' : ":#{port}"
end

#POSTObject Also known as: request_parameters

Override Rack’s POST method to support indifferent access



431
432
433
# File 'lib/action_controller/request.rb', line 431

def POST
  @env["action_controller.request.request_parameters"] ||= normalize_parameters(super)
end

#post?Boolean

Is this a POST request? Equivalent to request.method == :post.

Returns:

  • (Boolean)


52
53
54
# File 'lib/action_controller/request.rb', line 52

def post?
  request_method == :post
end

#protocolObject

Returns ‘https://’ if this is an SSL request and ‘http://’ otherwise.



265
266
267
# File 'lib/action_controller/request.rb', line 265

def protocol
  ssl? ? 'https://' : 'http://'
end

#put?Boolean

Is this a PUT request? Equivalent to request.method == :put.

Returns:

  • (Boolean)


57
58
59
# File 'lib/action_controller/request.rb', line 57

def put?
  request_method == :put
end

#query_stringObject

Returns the query string, accounting for server idiosyncrasies.



336
337
338
# File 'lib/action_controller/request.rb', line 336

def query_string
  @env['QUERY_STRING'].present? ? @env['QUERY_STRING'] : (@env['REQUEST_URI'].split('?', 2)[1] || '')
end

#raw_host_with_portObject

Returns the host for this request, such as “example.com”.



275
276
277
278
279
280
281
# File 'lib/action_controller/request.rb', line 275

def raw_host_with_port
  if forwarded = env["HTTP_X_FORWARDED_HOST"]
    forwarded.split(/,\s?/).last
  else
    env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
  end
end

#raw_postObject

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



375
376
377
378
379
380
381
# File 'lib/action_controller/request.rb', line 375

def raw_post
  unless @env.include? 'RAW_POST_DATA'
    @env['RAW_POST_DATA'] = body.read(@env['CONTENT_LENGTH'].to_i)
    body.rewind if body.respond_to?(:rewind)
  end
  @env['RAW_POST_DATA']
end

#remote_ipObject

Determines originating IP address. REMOTE_ADDR is the standard but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or HTTP_X_FORWARDED_FOR are set by proxies so check for these if REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma- delimited list in the case of multiple chained proxies; the last address which is not trusted is the originating IP.



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/action_controller/request.rb', line 221

def remote_ip
  remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].scan(/[^,\s]+/)

  unless remote_addr_list.blank?
    not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES}
    return not_trusted_addrs.first unless not_trusted_addrs.empty?
  end
  remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')

  if @env.include? 'HTTP_CLIENT_IP'
    if ActionController::Base.ip_spoofing_check && remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
      # We don't know which came from the proxy, and which from the user
      raise ActionControllerError.new(<<EOM)
IP spoofing attack?!
HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
EOM
    end

    return @env['HTTP_CLIENT_IP']
  end

  if remote_ips
    while remote_ips.size > 1 && TRUSTED_PROXIES =~ remote_ips.last.strip
      remote_ips.pop
    end

    return remote_ips.last.strip
  end

  @env['REMOTE_ADDR']
end

#request_methodObject

Returns the true HTTP request method as a lowercase symbol, such as :get. If the request method is not listed in the HTTP_METHODS constant above, an UnknownHttpMethod exception is raised.



34
35
36
# File 'lib/action_controller/request.rb', line 34

def request_method
  @request_method ||= HTTP_METHOD_LOOKUP[super] || raise(UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
end

#request_uriObject

Returns the request URI, accounting for server idiosyncrasies. WEBrick includes the full URL. IIS leaves REQUEST_URI blank.



342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/action_controller/request.rb', line 342

def request_uri
  if uri = @env['REQUEST_URI']
    # Remove domain, which webrick puts into the request_uri.
    (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
  else
    # Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
    uri = @env['PATH_INFO'].to_s

    if script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
      uri = uri.sub(/#{script_filename}\//, '')
    end

    env_qs = @env['QUERY_STRING'].to_s
    uri += "?#{env_qs}" unless env_qs.empty?

    if uri.blank?
      @env.delete('REQUEST_URI')
    else
      @env['REQUEST_URI'] = uri
    end
  end
end

#reset_sessionObject



448
449
450
451
# File 'lib/action_controller/request.rb', line 448

def reset_session
  @env['rack.session.options'].delete(:id)
  @env['rack.session'] = {}
end

#server_portObject



461
462
463
# File 'lib/action_controller/request.rb', line 461

def server_port
  @env['SERVER_PORT'].to_i
end

#server_softwareObject

Returns the lowercase name of the HTTP server software.



255
256
257
# File 'lib/action_controller/request.rb', line 255

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

#sessionObject



440
441
442
# File 'lib/action_controller/request.rb', line 440

def session
  @env['rack.session'] ||= {}
end

#session=(session) ⇒ Object

:nodoc:



444
445
446
# File 'lib/action_controller/request.rb', line 444

def session=(session) #:nodoc:
  @env['rack.session'] = session
end

#session_optionsObject



453
454
455
# File 'lib/action_controller/request.rb', line 453

def session_options
  @env['rack.session.options'] ||= {}
end

#session_options=(options) ⇒ Object



457
458
459
# File 'lib/action_controller/request.rb', line 457

def session_options=(options)
  @env['rack.session.options'] = options
end

#ssl?Boolean

Is this an SSL request?

Returns:

  • (Boolean)


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

def ssl?
  @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
end

#standard_portObject

Returns the standard port number for this request’s protocol.



304
305
306
307
308
309
# File 'lib/action_controller/request.rb', line 304

def standard_port
  case protocol
    when 'https://' then 443
    else 80
  end
end

#subdomains(tld_length = 1) ⇒ Object

Returns all the subdomains as an array, so ["dev", "www"] would be returned for “dev.www.rubyonrails.org”. You can specify a different tld_length, such as 2 to catch ["www"] instead of ["www", "rubyonrails"] in “www.rubyonrails.co.uk”.



329
330
331
332
333
# File 'lib/action_controller/request.rb', line 329

def subdomains(tld_length = 1)
  return [] unless named_host?(host)
  parts = host.split('.')
  parts[0..-(tld_length+2)]
end

#symbolized_path_parametersObject

The same as path_parameters with explicitly symbolized keys.



395
396
397
# File 'lib/action_controller/request.rb', line 395

def symbolized_path_parameters
  @symbolized_path_parameters ||= path_parameters.symbolize_keys
end

#template_formatObject

Returns a symbolized version of the :format parameter of the request. If no format is given it returns :jsfor Ajax requests and :html otherwise.



187
188
189
190
191
192
193
194
195
196
197
# File 'lib/action_controller/request.rb', line 187

def template_format
  parameter_format = parameters[:format]

  if parameter_format
    parameter_format
  elsif xhr?
    :js
  else
    :html
  end
end

#urlObject

Returns the complete URL used for this request.



260
261
262
# File 'lib/action_controller/request.rb', line 260

def url
  protocol + host_with_port + request_uri
end

#xml_http_request?Boolean Also known as: xhr?

Returns true if the request’s “X-Requested-With” header contains “XMLHttpRequest”. (The Prototype Javascript library sends this header with every Ajax request.)

Returns:

  • (Boolean)


206
207
208
# File 'lib/action_controller/request.rb', line 206

def xml_http_request?
  !(@env['HTTP_X_REQUESTED_WITH'] !~ /XMLHttpRequest/i)
end