actionpack 3.2.22.5 → 4.0.0.beta1

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 (265) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +641 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller.rb +1 -8
  6. data/lib/abstract_controller/asset_paths.rb +2 -2
  7. data/lib/abstract_controller/base.rb +39 -37
  8. data/lib/abstract_controller/callbacks.rb +101 -82
  9. data/lib/abstract_controller/collector.rb +7 -3
  10. data/lib/abstract_controller/helpers.rb +23 -11
  11. data/lib/abstract_controller/layouts.rb +68 -73
  12. data/lib/abstract_controller/logger.rb +1 -2
  13. data/lib/abstract_controller/rendering.rb +22 -13
  14. data/lib/abstract_controller/translation.rb +16 -1
  15. data/lib/abstract_controller/url_for.rb +6 -6
  16. data/lib/abstract_controller/view_paths.rb +1 -1
  17. data/lib/action_controller.rb +15 -6
  18. data/lib/action_controller/base.rb +46 -22
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/caching/fragments.rb +23 -53
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  23. data/lib/action_controller/log_subscriber.rb +11 -8
  24. data/lib/action_controller/metal.rb +16 -30
  25. data/lib/action_controller/metal/conditional_get.rb +76 -32
  26. data/lib/action_controller/metal/data_streaming.rb +20 -26
  27. data/lib/action_controller/metal/exceptions.rb +19 -6
  28. data/lib/action_controller/metal/flash.rb +24 -9
  29. data/lib/action_controller/metal/force_ssl.rb +32 -9
  30. data/lib/action_controller/metal/head.rb +25 -4
  31. data/lib/action_controller/metal/helpers.rb +6 -9
  32. data/lib/action_controller/metal/hide_actions.rb +1 -2
  33. data/lib/action_controller/metal/http_authentication.rb +105 -87
  34. data/lib/action_controller/metal/implicit_render.rb +1 -1
  35. data/lib/action_controller/metal/instrumentation.rb +2 -1
  36. data/lib/action_controller/metal/live.rb +141 -0
  37. data/lib/action_controller/metal/mime_responds.rb +161 -47
  38. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  39. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  40. data/lib/action_controller/metal/redirecting.rb +15 -20
  41. data/lib/action_controller/metal/renderers.rb +11 -9
  42. data/lib/action_controller/metal/rendering.rb +8 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  44. data/lib/action_controller/metal/responder.rb +20 -19
  45. data/lib/action_controller/metal/streaming.rb +12 -18
  46. data/lib/action_controller/metal/strong_parameters.rb +516 -0
  47. data/lib/action_controller/metal/testing.rb +13 -18
  48. data/lib/action_controller/metal/url_for.rb +27 -25
  49. data/lib/action_controller/model_naming.rb +12 -0
  50. data/lib/action_controller/railtie.rb +33 -17
  51. data/lib/action_controller/railties/helpers.rb +22 -0
  52. data/lib/action_controller/record_identifier.rb +18 -72
  53. data/lib/action_controller/test_case.rb +215 -123
  54. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  55. data/lib/action_dispatch.rb +27 -19
  56. data/lib/action_dispatch/http/cache.rb +63 -11
  57. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  59. data/lib/action_dispatch/http/headers.rb +27 -19
  60. data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
  61. data/lib/action_dispatch/http/mime_type.rb +145 -113
  62. data/lib/action_dispatch/http/mime_types.rb +1 -1
  63. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  64. data/lib/action_dispatch/http/parameters.rb +12 -5
  65. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  66. data/lib/action_dispatch/http/request.rb +49 -18
  67. data/lib/action_dispatch/http/response.rb +129 -35
  68. data/lib/action_dispatch/http/upload.rb +60 -17
  69. data/lib/action_dispatch/http/url.rb +53 -31
  70. data/lib/action_dispatch/journey.rb +5 -0
  71. data/lib/action_dispatch/journey/backwards.rb +5 -0
  72. data/lib/action_dispatch/journey/formatter.rb +146 -0
  73. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  74. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  75. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  76. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  77. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  78. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  79. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  80. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  81. data/lib/action_dispatch/journey/parser.rb +206 -0
  82. data/lib/action_dispatch/journey/parser.y +47 -0
  83. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  84. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  85. data/lib/action_dispatch/journey/route.rb +116 -0
  86. data/lib/action_dispatch/journey/router.rb +164 -0
  87. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  88. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  89. data/lib/action_dispatch/journey/routes.rb +75 -0
  90. data/lib/action_dispatch/journey/scanner.rb +61 -0
  91. data/lib/action_dispatch/journey/visitors.rb +189 -0
  92. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  93. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  94. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  95. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  96. data/lib/action_dispatch/middleware/cookies.rb +168 -57
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  98. data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -3
  99. data/lib/action_dispatch/middleware/flash.rb +58 -58
  100. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +31 -14
  102. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  103. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  104. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
  108. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  109. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  110. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  111. data/lib/action_dispatch/middleware/stack.rb +6 -1
  112. data/lib/action_dispatch/middleware/static.rb +5 -24
  113. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  114. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  116. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  117. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  124. data/lib/action_dispatch/railtie.rb +16 -6
  125. data/lib/action_dispatch/request/session.rb +181 -0
  126. data/lib/action_dispatch/routing.rb +41 -40
  127. data/lib/action_dispatch/routing/inspector.rb +240 -0
  128. data/lib/action_dispatch/routing/mapper.rb +501 -273
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  130. data/lib/action_dispatch/routing/redirection.rb +46 -29
  131. data/lib/action_dispatch/routing/route_set.rb +203 -164
  132. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  133. data/lib/action_dispatch/routing/url_for.rb +48 -33
  134. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  135. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  136. data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
  137. data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
  138. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  139. data/lib/action_dispatch/testing/integration.rb +41 -22
  140. data/lib/action_dispatch/testing/test_process.rb +9 -6
  141. data/lib/action_dispatch/testing/test_request.rb +7 -3
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_pack/version.rb +4 -4
  144. data/lib/action_view.rb +17 -8
  145. data/lib/action_view/base.rb +15 -34
  146. data/lib/action_view/buffers.rb +1 -1
  147. data/lib/action_view/context.rb +4 -4
  148. data/lib/action_view/dependency_tracker.rb +91 -0
  149. data/lib/action_view/digestor.rb +85 -0
  150. data/lib/action_view/flows.rb +1 -4
  151. data/lib/action_view/helpers.rb +2 -4
  152. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  153. data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
  154. data/lib/action_view/helpers/asset_url_helper.rb +354 -0
  155. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  156. data/lib/action_view/helpers/cache_helper.rb +150 -18
  157. data/lib/action_view/helpers/capture_helper.rb +42 -29
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  159. data/lib/action_view/helpers/date_helper.rb +268 -247
  160. data/lib/action_view/helpers/debug_helper.rb +10 -11
  161. data/lib/action_view/helpers/form_helper.rb +904 -547
  162. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  163. data/lib/action_view/helpers/form_tag_helper.rb +188 -88
  164. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  165. data/lib/action_view/helpers/number_helper.rb +148 -354
  166. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  167. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  168. data/lib/action_view/helpers/rendering_helper.rb +2 -4
  169. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  170. data/lib/action_view/helpers/tag_helper.rb +43 -37
  171. data/lib/action_view/helpers/tags.rb +39 -0
  172. data/lib/action_view/helpers/tags/base.rb +148 -0
  173. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  174. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  175. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  176. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  177. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  178. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  179. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  180. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  181. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  182. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  183. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  184. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  185. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  186. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  187. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  188. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  189. data/lib/action_view/helpers/tags/label.rb +65 -0
  190. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  191. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  192. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  193. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  194. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  195. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  196. data/lib/action_view/helpers/tags/select.rb +41 -0
  197. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  198. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  199. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  200. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  201. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  202. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  203. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  204. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  205. data/lib/action_view/helpers/text_helper.rb +126 -113
  206. data/lib/action_view/helpers/translation_helper.rb +32 -16
  207. data/lib/action_view/helpers/url_helper.rb +200 -271
  208. data/lib/action_view/locale/en.yml +1 -105
  209. data/lib/action_view/log_subscriber.rb +6 -4
  210. data/lib/action_view/lookup_context.rb +15 -39
  211. data/lib/action_view/model_naming.rb +12 -0
  212. data/lib/action_view/path_set.rb +9 -39
  213. data/lib/action_view/railtie.rb +6 -22
  214. data/lib/action_view/record_identifier.rb +84 -0
  215. data/lib/action_view/renderer/abstract_renderer.rb +10 -19
  216. data/lib/action_view/renderer/partial_renderer.rb +144 -81
  217. data/lib/action_view/renderer/renderer.rb +2 -19
  218. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  219. data/lib/action_view/renderer/template_renderer.rb +14 -13
  220. data/lib/action_view/routing_url_for.rb +107 -0
  221. data/lib/action_view/template.rb +22 -21
  222. data/lib/action_view/template/error.rb +22 -12
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/handlers/builder.rb +1 -1
  225. data/lib/action_view/template/handlers/erb.rb +11 -16
  226. data/lib/action_view/template/handlers/raw.rb +11 -0
  227. data/lib/action_view/template/resolver.rb +111 -83
  228. data/lib/action_view/template/text.rb +12 -8
  229. data/lib/action_view/template/types.rb +57 -0
  230. data/lib/action_view/test_case.rb +66 -43
  231. data/lib/action_view/testing/resolvers.rb +3 -2
  232. data/lib/action_view/vendor/html-scanner.rb +20 -0
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  235. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +18 -7
  236. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
  237. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  238. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  239. metadata +135 -125
  240. data/lib/action_controller/caching/actions.rb +0 -185
  241. data/lib/action_controller/caching/pages.rb +0 -187
  242. data/lib/action_controller/caching/sweeping.rb +0 -97
  243. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  244. data/lib/action_controller/metal/compatibility.rb +0 -65
  245. data/lib/action_controller/metal/session_management.rb +0 -14
  246. data/lib/action_controller/railties/paths.rb +0 -25
  247. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  248. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  249. data/lib/action_dispatch/middleware/head.rb +0 -18
  250. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  251. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  252. data/lib/action_view/asset_paths.rb +0 -142
  253. data/lib/action_view/helpers/asset_paths.rb +0 -7
  254. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  255. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  256. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  257. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  258. data/lib/sprockets/assets.rake +0 -99
  259. data/lib/sprockets/bootstrap.rb +0 -37
  260. data/lib/sprockets/compressors.rb +0 -83
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  263. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  264. data/lib/sprockets/railtie.rb +0 -62
  265. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,4 +1,3 @@
1
- require 'active_support/core_ext/file/path'
2
1
  require 'action_controller/metal/exceptions'
3
2
 
4
3
  module ActionController #:nodoc:
@@ -9,15 +8,13 @@ module ActionController #:nodoc:
9
8
 
10
9
  include ActionController::Rendering
11
10
 
12
- DEFAULT_SEND_FILE_OPTIONS = {
13
- :type => 'application/octet-stream'.freeze,
14
- :disposition => 'attachment'.freeze,
15
- }.freeze
11
+ DEFAULT_SEND_FILE_TYPE = 'application/octet-stream'.freeze #:nodoc:
12
+ DEFAULT_SEND_FILE_DISPOSITION = 'attachment'.freeze #:nodoc:
16
13
 
17
14
  protected
18
15
  # Sends the file. This uses a server-appropriate method (such as X-Sendfile)
19
16
  # via the Rack::Sendfile middleware. The header to use is set via
20
- # config.action_dispatch.x_sendfile_header.
17
+ # +config.action_dispatch.x_sendfile_header+.
21
18
  # Your server can also configure this for you by setting the X-Sendfile-Type header.
22
19
  #
23
20
  # Be careful to sanitize the path parameter if it is coming from a web
@@ -50,11 +47,11 @@ module ActionController #:nodoc:
50
47
  #
51
48
  # Show a JPEG in the browser:
52
49
  #
53
- # send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
50
+ # send_file '/path/to.jpeg', type: 'image/jpeg', disposition: 'inline'
54
51
  #
55
52
  # Show a 404 page in the browser:
56
53
  #
57
- # send_file '/path/to/404.html', :type => 'text/html; charset=utf-8', :status => 404
54
+ # send_file '/path/to/404.html', type: 'text/html; charset=utf-8', status: 404
58
55
  #
59
56
  # Read about the other Content-* HTTP headers if you'd like to
60
57
  # provide the user with more information (such as Content-Description) in
@@ -99,7 +96,7 @@ module ActionController #:nodoc:
99
96
  end
100
97
 
101
98
  # Sends the given binary data to the browser. This method is similar to
102
- # <tt>render :text => data</tt>, but also allows you to specify whether
99
+ # <tt>render text: data</tt>, but also allows you to specify whether
103
100
  # the browser should display the response as a file attachment (i.e. in a
104
101
  # download dialog) or as inline data. You may also set the content type,
105
102
  # the apparent file name, and other things.
@@ -120,15 +117,15 @@ module ActionController #:nodoc:
120
117
  #
121
118
  # Download a dynamically-generated tarball:
122
119
  #
123
- # send_data generate_tgz('dir'), :filename => 'dir.tgz'
120
+ # send_data generate_tgz('dir'), filename: 'dir.tgz'
124
121
  #
125
122
  # Display an image Active Record in the browser:
126
123
  #
127
- # send_data image.data, :type => image.content_type, :disposition => 'inline'
124
+ # send_data image.data, type: image.content_type, disposition: 'inline'
128
125
  #
129
126
  # See +send_file+ for more information on HTTP Content-* headers and caching.
130
127
  def send_data(data, options = {}) #:doc:
131
- send_file_headers! options.dup
128
+ send_file_headers! options
132
129
  render options.slice(:status, :content_type).merge(:text => data)
133
130
  end
134
131
 
@@ -136,15 +133,8 @@ module ActionController #:nodoc:
136
133
  def send_file_headers!(options)
137
134
  type_provided = options.has_key?(:type)
138
135
 
139
- options.update(DEFAULT_SEND_FILE_OPTIONS.merge(options))
140
- [:type, :disposition].each do |arg|
141
- raise ArgumentError, ":#{arg} option required" if options[arg].nil?
142
- end
143
-
144
- disposition = options[:disposition].to_s
145
- disposition += %(; filename="#{options[:filename]}") if options[:filename]
146
-
147
- content_type = options[:type]
136
+ content_type = options.fetch(:type, DEFAULT_SEND_FILE_TYPE)
137
+ raise ArgumentError, ":type option required" if content_type.nil?
148
138
 
149
139
  if content_type.is_a?(Symbol)
150
140
  extension = Mime[content_type]
@@ -153,15 +143,19 @@ module ActionController #:nodoc:
153
143
  else
154
144
  if !type_provided && options[:filename]
155
145
  # If type wasn't provided, try guessing from file extension.
156
- content_type = Mime::Type.lookup_by_extension(File.extname(options[:filename]).downcase.tr('.','')) || content_type
146
+ content_type = Mime::Type.lookup_by_extension(File.extname(options[:filename]).downcase.delete('.')) || content_type
157
147
  end
158
148
  self.content_type = content_type
159
149
  end
160
150
 
161
- headers.merge!(
162
- 'Content-Disposition' => disposition,
163
- 'Content-Transfer-Encoding' => 'binary'
164
- )
151
+ disposition = options.fetch(:disposition, DEFAULT_SEND_FILE_DISPOSITION)
152
+ unless disposition.nil?
153
+ disposition = disposition.to_s
154
+ disposition += %(; filename="#{options[:filename]}") if options[:filename]
155
+ headers['Content-Disposition'] = disposition
156
+ end
157
+
158
+ headers['Content-Transfer-Encoding'] = 'binary'
165
159
 
166
160
  response.sending_file = true
167
161
 
@@ -2,6 +2,18 @@ module ActionController
2
2
  class ActionControllerError < StandardError #:nodoc:
3
3
  end
4
4
 
5
+ class BadRequest < ActionControllerError #:nodoc:
6
+ attr_reader :original_exception
7
+
8
+ def initialize(type = nil, e = nil)
9
+ return super() unless type && e
10
+
11
+ super("Invalid #{type} parameters: #{e.message}")
12
+ @original_exception = e
13
+ set_backtrace e.backtrace
14
+ end
15
+ end
16
+
5
17
  class RenderError < ActionControllerError #:nodoc:
6
18
  end
7
19
 
@@ -13,9 +25,10 @@ module ActionController
13
25
  end
14
26
  end
15
27
 
16
- class MethodNotAllowed < ActionControllerError #:nodoc:
17
- attr_reader :allowed_methods
28
+ class ActionController::UrlGenerationError < RoutingError #:nodoc:
29
+ end
18
30
 
31
+ class MethodNotAllowed < ActionControllerError #:nodoc:
19
32
  def initialize(*allowed_methods)
20
33
  super("Only #{allowed_methods.to_sentence(:locale => :en)} requests are allowed.")
21
34
  end
@@ -30,9 +43,6 @@ module ActionController
30
43
  class MissingFile < ActionControllerError #:nodoc:
31
44
  end
32
45
 
33
- class RenderError < ActionControllerError #:nodoc:
34
- end
35
-
36
46
  class SessionOverflowError < ActionControllerError #:nodoc:
37
47
  DEFAULT_MESSAGE = 'Your session data is larger than the data column in which it is to be stored. You must increase the size of your data column if you intend to store large data.'
38
48
 
@@ -43,4 +53,7 @@ module ActionController
43
53
 
44
54
  class UnknownHttpMethod < ActionControllerError #:nodoc:
45
55
  end
46
- end
56
+
57
+ class UnknownFormat < ActionControllerError #:nodoc:
58
+ end
59
+ end
@@ -3,19 +3,34 @@ module ActionController #:nodoc:
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- delegate :flash, :to => :request
7
- delegate :alert, :notice, :to => "request.flash"
8
- helper_method :alert, :notice
6
+ class_attribute :_flash_types, instance_accessor: false
7
+ self._flash_types = []
8
+
9
+ delegate :flash, to: :request
10
+ add_flash_types(:alert, :notice)
9
11
  end
10
12
 
11
- protected
12
- def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
13
- if alert = response_status_and_flash.delete(:alert)
14
- flash[:alert] = alert
13
+ module ClassMethods
14
+ def add_flash_types(*types)
15
+ types.each do |type|
16
+ next if _flash_types.include?(type)
17
+
18
+ define_method(type) do
19
+ request.flash[type]
20
+ end
21
+ helper_method type
22
+
23
+ _flash_types << type
15
24
  end
25
+ end
26
+ end
16
27
 
17
- if notice = response_status_and_flash.delete(:notice)
18
- flash[:notice] = notice
28
+ protected
29
+ def redirect_to(options = {}, response_status_and_flash = {}) #:doc:
30
+ self.class._flash_types.each do |flash_type|
31
+ if type = response_status_and_flash.delete(flash_type)
32
+ flash[flash_type] = type
33
+ end
19
34
  end
20
35
 
21
36
  if other_flashes = response_status_and_flash.delete(:flash)
@@ -18,22 +18,45 @@ module ActionController
18
18
  # Force the request to this particular controller or specified actions to be
19
19
  # under HTTPS protocol.
20
20
  #
21
- # Note that this method will not be effective on development environment.
21
+ # If you need to disable this for any reason (e.g. development) then you can use
22
+ # an +:if+ or +:unless+ condition.
23
+ #
24
+ # class AccountsController < ApplicationController
25
+ # force_ssl if: :ssl_configured?
26
+ #
27
+ # def ssl_configured?
28
+ # !Rails.env.development?
29
+ # end
30
+ # end
22
31
  #
23
32
  # ==== Options
33
+ # * <tt>host</tt> - Redirect to a different host name
24
34
  # * <tt>only</tt> - The callback should be run only for this action
25
- # * <tt>except</tt> - The callback should be run for all actions except this action
35
+ # * <tt>except</tt> - The callback should be run for all actions except this action
36
+ # * <tt>if</tt> - A symbol naming an instance method or a proc; the callback
37
+ # will be called only when it returns a true value.
38
+ # * <tt>unless</tt> - A symbol naming an instance method or a proc; the callback
39
+ # will be called only when it returns a false value.
26
40
  def force_ssl(options = {})
27
41
  host = options.delete(:host)
28
- before_filter(options) do
29
- if !request.ssl? && !Rails.env.development?
30
- redirect_options = {:protocol => 'https://', :status => :moved_permanently}
31
- redirect_options.merge!(:host => host) if host
32
- redirect_options.merge!(:params => request.query_parameters)
33
- redirect_to redirect_options
34
- end
42
+ before_action(options) do
43
+ force_ssl_redirect(host)
35
44
  end
36
45
  end
37
46
  end
47
+
48
+ # Redirect the existing request to use the HTTPS protocol.
49
+ #
50
+ # ==== Parameters
51
+ # * <tt>host</tt> - Redirect to a different host name
52
+ def force_ssl_redirect(host = nil)
53
+ unless request.ssl?
54
+ redirect_options = {:protocol => 'https://', :status => :moved_permanently}
55
+ redirect_options.merge!(:host => host) if host
56
+ redirect_options.merge!(:params => request.query_parameters)
57
+ flash.keep if respond_to?(:flash)
58
+ redirect_to redirect_options
59
+ end
60
+ end
38
61
  end
39
62
  end
@@ -7,9 +7,9 @@ module ActionController
7
7
  # This allows you to easily return a response that consists only of
8
8
  # significant headers:
9
9
  #
10
- # head :created, :location => person_path(@person)
10
+ # head :created, location: person_path(@person)
11
11
  #
12
- # head :created, :location => @person
12
+ # head :created, location: @person
13
13
  #
14
14
  # It can also be used to return exceptional conditions:
15
15
  #
@@ -28,8 +28,29 @@ module ActionController
28
28
 
29
29
  self.status = status
30
30
  self.location = url_for(location) if location
31
- self.content_type = content_type || (Mime[formats.first] if formats)
32
- self.response_body = " "
31
+
32
+ if include_content?(self.status)
33
+ self.content_type = content_type || (Mime[formats.first] if formats)
34
+ self.response.charset = false if self.response
35
+ self.response_body = " "
36
+ else
37
+ headers.delete('Content-Type')
38
+ headers.delete('Content-Length')
39
+ self.response_body = ""
40
+ end
41
+ end
42
+
43
+ private
44
+ # :nodoc:
45
+ def include_content?(status)
46
+ case status
47
+ when 100..199
48
+ false
49
+ when 204, 205, 304
50
+ false
51
+ else
52
+ true
53
+ end
33
54
  end
34
55
  end
35
56
  end
@@ -1,6 +1,3 @@
1
- require 'active_support/core_ext/array/wrap'
2
- require 'active_support/core_ext/class/attribute'
3
-
4
1
  module ActionController
5
2
  # The \Rails framework provides a large number of helpers for working with assets, dates, forms,
6
3
  # numbers and model objects, to name a few. These helpers are available to all templates
@@ -17,7 +14,6 @@ module ActionController
17
14
  # Additional helpers can be specified using the +helper+ class method in ActionController::Base or any
18
15
  # controller which inherits from it.
19
16
  #
20
- # ==== Examples
21
17
  # The +to_s+ method from the \Time class can be wrapped in a helper method to display a custom message if
22
18
  # a \Time object is blank:
23
19
  #
@@ -53,6 +49,7 @@ module ActionController
53
49
  module Helpers
54
50
  extend ActiveSupport::Concern
55
51
 
52
+ class << self; attr_accessor :helpers_path; end
56
53
  include AbstractController::Helpers
57
54
 
58
55
  included do
@@ -93,12 +90,12 @@ module ActionController
93
90
  end
94
91
 
95
92
  def all_helpers_from_path(path)
96
- helpers = []
97
- Array.wrap(path).each do |_path|
98
- extract = /^#{Regexp.quote(_path.to_s)}\/?(.*)_helper.rb$/
99
- helpers += Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
93
+ helpers = Array(path).flat_map do |_path|
94
+ extract = /^#{Regexp.quote(_path.to_s)}\/?(.*)_helper.rb$/
95
+ names = Dir["#{_path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') }
96
+ names.sort!
97
+ names
100
98
  end
101
- helpers.sort!
102
99
  helpers.uniq!
103
100
  helpers
104
101
  end
@@ -1,4 +1,3 @@
1
- require 'active_support/core_ext/class/attribute'
2
1
 
3
2
  module ActionController
4
3
  # Adds the ability to prevent public methods on a controller to be called as actions.
@@ -28,7 +27,7 @@ module ActionController
28
27
  end
29
28
 
30
29
  def visible_action?(action_name)
31
- not hidden_actions.include?(action_name)
30
+ action_methods.include?(action_name)
32
31
  end
33
32
 
34
33
  # Overrides AbstractController::Base#action_methods to remove any methods
@@ -1,22 +1,21 @@
1
- require 'active_support/base64'
2
- require 'active_support/core_ext/object/blank'
3
- require 'active_support/security_utils'
1
+ require 'base64'
4
2
 
5
3
  module ActionController
4
+ # Makes it dead easy to do HTTP Basic, Digest and Token authentication.
6
5
  module HttpAuthentication
7
- # Makes it dead easy to do HTTP \Basic and \Digest authentication.
6
+ # Makes it dead easy to do HTTP \Basic authentication.
8
7
  #
9
8
  # === Simple \Basic example
10
9
  #
11
10
  # class PostsController < ApplicationController
12
- # http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index
11
+ # http_basic_authenticate_with name: "dhh", password: "secret", except: :index
13
12
  #
14
13
  # def index
15
- # render :text => "Everyone can see me!"
14
+ # render text: "Everyone can see me!"
16
15
  # end
17
16
  #
18
17
  # def edit
19
- # render :text => "I'm only accessible if you know the password"
18
+ # render text: "I'm only accessible if you know the password"
20
19
  # end
21
20
  # end
22
21
  #
@@ -26,7 +25,7 @@ module ActionController
26
25
  # the regular HTML interface is protected by a session approach:
27
26
  #
28
27
  # class ApplicationController < ActionController::Base
29
- # before_filter :set_account, :authenticate
28
+ # before_action :set_account, :authenticate
30
29
  #
31
30
  # protected
32
31
  # def set_account
@@ -61,47 +60,6 @@ module ActionController
61
60
  #
62
61
  # assert_equal 200, status
63
62
  # end
64
- #
65
- # === Simple \Digest example
66
- #
67
- # require 'digest/md5'
68
- # class PostsController < ApplicationController
69
- # REALM = "SuperSecret"
70
- # USERS = {"dhh" => "secret", #plain text password
71
- # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password
72
- #
73
- # before_filter :authenticate, :except => [:index]
74
- #
75
- # def index
76
- # render :text => "Everyone can see me!"
77
- # end
78
- #
79
- # def edit
80
- # render :text => "I'm only accessible if you know the password"
81
- # end
82
- #
83
- # private
84
- # def authenticate
85
- # authenticate_or_request_with_http_digest(REALM) do |username|
86
- # USERS[username]
87
- # end
88
- # end
89
- # end
90
- #
91
- # === Notes
92
- #
93
- # The +authenticate_or_request_with_http_digest+ block must return the user's password
94
- # or the ha1 digest hash so the framework can appropriately hash to check the user's
95
- # credentials. Returning +nil+ will cause authentication to fail.
96
- #
97
- # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
98
- # the password file or database is compromised, the attacker would be able to use the ha1 hash to
99
- # authenticate as the user at this +realm+, but would not have the user's password to try using at
100
- # other sites.
101
- #
102
- # In rare instances, web servers or front proxies strip authorization headers before
103
- # they reach your application. You can debug this situation by logging all environment
104
- # variables, and check for HTTP_AUTHORIZATION, amongst others.
105
63
  module Basic
106
64
  extend self
107
65
 
@@ -110,13 +68,9 @@ module ActionController
110
68
 
111
69
  module ClassMethods
112
70
  def http_basic_authenticate_with(options = {})
113
- before_filter(options.except(:name, :password, :realm)) do
71
+ before_action(options.except(:name, :password, :realm)) do
114
72
  authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
115
- # This comparison uses & so that it doesn't short circuit and
116
- # uses `variable_size_secure_compare` so that length information
117
- # isn't leaked.
118
- ActiveSupport::SecurityUtils.variable_size_secure_compare(name, options[:name]) &
119
- ActiveSupport::SecurityUtils.variable_size_secure_compare(password, options[:password])
73
+ name == options[:name] && password == options[:password]
120
74
  end
121
75
  end
122
76
  end
@@ -160,6 +114,48 @@ module ActionController
160
114
  end
161
115
  end
162
116
 
117
+ # Makes it dead easy to do HTTP \Digest authentication.
118
+ #
119
+ # === Simple \Digest example
120
+ #
121
+ # require 'digest/md5'
122
+ # class PostsController < ApplicationController
123
+ # REALM = "SuperSecret"
124
+ # USERS = {"dhh" => "secret", #plain text password
125
+ # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password
126
+ #
127
+ # before_action :authenticate, except: [:index]
128
+ #
129
+ # def index
130
+ # render text: "Everyone can see me!"
131
+ # end
132
+ #
133
+ # def edit
134
+ # render text: "I'm only accessible if you know the password"
135
+ # end
136
+ #
137
+ # private
138
+ # def authenticate
139
+ # authenticate_or_request_with_http_digest(REALM) do |username|
140
+ # USERS[username]
141
+ # end
142
+ # end
143
+ # end
144
+ #
145
+ # === Notes
146
+ #
147
+ # The +authenticate_or_request_with_http_digest+ block must return the user's password
148
+ # or the ha1 digest hash so the framework can appropriately hash to check the user's
149
+ # credentials. Returning +nil+ will cause authentication to fail.
150
+ #
151
+ # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
152
+ # the password file or database is compromised, the attacker would be able to use the ha1 hash to
153
+ # authenticate as the user at this +realm+, but would not have the user's password to try using at
154
+ # other sites.
155
+ #
156
+ # In rare instances, web servers or front proxies strip authorization headers before
157
+ # they reach your application. You can debug this situation by logging all environment
158
+ # variables, and check for HTTP_AUTHORIZATION, amongst others.
163
159
  module Digest
164
160
  extend self
165
161
 
@@ -197,7 +193,7 @@ module ActionController
197
193
  return false unless password
198
194
 
199
195
  method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD']
200
- uri = credentials[:uri][0,1] == '/' ? request.original_fullpath : request.original_url
196
+ uri = credentials[:uri]
201
197
 
202
198
  [true, false].any? do |trailing_question_mark|
203
199
  [true, false].any? do |password_is_ha1|
@@ -232,7 +228,7 @@ module ActionController
232
228
  end
233
229
 
234
230
  def decode_credentials(header)
235
- HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
231
+ ActiveSupport::HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/, '').split(',').map do |pair|
236
232
  key, value = pair.split('=', 2)
237
233
  [key.strip, value.to_s.gsub(/^"|"$/,'').delete('\'')]
238
234
  end]
@@ -253,9 +249,9 @@ module ActionController
253
249
  end
254
250
 
255
251
  def secret_token(request)
256
- secret = request.env["action_dispatch.secret_token"]
257
- raise "You must set config.secret_token in your app's config" if secret.blank?
258
- secret
252
+ key_generator = request.env["action_dispatch.key_generator"]
253
+ http_auth_salt = request.env["action_dispatch.http_auth_salt"]
254
+ key_generator.generate_key(http_auth_salt)
259
255
  end
260
256
 
261
257
  # Uses an MD5 digest based on time to generate a value to be used only once.
@@ -268,7 +264,7 @@ module ActionController
268
264
  # The quality of the implementation depends on a good choice.
269
265
  # A nonce might, for example, be constructed as the base 64 encoding of
270
266
  #
271
- # => time-stamp H(time-stamp ":" ETag ":" private-key)
267
+ # time-stamp H(time-stamp ":" ETag ":" private-key)
272
268
  #
273
269
  # where time-stamp is a server-generated time or other non-repeating value,
274
270
  # ETag is the value of the HTTP ETag header associated with the requested entity,
@@ -284,7 +280,7 @@ module ActionController
284
280
  #
285
281
  # An implementation might choose not to accept a previously used nonce or a previously used digest, in order to
286
282
  # protect against a replay attack. Or, an implementation might choose to use one-time nonces or digests for
287
- # POST or PUT requests and a time-stamp for GET requests. For more details on the issues involved see Section 4
283
+ # POST, PUT, or PATCH requests and a time-stamp for GET requests. For more details on the issues involved see Section 4
288
284
  # of this document.
289
285
  #
290
286
  # The nonce is opaque to the client. Composed of Time, and hash of Time with secret
@@ -294,11 +290,11 @@ module ActionController
294
290
  t = time.to_i
295
291
  hashed = [t, secret_key]
296
292
  digest = ::Digest::MD5.hexdigest(hashed.join(":"))
297
- ::Base64.encode64("#{t}:#{digest}").gsub("\n", '')
293
+ ::Base64.strict_encode64("#{t}:#{digest}")
298
294
  end
299
295
 
300
296
  # Might want a shorter timeout depending on whether the request
301
- # is a PUT or POST, and if client is browser or web service.
297
+ # is a PATCH, PUT, or POST, and if client is browser or web service.
302
298
  # Can be much shorter if the Stale directive is implemented. This would
303
299
  # allow a user to use new nonce without prompting user again for their
304
300
  # username and password.
@@ -321,14 +317,14 @@ module ActionController
321
317
  # class PostsController < ApplicationController
322
318
  # TOKEN = "secret"
323
319
  #
324
- # before_filter :authenticate, :except => [ :index ]
320
+ # before_action :authenticate, except: [ :index ]
325
321
  #
326
322
  # def index
327
- # render :text => "Everyone can see me!"
323
+ # render text: "Everyone can see me!"
328
324
  # end
329
325
  #
330
326
  # def edit
331
- # render :text => "I'm only accessible if you know the password"
327
+ # render text: "I'm only accessible if you know the password"
332
328
  # end
333
329
  #
334
330
  # private
@@ -344,7 +340,7 @@ module ActionController
344
340
  # the regular HTML interface is protected by a session approach:
345
341
  #
346
342
  # class ApplicationController < ActionController::Base
347
- # before_filter :set_account, :authenticate
343
+ # before_action :set_account, :authenticate
348
344
  #
349
345
  # protected
350
346
  # def set_account
@@ -375,7 +371,7 @@ module ActionController
375
371
  # def test_access_granted_from_xml
376
372
  # get(
377
373
  # "/notes/1.xml", nil,
378
- # :authorization => ActionController::HttpAuthentication::Token.encode_credentials(users(:dhh).token)
374
+ # 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Token.encode_credentials(users(:dhh).token)
379
375
  # )
380
376
  #
381
377
  # assert_equal 200, status
@@ -388,6 +384,8 @@ module ActionController
388
384
  #
389
385
  # RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
390
386
  module Token
387
+ TOKEN_REGEX = /^Token /
388
+ AUTHN_PAIR_DELIMITERS = /(?:,|;|\t+)/
391
389
  extend self
392
390
 
393
391
  module ControllerMethods
@@ -404,16 +402,20 @@ module ActionController
404
402
  end
405
403
  end
406
404
 
407
- # If token Authorization header is present, call the login procedure with
408
- # the present token and options.
405
+ # If token Authorization header is present, call the login
406
+ # procedure with the present token and options.
409
407
  #
410
- # controller - ActionController::Base instance for the current request.
411
- # login_procedure - Proc to call if a token is present. The Proc should
412
- # take 2 arguments:
413
- # authenticate(controller) { |token, options| ... }
408
+ # [controller]
409
+ # ActionController::Base instance for the current request.
414
410
  #
415
- # Returns the return value of `&login_procedure` if a token is found.
416
- # Returns nil if no token is found.
411
+ # [login_procedure]
412
+ # Proc to call if a token is present. The Proc should take two arguments:
413
+ #
414
+ # authenticate(controller) { |token, options| ... }
415
+ #
416
+ # Returns the return value of <tt>login_procedure</tt> if a
417
+ # token is found. Returns <tt>nil</tt> if no token is found.
418
+
417
419
  def authenticate(controller, &login_procedure)
418
420
  token, options = token_and_options(controller.request)
419
421
  unless token.blank?
@@ -424,25 +426,41 @@ module ActionController
424
426
  # Parses the token and options out of the token authorization header. If
425
427
  # the header looks like this:
426
428
  # Authorization: Token token="abc", nonce="def"
427
- # Then the returned token is "abc", and the options is {:nonce => "def"}
429
+ # Then the returned token is "abc", and the options is {nonce: "def"}
428
430
  #
429
431
  # request - ActionDispatch::Request instance with the current headers.
430
432
  #
431
433
  # Returns an Array of [String, Hash] if a token is present.
432
434
  # Returns nil if no token is found.
433
435
  def token_and_options(request)
434
- if request.authorization.to_s[/^Token (.*)/]
435
- values = Hash[$1.split(',').map do |value|
436
- value.strip! # remove any spaces between commas and values
437
- key, value = value.split(/\=\"?/) # split key=value pairs
438
- value.chomp!('"') # chomp trailing " in value
439
- value.gsub!(/\\\"/, '"') # unescape remaining quotes
440
- [key, value]
441
- end]
442
- [values.delete("token"), values.with_indifferent_access]
436
+ authorization_request = request.authorization.to_s
437
+ if authorization_request[TOKEN_REGEX]
438
+ params = token_params_from authorization_request
439
+ [params.shift.last, Hash[params].with_indifferent_access]
443
440
  end
444
441
  end
445
442
 
443
+ def token_params_from(auth)
444
+ rewrite_param_values params_array_from raw_params auth
445
+ end
446
+
447
+ # Takes raw_params and turns it into an array of parameters
448
+ def params_array_from(raw_params)
449
+ raw_params.map { |param| param.split %r/=(.+)?/ }
450
+ end
451
+
452
+ # This removes the `"` characters wrapping the value.
453
+ def rewrite_param_values(array_params)
454
+ array_params.each { |param| param.last.gsub! %r/^"|"$/, '' }
455
+ end
456
+
457
+ # This method takes an authorization body and splits up the key-value
458
+ # pairs by the standardized `:`, `;`, or `\t` delimiters defined in
459
+ # `AUTHN_PAIR_DELIMITERS`.
460
+ def raw_params(auth)
461
+ auth.sub(TOKEN_REGEX, '').split(/"\s*#{AUTHN_PAIR_DELIMITERS}\s*/)
462
+ end
463
+
446
464
  # Encodes the given token and options into an Authorization header value.
447
465
  #
448
466
  # token - String token.