Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 261 lines (222 sloc) 8.517 kb
7ed819a Christian Neukirchen Add Rack::Response and Rack::Utils
chneukirchen authored
1 require 'rack/utils'
2
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
3 module Rack
376fa1e Christian Neukirchen Add RDocs
chneukirchen authored
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.
7 #
8 # req = Rack::Request.new(env)
9 # req.post?
10 # req.params["data"]
eefbed8 Matt Todd Added Rack::Request initialization memoization to reduce repetitive inst...
mtodd authored
11 #
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.
230d62c Christian Neukirchen Fix trailing whitespace. Sigh.
chneukirchen authored
15
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
16 class Request
376fa1e Christian Neukirchen Add RDocs
chneukirchen authored
17 # The environment of the request.
05ab0f9 Christian Neukirchen More convenience for Rack::Request
chneukirchen authored
18 attr_reader :env
230d62c Christian Neukirchen Fix trailing whitespace. Sigh.
chneukirchen authored
19
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
20 def initialize(env)
21 @env = env
22 end
23
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
24 def body; @env["rack.input"] end
25 def scheme; @env["rack.url_scheme"] end
26 def script_name; @env["SCRIPT_NAME"].to_s end
27 def path_info; @env["PATH_INFO"].to_s end
28 def port; @env["SERVER_PORT"].to_i end
29 def request_method; @env["REQUEST_METHOD"] end
30 def query_string; @env["QUERY_STRING"].to_s end
31 def content_length; @env['CONTENT_LENGTH'] end
32 def content_type; @env['CONTENT_TYPE'] end
33 def session; @env['rack.session'] ||= {} end
34 def session_options; @env['rack.session.options'] ||= {} end
df22480 Joshua Peek rack.logger specification
josh authored
35 def logger; @env['rack.logger'] end
fe40ec2 Christian Neukirchen Fix that Request assumes form-data even when Content-Type says otherwise
chneukirchen authored
36
37 # The media type (type/subtype) portion of the CONTENT_TYPE header
38 # without any media type parameters. e.g., when CONTENT_TYPE is
39 # "text/plain;charset=utf-8", the media-type is "text/plain".
40 #
41 # For more information on the use of media types in HTTP, see:
42 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
43 def media_type
939fa7d TJ Holowaychuk Refactored Rack::Request#media_type
tj authored
44 content_type && content_type.split(/\s*[;,]\s*/, 2).first.downcase
fe40ec2 Christian Neukirchen Fix that Request assumes form-data even when Content-Type says otherwise
chneukirchen authored
45 end
46
47 # The media type parameters provided in CONTENT_TYPE as a Hash, or
48 # an empty Hash if no CONTENT_TYPE or media-type parameters were
49 # provided. e.g., when the CONTENT_TYPE is "text/plain;charset=utf-8",
50 # this method responds with the following Hash:
51 # { 'charset' => 'utf-8' }
52 def media_type_params
53 return {} if content_type.nil?
54 content_type.split(/\s*[;,]\s*/)[1..-1].
55 collect { |s| s.split('=', 2) }.
56 inject({}) { |hash,(k,v)| hash[k.downcase] = v ; hash }
57 end
58
59 # The character set of the request body if a "charset" media type
60 # parameter was given, or nil if no "charset" was specified. Note
61 # that, per RFC2616, text/* media types that specify no explicit
62 # charset are to be considered ISO-8859-1.
63 def content_charset
64 media_type_params['charset']
65 end
a18fc32 Christian Neukirchen Rename Request#method to #request_method to not confuse stdlibs
chneukirchen authored
66
fb32ff7 Joshua Peek Request#host knows about forwared host [#77 state:resolved]
josh authored
67 def host_with_port
68 if forwarded = @env["HTTP_X_FORWARDED_HOST"]
69 forwarded.split(/,\s?/).last
70 else
71 @env['HTTP_HOST'] || "#{@env['SERVER_NAME'] || @env['SERVER_ADDR']}:#{@env['SERVER_PORT']}"
72 end
73 end
74
c95b751 Christian Neukirchen Remove the port number of HTTP_HOST and SERVER_NAME
chneukirchen authored
75 def host
76 # Remove port number.
fb32ff7 Joshua Peek Request#host knows about forwared host [#77 state:resolved]
josh authored
77 host_with_port.to_s.gsub(/:\d+\z/, '')
c95b751 Christian Neukirchen Remove the port number of HTTP_HOST and SERVER_NAME
chneukirchen authored
78 end
79
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
80 def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end
81 def path_info=(s); @env["PATH_INFO"] = s.to_s end
a18fc32 Christian Neukirchen Rename Request#method to #request_method to not confuse stdlibs
chneukirchen authored
82
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
83 def get?; request_method == "GET" end
84 def post?; request_method == "POST" end
85 def put?; request_method == "PUT" end
86 def delete?; request_method == "DELETE" end
87 def head?; request_method == "HEAD" end
fe40ec2 Christian Neukirchen Fix that Request assumes form-data even when Content-Type says otherwise
chneukirchen authored
88
89 # The set of form-data media-types. Requests that do not indicate
90 # one of the media types presents in this list will not be eligible
91 # for form-data / param parsing.
92 FORM_DATA_MEDIA_TYPES = [
93 nil,
94 'application/x-www-form-urlencoded',
95 'multipart/form-data'
96 ]
97
6674f36 better multipart handling
eTM authored
98 # The set of media-types. Requests that do not indicate
99 # one of the media types presents in this list will not be eligible
100 # for param parsing like soap attachments or generic multiparts
101 PARSEABLE_DATA_MEDIA_TYPES = [
102 'multipart/related',
103 'multipart/mixed'
df22480 Joshua Peek rack.logger specification
josh authored
104 ]
6674f36 better multipart handling
eTM authored
105
fe40ec2 Christian Neukirchen Fix that Request assumes form-data even when Content-Type says otherwise
chneukirchen authored
106 # Determine whether the request body contains form-data by checking
107 # the request media_type against registered form-data media-types:
108 # "application/x-www-form-urlencoded" and "multipart/form-data". The
109 # list of form-data media types can be modified through the
110 # +FORM_DATA_MEDIA_TYPES+ array.
111 def form_data?
112 FORM_DATA_MEDIA_TYPES.include?(media_type)
113 end
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
114
6674f36 better multipart handling
eTM authored
115 # Determine whether the request body contains data by checking
116 # the request media_type against registered parse-data media-types
117 def parseable_data?
118 PARSEABLE_DATA_MEDIA_TYPES.include?(media_type)
119 end
120
376fa1e Christian Neukirchen Add RDocs
chneukirchen authored
121 # Returns the data recieved in the query string.
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
122 def GET
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
123 if @env["rack.request.query_string"] == query_string
124 @env["rack.request.query_hash"]
6c80c6c Christian Neukirchen Cache the parsed things in Rack::Request
chneukirchen authored
125 else
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
126 @env["rack.request.query_string"] = query_string
127 @env["rack.request.query_hash"] =
128 Utils.parse_nested_query(query_string)
6c80c6c Christian Neukirchen Cache the parsed things in Rack::Request
chneukirchen authored
129 end
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
130 end
131
376fa1e Christian Neukirchen Add RDocs
chneukirchen authored
132 # Returns the data recieved in the request body.
133 #
134 # This method support both application/x-www-form-urlencoded and
135 # multipart/form-data.
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
136 def POST
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
137 if @env["rack.input"].nil?
01c1770 Jeremy Kemper Rack::Request#POST raises if rack.input is missing instead of returning ...
jeremy authored
138 raise "Missing rack.input"
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
139 elsif @env["rack.request.form_input"].eql? @env["rack.input"]
140 @env["rack.request.form_hash"]
6674f36 better multipart handling
eTM authored
141 elsif form_data? || parseable_data?
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
142 @env["rack.request.form_input"] = @env["rack.input"]
143 unless @env["rack.request.form_hash"] =
144 Utils::Multipart.parse_multipart(env)
145 form_vars = @env["rack.input"].read
0f081dd Joshua Peek Clean up Safari's ajax POST body
josh authored
146
147 # Fix for Safari Ajax postings that always append \0
148 form_vars.sub!(/\0\z/, '')
149
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
150 @env["rack.request.form_vars"] = form_vars
151 @env["rack.request.form_hash"] = Utils.parse_nested_query(form_vars)
3513f4f Joshua Peek Add tests for multipart uploads. Also ensure multipart parser tries to r...
josh authored
152
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
153 @env["rack.input"].rewind
4fe5360 Christian Neukirchen Make Rack::Request read multipart form data
chneukirchen authored
154 end
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
155 @env["rack.request.form_hash"]
fe40ec2 Christian Neukirchen Fix that Request assumes form-data even when Content-Type says otherwise
chneukirchen authored
156 else
157 {}
6c80c6c Christian Neukirchen Cache the parsed things in Rack::Request
chneukirchen authored
158 end
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
159 end
160
376fa1e Christian Neukirchen Add RDocs
chneukirchen authored
161 # The union of GET and POST data.
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
162 def params
8d01dc0 Avoid slurping or parsing request body on PUT requests
Eric Wong authored
163 self.put? ? self.GET : self.GET.update(self.POST)
67a7507 Christian Neukirchen handle EOFError exception in Request#params
chneukirchen authored
164 rescue EOFError => e
165 self.GET
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
166 end
167
de7411c Michael Fellinger add some features to Request and the corresponding tests for them
manveru authored
168 # shortcut for request.params[key]
169 def [](key)
170 params[key.to_s]
171 end
172
173 # shortcut for request.params[key] = value
174 def []=(key, value)
175 params[key.to_s] = value
176 end
177
178 # like Hash#values_at
179 def values_at(*keys)
180 keys.map{|key| params[key] }
181 end
182
183 # the referer of the client or '/'
184 def referer
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
185 @env['HTTP_REFERER'] || '/'
de7411c Michael Fellinger add some features to Request and the corresponding tests for them
manveru authored
186 end
187 alias referrer referer
188
e2a1a64 Joshua Peek Request#user_agent
josh authored
189 def user_agent
190 @env['HTTP_USER_AGENT']
191 end
de7411c Michael Fellinger add some features to Request and the corresponding tests for them
manveru authored
192
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
193 def cookies
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
194 return {} unless @env["HTTP_COOKIE"]
b68c2d5 Christian Neukirchen Return empty hash on lack of cookies
chneukirchen authored
195
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
196 if @env["rack.request.cookie_string"] == @env["HTTP_COOKIE"]
197 @env["rack.request.cookie_hash"]
6c80c6c Christian Neukirchen Cache the parsed things in Rack::Request
chneukirchen authored
198 else
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
199 @env["rack.request.cookie_string"] = @env["HTTP_COOKIE"]
4a08f8a Conform to RFC 2109 regarding multiple values for same cookie
Aman Gupta authored
200 # According to RFC 2109:
201 # If multiple cookies satisfy the criteria above, they are ordered in
202 # the Cookie header such that those with more specific Path attributes
203 # precede those with less specific. Ordering with respect to other
204 # attributes (e.g., Domain) is unspecified.
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
205 @env["rack.request.cookie_hash"] =
206 Utils.parse_query(@env["rack.request.cookie_string"], ';,').inject({}) {|h,(k,v)|
acb8695 Christian Neukirchen Fix cookie parsing
chneukirchen authored
207 h[k] = Array === v ? v.first : v
4a08f8a Conform to RFC 2109 regarding multiple values for same cookie
Aman Gupta authored
208 h
209 }
6c80c6c Christian Neukirchen Cache the parsed things in Rack::Request
chneukirchen authored
210 end
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
211 end
212
213 def xhr?
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
214 @env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest"
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
215 end
fd51d36 Christian Neukirchen Add Request#url
chneukirchen authored
216
376fa1e Christian Neukirchen Add RDocs
chneukirchen authored
217 # Tries to return a remake of the original request URL as a string.
fd51d36 Christian Neukirchen Add Request#url
chneukirchen authored
218 def url
219 url = scheme + "://"
220 url << host
221
222 if scheme == "https" && port != 443 ||
223 scheme == "http" && port != 80
224 url << ":#{port}"
225 end
226
234c062 Christian Neukirchen Add Request#fullpath
chneukirchen authored
227 url << fullpath
fd51d36 Christian Neukirchen Add Request#url
chneukirchen authored
228
229 url
230 end
df22480 Joshua Peek rack.logger specification
josh authored
231
3a544a7 TJ Holowaychuk Added Rack::Request#path
tj authored
232 def path
233 script_name + path_info
234 end
df22480 Joshua Peek rack.logger specification
josh authored
235
234c062 Christian Neukirchen Add Request#fullpath
chneukirchen authored
236 def fullpath
3a544a7 TJ Holowaychuk Added Rack::Request#path
tj authored
237 query_string.empty? ? path : "#{path}?#{query_string}"
234c062 Christian Neukirchen Add Request#fullpath
chneukirchen authored
238 end
0f2dab5 Christoffer Sawicki Added support for Accept-Encoding (via Request#accept_encoding and Utils...
qerub authored
239
240 def accept_encoding
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
241 @env["HTTP_ACCEPT_ENCODING"].to_s.split(/,\s*/).map do |part|
0f2dab5 Christoffer Sawicki Added support for Accept-Encoding (via Request#accept_encoding and Utils...
qerub authored
242 m = /^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/.match(part) # From WEBrick
243
244 if m
245 [m[1], (m[2] || 1.0).to_f]
246 else
247 raise "Invalid value for Accept-Encoding: #{part.inspect}"
248 end
249 end
250 end
a48eb51 Michael Fellinger Add Request#ip and corresponding spec
manveru authored
251
252 def ip
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
253 if addr = @env['HTTP_X_FORWARDED_FOR']
a48eb51 Michael Fellinger Add Request#ip and corresponding spec
manveru authored
254 addr.split(',').last.strip
255 else
71030b9 Joshua Peek Revert "Add common HTTP strings to Rack::Const"
josh authored
256 @env['REMOTE_ADDR']
a48eb51 Michael Fellinger Add Request#ip and corresponding spec
manveru authored
257 end
258 end
5f13e3d Christian Neukirchen Add Rack::Request
chneukirchen authored
259 end
260 end
Something went wrong with that request. Please try again.