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



488
489
490
491
# File 'lib/action_controller/request.rb', line 488

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



484
485
486
# File 'lib/action_controller/request.rb', line 484

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



476
477
478
479
480
481
482
# File 'lib/action_controller/request.rb', line 476

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, body_size, env) ⇒ Object



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

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

.parse_query_parameters(query_string) ⇒ Object



433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/action_controller/request.rb', line 433

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



447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
# File 'lib/action_controller/request.rb', line 447

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



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

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.



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

def body
end

#content_lengthObject



70
71
72
# File 'lib/action_controller/request.rb', line 70

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.



78
79
80
# File 'lib/action_controller/request.rb', line 78

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

#cookiesObject

:nodoc:



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

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



222
223
224
225
226
# File 'lib/action_controller/request.rb', line 222

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)


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

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


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

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

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

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


66
67
68
# File 'lib/action_controller/request.rb', line 66

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

#hostObject

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



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

def host
end

#host_with_portObject

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



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

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.



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

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



271
272
273
274
275
276
277
# File 'lib/action_controller/request.rb', line 271

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'}


326
327
328
# File 'lib/action_controller/request.rb', line 326

def path_parameters
  @path_parameters ||= {}
end

#path_parameters=(parameters) ⇒ Object

:nodoc:



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

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.



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

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.



216
217
218
# File 'lib/action_controller/request.rb', line 216

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.



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

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:



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

def query_parameters #:nodoc:
end

#query_stringObject

Return the query string, accounting for server idiosyncracies.



238
239
240
241
242
243
244
# File 'lib/action_controller/request.rb', line 238

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.



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

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.



283
284
285
286
287
288
289
290
291
292
# File 'lib/action_controller/request.rb', line 283

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.



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
164
165
166
167
168
# File 'lib/action_controller/request.rb', line 137

def remote_ip
  remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].split(',').collect(&:strip)

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

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:



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

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.



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/action_controller/request.rb', line 248

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:



355
356
# File 'lib/action_controller/request.rb', line 355

def reset_session #:nodoc:
end

#server_softwareObject

Returns the lowercase name of the HTTP server software.



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

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

#sessionObject

:nodoc:



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

def session #:nodoc:
end

#session=(session) ⇒ Object

:nodoc:



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

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

#ssl?Boolean

Is this an SSL request?

Returns:

  • (Boolean)


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

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

#standard_portObject

Returns the standard port number for this request’s protocol



207
208
209
210
211
212
# File 'lib/action_controller/request.rb', line 207

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



231
232
233
234
235
# File 'lib/action_controller/request.rb', line 231

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



316
317
318
# File 'lib/action_controller/request.rb', line 316

def symbolized_path_parameters 
  @symbolized_path_parameters ||= path_parameters.symbolize_keys
end

#urlObject

Returns the complete URL used for this request



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

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)


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

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