halorgium-actionpack 3.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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