Class: ActionController::AbstractRequest

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

Overview

CgiRequest and TestRequest provide concrete implementations.

Direct Known Subclasses

CgiRequest, TestRequest

Constant Summary collapse

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 Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#envObject (readonly)

The hash of environment variables for this request, such as { ‘RAILS_ENV’ => ‘production’ }.



16
17
18
# File 'lib/action_controller/request.rb', line 16

def env
  @env
end

Class Method Details

.clean_up_ajax_request_body!(body) ⇒ Object



475
476
477
478
# File 'lib/action_controller/request.rb', line 475

def clean_up_ajax_request_body!(body)
  body.chop! if body[-1] == 0
  body.gsub!(/&_=$/, '')
end

.extract_content_type_without_parameters(content_type_with_parameters) ⇒ Object



471
472
473
# File 'lib/action_controller/request.rb', line 471

def extract_content_type_without_parameters(content_type_with_parameters)
  $1.strip.downcase if content_type_with_parameters =~ /^([^,\;]*)/
end

.extract_multipart_boundary(content_type_with_parameters) ⇒ Object



463
464
465
466
467
468
469
# File 'lib/action_controller/request.rb', line 463

def extract_multipart_boundary(content_type_with_parameters)
  if content_type_with_parameters =~ MULTIPART_BOUNDARY
    ['multipart/form-data', $1.dup]
  else
    extract_content_type_without_parameters(content_type_with_parameters)
  end
end

.parse_multipart_form_parameters(body, boundary, content_length, env) ⇒ Object



459
460
461
# File 'lib/action_controller/request.rb', line 459

def parse_multipart_form_parameters(body, boundary, content_length, env)
  parse_request_parameters(read_multipart(body, boundary, content_length, env))
end

.parse_query_parameters(query_string) ⇒ Object



420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/action_controller/request.rb', line 420

def parse_query_parameters(query_string)
  return {} if query_string.blank?

  pairs = query_string.split('&').collect do |chunk|
    next if chunk.empty?
    key, value = chunk.split('=', 2)
    next if key.empty?
    value = value.nil? ? nil : CGI.unescape(value)
    [ CGI.unescape(key), value ]
  end.compact

  UrlEncodedPairParser.new(pairs).result
end

.parse_request_parameters(params) ⇒ Object



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

def parse_request_parameters(params)
  parser = UrlEncodedPairParser.new

  params = params.dup
  until params.empty?
    for key, value in params
      if key.blank?
        params.delete key
      elsif !key.include?('[')
        # much faster to test for the most common case first (GET)
        # and avoid the call to build_deep_hash
        parser.result[key] = get_typed_value(value[0])
        params.delete key
      elsif value.is_a?(Array)
        parser.parse(key, get_typed_value(value.shift))
        params.delete key if value.empty?
      else
        raise TypeError, "Expected array, found #{value.inspect}"
      end
    end
  end

  parser.result
end

Instance Method Details

#acceptsObject

Returns the accepted MIME type for the request



81
82
83
84
85
86
87
88
# File 'lib/action_controller/request.rb', line 81

def accepts
  @accepts ||=
    if @env['HTTP_ACCEPT'].to_s.strip.empty?
      [ content_type, Mime::ALL ].compact # make sure content_type being nil is not included
    else
      Mime::Type.parse(@env['HTTP_ACCEPT'])
    end
end

#bodyObject

The request body is an IO input stream.



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

def body
end

#content_lengthObject



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

def content_length
  @content_length ||= env['CONTENT_LENGTH'].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.



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

def content_type
  @content_type ||= Mime::Type.lookup(content_type_without_parameters)
end

#cookiesObject

:nodoc:



340
341
# File 'lib/action_controller/request.rb', line 340

def cookies #:nodoc:
end

#delete?Boolean

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

Returns:

  • (Boolean)


54
55
56
# File 'lib/action_controller/request.rb', line 54

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”.



217
218
219
220
221
# File 'lib/action_controller/request.rb', line 217

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

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

#formatObject

Returns the Mime type for the format used in the request. If there is no format available, the first of the accept types will be used. Examples:

GET /posts/5.xml   | request.format => Mime::XML
GET /posts/5.xhtml | request.format => Mime::HTML
GET /posts/5       | request.format => request.accepts.first (usually Mime::HTML for browsers)


96
97
98
# File 'lib/action_controller/request.rb', line 96

def format
  @format ||= parameters[:format] ? Mime::Type.lookup_by_extension(parameters[:format]) : accepts.first
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. Example:

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


112
113
114
115
# File 'lib/action_controller/request.rb', line 112

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

#get?Boolean

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

Returns:

  • (Boolean)


39
40
41
# File 'lib/action_controller/request.rb', line 39

def get?
  method == :get
end

#head?Boolean

Is this a HEAD request? request.method sees HEAD as :get, so check the HTTP method directly.

Returns:

  • (Boolean)


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

def head?
  request_method == :head
end

#headersObject



64
65
66
# File 'lib/action_controller/request.rb', line 64

def headers
  @env
end

#hostObject

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



187
188
# File 'lib/action_controller/request.rb', line 187

def host
end

#host_with_portObject

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



192
193
194
# File 'lib/action_controller/request.rb', line 192

def host_with_port
  @host_with_port ||= host + port_string
end

#methodObject

The HTTP request method as a lowercase symbol, such as :get. Note, HEAD is returned as :get since the two are functionally equivalent from the application’s perspective.



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

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

#parametersObject

Returns both GET and POST parameters in a single hash.



301
302
303
# File 'lib/action_controller/request.rb', line 301

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



266
267
268
269
270
271
272
# File 'lib/action_controller/request.rb', line 266

def path
  path = (uri = request_uri) ? uri.split('?').first.to_s : ''

  # Cut off the path to the installation directory if given
  path.sub!(%r/^#{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. See symbolized_path_parameters for symbolized keys.

Example:

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


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

def path_parameters
  @path_parameters ||= {}
end

#path_parameters=(parameters) ⇒ Object

:nodoc:



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

def path_parameters=(parameters) #:nodoc:
  @path_parameters = parameters
  @symbolized_path_parameters = @parameters = nil
end

#portObject

Returns the port number of this request as an integer.



197
198
199
# File 'lib/action_controller/request.rb', line 197

def port
  @port_as_int ||= @env['SERVER_PORT'].to_i
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.



211
212
213
# File 'lib/action_controller/request.rb', line 211

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

#post?Boolean

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

Returns:

  • (Boolean)


44
45
46
# File 'lib/action_controller/request.rb', line 44

def post?
  request_method == :post
end

#protocolObject

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



177
178
179
# File 'lib/action_controller/request.rb', line 177

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

#put?Boolean

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

Returns:

  • (Boolean)


49
50
51
# File 'lib/action_controller/request.rb', line 49

def put?
  request_method == :put
end

#query_parametersObject

:nodoc:



334
335
# File 'lib/action_controller/request.rb', line 334

def query_parameters #:nodoc:
end

#query_stringObject

Return the query string, accounting for server idiosyncracies.



233
234
235
236
237
238
239
# File 'lib/action_controller/request.rb', line 233

def query_string
  if uri = @env['REQUEST_URI']
    uri.split('?', 2)[1] || ''
  else
    @env['QUERY_STRING'] || ''
  end
end

#raw_postObject

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



292
293
294
295
296
297
298
# File 'lib/action_controller/request.rb', line 292

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

#relative_url_rootObject

Returns the path minus the web server relative installation directory. This can be set with the environment variable RAILS_RELATIVE_URL_ROOT. It can be automatically extracted for Apache setups. If the server is not Apache, this method returns an empty string.



278
279
280
281
282
283
284
285
286
287
# File 'lib/action_controller/request.rb', line 278

def relative_url_root
  @@relative_url_root ||= case
    when @env["RAILS_RELATIVE_URL_ROOT"]
      @env["RAILS_RELATIVE_URL_ROOT"]
    when server_software == 'apache'
      @env["SCRIPT_NAME"].to_s.sub(/\/dispatch\.(fcgi|rb|cgi)$/, '')
    else
      ''
  end
end

#remote_ipObject

Determine 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.



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/action_controller/request.rb', line 136

def remote_ip
  if TRUSTED_PROXIES !~ @env['REMOTE_ADDR']
    return @env['REMOTE_ADDR']
  end

  if @env.include? 'HTTP_CLIENT_IP'
    if @env.include? 'HTTP_X_FORWARDED_FOR'
      # 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 @env.include? 'HTTP_X_FORWARDED_FOR' then
    remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',')
    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

The true HTTP request method as a lowercase symbol, such as :get. UnknownHttpMethod is raised for invalid methods not listed in ACCEPTED_HTTP_METHODS.



20
21
22
23
24
25
26
27
28
29
# File 'lib/action_controller/request.rb', line 20

def request_method
  @request_method ||= begin
    method = ((@env['REQUEST_METHOD'] == 'POST' && !parameters[:_method].blank?) ? parameters[:_method].to_s : @env['REQUEST_METHOD']).downcase
    if ACCEPTED_HTTP_METHODS.include?(method)
      method.to_sym
    else
      raise UnknownHttpMethod, "#{method}, accepted HTTP methods are #{ACCEPTED_HTTP_METHODS.to_a.to_sentence}"
    end
  end
end

#request_parametersObject

:nodoc:



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

def request_parameters #:nodoc:
end

#request_uriObject

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



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/action_controller/request.rb', line 243

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.
    script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
    uri = @env['PATH_INFO']
    uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil?
    unless (env_qs = @env['QUERY_STRING']).nil? || env_qs.empty?
      uri << '?' << env_qs
    end

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

#reset_sessionObject

:nodoc:



350
351
# File 'lib/action_controller/request.rb', line 350

def reset_session #:nodoc:
end

#server_softwareObject

Returns the lowercase name of the HTTP server software.



166
167
168
# File 'lib/action_controller/request.rb', line 166

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

#sessionObject

:nodoc:



343
344
# File 'lib/action_controller/request.rb', line 343

def session #:nodoc:
end

#session=(session) ⇒ Object

:nodoc:



346
347
348
# File 'lib/action_controller/request.rb', line 346

def session=(session) #:nodoc:
  @session = session
end

#ssl?Boolean

Is this an SSL request?

Returns:

  • (Boolean)


182
183
184
# File 'lib/action_controller/request.rb', line 182

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

#standard_portObject

Returns the standard port number for this request’s protocol



202
203
204
205
206
207
# File 'lib/action_controller/request.rb', line 202

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”.



226
227
228
229
230
# File 'lib/action_controller/request.rb', line 226

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



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

def symbolized_path_parameters 
  @symbolized_path_parameters ||= path_parameters.symbolize_keys
end

#urlObject

Returns the complete URL used for this request



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

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)


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

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