halorgium-actionpack 3.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/CHANGELOG +5179 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +409 -0
  4. data/lib/abstract_controller.rb +16 -0
  5. data/lib/abstract_controller/base.rb +158 -0
  6. data/lib/abstract_controller/callbacks.rb +113 -0
  7. data/lib/abstract_controller/exceptions.rb +12 -0
  8. data/lib/abstract_controller/helpers.rb +151 -0
  9. data/lib/abstract_controller/layouts.rb +250 -0
  10. data/lib/abstract_controller/localized_cache.rb +49 -0
  11. data/lib/abstract_controller/logger.rb +61 -0
  12. data/lib/abstract_controller/rendering_controller.rb +188 -0
  13. data/lib/action_controller.rb +72 -0
  14. data/lib/action_controller/base.rb +168 -0
  15. data/lib/action_controller/caching.rb +80 -0
  16. data/lib/action_controller/caching/actions.rb +163 -0
  17. data/lib/action_controller/caching/fragments.rb +116 -0
  18. data/lib/action_controller/caching/pages.rb +154 -0
  19. data/lib/action_controller/caching/sweeping.rb +97 -0
  20. data/lib/action_controller/deprecated.rb +4 -0
  21. data/lib/action_controller/deprecated/integration_test.rb +2 -0
  22. data/lib/action_controller/deprecated/performance_test.rb +1 -0
  23. data/lib/action_controller/dispatch/dispatcher.rb +57 -0
  24. data/lib/action_controller/metal.rb +129 -0
  25. data/lib/action_controller/metal/benchmarking.rb +73 -0
  26. data/lib/action_controller/metal/compatibility.rb +145 -0
  27. data/lib/action_controller/metal/conditional_get.rb +86 -0
  28. data/lib/action_controller/metal/configuration.rb +28 -0
  29. data/lib/action_controller/metal/cookies.rb +105 -0
  30. data/lib/action_controller/metal/exceptions.rb +55 -0
  31. data/lib/action_controller/metal/filter_parameter_logging.rb +77 -0
  32. data/lib/action_controller/metal/flash.rb +162 -0
  33. data/lib/action_controller/metal/head.rb +27 -0
  34. data/lib/action_controller/metal/helpers.rb +115 -0
  35. data/lib/action_controller/metal/hide_actions.rb +47 -0
  36. data/lib/action_controller/metal/http_authentication.rb +312 -0
  37. data/lib/action_controller/metal/layouts.rb +171 -0
  38. data/lib/action_controller/metal/mime_responds.rb +317 -0
  39. data/lib/action_controller/metal/rack_convenience.rb +27 -0
  40. data/lib/action_controller/metal/redirector.rb +22 -0
  41. data/lib/action_controller/metal/render_options.rb +103 -0
  42. data/lib/action_controller/metal/rendering_controller.rb +57 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +108 -0
  44. data/lib/action_controller/metal/rescuable.rb +13 -0
  45. data/lib/action_controller/metal/responder.rb +200 -0
  46. data/lib/action_controller/metal/session.rb +15 -0
  47. data/lib/action_controller/metal/session_management.rb +45 -0
  48. data/lib/action_controller/metal/streaming.rb +188 -0
  49. data/lib/action_controller/metal/testing.rb +39 -0
  50. data/lib/action_controller/metal/url_for.rb +41 -0
  51. data/lib/action_controller/metal/verification.rb +130 -0
  52. data/lib/action_controller/middleware.rb +38 -0
  53. data/lib/action_controller/notifications.rb +10 -0
  54. data/lib/action_controller/polymorphic_routes.rb +183 -0
  55. data/lib/action_controller/record_identifier.rb +91 -0
  56. data/lib/action_controller/testing/process.rb +111 -0
  57. data/lib/action_controller/testing/test_case.rb +345 -0
  58. data/lib/action_controller/translation.rb +13 -0
  59. data/lib/action_controller/url_rewriter.rb +204 -0
  60. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  61. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  62. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  63. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +176 -0
  64. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  65. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  66. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  67. data/lib/action_dispatch.rb +70 -0
  68. data/lib/action_dispatch/http/headers.rb +33 -0
  69. data/lib/action_dispatch/http/mime_type.rb +231 -0
  70. data/lib/action_dispatch/http/mime_types.rb +23 -0
  71. data/lib/action_dispatch/http/request.rb +539 -0
  72. data/lib/action_dispatch/http/response.rb +290 -0
  73. data/lib/action_dispatch/http/status_codes.rb +42 -0
  74. data/lib/action_dispatch/http/utils.rb +20 -0
  75. data/lib/action_dispatch/middleware/callbacks.rb +50 -0
  76. data/lib/action_dispatch/middleware/params_parser.rb +79 -0
  77. data/lib/action_dispatch/middleware/rescue.rb +26 -0
  78. data/lib/action_dispatch/middleware/session/abstract_store.rb +208 -0
  79. data/lib/action_dispatch/middleware/session/cookie_store.rb +235 -0
  80. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +47 -0
  81. data/lib/action_dispatch/middleware/show_exceptions.rb +143 -0
  82. data/lib/action_dispatch/middleware/stack.rb +116 -0
  83. data/lib/action_dispatch/middleware/static.rb +44 -0
  84. data/lib/action_dispatch/middleware/string_coercion.rb +29 -0
  85. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +24 -0
  86. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +26 -0
  87. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +10 -0
  88. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +29 -0
  89. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +2 -0
  90. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +10 -0
  91. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +21 -0
  92. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +2 -0
  93. data/lib/action_dispatch/routing.rb +381 -0
  94. data/lib/action_dispatch/routing/deprecated_mapper.rb +878 -0
  95. data/lib/action_dispatch/routing/mapper.rb +327 -0
  96. data/lib/action_dispatch/routing/route.rb +49 -0
  97. data/lib/action_dispatch/routing/route_set.rb +497 -0
  98. data/lib/action_dispatch/testing/assertions.rb +8 -0
  99. data/lib/action_dispatch/testing/assertions/dom.rb +35 -0
  100. data/lib/action_dispatch/testing/assertions/model.rb +19 -0
  101. data/lib/action_dispatch/testing/assertions/response.rb +145 -0
  102. data/lib/action_dispatch/testing/assertions/routing.rb +144 -0
  103. data/lib/action_dispatch/testing/assertions/selector.rb +639 -0
  104. data/lib/action_dispatch/testing/assertions/tag.rb +123 -0
  105. data/lib/action_dispatch/testing/integration.rb +504 -0
  106. data/lib/action_dispatch/testing/performance_test.rb +15 -0
  107. data/lib/action_dispatch/testing/test_request.rb +83 -0
  108. data/lib/action_dispatch/testing/test_response.rb +131 -0
  109. data/lib/action_pack.rb +24 -0
  110. data/lib/action_pack/version.rb +9 -0
  111. data/lib/action_view.rb +58 -0
  112. data/lib/action_view/base.rb +308 -0
  113. data/lib/action_view/context.rb +44 -0
  114. data/lib/action_view/erb/util.rb +48 -0
  115. data/lib/action_view/helpers.rb +62 -0
  116. data/lib/action_view/helpers/active_model_helper.rb +306 -0
  117. data/lib/action_view/helpers/ajax_helper.rb +68 -0
  118. data/lib/action_view/helpers/asset_tag_helper.rb +830 -0
  119. data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
  120. data/lib/action_view/helpers/cache_helper.rb +39 -0
  121. data/lib/action_view/helpers/capture_helper.rb +168 -0
  122. data/lib/action_view/helpers/date_helper.rb +988 -0
  123. data/lib/action_view/helpers/debug_helper.rb +38 -0
  124. data/lib/action_view/helpers/form_helper.rb +1102 -0
  125. data/lib/action_view/helpers/form_options_helper.rb +600 -0
  126. data/lib/action_view/helpers/form_tag_helper.rb +495 -0
  127. data/lib/action_view/helpers/javascript_helper.rb +208 -0
  128. data/lib/action_view/helpers/number_helper.rb +311 -0
  129. data/lib/action_view/helpers/prototype_helper.rb +1309 -0
  130. data/lib/action_view/helpers/raw_output_helper.rb +9 -0
  131. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  132. data/lib/action_view/helpers/record_tag_helper.rb +58 -0
  133. data/lib/action_view/helpers/sanitize_helper.rb +259 -0
  134. data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
  135. data/lib/action_view/helpers/tag_helper.rb +151 -0
  136. data/lib/action_view/helpers/text_helper.rb +594 -0
  137. data/lib/action_view/helpers/translation_helper.rb +39 -0
  138. data/lib/action_view/helpers/url_helper.rb +639 -0
  139. data/lib/action_view/locale/en.yml +117 -0
  140. data/lib/action_view/paths.rb +80 -0
  141. data/lib/action_view/render/partials.rb +342 -0
  142. data/lib/action_view/render/rendering.rb +134 -0
  143. data/lib/action_view/safe_buffer.rb +28 -0
  144. data/lib/action_view/template/error.rb +101 -0
  145. data/lib/action_view/template/handler.rb +36 -0
  146. data/lib/action_view/template/handlers.rb +52 -0
  147. data/lib/action_view/template/handlers/builder.rb +17 -0
  148. data/lib/action_view/template/handlers/erb.rb +53 -0
  149. data/lib/action_view/template/handlers/rjs.rb +18 -0
  150. data/lib/action_view/template/resolver.rb +165 -0
  151. data/lib/action_view/template/template.rb +131 -0
  152. data/lib/action_view/template/text.rb +38 -0
  153. data/lib/action_view/test_case.rb +163 -0
  154. metadata +236 -0
@@ -0,0 +1,23 @@
1
+ # Build list of Mime types for HTTP responses
2
+ # http://www.iana.org/assignments/media-types/
3
+
4
+ Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
5
+ Mime::Type.register "text/plain", :text, [], %w(txt)
6
+ Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript )
7
+ Mime::Type.register "text/css", :css
8
+ Mime::Type.register "text/calendar", :ics
9
+ Mime::Type.register "text/csv", :csv
10
+ Mime::Type.register "application/xml", :xml, %w( text/xml application/x-xml )
11
+ Mime::Type.register "application/rss+xml", :rss
12
+ Mime::Type.register "application/atom+xml", :atom
13
+ Mime::Type.register "application/x-yaml", :yaml, %w( text/yaml )
14
+
15
+ Mime::Type.register "multipart/form-data", :multipart_form
16
+ Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
17
+
18
+ # http://www.ietf.org/rfc/rfc4627.txt
19
+ # http://www.json.org/JSONRequest.html
20
+ Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
21
+
22
+ # Create Mime::ALL but do not add it to the SET.
23
+ Mime::ALL = Mime::Type.new("*/*", :all, [])
@@ -0,0 +1,539 @@
1
+ require 'tempfile'
2
+ require 'stringio'
3
+ require 'strscan'
4
+
5
+ require 'active_support/memoizable'
6
+ require 'active_support/core_ext/array/wrap'
7
+ require 'active_support/core_ext/hash/indifferent_access'
8
+ require 'active_support/core_ext/object/tap'
9
+
10
+ module ActionDispatch
11
+ class Request < Rack::Request
12
+
13
+ %w[ AUTH_TYPE GATEWAY_INTERFACE
14
+ PATH_TRANSLATED REMOTE_HOST
15
+ REMOTE_IDENT REMOTE_USER REMOTE_ADDR
16
+ SERVER_NAME SERVER_PROTOCOL
17
+
18
+ HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
19
+ HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
20
+ HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
21
+ define_method(env.sub(/^HTTP_/n, '').downcase) do
22
+ @env[env]
23
+ end
24
+ end
25
+
26
+ def key?(key)
27
+ @env.key?(key)
28
+ end
29
+
30
+ HTTP_METHODS = %w(get head put post delete options)
31
+ HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
32
+
33
+ # Returns the true HTTP request \method as a lowercase symbol, such as
34
+ # <tt>:get</tt>. If the request \method is not listed in the HTTP_METHODS
35
+ # constant above, an UnknownHttpMethod exception is raised.
36
+ def request_method
37
+ HTTP_METHOD_LOOKUP[super] || raise(ActionController::UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
38
+ end
39
+
40
+ # Returns the HTTP request \method used for action processing as a
41
+ # lowercase symbol, such as <tt>:post</tt>. (Unlike #request_method, this
42
+ # method returns <tt>:get</tt> for a HEAD request because the two are
43
+ # functionally equivalent from the application's perspective.)
44
+ def method
45
+ request_method == :head ? :get : request_method
46
+ end
47
+
48
+ # Is this a GET (or HEAD) request? Equivalent to <tt>request.method == :get</tt>.
49
+ def get?
50
+ method == :get
51
+ end
52
+
53
+ # Is this a POST request? Equivalent to <tt>request.method == :post</tt>.
54
+ def post?
55
+ request_method == :post
56
+ end
57
+
58
+ # Is this a PUT request? Equivalent to <tt>request.method == :put</tt>.
59
+ def put?
60
+ request_method == :put
61
+ end
62
+
63
+ # Is this a DELETE request? Equivalent to <tt>request.method == :delete</tt>.
64
+ def delete?
65
+ request_method == :delete
66
+ end
67
+
68
+ # Is this a HEAD request? Since <tt>request.method</tt> sees HEAD as <tt>:get</tt>,
69
+ # this \method checks the actual HTTP \method directly.
70
+ def head?
71
+ request_method == :head
72
+ end
73
+
74
+ # Provides access to the request's HTTP headers, for example:
75
+ #
76
+ # request.headers["Content-Type"] # => "text/plain"
77
+ def headers
78
+ Http::Headers.new(@env)
79
+ end
80
+
81
+ # Returns the content length of the request as an integer.
82
+ def content_length
83
+ super.to_i
84
+ end
85
+
86
+ # The MIME type of the HTTP request, such as Mime::XML.
87
+ #
88
+ # For backward compatibility, the post \format is extracted from the
89
+ # X-Post-Data-Format HTTP header if present.
90
+ def content_type
91
+ @env["action_dispatch.request.content_type"] ||= begin
92
+ if @env['CONTENT_TYPE'] =~ /^([^,\;]*)/
93
+ Mime::Type.lookup($1.strip.downcase)
94
+ else
95
+ nil
96
+ end
97
+ end
98
+ end
99
+
100
+ def forgery_whitelisted?
101
+ method == :get || xhr? || content_type.nil? || !content_type.verify_request?
102
+ end
103
+
104
+ def media_type
105
+ content_type.to_s
106
+ end
107
+
108
+ # Returns the accepted MIME type for the request.
109
+ def accepts
110
+ @env["action_dispatch.request.accepts"] ||= begin
111
+ header = @env['HTTP_ACCEPT'].to_s.strip
112
+
113
+ if header.empty?
114
+ [content_type]
115
+ else
116
+ Mime::Type.parse(header)
117
+ end
118
+ end
119
+ end
120
+
121
+ def if_modified_since
122
+ if since = env['HTTP_IF_MODIFIED_SINCE']
123
+ Time.rfc2822(since) rescue nil
124
+ end
125
+ end
126
+
127
+ def if_none_match
128
+ env['HTTP_IF_NONE_MATCH']
129
+ end
130
+
131
+ def not_modified?(modified_at)
132
+ if_modified_since && modified_at && if_modified_since >= modified_at
133
+ end
134
+
135
+ def etag_matches?(etag)
136
+ if_none_match && if_none_match == etag
137
+ end
138
+
139
+ # Check response freshness (Last-Modified and ETag) against request
140
+ # If-Modified-Since and If-None-Match conditions. If both headers are
141
+ # supplied, both must match, or the request is not considered fresh.
142
+ def fresh?(response)
143
+ last_modified = if_modified_since
144
+ etag = if_none_match
145
+
146
+ return false unless last_modified || etag
147
+
148
+ success = true
149
+ success &&= not_modified?(response.last_modified) if last_modified
150
+ success &&= etag_matches?(response.etag) if etag
151
+ success
152
+ end
153
+
154
+ # Returns the Mime type for the \format used in the request.
155
+ #
156
+ # GET /posts/5.xml | request.format => Mime::XML
157
+ # GET /posts/5.xhtml | request.format => Mime::HTML
158
+ # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
159
+ #
160
+ def format(view_path = [])
161
+ formats.first
162
+ end
163
+
164
+ def formats
165
+ accept = @env['HTTP_ACCEPT']
166
+
167
+ @env["action_dispatch.request.formats"] ||=
168
+ if parameters[:format]
169
+ [Mime[parameters[:format]]]
170
+ elsif xhr? || (accept && !accept.include?(?,))
171
+ accepts
172
+ else
173
+ [Mime::HTML]
174
+ end
175
+ end
176
+
177
+ # Sets the \format by string extension, which can be used to force custom formats
178
+ # that are not controlled by the extension.
179
+ #
180
+ # class ApplicationController < ActionController::Base
181
+ # before_filter :adjust_format_for_iphone
182
+ #
183
+ # private
184
+ # def adjust_format_for_iphone
185
+ # request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
186
+ # end
187
+ # end
188
+ def format=(extension)
189
+ parameters[:format] = extension.to_s
190
+ @env["action_dispatch.request.formats"] = [Mime::Type.lookup_by_extension(parameters[:format])]
191
+ end
192
+
193
+ # Returns a symbolized version of the <tt>:format</tt> parameter of the request.
194
+ # If no \format is given it returns <tt>:js</tt>for Ajax requests and <tt>:html</tt>
195
+ # otherwise.
196
+ def template_format
197
+ parameter_format = parameters[:format]
198
+
199
+ if parameter_format
200
+ parameter_format
201
+ elsif xhr?
202
+ :js
203
+ else
204
+ :html
205
+ end
206
+ end
207
+
208
+ # Returns true if the request's "X-Requested-With" header contains
209
+ # "XMLHttpRequest". (The Prototype Javascript library sends this header with
210
+ # every Ajax request.)
211
+ def xml_http_request?
212
+ !(@env['HTTP_X_REQUESTED_WITH'] !~ /XMLHttpRequest/i)
213
+ end
214
+ alias :xhr? :xml_http_request?
215
+
216
+ # Which IP addresses are "trusted proxies" that can be stripped from
217
+ # the right-hand-side of X-Forwarded-For
218
+ TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
219
+
220
+ # Determines originating IP address. REMOTE_ADDR is the standard
221
+ # but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or
222
+ # HTTP_X_FORWARDED_FOR are set by proxies so check for these if
223
+ # REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma-
224
+ # delimited list in the case of multiple chained proxies; the last
225
+ # address which is not trusted is the originating IP.
226
+ def remote_ip
227
+ remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].scan(/[^,\s]+/)
228
+
229
+ unless remote_addr_list.blank?
230
+ not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES || addr =~ ActionController::Base.trusted_proxies}
231
+ return not_trusted_addrs.first unless not_trusted_addrs.empty?
232
+ end
233
+ remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')
234
+
235
+ if @env.include? 'HTTP_CLIENT_IP'
236
+ if ActionController::Base.ip_spoofing_check && remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
237
+ # We don't know which came from the proxy, and which from the user
238
+ raise ActionController::ActionControllerError.new(<<EOM)
239
+ IP spoofing attack?!
240
+ HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
241
+ HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
242
+ EOM
243
+ end
244
+
245
+ return @env['HTTP_CLIENT_IP']
246
+ end
247
+
248
+ if remote_ips
249
+ while remote_ips.size > 1 && (TRUSTED_PROXIES =~ remote_ips.last.strip || ActionController::Base.trusted_proxies =~ remote_ips.last.strip)
250
+ remote_ips.pop
251
+ end
252
+
253
+ return remote_ips.last.strip
254
+ end
255
+
256
+ @env['REMOTE_ADDR']
257
+ end
258
+
259
+ # Returns the lowercase name of the HTTP server software.
260
+ def server_software
261
+ (@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
262
+ end
263
+
264
+ # Returns the complete URL used for this request.
265
+ def url
266
+ protocol + host_with_port + request_uri
267
+ end
268
+
269
+ # Returns 'https://' if this is an SSL request and 'http://' otherwise.
270
+ def protocol
271
+ ssl? ? 'https://' : 'http://'
272
+ end
273
+
274
+ # Is this an SSL request?
275
+ def ssl?
276
+ @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
277
+ end
278
+
279
+ # Returns the \host for this request, such as "example.com".
280
+ def raw_host_with_port
281
+ if forwarded = env["HTTP_X_FORWARDED_HOST"]
282
+ forwarded.split(/,\s?/).last
283
+ else
284
+ env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
285
+ end
286
+ end
287
+
288
+ # Returns the host for this request, such as example.com.
289
+ def host
290
+ raw_host_with_port.sub(/:\d+$/, '')
291
+ end
292
+
293
+ # Returns a \host:\port string for this request, such as "example.com" or
294
+ # "example.com:8080".
295
+ def host_with_port
296
+ "#{host}#{port_string}"
297
+ end
298
+
299
+ # Returns the port number of this request as an integer.
300
+ def port
301
+ if raw_host_with_port =~ /:(\d+)$/
302
+ $1.to_i
303
+ else
304
+ standard_port
305
+ end
306
+ end
307
+
308
+ # Returns the standard \port number for this request's protocol.
309
+ def standard_port
310
+ case protocol
311
+ when 'https://' then 443
312
+ else 80
313
+ end
314
+ end
315
+
316
+ # Returns a \port suffix like ":8080" if the \port number of this request
317
+ # is not the default HTTP \port 80 or HTTPS \port 443.
318
+ def port_string
319
+ port == standard_port ? '' : ":#{port}"
320
+ end
321
+
322
+ def server_port
323
+ @env['SERVER_PORT'].to_i
324
+ end
325
+
326
+ # Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
327
+ # a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
328
+ def domain(tld_length = 1)
329
+ return nil unless named_host?(host)
330
+
331
+ host.split('.').last(1 + tld_length).join('.')
332
+ end
333
+
334
+ # Returns all the \subdomains as an array, so <tt>["dev", "www"]</tt> would be
335
+ # returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
336
+ # such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
337
+ # in "www.rubyonrails.co.uk".
338
+ def subdomains(tld_length = 1)
339
+ return [] unless named_host?(host)
340
+ parts = host.split('.')
341
+ parts[0..-(tld_length+2)]
342
+ end
343
+
344
+ # Returns the query string, accounting for server idiosyncrasies.
345
+ def query_string
346
+ @env['QUERY_STRING'].present? ? @env['QUERY_STRING'] : (@env['REQUEST_URI'].to_s.split('?', 2)[1] || '')
347
+ end
348
+
349
+ # Returns the request URI, accounting for server idiosyncrasies.
350
+ # WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
351
+ def request_uri
352
+ if uri = @env['REQUEST_URI']
353
+ # Remove domain, which webrick puts into the request_uri.
354
+ (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
355
+ else
356
+ # Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
357
+ uri = @env['PATH_INFO'].to_s
358
+
359
+ if script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
360
+ uri = uri.sub(/#{script_filename}\//, '')
361
+ end
362
+
363
+ env_qs = @env['QUERY_STRING'].to_s
364
+ uri += "?#{env_qs}" unless env_qs.empty?
365
+
366
+ if uri.blank?
367
+ @env.delete('REQUEST_URI')
368
+ else
369
+ @env['REQUEST_URI'] = uri
370
+ end
371
+ end
372
+ end
373
+
374
+ # Returns the interpreted \path to requested resource after all the installation
375
+ # directory of this application was taken into account.
376
+ def path
377
+ path = request_uri.to_s[/\A[^\?]*/]
378
+ path.sub!(/\A#{ActionController::Base.relative_url_root}/, '')
379
+ path
380
+ end
381
+
382
+ # Read the request \body. This is useful for web services that need to
383
+ # work with raw requests directly.
384
+ def raw_post
385
+ unless @env.include? 'RAW_POST_DATA'
386
+ @env['RAW_POST_DATA'] = body.read(@env['CONTENT_LENGTH'].to_i)
387
+ body.rewind if body.respond_to?(:rewind)
388
+ end
389
+ @env['RAW_POST_DATA']
390
+ end
391
+
392
+ # Returns both GET and POST \parameters in a single hash.
393
+ def parameters
394
+ @env["action_dispatch.request.parameters"] ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
395
+ end
396
+ alias_method :params, :parameters
397
+
398
+ def path_parameters=(parameters) #:nodoc:
399
+ @env.delete("action_dispatch.request.symbolized_path_parameters")
400
+ @env.delete("action_dispatch.request.parameters")
401
+ @env["action_dispatch.request.path_parameters"] = parameters
402
+ end
403
+
404
+ # The same as <tt>path_parameters</tt> with explicitly symbolized keys.
405
+ def symbolized_path_parameters
406
+ @env["action_dispatch.request.symbolized_path_parameters"] ||= path_parameters.symbolize_keys
407
+ end
408
+
409
+ # Returns a hash with the \parameters used to form the \path of the request.
410
+ # Returned hash keys are strings:
411
+ #
412
+ # {'action' => 'my_action', 'controller' => 'my_controller'}
413
+ #
414
+ # See <tt>symbolized_path_parameters</tt> for symbolized keys.
415
+ def path_parameters
416
+ @env["action_dispatch.request.path_parameters"] ||= {}
417
+ end
418
+
419
+ # The request body is an IO input stream. If the RAW_POST_DATA environment
420
+ # variable is already set, wrap it in a StringIO.
421
+ def body
422
+ if raw_post = @env['RAW_POST_DATA']
423
+ raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
424
+ StringIO.new(raw_post)
425
+ else
426
+ @env['rack.input']
427
+ end
428
+ end
429
+
430
+ def form_data?
431
+ FORM_DATA_MEDIA_TYPES.include?(content_type.to_s)
432
+ end
433
+
434
+ # Override Rack's GET method to support indifferent access
435
+ def GET
436
+ @env["action_dispatch.request.query_parameters"] ||= normalize_parameters(super)
437
+ end
438
+ alias_method :query_parameters, :GET
439
+
440
+ # Override Rack's POST method to support indifferent access
441
+ def POST
442
+ @env["action_dispatch.request.request_parameters"] ||= normalize_parameters(super)
443
+ end
444
+ alias_method :request_parameters, :POST
445
+
446
+ def body_stream #:nodoc:
447
+ @env['rack.input']
448
+ end
449
+
450
+ def reset_session
451
+ self.session_options.delete(:id)
452
+ self.session = {}
453
+ end
454
+
455
+ def session=(session) #:nodoc:
456
+ @env['rack.session'] = session
457
+ end
458
+
459
+ def session_options=(options)
460
+ @env['rack.session.options'] = options
461
+ end
462
+
463
+ def flash
464
+ session['flash'] || {}
465
+ end
466
+
467
+ # Receives an array of mimes and return the first user sent mime that
468
+ # matches the order array.
469
+ #
470
+ def negotiate_mime(order)
471
+ formats.each do |priority|
472
+ if priority == Mime::ALL
473
+ return order.first
474
+ elsif order.include?(priority)
475
+ return priority
476
+ end
477
+ end
478
+
479
+ order.include?(Mime::ALL) ? formats.first : nil
480
+ end
481
+
482
+ private
483
+
484
+ def named_host?(host)
485
+ !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
486
+ end
487
+
488
+ module UploadedFile
489
+ def self.extended(object)
490
+ object.class_eval do
491
+ attr_accessor :original_path, :content_type
492
+ alias_method :local_path, :path
493
+ end
494
+ end
495
+
496
+ # Take the basename of the upload's original filename.
497
+ # This handles the full Windows paths given by Internet Explorer
498
+ # (and perhaps other broken user agents) without affecting
499
+ # those which give the lone filename.
500
+ # The Windows regexp is adapted from Perl's File::Basename.
501
+ def original_filename
502
+ unless defined? @original_filename
503
+ @original_filename =
504
+ unless original_path.blank?
505
+ if original_path =~ /^(?:.*[:\\\/])?(.*)/m
506
+ $1
507
+ else
508
+ File.basename original_path
509
+ end
510
+ end
511
+ end
512
+ @original_filename
513
+ end
514
+ end
515
+
516
+ # Convert nested Hashs to HashWithIndifferentAccess and replace
517
+ # file upload hashs with UploadedFile objects
518
+ def normalize_parameters(value)
519
+ case value
520
+ when Hash
521
+ if value.has_key?(:tempfile)
522
+ upload = value[:tempfile]
523
+ upload.extend(UploadedFile)
524
+ upload.original_path = value[:filename]
525
+ upload.content_type = value[:type]
526
+ upload
527
+ else
528
+ h = {}
529
+ value.each { |k, v| h[k] = normalize_parameters(v) }
530
+ h.with_indifferent_access
531
+ end
532
+ when Array
533
+ value.map { |e| normalize_parameters(e) }
534
+ else
535
+ value
536
+ end
537
+ end
538
+ end
539
+ end