4 # Rack::Request provides a convenient interface to a Rack
5 # environment. It is stateless, the environment +env+ passed to the
6 # constructor will be directly modified.
8 # req = Rack::Request.new(env)
12 # The environment hash passed will store a reference to the Request object
13 # instantiated so that it will only instantiate if an instance of the Request
14 # object doesn't already exist.
17 # The environment of the request.
21 if self == Rack
::Request
22 env["rack.request"] ||= super
32 def body
; @env["rack.input"] end
33 def scheme
; @env["rack.url_scheme"] end
34 def script_name
; @env["SCRIPT_NAME"].to_s
end
35 def path_info
; @env["PATH_INFO"].to_s
end
36 def port
; @env["SERVER_PORT"].to_i
end
37 def request_method
; @env["REQUEST_METHOD"] end
38 def query_string
; @env["QUERY_STRING"].to_s
end
39 def content_length
; @env['CONTENT_LENGTH'] end
40 def content_type
; @env['CONTENT_TYPE'] end
42 # The media type (type/subtype) portion of the CONTENT_TYPE header
43 # without any media type parameters. e.g., when CONTENT_TYPE is
44 # "text/plain;charset=utf-8", the media-type is "text/plain".
46 # For more information on the use of media types in HTTP, see:
47 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
49 content_type
&& content_type
.split(/\s*[;,]\s*/, 2)[0].downcase
52 # The media type parameters provided in CONTENT_TYPE as a Hash, or
53 # an empty Hash if no CONTENT_TYPE or media-type parameters were
54 # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8",
55 # this method responds with the following Hash:
56 # { 'charset' => 'utf-8' }
58 return {} if content_type
.nil?
59 content_type
.split(/\s*[;,]\s*/)[1..-1].
60 collect
{ |s
| s
.split('=', 2) }.
61 inject({}) { |hash
,(k
,v
)| hash
[k
.downcase
] = v
; hash
}
64 # The character set of the request body if a "charset" media type
65 # parameter was given, or nil if no "charset" was specified. Note
66 # that, per RFC2616, text/* media types that specify no explicit
67 # charset are to be considered ISO-8859-1.
69 media_type_params
['charset']
74 (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '')
77 def script_name
=(s
); @env["SCRIPT_NAME"] = s
.to_s
end
78 def path_info
=(s
); @env["PATH_INFO"] = s
.to_s
end
80 def get
?; request_method
== "GET" end
81 def post
?; request_method
== "POST" end
82 def put
?; request_method
== "PUT" end
83 def delete
?; request_method
== "DELETE" end
84 def head
?; request_method
== "HEAD" end
86 # The set of form-data media-types. Requests that do not indicate
87 # one of the media types presents in this list will not be eligible
88 # for form-data / param parsing.
89 FORM_DATA_MEDIA_TYPES
= [
91 'application/x-www-form-urlencoded',
95 # Determine whether the request body contains form-data by checking
96 # the request media_type against registered form-data media-types:
97 # "application/x-www-form-urlencoded" and "multipart/form-data". The
98 # list of form-data media types can be modified through the
99 # +FORM_DATA_MEDIA_TYPES+ array.
101 FORM_DATA_MEDIA_TYPES
.include?(media_type
)
104 # Returns the data recieved in the query string.
106 if @env["rack.request.query_string"] == query_string
107 @env["rack.request.query_hash"]
109 @env["rack.request.query_string"] = query_string
110 @env["rack.request.query_hash"] =
111 Utils
.parse_nested_query(query_string
)
115 # Returns the data recieved in the request body.
117 # This method support both application/x-www-form-urlencoded and
118 # multipart/form-data.
120 if @env["rack.request.form_input"].eql
? @env["rack.input"]
121 @env["rack.request.form_hash"]
123 @env["rack.request.form_input"] = @env["rack.input"]
124 unless @env["rack.request.form_hash"] =
125 Utils
::Multipart.parse_multipart(env)
126 form_vars
= @env["rack.input"].read
128 # Fix for Safari Ajax postings that always append \0
129 form_vars
.sub
!(/\0\z/, '')
131 @env["rack.request.form_vars"] = form_vars
132 @env["rack.request.form_hash"] = Utils
.parse_nested_query(form_vars
)
135 @env["rack.input"].rewind
if @env["rack.input"].respond_to
?(:rewind)
137 # Handles exceptions raised by input streams that cannot be rewound
138 # such as when using plain CGI under Apache
141 @env["rack.request.form_hash"]
147 # The union of GET and POST data.
149 self.put
? ? self.GET
: self.GET
.update(self.POST
)
154 # shortcut for request.params[key]
159 # shortcut for request.params[key] = value
161 params
[key
.to_s
] = value
164 # like Hash#values_at
166 keys
.map
{|key
| params
[key
] }
169 # the referer of the client or '/'
171 @env['HTTP_REFERER'] || '/'
173 alias referrer referer
177 return {} unless @env["HTTP_COOKIE"]
179 if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"]
180 @env["rack.request.cookie_hash"]
182 @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"]
183 # According to RFC 2109:
184 # If multiple cookies satisfy the criteria above, they are ordered in
185 # the Cookie header such that those with more specific Path attributes
186 # precede those with less specific. Ordering with respect to other
187 # attributes (e.g., Domain) is unspecified.
188 @env["rack.request.cookie_hash"] =
189 Utils
.parse_query(@env["rack.request.cookie_string"], ';,').inject({}) {|h
,(k
,v
)|
190 h
[k
] = Array
=== v
? v
.first
: v
197 @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest"
200 # Tries to return a remake of the original request URL as a string.
205 if scheme
== "https" && port
!= 443 ||
206 scheme
== "http" && port
!= 80
216 path
= script_name
+ path_info
217 path
<< "?" << query_string
unless query_string
.empty
?
222 @env["HTTP_ACCEPT_ENCODING"].to_s
.split(/,\s*/).map
do |part
|
223 m
= /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part
) # From WEBrick
226 [m
[1], (m
[2] || 1.0).to_f
]
228 raise "Invalid value for Accept-Encoding: #{part.inspect}"
234 if addr
= @env['HTTP_X_FORWARDED_FOR']
235 addr
.split(',').last
.strip