Class: Rack::Request

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

Overview

Rack::Request provides a convenient interface to a Rack environment. It is stateless, the environment env passed to the constructor will be directly modified.

req = Rack::Request.new(env)
req.post?
req.params["data"]

The environment hash passed will store a reference to the Request object instantiated so that it will only instantiate if an instance of the Request object doesn’t already exist.

Constant Summary collapse

FORM_DATA_MEDIA_TYPES =

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

[
  'application/x-www-form-urlencoded',
  'multipart/form-data'
]
PARSEABLE_DATA_MEDIA_TYPES =

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

[
  'multipart/related',
  'multipart/mixed'
]
DEFAULT_PORTS =

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

{ 'http' => 80, 'https' => 443, 'coffee' => 80 }

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env) ⇒ Request

Returns a new instance of Request.



20
21
22
# File 'lib/rack/request.rb', line 20

def initialize(env)
  @env = env
end

Instance Attribute Details

#envObject (readonly)

The environment of the request.



18
19
20
# File 'lib/rack/request.rb', line 18

def env
  @env
end

Instance Method Details

#[](key) ⇒ Object

shortcut for request.params



266
267
268
# File 'lib/rack/request.rb', line 266

def [](key)
  params[key.to_s]
end

#[]=(key, value) ⇒ Object

shortcut for request.params = value

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



273
274
275
# File 'lib/rack/request.rb', line 273

def []=(key, value)
  params[key.to_s] = value
end

#accept_encodingObject



333
334
335
336
337
338
339
340
341
342
# File 'lib/rack/request.rb', line 333

def accept_encoding
  @env["HTTP_ACCEPT_ENCODING"].to_s.split(/\s*,\s*/).map do |part|
    encoding, parameters = part.split(/\s*;\s*/, 2)
    quality = 1.0
    if parameters and /\Aq=([\d.]+)/ =~ parameters
      quality = $1.to_f
    end
    [encoding, quality]
  end
end

#base_urlObject



314
315
316
317
318
# File 'lib/rack/request.rb', line 314

def base_url
  url = "#{scheme}://#{host}"
  url << ":#{port}" if port != DEFAULT_PORTS[scheme]
  url
end

#bodyObject



24
# File 'lib/rack/request.rb', line 24

def body;            @env["rack.input"]                       end

#content_charsetObject

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.



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

def content_charset
  media_type_params['charset']
end

#content_lengthObject



29
# File 'lib/rack/request.rb', line 29

def content_length;  @env['CONTENT_LENGTH']                   end

#content_typeObject



31
32
33
34
# File 'lib/rack/request.rb', line 31

def content_type
  content_type = @env['CONTENT_TYPE']
  content_type.nil? || content_type.empty? ? nil : content_type
end

#cookiesObject



292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/rack/request.rb', line 292

def cookies
  hash   = @env["rack.request.cookie_hash"] ||= {}
  string = @env["HTTP_COOKIE"]

  return hash if string == @env["rack.request.cookie_string"]
  hash.clear

  # According to RFC 2109:
  #   If multiple cookies satisfy the criteria above, they are ordered in
  #   the Cookie header such that those with more specific Path attributes
  #   precede those with less specific.  Ordering with respect to other
  #   attributes (e.g., Domain) is unspecified.
  cookies = Utils.parse_query(string, ';,') { |s| Rack::Utils.unescape(s) rescue s }
  cookies.each { |k,v| hash[k] = Array === v ? v.first : v }
  @env["rack.request.cookie_string"] = string
  hash
end

#delete?Boolean

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

Returns:

  • (Boolean)


120
# File 'lib/rack/request.rb', line 120

def delete?;  request_method == "DELETE"  end

#delete_param(k) ⇒ Object

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 is not touched.



259
260
261
262
263
# File 'lib/rack/request.rb', line 259

def delete_param(k)
  v = [ self.POST.delete(k), self.GET.delete(k) ].compact.first
  @params = nil
  v
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 also assumed to contain form-data when no Content-Type header is provided and the request_method is POST.

Returns:

  • (Boolean)


172
173
174
175
176
# File 'lib/rack/request.rb', line 172

def form_data?
  type = media_type
  meth = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD']
  (meth == 'POST' && type.nil?) || FORM_DATA_MEDIA_TYPES.include?(type)
end

#fullpathObject



329
330
331
# File 'lib/rack/request.rb', line 329

def fullpath
  query_string.empty? ? path : "#{path}?#{query_string}"
end

#GETObject

Returns the data received in the query string.



185
186
187
188
189
190
191
192
# File 'lib/rack/request.rb', line 185

def GET
  if @env["rack.request.query_string"] == query_string
    @env["rack.request.query_hash"]
  else
    @env["rack.request.query_string"] = query_string
    @env["rack.request.query_hash"]   = parse_query(query_string)
  end
end

#get?Boolean

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

Returns:

  • (Boolean)


123
# File 'lib/rack/request.rb', line 123

def get?;     request_method == "GET"     end

#head?Boolean

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

Returns:

  • (Boolean)


126
# File 'lib/rack/request.rb', line 126

def head?;    request_method == "HEAD"    end

#hostObject



110
111
112
113
# File 'lib/rack/request.rb', line 110

def host
  # Remove port number.
  host_with_port.to_s.gsub(/:\d+\z/, '')
end

#host_with_portObject



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

def 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

#ipObject



348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/rack/request.rb', line 348

def ip
  remote_addrs = split_ip_addresses(@env['REMOTE_ADDR'])
  remote_addrs = reject_trusted_ip_addresses(remote_addrs)

  return remote_addrs.first if remote_addrs.any?

  forwarded_ips = split_ip_addresses(@env['HTTP_X_FORWARDED_FOR'])

  if client_ip = @env['HTTP_CLIENT_IP']
    # If forwarded_ips doesn't include the client_ip, it might be an
    # ip spoofing attempt, so we ignore HTTP_CLIENT_IP
    return client_ip if forwarded_ips.include?(client_ip)
  end

  return reject_trusted_ip_addresses(forwarded_ips).last || @env["REMOTE_ADDR"]
end

#loggerObject



38
# File 'lib/rack/request.rb', line 38

def logger;          @env['rack.logger']                      end

#media_typeObject

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



46
47
48
# File 'lib/rack/request.rb', line 46

def media_type
  content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase
end

#media_type_paramsObject

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


55
56
57
58
59
60
# File 'lib/rack/request.rb', line 55

def media_type_params
  return {} if content_type.nil?
  Hash[*content_type.split(/\s*[;,]\s*/)[1..-1].
    collect { |s| s.split('=', 2) }.
    map { |k,v| [k.downcase, v] }.flatten]
end

#options?Boolean

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

Returns:

  • (Boolean)


129
# File 'lib/rack/request.rb', line 129

def options?; request_method == "OPTIONS" end

#paramsObject

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.



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

def params
  @params ||= self.GET.merge(self.POST)
rescue EOFError
  self.GET.dup
end

#parseable_data?Boolean

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

Returns:

  • (Boolean)


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

def parseable_data?
  PARSEABLE_DATA_MEDIA_TYPES.include?(media_type)
end

#patch?Boolean

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

Returns:

  • (Boolean)


132
# File 'lib/rack/request.rb', line 132

def patch?;   request_method == "PATCH"   end

#pathObject



325
326
327
# File 'lib/rack/request.rb', line 325

def path
  script_name + path_info
end

#path_infoObject



26
# File 'lib/rack/request.rb', line 26

def path_info;       @env["PATH_INFO"].to_s                   end

#path_info=(s) ⇒ Object



116
# File 'lib/rack/request.rb', line 116

def path_info=(s);   @env["PATH_INFO"] = s.to_s               end

#portObject



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rack/request.rb', line 96

def port
  if port = host_with_port.split(/:/)[1]
    port.to_i
  elsif port = @env['HTTP_X_FORWARDED_PORT']
    port.to_i
  elsif @env.has_key?("HTTP_X_FORWARDED_HOST")
    DEFAULT_PORTS[scheme]
  elsif @env.has_key?("HTTP_X_FORWARDED_PROTO")
    DEFAULT_PORTS[@env['HTTP_X_FORWARDED_PROTO']]
  else
    @env["SERVER_PORT"].to_i
  end
end

#POSTObject

Returns the data received in the request body.

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



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/rack/request.rb', line 198

def POST
  if @env["rack.input"].nil?
    raise "Missing rack.input"
  elsif @env["rack.request.form_input"].equal? @env["rack.input"]
    @env["rack.request.form_hash"]
  elsif form_data? || parseable_data?
    @env["rack.request.form_input"] = @env["rack.input"]
    unless @env["rack.request.form_hash"] = parse_multipart(env)
      form_vars = @env["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[-1] == ?\0

      @env["rack.request.form_vars"] = form_vars
      @env["rack.request.form_hash"] = parse_query(form_vars)

      @env["rack.input"].rewind
    end
    @env["rack.request.form_hash"]
  else
    {}
  end
end

#post?Boolean

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

Returns:

  • (Boolean)


135
# File 'lib/rack/request.rb', line 135

def post?;    request_method == "POST"    end

#put?Boolean

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

Returns:

  • (Boolean)


138
# File 'lib/rack/request.rb', line 138

def put?;     request_method == "PUT"     end

#query_stringObject



28
# File 'lib/rack/request.rb', line 28

def query_string;    @env["QUERY_STRING"].to_s                end

#refererObject Also known as: referrer

the referer of the client



283
284
285
# File 'lib/rack/request.rb', line 283

def referer
  @env['HTTP_REFERER']
end

#request_methodObject



27
# File 'lib/rack/request.rb', line 27

def request_method;  @env["REQUEST_METHOD"]                   end

#schemeObject



70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rack/request.rb', line 70

def scheme
  if @env['HTTPS'] == 'on'
    'https'
  elsif @env['HTTP_X_FORWARDED_SSL'] == 'on'
    'https'
  elsif @env['HTTP_X_FORWARDED_SCHEME']
    @env['HTTP_X_FORWARDED_SCHEME']
  elsif @env['HTTP_X_FORWARDED_PROTO']
    @env['HTTP_X_FORWARDED_PROTO'].split(',')[0]
  else
    @env["rack.url_scheme"]
  end
end

#script_nameObject



25
# File 'lib/rack/request.rb', line 25

def script_name;     @env["SCRIPT_NAME"].to_s                 end

#script_name=(s) ⇒ Object



115
# File 'lib/rack/request.rb', line 115

def script_name=(s); @env["SCRIPT_NAME"] = s.to_s             end

#sessionObject



36
# File 'lib/rack/request.rb', line 36

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

#session_optionsObject



37
# File 'lib/rack/request.rb', line 37

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

#ssl?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/rack/request.rb', line 84

def ssl?
  scheme == 'https'
end

#trace?Boolean

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

Returns:

  • (Boolean)


141
# File 'lib/rack/request.rb', line 141

def trace?;   request_method == "TRACE"   end

#trusted_proxy?(ip) ⇒ Boolean

Returns:

  • (Boolean)


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

def trusted_proxy?(ip)
  ip =~ /\A127\.0\.0\.1\Z|\A(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.|\A::1\Z|\Afd[0-9a-f]{2}:.+|\Alocalhost\Z|\Aunix\Z|\Aunix:/i
end

#update_param(k, v) ⇒ Object

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 is not touched.



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/rack/request.rb', line 237

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
  @params = nil
  nil
end

#urlObject

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



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

def url
  base_url + fullpath
end

#user_agentObject



288
289
290
# File 'lib/rack/request.rb', line 288

def user_agent
  @env['HTTP_USER_AGENT']
end

#values_at(*keys) ⇒ Object

like Hash#values_at



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

def values_at(*keys)
  keys.map{|key| params[key] }
end

#xhr?Boolean

Returns:

  • (Boolean)


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

def xhr?
  @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest"
end