actionpack 2.1.2 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (200) hide show
  1. data/CHANGELOG +223 -7
  2. data/README +6 -12
  3. data/Rakefile +11 -11
  4. data/lib/action_controller.rb +9 -9
  5. data/lib/action_controller/assertions/response_assertions.rb +29 -78
  6. data/lib/action_controller/assertions/routing_assertions.rb +33 -33
  7. data/lib/action_controller/assertions/selector_assertions.rb +9 -5
  8. data/lib/action_controller/base.rb +227 -161
  9. data/lib/action_controller/benchmarking.rb +37 -24
  10. data/lib/action_controller/caching/actions.rb +53 -21
  11. data/lib/action_controller/caching/fragments.rb +10 -36
  12. data/lib/action_controller/caching/sweeping.rb +3 -3
  13. data/lib/action_controller/cgi_ext/session.rb +2 -22
  14. data/lib/action_controller/cgi_process.rb +8 -46
  15. data/lib/action_controller/components.rb +4 -1
  16. data/lib/action_controller/cookies.rb +10 -0
  17. data/lib/action_controller/dispatcher.rb +49 -15
  18. data/lib/action_controller/filters.rb +48 -10
  19. data/lib/action_controller/headers.rb +16 -14
  20. data/lib/action_controller/helpers.rb +2 -2
  21. data/lib/action_controller/http_authentication.rb +1 -1
  22. data/lib/action_controller/integration.rb +57 -60
  23. data/lib/action_controller/layout.rb +27 -53
  24. data/lib/action_controller/mime_responds.rb +5 -1
  25. data/lib/action_controller/mime_type.rb +64 -42
  26. data/lib/action_controller/mime_types.rb +2 -1
  27. data/lib/action_controller/performance_test.rb +16 -0
  28. data/lib/action_controller/polymorphic_routes.rb +16 -9
  29. data/lib/action_controller/rack_process.rb +303 -0
  30. data/lib/action_controller/request.rb +205 -97
  31. data/lib/action_controller/request_forgery_protection.rb +2 -2
  32. data/lib/action_controller/request_profiler.rb +0 -0
  33. data/lib/action_controller/rescue.rb +20 -115
  34. data/lib/action_controller/resources.rb +186 -83
  35. data/lib/action_controller/response.rb +140 -26
  36. data/lib/action_controller/routing.rb +28 -30
  37. data/lib/action_controller/routing/builder.rb +45 -54
  38. data/lib/action_controller/routing/optimisations.rb +31 -21
  39. data/lib/action_controller/routing/recognition_optimisation.rb +33 -27
  40. data/lib/action_controller/routing/route.rb +162 -147
  41. data/lib/action_controller/routing/route_set.rb +8 -7
  42. data/lib/action_controller/routing/routing_ext.rb +4 -1
  43. data/lib/action_controller/routing/segments.rb +50 -21
  44. data/lib/action_controller/session/cookie_store.rb +3 -2
  45. data/lib/action_controller/session/drb_server.rb +7 -7
  46. data/lib/action_controller/session_management.rb +6 -2
  47. data/lib/action_controller/streaming.rb +15 -8
  48. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  49. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  50. data/lib/action_controller/test_case.rb +66 -2
  51. data/lib/action_controller/test_process.rb +71 -66
  52. data/lib/action_controller/translation.rb +13 -0
  53. data/lib/action_controller/url_rewriter.rb +90 -13
  54. data/lib/action_controller/vendor/html-scanner/html/node.rb +9 -2
  55. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +1 -1
  56. data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -2
  57. data/lib/action_controller/verification.rb +2 -2
  58. data/lib/action_pack/version.rb +1 -1
  59. data/lib/action_view.rb +19 -11
  60. data/lib/action_view/base.rb +184 -150
  61. data/lib/action_view/helpers.rb +38 -0
  62. data/lib/action_view/helpers/active_record_helper.rb +56 -27
  63. data/lib/action_view/helpers/asset_tag_helper.rb +356 -153
  64. data/lib/action_view/helpers/atom_feed_helper.rb +74 -19
  65. data/lib/action_view/helpers/benchmark_helper.rb +3 -3
  66. data/lib/action_view/helpers/cache_helper.rb +1 -2
  67. data/lib/action_view/helpers/capture_helper.rb +19 -44
  68. data/lib/action_view/helpers/date_helper.rb +486 -296
  69. data/lib/action_view/helpers/debug_helper.rb +20 -13
  70. data/lib/action_view/helpers/form_helper.rb +71 -30
  71. data/lib/action_view/helpers/form_options_helper.rb +15 -85
  72. data/lib/action_view/helpers/form_tag_helper.rb +61 -38
  73. data/lib/action_view/helpers/javascript_helper.rb +80 -89
  74. data/lib/action_view/helpers/number_helper.rb +179 -74
  75. data/lib/action_view/helpers/prototype_helper.rb +216 -201
  76. data/lib/action_view/helpers/record_tag_helper.rb +4 -5
  77. data/lib/action_view/helpers/sanitize_helper.rb +65 -33
  78. data/lib/action_view/helpers/scriptaculous_helper.rb +2 -2
  79. data/lib/action_view/helpers/tag_helper.rb +39 -22
  80. data/lib/action_view/helpers/text_helper.rb +212 -118
  81. data/lib/action_view/helpers/translation_helper.rb +21 -0
  82. data/lib/action_view/helpers/url_helper.rb +100 -58
  83. data/lib/action_view/inline_template.rb +13 -14
  84. data/lib/action_view/locale/en.yml +91 -0
  85. data/lib/action_view/partials.rb +100 -55
  86. data/lib/action_view/paths.rb +125 -0
  87. data/lib/action_view/renderable.rb +102 -0
  88. data/lib/action_view/renderable_partial.rb +48 -0
  89. data/lib/action_view/template.rb +90 -101
  90. data/lib/action_view/template_error.rb +11 -21
  91. data/lib/action_view/template_handler.rb +8 -28
  92. data/lib/action_view/template_handlers.rb +45 -0
  93. data/lib/action_view/template_handlers/builder.rb +5 -15
  94. data/lib/action_view/template_handlers/erb.rb +9 -6
  95. data/lib/action_view/template_handlers/rjs.rb +2 -17
  96. data/lib/action_view/test_case.rb +7 -4
  97. data/test/abstract_unit.rb +4 -1
  98. data/test/active_record_unit.rb +28 -30
  99. data/test/activerecord/render_partial_with_record_identification_test.rb +25 -12
  100. data/test/controller/action_pack_assertions_test.rb +8 -37
  101. data/test/controller/addresses_render_test.rb +0 -3
  102. data/test/controller/assert_select_test.rb +51 -24
  103. data/test/controller/base_test.rb +4 -4
  104. data/test/controller/caching_test.rb +136 -66
  105. data/test/controller/capture_test.rb +1 -21
  106. data/test/controller/cgi_test.rb +157 -10
  107. data/test/controller/components_test.rb +41 -25
  108. data/test/controller/content_type_test.rb +49 -17
  109. data/test/controller/cookie_test.rb +1 -1
  110. data/test/controller/deprecation/deprecated_base_methods_test.rb +0 -3
  111. data/test/controller/dispatcher_test.rb +9 -1
  112. data/test/controller/filter_params_test.rb +2 -2
  113. data/test/controller/filters_test.rb +13 -13
  114. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  115. data/test/controller/html-scanner/node_test.rb +21 -0
  116. data/test/controller/html-scanner/sanitizer_test.rb +14 -0
  117. data/test/controller/integration_test.rb +167 -6
  118. data/test/controller/layout_test.rb +11 -68
  119. data/test/controller/logging_test.rb +46 -0
  120. data/test/controller/mime_responds_test.rb +61 -59
  121. data/test/controller/mime_type_test.rb +6 -6
  122. data/test/controller/polymorphic_routes_test.rb +37 -2
  123. data/test/controller/rack_test.rb +323 -0
  124. data/test/controller/redirect_test.rb +72 -71
  125. data/test/controller/render_test.rb +1120 -108
  126. data/test/controller/request_forgery_protection_test.rb +66 -52
  127. data/test/controller/request_test.rb +103 -146
  128. data/test/controller/rescue_test.rb +20 -24
  129. data/test/controller/resources_test.rb +408 -25
  130. data/test/controller/routing_test.rb +1774 -1774
  131. data/test/controller/send_file_test.rb +0 -4
  132. data/test/controller/session/cookie_store_test.rb +53 -1
  133. data/test/controller/test_test.rb +15 -37
  134. data/test/controller/translation_test.rb +26 -0
  135. data/test/controller/url_rewriter_test.rb +27 -28
  136. data/test/controller/view_paths_test.rb +48 -47
  137. data/test/fixtures/_top_level_partial.html.erb +1 -0
  138. data/test/fixtures/_top_level_partial_only.erb +1 -0
  139. data/test/fixtures/developers/_developer.erb +1 -0
  140. data/test/fixtures/fun/games/_game.erb +1 -0
  141. data/test/fixtures/fun/serious/games/_game.erb +1 -0
  142. data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +3 -0
  143. data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +6 -0
  144. data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +5 -0
  145. data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +2 -0
  146. data/test/fixtures/layouts/_column.html.erb +2 -0
  147. data/test/fixtures/projects/_project.erb +1 -0
  148. data/test/fixtures/public/javascripts/subdir/subdir.js +1 -0
  149. data/test/fixtures/public/stylesheets/subdir/subdir.css +1 -0
  150. data/test/fixtures/replies/_reply.erb +1 -0
  151. data/test/fixtures/test/_counter.html.erb +1 -0
  152. data/test/fixtures/test/_customer.erb +1 -1
  153. data/test/fixtures/test/_customer_with_var.erb +1 -0
  154. data/test/fixtures/test/_layout_for_block_with_args.html.erb +3 -0
  155. data/test/fixtures/test/_local_inspector.html.erb +1 -0
  156. data/test/fixtures/test/_partial_with_only_html_version.html.erb +1 -0
  157. data/test/fixtures/test/hello.builder +1 -1
  158. data/test/fixtures/test/hyphen-ated.erb +1 -0
  159. data/test/fixtures/test/implicit_content_type.atom.builder +2 -0
  160. data/test/fixtures/test/nested_layout.erb +3 -0
  161. data/test/fixtures/test/non_erb_block_content_for.builder +1 -1
  162. data/test/fixtures/test/sub_template_raise.html.erb +1 -0
  163. data/test/fixtures/test/template.erb +1 -0
  164. data/test/fixtures/test/using_layout_around_block_with_args.html.erb +1 -0
  165. data/test/template/active_record_helper_i18n_test.rb +46 -0
  166. data/test/template/active_record_helper_test.rb +24 -24
  167. data/test/template/asset_tag_helper_test.rb +161 -29
  168. data/test/template/atom_feed_helper_test.rb +114 -5
  169. data/test/template/compiled_templates_test.rb +59 -0
  170. data/test/template/date_helper_i18n_test.rb +113 -0
  171. data/test/template/date_helper_test.rb +403 -109
  172. data/test/template/form_helper_test.rb +213 -154
  173. data/test/template/form_options_helper_test.rb +249 -897
  174. data/test/template/form_tag_helper_test.rb +80 -32
  175. data/test/template/javascript_helper_test.rb +17 -18
  176. data/test/template/number_helper_i18n_test.rb +54 -0
  177. data/test/template/number_helper_test.rb +43 -13
  178. data/test/template/prototype_helper_test.rb +101 -84
  179. data/test/template/record_tag_helper_test.rb +24 -20
  180. data/test/template/render_test.rb +193 -0
  181. data/test/template/sanitize_helper_test.rb +3 -3
  182. data/test/template/tag_helper_test.rb +34 -14
  183. data/test/template/text_helper_test.rb +83 -9
  184. data/test/template/translation_helper_test.rb +28 -0
  185. data/test/template/url_helper_test.rb +55 -18
  186. metadata +57 -18
  187. data/lib/action_view/helpers/javascripts/controls.js +0 -963
  188. data/lib/action_view/helpers/javascripts/dragdrop.js +0 -972
  189. data/lib/action_view/helpers/javascripts/effects.js +0 -1120
  190. data/lib/action_view/helpers/javascripts/prototype.js +0 -4225
  191. data/lib/action_view/partial_template.rb +0 -70
  192. data/lib/action_view/template_finder.rb +0 -177
  193. data/lib/action_view/template_handlers/compilable.rb +0 -128
  194. data/test/controller/custom_handler_test.rb +0 -45
  195. data/test/controller/new_render_test.rb +0 -945
  196. data/test/fixtures/test/block_content_for.erb +0 -2
  197. data/test/fixtures/test/erb_content_for.erb +0 -2
  198. data/test/template/deprecated_erb_variable_test.rb +0 -9
  199. data/test/template/template_finder_test.rb +0 -73
  200. data/test/template/template_object_test.rb +0 -95
@@ -2,33 +2,38 @@ require 'tempfile'
2
2
  require 'stringio'
3
3
  require 'strscan'
4
4
 
5
- module ActionController
6
- # HTTP methods which are accepted by default.
7
- ACCEPTED_HTTP_METHODS = Set.new(%w( get head put post delete options ))
5
+ require 'active_support/memoizable'
8
6
 
7
+ module ActionController
9
8
  # CgiRequest and TestRequest provide concrete implementations.
10
9
  class AbstractRequest
11
- cattr_accessor :relative_url_root
12
- remove_method :relative_url_root
10
+ extend ActiveSupport::Memoizable
11
+
12
+ def self.relative_url_root=(relative_url_root)
13
+ ActiveSupport::Deprecation.warn(
14
+ "ActionController::AbstractRequest.relative_url_root= has been renamed." +
15
+ "You can now set it with config.action_controller.relative_url_root=", caller)
16
+ ActionController::Base.relative_url_root=relative_url_root
17
+ end
18
+
19
+ HTTP_METHODS = %w(get head put post delete options)
20
+ HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
13
21
 
14
22
  # The hash of environment variables for this request,
15
23
  # such as { 'RAILS_ENV' => 'production' }.
16
24
  attr_reader :env
17
25
 
18
- # The true HTTP request method as a lowercase symbol, such as <tt>:get</tt>.
26
+ # The true HTTP request \method as a lowercase symbol, such as <tt>:get</tt>.
19
27
  # UnknownHttpMethod is raised for invalid methods not listed in ACCEPTED_HTTP_METHODS.
20
28
  def request_method
21
- @request_method ||= begin
22
- method = ((@env['REQUEST_METHOD'] == 'POST' && !parameters[:_method].blank?) ? parameters[:_method].to_s : @env['REQUEST_METHOD']).downcase
23
- if ACCEPTED_HTTP_METHODS.include?(method)
24
- method.to_sym
25
- else
26
- raise UnknownHttpMethod, "#{method}, accepted HTTP methods are #{ACCEPTED_HTTP_METHODS.to_a.to_sentence}"
27
- end
28
- end
29
+ method = @env['REQUEST_METHOD']
30
+ method = parameters[:_method] if method == 'POST' && !parameters[:_method].blank?
31
+
32
+ HTTP_METHOD_LOOKUP[method] || raise(UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence}")
29
33
  end
34
+ memoize :request_method
30
35
 
31
- # The HTTP request method as a lowercase symbol, such as <tt>:get</tt>.
36
+ # The HTTP request \method as a lowercase symbol, such as <tt>:get</tt>.
32
37
  # Note, HEAD is returned as <tt>:get</tt> since the two are functionally
33
38
  # equivalent from the application's perspective.
34
39
  def method
@@ -55,57 +60,107 @@ module ActionController
55
60
  request_method == :delete
56
61
  end
57
62
 
58
- # Is this a HEAD request? <tt>request.method</tt> sees HEAD as <tt>:get</tt>,
59
- # so check the HTTP method directly.
63
+ # Is this a HEAD request? Since <tt>request.method</tt> sees HEAD as <tt>:get</tt>,
64
+ # this \method checks the actual HTTP \method directly.
60
65
  def head?
61
66
  request_method == :head
62
67
  end
63
68
 
64
- # Provides acccess to the request's HTTP headers, for example:
65
- # request.headers["Content-Type"] # => "text/plain"
69
+ # Provides access to the request's HTTP headers, for example:
70
+ #
71
+ # request.headers["Content-Type"] # => "text/plain"
66
72
  def headers
67
- @headers ||= ActionController::Http::Headers.new(@env)
73
+ ActionController::Http::Headers.new(@env)
68
74
  end
75
+ memoize :headers
69
76
 
77
+ # Returns the content length of the request as an integer.
70
78
  def content_length
71
- @content_length ||= env['CONTENT_LENGTH'].to_i
79
+ @env['CONTENT_LENGTH'].to_i
72
80
  end
81
+ memoize :content_length
73
82
 
74
83
  # The MIME type of the HTTP request, such as Mime::XML.
75
84
  #
76
- # For backward compatibility, the post format is extracted from the
85
+ # For backward compatibility, the post \format is extracted from the
77
86
  # X-Post-Data-Format HTTP header if present.
78
87
  def content_type
79
- @content_type ||= Mime::Type.lookup(content_type_without_parameters)
88
+ Mime::Type.lookup(content_type_without_parameters)
80
89
  end
90
+ memoize :content_type
81
91
 
82
- # Returns the accepted MIME type for the request
92
+ # Returns the accepted MIME type for the request.
83
93
  def accepts
84
- @accepts ||=
85
- if @env['HTTP_ACCEPT'].to_s.strip.empty?
86
- [ content_type, Mime::ALL ].compact # make sure content_type being nil is not included
87
- else
88
- Mime::Type.parse(@env['HTTP_ACCEPT'])
89
- end
94
+ header = @env['HTTP_ACCEPT'].to_s.strip
95
+
96
+ if header.empty?
97
+ [content_type, Mime::ALL].compact
98
+ else
99
+ Mime::Type.parse(header)
100
+ end
101
+ end
102
+ memoize :accepts
103
+
104
+ def if_modified_since
105
+ if since = env['HTTP_IF_MODIFIED_SINCE']
106
+ Time.rfc2822(since) rescue nil
107
+ end
90
108
  end
109
+ memoize :if_modified_since
91
110
 
92
- # Returns the Mime type for the format used in the request. If there is no format available, the first of the
93
- # accept types will be used. Examples:
111
+ def if_none_match
112
+ env['HTTP_IF_NONE_MATCH']
113
+ end
114
+
115
+ def not_modified?(modified_at)
116
+ if_modified_since && modified_at && if_modified_since >= modified_at
117
+ end
118
+
119
+ def etag_matches?(etag)
120
+ if_none_match && if_none_match == etag
121
+ end
122
+
123
+ # Check response freshness (Last-Modified and ETag) against request
124
+ # If-Modified-Since and If-None-Match conditions. If both headers are
125
+ # supplied, both must match, or the request is not considered fresh.
126
+ def fresh?(response)
127
+ case
128
+ when if_modified_since && if_none_match
129
+ not_modified?(response.last_modified) && etag_matches?(response.etag)
130
+ when if_modified_since
131
+ not_modified?(response.last_modified)
132
+ when if_none_match
133
+ etag_matches?(response.etag)
134
+ else
135
+ false
136
+ end
137
+ end
138
+
139
+ # Returns the Mime type for the \format used in the request.
94
140
  #
95
141
  # GET /posts/5.xml | request.format => Mime::XML
96
142
  # GET /posts/5.xhtml | request.format => Mime::HTML
97
- # GET /posts/5 | request.format => request.accepts.first (usually Mime::HTML for browsers)
143
+ # 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>
98
144
  def format
99
- @format ||= parameters[:format] ? Mime::Type.lookup_by_extension(parameters[:format]) : accepts.first
145
+ @format ||=
146
+ if parameters[:format]
147
+ Mime::Type.lookup_by_extension(parameters[:format])
148
+ elsif ActionController::Base.use_accept_header
149
+ accepts.first
150
+ elsif xhr?
151
+ Mime::Type.lookup_by_extension("js")
152
+ else
153
+ Mime::Type.lookup_by_extension("html")
154
+ end
100
155
  end
101
-
102
-
103
- # Sets the format by string extension, which can be used to force custom formats that are not controlled by the extension.
104
- # Example:
156
+
157
+
158
+ # Sets the \format by string extension, which can be used to force custom formats
159
+ # that are not controlled by the extension.
105
160
  #
106
161
  # class ApplicationController < ActionController::Base
107
162
  # before_filter :adjust_format_for_iphone
108
- #
163
+ #
109
164
  # private
110
165
  # def adjust_format_for_iphone
111
166
  # request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
@@ -116,6 +171,25 @@ module ActionController
116
171
  @format = Mime::Type.lookup_by_extension(parameters[:format])
117
172
  end
118
173
 
174
+ # Returns a symbolized version of the <tt>:format</tt> parameter of the request.
175
+ # If no \format is given it returns <tt>:js</tt>for Ajax requests and <tt>:html</tt>
176
+ # otherwise.
177
+ def template_format
178
+ parameter_format = parameters[:format]
179
+
180
+ if parameter_format
181
+ parameter_format
182
+ elsif xhr?
183
+ :js
184
+ else
185
+ :html
186
+ end
187
+ end
188
+
189
+ def cache_format
190
+ parameters[:format]
191
+ end
192
+
119
193
  # Returns true if the request's "X-Requested-With" header contains
120
194
  # "XMLHttpRequest". (The Prototype Javascript library sends this header with
121
195
  # every Ajax request.)
@@ -128,7 +202,7 @@ module ActionController
128
202
  # the right-hand-side of X-Forwarded-For
129
203
  TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
130
204
 
131
- # Determine originating IP address. REMOTE_ADDR is the standard
205
+ # Determines originating IP address. REMOTE_ADDR is the standard
132
206
  # but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or
133
207
  # HTTP_X_FORWARDED_FOR are set by proxies so check for these if
134
208
  # REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma-
@@ -166,44 +240,65 @@ EOM
166
240
 
167
241
  @env['REMOTE_ADDR']
168
242
  end
243
+ memoize :remote_ip
169
244
 
170
245
  # Returns the lowercase name of the HTTP server software.
171
246
  def server_software
172
247
  (@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
173
248
  end
249
+ memoize :server_software
174
250
 
175
251
 
176
- # Returns the complete URL used for this request
252
+ # Returns the complete URL used for this request.
177
253
  def url
178
254
  protocol + host_with_port + request_uri
179
255
  end
256
+ memoize :url
180
257
 
181
- # Return 'https://' if this is an SSL request and 'http://' otherwise.
258
+ # Returns 'https://' if this is an SSL request and 'http://' otherwise.
182
259
  def protocol
183
260
  ssl? ? 'https://' : 'http://'
184
261
  end
262
+ memoize :protocol
185
263
 
186
264
  # Is this an SSL request?
187
265
  def ssl?
188
266
  @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
189
267
  end
190
268
 
269
+ # Returns the \host for this request, such as "example.com".
270
+ def raw_host_with_port
271
+ if forwarded = env["HTTP_X_FORWARDED_HOST"]
272
+ forwarded.split(/,\s?/).last
273
+ else
274
+ env['HTTP_HOST'] || env['SERVER_NAME'] || "#{env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
275
+ end
276
+ end
277
+
191
278
  # Returns the host for this request, such as example.com.
192
279
  def host
280
+ raw_host_with_port.sub(/:\d+$/, '')
193
281
  end
282
+ memoize :host
194
283
 
195
- # Returns a host:port string for this request, such as example.com or
196
- # example.com:8080.
284
+ # Returns a \host:\port string for this request, such as "example.com" or
285
+ # "example.com:8080".
197
286
  def host_with_port
198
- @host_with_port ||= host + port_string
287
+ "#{host}#{port_string}"
199
288
  end
289
+ memoize :host_with_port
200
290
 
201
291
  # Returns the port number of this request as an integer.
202
292
  def port
203
- @port_as_int ||= @env['SERVER_PORT'].to_i
293
+ if raw_host_with_port =~ /:(\d+)$/
294
+ $1.to_i
295
+ else
296
+ standard_port
297
+ end
204
298
  end
299
+ memoize :port
205
300
 
206
- # Returns the standard port number for this request's protocol
301
+ # Returns the standard \port number for this request's protocol.
207
302
  def standard_port
208
303
  case protocol
209
304
  when 'https://' then 443
@@ -211,13 +306,13 @@ EOM
211
306
  end
212
307
  end
213
308
 
214
- # Returns a port suffix like ":8080" if the port number of this request
215
- # is not the default HTTP port 80 or HTTPS port 443.
309
+ # Returns a \port suffix like ":8080" if the \port number of this request
310
+ # is not the default HTTP \port 80 or HTTPS \port 443.
216
311
  def port_string
217
- (port == standard_port) ? '' : ":#{port}"
312
+ port == standard_port ? '' : ":#{port}"
218
313
  end
219
314
 
220
- # Returns the domain part of a host, such as rubyonrails.org in "www.rubyonrails.org". You can specify
315
+ # Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
221
316
  # a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
222
317
  def domain(tld_length = 1)
223
318
  return nil unless named_host?(host)
@@ -225,8 +320,9 @@ EOM
225
320
  host.split('.').last(1 + tld_length).join('.')
226
321
  end
227
322
 
228
- # Returns all the subdomains as an array, so ["dev", "www"] would be returned for "dev.www.rubyonrails.org".
229
- # You can specify a different <tt>tld_length</tt>, such as 2 to catch ["www"] instead of ["www", "rubyonrails"]
323
+ # Returns all the \subdomains as an array, so <tt>["dev", "www"]</tt> would be
324
+ # returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
325
+ # such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
230
326
  # in "www.rubyonrails.co.uk".
231
327
  def subdomains(tld_length = 1)
232
328
  return [] unless named_host?(host)
@@ -234,7 +330,7 @@ EOM
234
330
  parts[0..-(tld_length+2)]
235
331
  end
236
332
 
237
- # Return the query string, accounting for server idiosyncracies.
333
+ # Returns the query string, accounting for server idiosyncrasies.
238
334
  def query_string
239
335
  if uri = @env['REQUEST_URI']
240
336
  uri.split('?', 2)[1] || ''
@@ -242,8 +338,9 @@ EOM
242
338
  @env['QUERY_STRING'] || ''
243
339
  end
244
340
  end
341
+ memoize :query_string
245
342
 
246
- # Return the request URI, accounting for server idiosyncracies.
343
+ # Returns the request URI, accounting for server idiosyncrasies.
247
344
  # WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
248
345
  def request_uri
249
346
  if uri = @env['REQUEST_URI']
@@ -251,48 +348,36 @@ EOM
251
348
  (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
252
349
  else
253
350
  # Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
254
- script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
255
- uri = @env['PATH_INFO']
256
- uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil?
257
- unless (env_qs = @env['QUERY_STRING']).nil? || env_qs.empty?
258
- uri << '?' << env_qs
351
+ uri = @env['PATH_INFO'].to_s
352
+
353
+ if script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
354
+ uri = uri.sub(/#{script_filename}\//, '')
259
355
  end
260
356
 
261
- if uri.nil?
357
+ env_qs = @env['QUERY_STRING'].to_s
358
+ uri += "?#{env_qs}" unless env_qs.empty?
359
+
360
+ if uri.blank?
262
361
  @env.delete('REQUEST_URI')
263
- uri
264
362
  else
265
363
  @env['REQUEST_URI'] = uri
266
364
  end
267
365
  end
268
366
  end
367
+ memoize :request_uri
269
368
 
270
- # Returns the interpreted path to requested resource after all the installation directory of this application was taken into account
369
+ # Returns the interpreted \path to requested resource after all the installation
370
+ # directory of this application was taken into account.
271
371
  def path
272
372
  path = (uri = request_uri) ? uri.split('?').first.to_s : ''
273
373
 
274
374
  # Cut off the path to the installation directory if given
275
- path.sub!(%r/^#{relative_url_root}/, '')
276
- path || ''
277
- end
278
-
279
- # Returns the path minus the web server relative installation directory.
280
- # This can be set with the environment variable RAILS_RELATIVE_URL_ROOT.
281
- # It can be automatically extracted for Apache setups. If the server is not
282
- # Apache, this method returns an empty string.
283
- def relative_url_root
284
- @@relative_url_root ||= case
285
- when @env["RAILS_RELATIVE_URL_ROOT"]
286
- @env["RAILS_RELATIVE_URL_ROOT"]
287
- when server_software == 'apache'
288
- @env["SCRIPT_NAME"].to_s.sub(/\/dispatch\.(fcgi|rb|cgi)$/, '')
289
- else
290
- ''
291
- end
375
+ path.sub!(%r/^#{ActionController::Base.relative_url_root}/, '')
376
+ path || ''
292
377
  end
378
+ memoize :path
293
379
 
294
-
295
- # Read the request body. This is useful for web services that need to
380
+ # Read the request \body. This is useful for web services that need to
296
381
  # work with raw requests directly.
297
382
  def raw_post
298
383
  unless env.include? 'RAW_POST_DATA'
@@ -302,7 +387,7 @@ EOM
302
387
  env['RAW_POST_DATA']
303
388
  end
304
389
 
305
- # Returns both GET and POST parameters in a single hash.
390
+ # Returns both GET and POST \parameters in a single hash.
306
391
  def parameters
307
392
  @parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
308
393
  end
@@ -312,34 +397,56 @@ EOM
312
397
  @symbolized_path_parameters = @parameters = nil
313
398
  end
314
399
 
315
- # The same as <tt>path_parameters</tt> with explicitly symbolized keys
316
- def symbolized_path_parameters
400
+ # The same as <tt>path_parameters</tt> with explicitly symbolized keys.
401
+ def symbolized_path_parameters
317
402
  @symbolized_path_parameters ||= path_parameters.symbolize_keys
318
403
  end
319
404
 
320
- # Returns a hash with the parameters used to form the path of the request.
321
- # Returned hash keys are strings. See <tt>symbolized_path_parameters</tt> for symbolized keys.
322
- #
323
- # Example:
405
+ # Returns a hash with the \parameters used to form the \path of the request.
406
+ # Returned hash keys are strings:
324
407
  #
325
408
  # {'action' => 'my_action', 'controller' => 'my_controller'}
409
+ #
410
+ # See <tt>symbolized_path_parameters</tt> for symbolized keys.
326
411
  def path_parameters
327
412
  @path_parameters ||= {}
328
413
  end
329
414
 
415
+ # The request body is an IO input stream. If the RAW_POST_DATA environment
416
+ # variable is already set, wrap it in a StringIO.
417
+ def body
418
+ if raw_post = env['RAW_POST_DATA']
419
+ raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
420
+ StringIO.new(raw_post)
421
+ else
422
+ body_stream
423
+ end
424
+ end
425
+
426
+ def remote_addr
427
+ @env['REMOTE_ADDR']
428
+ end
330
429
 
331
- #--
332
- # Must be implemented in the concrete request
333
- #++
430
+ def referrer
431
+ @env['HTTP_REFERER']
432
+ end
433
+ alias referer referrer
334
434
 
335
- # The request body is an IO input stream.
336
- def body
435
+
436
+ def query_parameters
437
+ @query_parameters ||= self.class.parse_query_parameters(query_string)
337
438
  end
338
439
 
339
- def query_parameters #:nodoc:
440
+ def request_parameters
441
+ @request_parameters ||= parse_formatted_request_parameters
340
442
  end
341
443
 
342
- def request_parameters #:nodoc:
444
+
445
+ #--
446
+ # Must be implemented in the concrete request
447
+ #++
448
+
449
+ def body_stream #:nodoc:
343
450
  end
344
451
 
345
452
  def cookies #:nodoc:
@@ -366,8 +473,9 @@ EOM
366
473
 
367
474
  # The raw content type string with its parameters stripped off.
368
475
  def content_type_without_parameters
369
- @content_type_without_parameters ||= self.class.extract_content_type_without_parameters(content_type_with_parameters)
476
+ self.class.extract_content_type_without_parameters(content_type_with_parameters)
370
477
  end
478
+ memoize :content_type_without_parameters
371
479
 
372
480
  private
373
481
  def content_type_from_legacy_post_data_format_header