actionpack 3.2.19 → 4.0.0

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 (263) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +850 -401
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +39 -37
  7. data/lib/abstract_controller/callbacks.rb +101 -82
  8. data/lib/abstract_controller/collector.rb +7 -3
  9. data/lib/abstract_controller/helpers.rb +25 -13
  10. data/lib/abstract_controller/layouts.rb +74 -74
  11. data/lib/abstract_controller/logger.rb +1 -2
  12. data/lib/abstract_controller/rendering.rb +30 -13
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +6 -6
  15. data/lib/abstract_controller/view_paths.rb +1 -1
  16. data/lib/abstract_controller.rb +1 -8
  17. data/lib/action_controller/base.rb +46 -22
  18. data/lib/action_controller/caching/fragments.rb +23 -53
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/log_subscriber.rb +16 -8
  23. data/lib/action_controller/metal/conditional_get.rb +76 -32
  24. data/lib/action_controller/metal/data_streaming.rb +20 -26
  25. data/lib/action_controller/metal/exceptions.rb +19 -6
  26. data/lib/action_controller/metal/flash.rb +24 -9
  27. data/lib/action_controller/metal/force_ssl.rb +70 -12
  28. data/lib/action_controller/metal/head.rb +25 -4
  29. data/lib/action_controller/metal/helpers.rb +5 -9
  30. data/lib/action_controller/metal/hide_actions.rb +0 -1
  31. data/lib/action_controller/metal/http_authentication.rb +107 -83
  32. data/lib/action_controller/metal/implicit_render.rb +1 -1
  33. data/lib/action_controller/metal/instrumentation.rb +2 -1
  34. data/lib/action_controller/metal/live.rb +175 -0
  35. data/lib/action_controller/metal/mime_responds.rb +161 -47
  36. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  37. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  38. data/lib/action_controller/metal/redirecting.rb +15 -20
  39. data/lib/action_controller/metal/renderers.rb +11 -9
  40. data/lib/action_controller/metal/rendering.rb +9 -1
  41. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  42. data/lib/action_controller/metal/responder.rb +20 -19
  43. data/lib/action_controller/metal/streaming.rb +12 -18
  44. data/lib/action_controller/metal/strong_parameters.rb +520 -0
  45. data/lib/action_controller/metal/testing.rb +13 -18
  46. data/lib/action_controller/metal/url_for.rb +28 -25
  47. data/lib/action_controller/metal.rb +17 -32
  48. data/lib/action_controller/model_naming.rb +12 -0
  49. data/lib/action_controller/railtie.rb +33 -17
  50. data/lib/action_controller/railties/helpers.rb +22 -0
  51. data/lib/action_controller/record_identifier.rb +18 -72
  52. data/lib/action_controller/test_case.rb +251 -131
  53. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  54. data/lib/action_controller.rb +15 -6
  55. data/lib/action_dispatch/http/cache.rb +63 -11
  56. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  57. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  58. data/lib/action_dispatch/http/headers.rb +49 -17
  59. data/lib/action_dispatch/http/mime_negotiation.rb +24 -1
  60. data/lib/action_dispatch/http/mime_type.rb +154 -100
  61. data/lib/action_dispatch/http/mime_types.rb +1 -1
  62. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  63. data/lib/action_dispatch/http/parameters.rb +28 -28
  64. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  65. data/lib/action_dispatch/http/request.rb +64 -18
  66. data/lib/action_dispatch/http/response.rb +130 -35
  67. data/lib/action_dispatch/http/upload.rb +63 -20
  68. data/lib/action_dispatch/http/url.rb +98 -35
  69. data/lib/action_dispatch/journey/backwards.rb +5 -0
  70. data/lib/action_dispatch/journey/formatter.rb +146 -0
  71. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  72. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  73. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  74. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  75. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  76. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  77. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  78. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  79. data/lib/action_dispatch/journey/parser.rb +206 -0
  80. data/lib/action_dispatch/journey/parser.y +47 -0
  81. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  82. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  83. data/lib/action_dispatch/journey/route.rb +124 -0
  84. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  85. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  86. data/lib/action_dispatch/journey/router.rb +166 -0
  87. data/lib/action_dispatch/journey/routes.rb +75 -0
  88. data/lib/action_dispatch/journey/scanner.rb +61 -0
  89. data/lib/action_dispatch/journey/visitors.rb +197 -0
  90. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  91. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  92. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  93. data/lib/action_dispatch/journey.rb +5 -0
  94. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  95. data/lib/action_dispatch/middleware/cookies.rb +259 -114
  96. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  97. data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -3
  98. data/lib/action_dispatch/middleware/flash.rb +58 -58
  99. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  100. data/lib/action_dispatch/middleware/public_exceptions.rb +30 -14
  101. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  102. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  103. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  104. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  105. data/lib/action_dispatch/middleware/session/cookie_store.rb +82 -28
  106. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  107. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  108. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  109. data/lib/action_dispatch/middleware/stack.rb +6 -1
  110. data/lib/action_dispatch/middleware/static.rb +2 -1
  111. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  112. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +7 -9
  114. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  115. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +127 -5
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  118. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  119. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  120. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  121. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  122. data/lib/action_dispatch/railtie.rb +16 -6
  123. data/lib/action_dispatch/request/session.rb +181 -0
  124. data/lib/action_dispatch/routing/inspector.rb +240 -0
  125. data/lib/action_dispatch/routing/mapper.rb +540 -291
  126. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  127. data/lib/action_dispatch/routing/redirection.rb +46 -29
  128. data/lib/action_dispatch/routing/route_set.rb +207 -164
  129. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  130. data/lib/action_dispatch/routing/url_for.rb +48 -33
  131. data/lib/action_dispatch/routing.rb +48 -83
  132. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  133. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  134. data/lib/action_dispatch/testing/assertions/routing.rb +42 -41
  135. data/lib/action_dispatch/testing/assertions/selector.rb +17 -22
  136. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  137. data/lib/action_dispatch/testing/integration.rb +65 -51
  138. data/lib/action_dispatch/testing/test_process.rb +9 -6
  139. data/lib/action_dispatch/testing/test_request.rb +7 -3
  140. data/lib/action_dispatch.rb +21 -15
  141. data/lib/action_pack/version.rb +7 -6
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_view/base.rb +15 -34
  144. data/lib/action_view/buffers.rb +7 -1
  145. data/lib/action_view/context.rb +4 -4
  146. data/lib/action_view/dependency_tracker.rb +93 -0
  147. data/lib/action_view/digestor.rb +85 -0
  148. data/lib/action_view/flows.rb +1 -4
  149. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  150. data/lib/action_view/helpers/asset_tag_helper.rb +215 -352
  151. data/lib/action_view/helpers/asset_url_helper.rb +355 -0
  152. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  153. data/lib/action_view/helpers/cache_helper.rb +150 -18
  154. data/lib/action_view/helpers/capture_helper.rb +44 -31
  155. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  156. data/lib/action_view/helpers/date_helper.rb +269 -248
  157. data/lib/action_view/helpers/debug_helper.rb +10 -11
  158. data/lib/action_view/helpers/form_helper.rb +931 -537
  159. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  160. data/lib/action_view/helpers/form_tag_helper.rb +190 -90
  161. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  162. data/lib/action_view/helpers/number_helper.rb +148 -329
  163. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  164. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  165. data/lib/action_view/helpers/rendering_helper.rb +2 -2
  166. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  167. data/lib/action_view/helpers/tag_helper.rb +46 -33
  168. data/lib/action_view/helpers/tags/base.rb +147 -0
  169. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  170. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  171. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  172. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  173. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  174. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  175. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  176. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  177. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  178. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  179. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  180. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  181. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  182. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  183. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  184. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  185. data/lib/action_view/helpers/tags/label.rb +65 -0
  186. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  187. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  188. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  189. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  190. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  191. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  192. data/lib/action_view/helpers/tags/select.rb +40 -0
  193. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  194. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  195. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  196. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  197. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  198. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  199. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  200. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  201. data/lib/action_view/helpers/tags.rb +39 -0
  202. data/lib/action_view/helpers/text_helper.rb +130 -114
  203. data/lib/action_view/helpers/translation_helper.rb +32 -16
  204. data/lib/action_view/helpers/url_helper.rb +211 -270
  205. data/lib/action_view/helpers.rb +2 -4
  206. data/lib/action_view/locale/en.yml +1 -105
  207. data/lib/action_view/log_subscriber.rb +6 -4
  208. data/lib/action_view/lookup_context.rb +15 -28
  209. data/lib/action_view/model_naming.rb +12 -0
  210. data/lib/action_view/path_set.rb +8 -20
  211. data/lib/action_view/railtie.rb +6 -22
  212. data/lib/action_view/record_identifier.rb +84 -0
  213. data/lib/action_view/renderer/abstract_renderer.rb +25 -19
  214. data/lib/action_view/renderer/partial_renderer.rb +158 -81
  215. data/lib/action_view/renderer/renderer.rb +8 -12
  216. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  217. data/lib/action_view/renderer/template_renderer.rb +12 -10
  218. data/lib/action_view/routing_url_for.rb +107 -0
  219. data/lib/action_view/template/error.rb +22 -12
  220. data/lib/action_view/template/handlers/builder.rb +1 -1
  221. data/lib/action_view/template/handlers/erb.rb +40 -19
  222. data/lib/action_view/template/handlers/raw.rb +11 -0
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/resolver.rb +107 -53
  225. data/lib/action_view/template/text.rb +12 -8
  226. data/lib/action_view/template/types.rb +57 -0
  227. data/lib/action_view/template.rb +25 -23
  228. data/lib/action_view/test_case.rb +67 -42
  229. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  230. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  231. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +13 -2
  232. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +9 -9
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  235. data/lib/action_view/vendor/html-scanner.rb +20 -0
  236. data/lib/action_view.rb +17 -8
  237. metadata +184 -214
  238. data/lib/action_controller/caching/actions.rb +0 -185
  239. data/lib/action_controller/caching/pages.rb +0 -187
  240. data/lib/action_controller/caching/sweeping.rb +0 -97
  241. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  242. data/lib/action_controller/metal/compatibility.rb +0 -65
  243. data/lib/action_controller/metal/session_management.rb +0 -14
  244. data/lib/action_controller/railties/paths.rb +0 -25
  245. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  246. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  247. data/lib/action_dispatch/middleware/head.rb +0 -18
  248. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  249. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  250. data/lib/action_view/asset_paths.rb +0 -142
  251. data/lib/action_view/helpers/asset_paths.rb +0 -7
  252. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  253. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  254. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  255. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  256. data/lib/sprockets/assets.rake +0 -99
  257. data/lib/sprockets/bootstrap.rb +0 -37
  258. data/lib/sprockets/compressors.rb +0 -83
  259. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  260. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/railtie.rb +0 -62
  263. data/lib/sprockets/static_compiler.rb +0 -56
@@ -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)
@@ -1,3 +1,6 @@
1
+ require 'active_support/core_ext/hash/except'
2
+ require 'active_support/core_ext/hash/slice'
3
+
1
4
  module ActionController
2
5
  # This module provides a method which will redirect browser to use HTTPS
3
6
  # protocol. This will ensure that user's sensitive information will be
@@ -14,26 +17,81 @@ module ActionController
14
17
  extend ActiveSupport::Concern
15
18
  include AbstractController::Callbacks
16
19
 
20
+ ACTION_OPTIONS = [:only, :except, :if, :unless]
21
+ URL_OPTIONS = [:protocol, :host, :domain, :subdomain, :port, :path]
22
+ REDIRECT_OPTIONS = [:status, :flash, :alert, :notice]
23
+
17
24
  module ClassMethods
18
25
  # Force the request to this particular controller or specified actions to be
19
26
  # under HTTPS protocol.
20
27
  #
21
- # Note that this method will not be effective on development environment.
28
+ # If you need to disable this for any reason (e.g. development) then you can use
29
+ # an +:if+ or +:unless+ condition.
30
+ #
31
+ # class AccountsController < ApplicationController
32
+ # force_ssl if: :ssl_configured?
33
+ #
34
+ # def ssl_configured?
35
+ # !Rails.env.development?
36
+ # end
37
+ # end
38
+ #
39
+ # ==== URL Options
40
+ # You can pass any of the following options to affect the redirect url
41
+ # * <tt>host</tt> - Redirect to a different host name
42
+ # * <tt>subdomain</tt> - Redirect to a different subdomain
43
+ # * <tt>domain</tt> - Redirect to a different domain
44
+ # * <tt>port</tt> - Redirect to a non-standard port
45
+ # * <tt>path</tt> - Redirect to a different path
46
+ #
47
+ # ==== Redirect Options
48
+ # You can pass any of the following options to affect the redirect status and response
49
+ # * <tt>status</tt> - Redirect with a custom status (default is 301 Moved Permanently)
50
+ # * <tt>flash</tt> - Set a flash message when redirecting
51
+ # * <tt>alert</tt> - Set a alert message when redirecting
52
+ # * <tt>notice</tt> - Set a notice message when redirecting
22
53
  #
23
- # ==== Options
24
- # * <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
54
+ # ==== Action Options
55
+ # You can pass any of the following options to affect the before_action callback
56
+ # * <tt>only</tt> - The callback should be run only for this action
57
+ # * <tt>except</tt> - The callback should be run for all actions except this action
58
+ # * <tt>if</tt> - A symbol naming an instance method or a proc; the callback
59
+ # will be called only when it returns a true value.
60
+ # * <tt>unless</tt> - A symbol naming an instance method or a proc; the callback
61
+ # will be called only when it returns a false value.
26
62
  def force_ssl(options = {})
27
- 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
63
+ action_options = options.slice(*ACTION_OPTIONS)
64
+ redirect_options = options.except(*ACTION_OPTIONS)
65
+ before_action(action_options) do
66
+ force_ssl_redirect(redirect_options)
35
67
  end
36
68
  end
37
69
  end
70
+
71
+ # Redirect the existing request to use the HTTPS protocol.
72
+ #
73
+ # ==== Parameters
74
+ # * <tt>host_or_options</tt> - Either a host name or any of the url & redirect options
75
+ # available to the <tt>force_ssl</tt> method.
76
+ def force_ssl_redirect(host_or_options = nil)
77
+ unless request.ssl?
78
+ options = {
79
+ :protocol => 'https://',
80
+ :host => request.host,
81
+ :path => request.fullpath,
82
+ :status => :moved_permanently
83
+ }
84
+
85
+ if host_or_options.is_a?(Hash)
86
+ options.merge!(host_or_options)
87
+ elsif host_or_options
88
+ options.merge!(:host => host_or_options)
89
+ end
90
+
91
+ secure_url = ActionDispatch::Http::URL.url_for(options.slice(*URL_OPTIONS))
92
+ flash.keep if respond_to?(:flash)
93
+ redirect_to secure_url, options.slice(*REDIRECT_OPTIONS)
94
+ end
95
+ end
38
96
  end
39
97
  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,11 @@ 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!
100
97
  end
101
- helpers.sort!
102
98
  helpers.uniq!
103
99
  helpers
104
100
  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.
@@ -1,21 +1,21 @@
1
- require 'active_support/base64'
2
- require 'active_support/core_ext/object/blank'
1
+ require 'base64'
3
2
 
4
3
  module ActionController
4
+ # Makes it dead easy to do HTTP Basic, Digest and Token authentication.
5
5
  module HttpAuthentication
6
- # Makes it dead easy to do HTTP \Basic and \Digest authentication.
6
+ # Makes it dead easy to do HTTP \Basic authentication.
7
7
  #
8
8
  # === Simple \Basic example
9
9
  #
10
10
  # class PostsController < ApplicationController
11
- # http_basic_authenticate_with :name => "dhh", :password => "secret", :except => :index
11
+ # http_basic_authenticate_with name: "dhh", password: "secret", except: :index
12
12
  #
13
13
  # def index
14
- # render :text => "Everyone can see me!"
14
+ # render text: "Everyone can see me!"
15
15
  # end
16
16
  #
17
17
  # def edit
18
- # render :text => "I'm only accessible if you know the password"
18
+ # render text: "I'm only accessible if you know the password"
19
19
  # end
20
20
  # end
21
21
  #
@@ -25,11 +25,11 @@ module ActionController
25
25
  # the regular HTML interface is protected by a session approach:
26
26
  #
27
27
  # class ApplicationController < ActionController::Base
28
- # before_filter :set_account, :authenticate
28
+ # before_action :set_account, :authenticate
29
29
  #
30
30
  # protected
31
31
  # def set_account
32
- # @account = Account.find_by_url_name(request.subdomains.first)
32
+ # @account = Account.find_by(url_name: request.subdomains.first)
33
33
  # end
34
34
  #
35
35
  # def authenticate
@@ -60,47 +60,6 @@ module ActionController
60
60
  #
61
61
  # assert_equal 200, status
62
62
  # end
63
- #
64
- # === Simple \Digest example
65
- #
66
- # require 'digest/md5'
67
- # class PostsController < ApplicationController
68
- # REALM = "SuperSecret"
69
- # USERS = {"dhh" => "secret", #plain text password
70
- # "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":"))} #ha1 digest password
71
- #
72
- # before_filter :authenticate, :except => [:index]
73
- #
74
- # def index
75
- # render :text => "Everyone can see me!"
76
- # end
77
- #
78
- # def edit
79
- # render :text => "I'm only accessible if you know the password"
80
- # end
81
- #
82
- # private
83
- # def authenticate
84
- # authenticate_or_request_with_http_digest(REALM) do |username|
85
- # USERS[username]
86
- # end
87
- # end
88
- # end
89
- #
90
- # === Notes
91
- #
92
- # The +authenticate_or_request_with_http_digest+ block must return the user's password
93
- # or the ha1 digest hash so the framework can appropriately hash to check the user's
94
- # credentials. Returning +nil+ will cause authentication to fail.
95
- #
96
- # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
97
- # the password file or database is compromised, the attacker would be able to use the ha1 hash to
98
- # authenticate as the user at this +realm+, but would not have the user's password to try using at
99
- # other sites.
100
- #
101
- # In rare instances, web servers or front proxies strip authorization headers before
102
- # they reach your application. You can debug this situation by logging all environment
103
- # variables, and check for HTTP_AUTHORIZATION, amongst others.
104
63
  module Basic
105
64
  extend self
106
65
 
@@ -109,7 +68,7 @@ module ActionController
109
68
 
110
69
  module ClassMethods
111
70
  def http_basic_authenticate_with(options = {})
112
- before_filter(options.except(:name, :password, :realm)) do
71
+ before_action(options.except(:name, :password, :realm)) do
113
72
  authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
114
73
  name == options[:name] && password == options[:password]
115
74
  end
@@ -155,6 +114,48 @@ module ActionController
155
114
  end
156
115
  end
157
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.
158
159
  module Digest
159
160
  extend self
160
161
 
@@ -192,7 +193,7 @@ module ActionController
192
193
  return false unless password
193
194
 
194
195
  method = request.env['rack.methodoverride.original_method'] || request.env['REQUEST_METHOD']
195
- uri = credentials[:uri][0,1] == '/' ? request.original_fullpath : request.original_url
196
+ uri = credentials[:uri]
196
197
 
197
198
  [true, false].any? do |trailing_question_mark|
198
199
  [true, false].any? do |password_is_ha1|
@@ -227,7 +228,7 @@ module ActionController
227
228
  end
228
229
 
229
230
  def decode_credentials(header)
230
- HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
231
+ ActiveSupport::HashWithIndifferentAccess[header.to_s.gsub(/^Digest\s+/, '').split(',').map do |pair|
231
232
  key, value = pair.split('=', 2)
232
233
  [key.strip, value.to_s.gsub(/^"|"$/,'').delete('\'')]
233
234
  end]
@@ -248,9 +249,9 @@ module ActionController
248
249
  end
249
250
 
250
251
  def secret_token(request)
251
- secret = request.env["action_dispatch.secret_token"]
252
- raise "You must set config.secret_token in your app's config" if secret.blank?
253
- 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)
254
255
  end
255
256
 
256
257
  # Uses an MD5 digest based on time to generate a value to be used only once.
@@ -263,7 +264,7 @@ module ActionController
263
264
  # The quality of the implementation depends on a good choice.
264
265
  # A nonce might, for example, be constructed as the base 64 encoding of
265
266
  #
266
- # => time-stamp H(time-stamp ":" ETag ":" private-key)
267
+ # time-stamp H(time-stamp ":" ETag ":" private-key)
267
268
  #
268
269
  # where time-stamp is a server-generated time or other non-repeating value,
269
270
  # ETag is the value of the HTTP ETag header associated with the requested entity,
@@ -279,7 +280,7 @@ module ActionController
279
280
  #
280
281
  # An implementation might choose not to accept a previously used nonce or a previously used digest, in order to
281
282
  # protect against a replay attack. Or, an implementation might choose to use one-time nonces or digests for
282
- # 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
283
284
  # of this document.
284
285
  #
285
286
  # The nonce is opaque to the client. Composed of Time, and hash of Time with secret
@@ -289,15 +290,16 @@ module ActionController
289
290
  t = time.to_i
290
291
  hashed = [t, secret_key]
291
292
  digest = ::Digest::MD5.hexdigest(hashed.join(":"))
292
- ::Base64.encode64("#{t}:#{digest}").gsub("\n", '')
293
+ ::Base64.strict_encode64("#{t}:#{digest}")
293
294
  end
294
295
 
295
296
  # Might want a shorter timeout depending on whether the request
296
- # 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.
297
298
  # Can be much shorter if the Stale directive is implemented. This would
298
299
  # allow a user to use new nonce without prompting user again for their
299
300
  # username and password.
300
301
  def validate_nonce(secret_key, request, value, seconds_to_timeout=5*60)
302
+ return false if value.nil?
301
303
  t = ::Base64.decode64(value).split(":").first.to_i
302
304
  nonce(secret_key, t) == value && (t - Time.now.to_i).abs <= seconds_to_timeout
303
305
  end
@@ -316,14 +318,14 @@ module ActionController
316
318
  # class PostsController < ApplicationController
317
319
  # TOKEN = "secret"
318
320
  #
319
- # before_filter :authenticate, :except => [ :index ]
321
+ # before_action :authenticate, except: [ :index ]
320
322
  #
321
323
  # def index
322
- # render :text => "Everyone can see me!"
324
+ # render text: "Everyone can see me!"
323
325
  # end
324
326
  #
325
327
  # def edit
326
- # render :text => "I'm only accessible if you know the password"
328
+ # render text: "I'm only accessible if you know the password"
327
329
  # end
328
330
  #
329
331
  # private
@@ -339,11 +341,11 @@ module ActionController
339
341
  # the regular HTML interface is protected by a session approach:
340
342
  #
341
343
  # class ApplicationController < ActionController::Base
342
- # before_filter :set_account, :authenticate
344
+ # before_action :set_account, :authenticate
343
345
  #
344
346
  # protected
345
347
  # def set_account
346
- # @account = Account.find_by_url_name(request.subdomains.first)
348
+ # @account = Account.find_by(url_name: request.subdomains.first)
347
349
  # end
348
350
  #
349
351
  # def authenticate
@@ -370,7 +372,7 @@ module ActionController
370
372
  # def test_access_granted_from_xml
371
373
  # get(
372
374
  # "/notes/1.xml", nil,
373
- # :authorization => ActionController::HttpAuthentication::Token.encode_credentials(users(:dhh).token)
375
+ # 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Token.encode_credentials(users(:dhh).token)
374
376
  # )
375
377
  #
376
378
  # assert_equal 200, status
@@ -383,6 +385,8 @@ module ActionController
383
385
  #
384
386
  # RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
385
387
  module Token
388
+ TOKEN_REGEX = /^Token /
389
+ AUTHN_PAIR_DELIMITERS = /(?:,|;|\t+)/
386
390
  extend self
387
391
 
388
392
  module ControllerMethods
@@ -399,16 +403,20 @@ module ActionController
399
403
  end
400
404
  end
401
405
 
402
- # If token Authorization header is present, call the login procedure with
403
- # the present token and options.
406
+ # If token Authorization header is present, call the login
407
+ # procedure with the present token and options.
404
408
  #
405
- # controller - ActionController::Base instance for the current request.
406
- # login_procedure - Proc to call if a token is present. The Proc should
407
- # take 2 arguments:
408
- # authenticate(controller) { |token, options| ... }
409
+ # [controller]
410
+ # ActionController::Base instance for the current request.
409
411
  #
410
- # Returns the return value of `&login_procedure` if a token is found.
411
- # Returns nil if no token is found.
412
+ # [login_procedure]
413
+ # Proc to call if a token is present. The Proc should take two arguments:
414
+ #
415
+ # authenticate(controller) { |token, options| ... }
416
+ #
417
+ # Returns the return value of <tt>login_procedure</tt> if a
418
+ # token is found. Returns <tt>nil</tt> if no token is found.
419
+
412
420
  def authenticate(controller, &login_procedure)
413
421
  token, options = token_and_options(controller.request)
414
422
  unless token.blank?
@@ -419,25 +427,41 @@ module ActionController
419
427
  # Parses the token and options out of the token authorization header. If
420
428
  # the header looks like this:
421
429
  # Authorization: Token token="abc", nonce="def"
422
- # Then the returned token is "abc", and the options is {:nonce => "def"}
430
+ # Then the returned token is "abc", and the options is {nonce: "def"}
423
431
  #
424
432
  # request - ActionDispatch::Request instance with the current headers.
425
433
  #
426
434
  # Returns an Array of [String, Hash] if a token is present.
427
435
  # Returns nil if no token is found.
428
436
  def token_and_options(request)
429
- if request.authorization.to_s[/^Token (.*)/]
430
- values = Hash[$1.split(',').map do |value|
431
- value.strip! # remove any spaces between commas and values
432
- key, value = value.split(/\=\"?/) # split key=value pairs
433
- value.chomp!('"') # chomp trailing " in value
434
- value.gsub!(/\\\"/, '"') # unescape remaining quotes
435
- [key, value]
436
- end]
437
- [values.delete("token"), values.with_indifferent_access]
437
+ authorization_request = request.authorization.to_s
438
+ if authorization_request[TOKEN_REGEX]
439
+ params = token_params_from authorization_request
440
+ [params.shift.last, Hash[params].with_indifferent_access]
438
441
  end
439
442
  end
440
443
 
444
+ def token_params_from(auth)
445
+ rewrite_param_values params_array_from raw_params auth
446
+ end
447
+
448
+ # Takes raw_params and turns it into an array of parameters
449
+ def params_array_from(raw_params)
450
+ raw_params.map { |param| param.split %r/=(.+)?/ }
451
+ end
452
+
453
+ # This removes the `"` characters wrapping the value.
454
+ def rewrite_param_values(array_params)
455
+ array_params.each { |param| param.last.gsub! %r/^"|"$/, '' }
456
+ end
457
+
458
+ # This method takes an authorization body and splits up the key-value
459
+ # pairs by the standardized `:`, `;`, or `\t` delimiters defined in
460
+ # `AUTHN_PAIR_DELIMITERS`.
461
+ def raw_params(auth)
462
+ auth.sub(TOKEN_REGEX, '').split(/"\s*#{AUTHN_PAIR_DELIMITERS}\s*/)
463
+ end
464
+
441
465
  # Encodes the given token and options into an Authorization header value.
442
466
  #
443
467
  # token - String token.
@@ -2,7 +2,7 @@ module ActionController
2
2
  module ImplicitRender
3
3
  def send_action(method, *args)
4
4
  ret = super
5
- default_render unless response_body
5
+ default_render unless performed?
6
6
  ret
7
7
  end
8
8
 
@@ -11,6 +11,7 @@ module ActionController
11
11
  extend ActiveSupport::Concern
12
12
 
13
13
  include AbstractController::Logger
14
+ include ActionController::RackDelegation
14
15
 
15
16
  attr_internal :view_runtime
16
17
 
@@ -59,7 +60,7 @@ module ActionController
59
60
  ActiveSupport::Notifications.instrument("redirect_to.action_controller") do |payload|
60
61
  result = super
61
62
  payload[:status] = response.status
62
- payload[:location] = response.location
63
+ payload[:location] = response.filtered_location
63
64
  result
64
65
  end
65
66
  end