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
@@ -1,6 +1,5 @@
1
1
  require 'securerandom'
2
2
  require 'active_support/core_ext/string/access'
3
- require 'active_support/core_ext/object/blank'
4
3
 
5
4
  module ActionDispatch
6
5
  # Makes a unique request id available to the action_dispatch.request_id env variable (which is then accessible through
@@ -19,10 +18,7 @@ module ActionDispatch
19
18
 
20
19
  def call(env)
21
20
  env["action_dispatch.request_id"] = external_request_id(env) || internal_request_id
22
- status, headers, body = @app.call(env)
23
-
24
- headers["X-Request-Id"] = env["action_dispatch.request_id"]
25
- [ status, headers, body ]
21
+ @app.call(env).tap { |_status, headers, _body| headers["X-Request-Id"] = env["action_dispatch.request_id"] }
26
22
  end
27
23
 
28
24
  private
@@ -33,7 +29,7 @@ module ActionDispatch
33
29
  end
34
30
 
35
31
  def internal_request_id
36
- SecureRandom.hex(16)
32
+ SecureRandom.uuid
37
33
  end
38
34
  end
39
35
  end
@@ -2,37 +2,31 @@ require 'rack/utils'
2
2
  require 'rack/request'
3
3
  require 'rack/session/abstract/id'
4
4
  require 'action_dispatch/middleware/cookies'
5
- require 'active_support/core_ext/object/blank'
5
+ require 'action_dispatch/request/session'
6
6
 
7
7
  module ActionDispatch
8
8
  module Session
9
9
  class SessionRestoreError < StandardError #:nodoc:
10
- end
10
+ attr_reader :original_exception
11
+
12
+ def initialize(const_error)
13
+ @original_exception = const_error
11
14
 
12
- module DestroyableSession
13
- def destroy
14
- clear
15
- options = @env[Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY] if @env
16
- options ||= {}
17
- @by.send(:destroy_session, @env, options[:id], options) if @by
18
- options[:id] = nil
19
- @loaded = false
15
+ super("Session contains objects whose class definition isn't available.\n" +
16
+ "Remember to require the classes for all objects kept in the session.\n" +
17
+ "(Original exception: #{const_error.message} [#{const_error.class}])\n")
20
18
  end
21
19
  end
22
20
 
23
- ::Rack::Session::Abstract::SessionHash.send :include, DestroyableSession
24
-
25
21
  module Compatibility
26
22
  def initialize(app, options = {})
27
23
  options[:key] ||= '_session_id'
28
- # FIXME Rack's secret is not being used
29
- options[:secret] ||= SecureRandom.hex(30)
30
24
  super
31
25
  end
32
26
 
33
27
  def generate_sid
34
28
  sid = SecureRandom.hex(16)
35
- sid.encode!('UTF-8') if sid.respond_to?(:encode!)
29
+ sid.encode!(Encoding::UTF_8)
36
30
  sid
37
31
  end
38
32
 
@@ -60,11 +54,8 @@ module ActionDispatch
60
54
  begin
61
55
  # Note that the regexp does not allow $1 to end with a ':'
62
56
  $1.constantize
63
- rescue LoadError, NameError => const_error
64
- raise ActionDispatch::Session::SessionRestoreError,
65
- "Session contains objects whose class definition isn't available.\n" +
66
- "Remember to require the classes for all objects kept in the session.\n" +
67
- "(Original exception: #{const_error.message} [#{const_error.class}])\n"
57
+ rescue LoadError, NameError => e
58
+ raise ActionDispatch::Session::SessionRestoreError, e, e.backtrace
68
59
  end
69
60
  retry
70
61
  else
@@ -73,9 +64,20 @@ module ActionDispatch
73
64
  end
74
65
  end
75
66
 
67
+ module SessionObject # :nodoc:
68
+ def prepare_session(env)
69
+ Request::Session.create(self, env, @default_options)
70
+ end
71
+
72
+ def loaded_session?(session)
73
+ !session.is_a?(Request::Session) || session.loaded?
74
+ end
75
+ end
76
+
76
77
  class AbstractStore < Rack::Session::Abstract::ID
77
78
  include Compatibility
78
79
  include StaleSessionCheck
80
+ include SessionObject
79
81
 
80
82
  private
81
83
 
@@ -1,53 +1,92 @@
1
1
  require 'active_support/core_ext/hash/keys'
2
- require 'active_support/core_ext/object/blank'
3
2
  require 'action_dispatch/middleware/session/abstract_store'
4
3
  require 'rack/session/cookie'
5
4
 
6
5
  module ActionDispatch
7
6
  module Session
8
- # This cookie-based session store is the Rails default. Sessions typically
9
- # contain at most a user_id and flash message; both fit within the 4K cookie
10
- # size limit. Cookie-based sessions are dramatically faster than the
11
- # alternatives.
7
+ # This cookie-based session store is the Rails default. It is
8
+ # dramatically faster than the alternatives.
12
9
  #
13
- # If you have more than 4K of session data or don't want your data to be
14
- # visible to the user, pick another session store.
10
+ # Sessions typically contain at most a user_id and flash message; both fit
11
+ # within the 4K cookie size limit. A CookieOverflow exception is raised if
12
+ # you attempt to store more than 4K of data.
15
13
  #
16
- # CookieOverflow is raised if you attempt to store more than 4K of data.
14
+ # The cookie jar used for storage is automatically configured to be the
15
+ # best possible option given your application's configuration.
17
16
  #
18
- # A message digest is included with the cookie to ensure data integrity:
19
- # a user cannot alter his +user_id+ without knowing the secret key
20
- # included in the hash. New apps are generated with a pregenerated secret
21
- # in config/environment.rb. Set your own for old apps you're upgrading.
17
+ # If you only have secret_token set, your cookies will be signed, but
18
+ # not encrypted. This means a user cannot alter his +user_id+ without
19
+ # knowing your app's secret key, but can easily read his +user_id+. This
20
+ # was the default for Rails 3 apps.
22
21
  #
23
- # Session options:
22
+ # If you have secret_key_base set, your cookies will be encrypted. This
23
+ # goes a step further than signed cookies in that encrypted cookies cannot
24
+ # be altered or read by users. This is the default starting in Rails 4.
24
25
  #
25
- # * <tt>:secret</tt>: An application-wide key string. It's important that
26
- # the secret is not vulnerable to a dictionary attack. Therefore, you
27
- # should choose a secret consisting of random numbers and letters and
28
- # more than 30 characters.
26
+ # If you have both secret_token and secret_key base set, your cookies will
27
+ # be encrypted, and signed cookies generated by Rails 3 will be
28
+ # transparently read and encrypted to provide a smooth upgrade path.
29
29
  #
30
- # :secret => '449fe2e7daee471bffae2fd8dc02313d'
30
+ # Configure your session store in config/initializers/session_store.rb:
31
31
  #
32
- # * <tt>:digest</tt>: The message digest algorithm used to verify session
33
- # integrity defaults to 'SHA1' but may be any digest provided by OpenSSL,
34
- # such as 'MD5', 'RIPEMD160', 'SHA256', etc.
32
+ # Myapp::Application.config.session_store :cookie_store, key: '_your_app_session'
35
33
  #
36
- # To generate a secret key for an existing application, run
37
- # "rake secret" and set the key in config/initializers/secret_token.rb.
34
+ # Configure your secret key in config/initializers/secret_token.rb:
35
+ #
36
+ # Myapp::Application.config.secret_key_base 'secret key'
37
+ #
38
+ # To generate a secret key for an existing application, run `rake secret`.
39
+ #
40
+ # If you are upgrading an existing Rails 3 app, you should leave your
41
+ # existing secret_token in place and simply add the new secret_key_base.
42
+ # Note that you should wait to set secret_key_base until you have 100% of
43
+ # your userbase on Rails 4 and are reasonably sure you will not need to
44
+ # rollback to Rails 3. This is because cookies signed based on the new
45
+ # secret_key_base in Rails 4 are not backwards compatible with Rails 3.
46
+ # You are free to leave your existing secret_token in place, not set the
47
+ # new secret_key_base, and ignore the deprecation warnings until you are
48
+ # reasonably sure that your upgrade is otherwise complete. Additionally,
49
+ # you should take care to make sure you are not relying on the ability to
50
+ # decode signed cookies generated by your app in external applications or
51
+ # Javascript before upgrading.
38
52
  #
39
53
  # Note that changing digest or secret invalidates all existing sessions!
40
- class CookieStore < Rack::Session::Cookie
54
+ class CookieStore < Rack::Session::Abstract::ID
41
55
  include Compatibility
42
56
  include StaleSessionCheck
57
+ include SessionObject
58
+
59
+ def initialize(app, options={})
60
+ super(app, options.merge!(:cookie_only => true))
61
+ end
62
+
63
+ def destroy_session(env, session_id, options)
64
+ new_sid = generate_sid unless options[:drop]
65
+ # Reset hash and Assign the new session id
66
+ env["action_dispatch.request.unsigned_session_cookie"] = new_sid ? { "session_id" => new_sid } : {}
67
+ new_sid
68
+ end
69
+
70
+ def load_session(env)
71
+ stale_session_check! do
72
+ data = unpacked_cookie_data(env)
73
+ data = persistent_session_id!(data)
74
+ [data["session_id"], data]
75
+ end
76
+ end
43
77
 
44
78
  private
45
79
 
80
+ def extract_session_id(env)
81
+ stale_session_check! do
82
+ unpacked_cookie_data(env)["session_id"]
83
+ end
84
+ end
85
+
46
86
  def unpacked_cookie_data(env)
47
87
  env["action_dispatch.request.unsigned_session_cookie"] ||= begin
48
88
  stale_session_check! do
49
- request = ActionDispatch::Request.new(env)
50
- if data = request.cookie_jar.signed[@key]
89
+ if data = get_cookie(env)
51
90
  data.stringify_keys!
52
91
  end
53
92
  data || {}
@@ -55,13 +94,28 @@ module ActionDispatch
55
94
  end
56
95
  end
57
96
 
97
+ def persistent_session_id!(data, sid=nil)
98
+ data ||= {}
99
+ data["session_id"] ||= sid || generate_sid
100
+ data
101
+ end
102
+
58
103
  def set_session(env, sid, session_data, options)
59
- session_data.merge!("session_id" => sid)
104
+ session_data["session_id"] = sid
105
+ session_data
60
106
  end
61
107
 
62
108
  def set_cookie(env, session_id, cookie)
109
+ cookie_jar(env)[@key] = cookie
110
+ end
111
+
112
+ def get_cookie(env)
113
+ cookie_jar(env)[@key]
114
+ end
115
+
116
+ def cookie_jar(env)
63
117
  request = ActionDispatch::Request.new(env)
64
- request.cookie_jar.signed[@key] = cookie
118
+ request.cookie_jar.signed_or_encrypted
65
119
  end
66
120
  end
67
121
  end
@@ -1,14 +1,19 @@
1
1
  require 'action_dispatch/middleware/session/abstract_store'
2
- require 'rack/session/memcache'
2
+ begin
3
+ require 'rack/session/dalli'
4
+ rescue LoadError => e
5
+ $stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
6
+ raise e
7
+ end
3
8
 
4
9
  module ActionDispatch
5
10
  module Session
6
- class MemCacheStore < Rack::Session::Memcache
11
+ class MemCacheStore < Rack::Session::Dalli
7
12
  include Compatibility
8
13
  include StaleSessionCheck
14
+ include SessionObject
9
15
 
10
16
  def initialize(app, options = {})
11
- require 'memcache'
12
17
  options[:expire_after] ||= options[:expires]
13
18
  super
14
19
  end
@@ -1,73 +1,40 @@
1
1
  require 'action_dispatch/http/request'
2
2
  require 'action_dispatch/middleware/exception_wrapper'
3
- require 'active_support/deprecation'
4
3
 
5
4
  module ActionDispatch
6
5
  # This middleware rescues any exception returned by the application
7
6
  # and calls an exceptions app that will wrap it in a format for the end user.
8
7
  #
9
8
  # The exceptions app should be passed as parameter on initialization
10
- # of ShowExceptions. Everytime there is an exception, ShowExceptions will
9
+ # of ShowExceptions. Every time there is an exception, ShowExceptions will
11
10
  # store the exception in env["action_dispatch.exception"], rewrite the
12
11
  # PATH_INFO to the exception status code and call the rack app.
13
- #
12
+ #
14
13
  # If the application returns a "X-Cascade" pass response, this middleware
15
14
  # will send an empty response as result with the correct status code.
16
15
  # If any exception happens inside the exceptions app, this middleware
17
16
  # catches the exceptions and returns a FAILSAFE_RESPONSE.
18
17
  class ShowExceptions
19
- FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'},
20
- ["<html><body><h1>500 Internal Server Error</h1>" <<
21
- "If you are the administrator of this website, then please read this web " <<
22
- "application's log file and/or the web server's log file to find out what " <<
23
- "went wrong.</body></html>"]]
24
-
25
- class << self
26
- def rescue_responses
27
- ActiveSupport::Deprecation.warn "ActionDispatch::ShowExceptions.rescue_responses is deprecated. " \
28
- "Please configure your exceptions using a railtie or in your application config instead."
29
- ExceptionWrapper.rescue_responses
30
- end
31
-
32
- def rescue_templates
33
- ActiveSupport::Deprecation.warn "ActionDispatch::ShowExceptions.rescue_templates is deprecated. " \
34
- "Please configure your exceptions using a railtie or in your application config instead."
35
- ExceptionWrapper.rescue_templates
36
- end
37
- end
38
-
39
- def initialize(app, exceptions_app = nil)
40
- if [true, false].include?(exceptions_app)
41
- ActiveSupport::Deprecation.warn "Passing consider_all_requests_local option to ActionDispatch::ShowExceptions middleware no longer works"
42
- exceptions_app = nil
43
- end
44
-
45
- if exceptions_app.nil?
46
- raise ArgumentError, "You need to pass an exceptions_app when initializing ActionDispatch::ShowExceptions. " \
47
- "In case you want to render pages from a public path, you can use ActionDispatch::PublicExceptions.new('path/to/public')"
48
- end
18
+ FAILSAFE_RESPONSE = [500, { 'Content-Type' => 'text/plain' },
19
+ ["500 Internal Server Error\n" \
20
+ "If you are the administrator of this website, then please read this web " \
21
+ "application's log file and/or the web server's log file to find out what " \
22
+ "went wrong."]]
49
23
 
24
+ def initialize(app, exceptions_app)
50
25
  @app = app
51
26
  @exceptions_app = exceptions_app
52
27
  end
53
28
 
54
29
  def call(env)
55
- begin
56
- response = @app.call(env)
57
- rescue Exception => exception
58
- raise exception if env['action_dispatch.show_exceptions'] == false
59
- end
60
-
61
- response || render_exception(env, exception)
30
+ @app.call(env)
31
+ rescue Exception => exception
32
+ raise exception if env['action_dispatch.show_exceptions'] == false
33
+ render_exception(env, exception)
62
34
  end
63
35
 
64
36
  private
65
37
 
66
- # Define this method because some plugins were monkey patching it.
67
- # Remove this after 3.2 is out with the other deprecations in this class.
68
- def status_code(*)
69
- end
70
-
71
38
  def render_exception(env, exception)
72
39
  wrapper = ExceptionWrapper.new(env, exception)
73
40
  status = wrapper.status_code
@@ -0,0 +1,70 @@
1
+ module ActionDispatch
2
+ class SSL
3
+ YEAR = 31536000
4
+
5
+ def self.default_hsts_options
6
+ { :expires => YEAR, :subdomains => false }
7
+ end
8
+
9
+ def initialize(app, options = {})
10
+ @app = app
11
+
12
+ @hsts = options.fetch(:hsts, {})
13
+ @hsts = {} if @hsts == true
14
+ @hsts = self.class.default_hsts_options.merge(@hsts) if @hsts
15
+
16
+ @host = options[:host]
17
+ @port = options[:port]
18
+ end
19
+
20
+ def call(env)
21
+ request = Request.new(env)
22
+
23
+ if request.ssl?
24
+ status, headers, body = @app.call(env)
25
+ headers = hsts_headers.merge(headers)
26
+ flag_cookies_as_secure!(headers)
27
+ [status, headers, body]
28
+ else
29
+ redirect_to_https(request)
30
+ end
31
+ end
32
+
33
+ private
34
+ def redirect_to_https(request)
35
+ url = URI(request.url)
36
+ url.scheme = "https"
37
+ url.host = @host if @host
38
+ url.port = @port if @port
39
+ headers = hsts_headers.merge('Content-Type' => 'text/html',
40
+ 'Location' => url.to_s)
41
+
42
+ [301, headers, []]
43
+ end
44
+
45
+ # http://tools.ietf.org/html/draft-hodges-strict-transport-sec-02
46
+ def hsts_headers
47
+ if @hsts
48
+ value = "max-age=#{@hsts[:expires].to_i}"
49
+ value += "; includeSubDomains" if @hsts[:subdomains]
50
+ { 'Strict-Transport-Security' => value }
51
+ else
52
+ {}
53
+ end
54
+ end
55
+
56
+ def flag_cookies_as_secure!(headers)
57
+ if cookies = headers['Set-Cookie']
58
+ cookies = cookies.split("\n")
59
+
60
+ headers['Set-Cookie'] = cookies.map { |cookie|
61
+ if cookie !~ /;\s+secure(;|$)/
62
+ "#{cookie}; secure"
63
+ else
64
+ cookie
65
+ end
66
+ }.join("\n")
67
+ end
68
+ end
69
+ end
70
+ end
@@ -75,6 +75,11 @@ module ActionDispatch
75
75
  middlewares[i]
76
76
  end
77
77
 
78
+ def unshift(*args, &block)
79
+ middleware = self.class::Middleware.new(*args, &block)
80
+ middlewares.unshift(middleware)
81
+ end
82
+
78
83
  def initialize_copy(other)
79
84
  self.middlewares = other.middlewares.dup
80
85
  end
@@ -110,7 +115,7 @@ module ActionDispatch
110
115
  def build(app = nil, &block)
111
116
  app ||= block
112
117
  raise "MiddlewareStack#build requires an app" unless app
113
- middlewares.reverse.inject(app) { |a, e| e.build(a) }
118
+ middlewares.freeze.reverse.inject(app) { |a, e| e.build(a) }
114
119
  end
115
120
 
116
121
  protected
@@ -1,4 +1,5 @@
1
1
  require 'rack/utils'
2
+ require 'active_support/core_ext/uri'
2
3
 
3
4
  module ActionDispatch
4
5
  class FileHandler
@@ -29,7 +30,7 @@ module ActionDispatch
29
30
 
30
31
  def ext
31
32
  @ext ||= begin
32
- ext = ::ActionController::Base.page_cache_extension
33
+ ext = ::ActionController::Base.default_static_extension
33
34
  "{,#{ext},/index#{ext}}"
34
35
  end
35
36
  end
@@ -1,8 +1,8 @@
1
1
  <% unless @exception.blamed_files.blank? %>
2
2
  <% if (hide = @exception.blamed_files.length > 8) %>
3
- <a href="#" onclick="document.getElementById('blame_trace').style.display='block'; return false;">Show blamed files</a>
3
+ <a href="#" onclick="return toggleTrace()">Toggle blamed files</a>
4
4
  <% end %>
5
- <pre id="blame_trace" <%='style="display:none"' if hide %>><code><%=h @exception.describe_blame %></code></pre>
5
+ <pre id="blame_trace" <%='style="display:none"' if hide %>><code><%= @exception.describe_blame %></code></pre>
6
6
  <% end %>
7
7
 
8
8
  <%
@@ -12,20 +12,23 @@
12
12
 
13
13
  request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
14
14
 
15
- def debug_hash(hash)
16
- hash.sort_by { |k, v| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
15
+ def debug_hash(object)
16
+ object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
17
17
  end unless self.class.method_defined?(:debug_hash)
18
18
  %>
19
19
 
20
20
  <h2 style="margin-top: 30px">Request</h2>
21
- <p><b>Parameters</b>: <pre><%=h request_dump %></pre></p>
21
+ <p><b>Parameters</b>:</p> <pre><%= request_dump %></pre>
22
22
 
23
- <p><a href="#" onclick="document.getElementById('session_dump').style.display='block'; return false;">Show session dump</a></p>
24
- <div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div>
25
-
26
- <p><a href="#" onclick="document.getElementById('env_dump').style.display='block'; return false;">Show env dump</a></p>
27
- <div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>
23
+ <div class="details">
24
+ <div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
25
+ <div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div>
26
+ </div>
28
27
 
28
+ <div class="details">
29
+ <div class="summary"><a href="#" onclick="return toggleEnvDump()">Toggle env dump</a></div>
30
+ <div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>
31
+ </div>
29
32
 
30
33
  <h2 style="margin-top: 30px">Response</h2>
31
- <p><b>Headers</b>: <pre><%=h defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></pre></p>
34
+ <p><b>Headers</b>:</p> <pre><%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></pre>
@@ -0,0 +1,25 @@
1
+ <% if @source_extract %>
2
+ <div class="source">
3
+ <div class="info">
4
+ Extracted source (around line <strong>#<%= @line_number %></strong>):
5
+ </div>
6
+ <div class="data">
7
+ <table cellpadding="0" cellspacing="0" class="lines">
8
+ <tr>
9
+ <td>
10
+ <pre class="line_numbers">
11
+ <% @source_extract.keys.each do |line_number| %>
12
+ <span><%= line_number -%></span>
13
+ <% end %>
14
+ </pre>
15
+ </td>
16
+ <td width="100%">
17
+ <pre>
18
+ <% @source_extract.each do |line, source| -%><div class="line<%= " active" if line == @line_number -%>"><%= source -%></div><% end -%>
19
+ </pre>
20
+ </td>
21
+ </tr>
22
+ </table>
23
+ </div>
24
+ </div>
25
+ <% end %>
@@ -1,10 +1,8 @@
1
1
  <%
2
- traces = [
3
- ["Application Trace", @application_trace],
4
- ["Framework Trace", @framework_trace],
5
- ["Full Trace", @full_trace]
6
- ]
7
- names = traces.collect {|name, trace| name}
2
+ traces = { "Application Trace" => @application_trace,
3
+ "Framework Trace" => @framework_trace,
4
+ "Full Trace" => @full_trace }
5
+ names = traces.keys
8
6
  %>
9
7
 
10
8
  <p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p>
@@ -12,15 +10,15 @@
12
10
  <div id="traces">
13
11
  <% names.each do |name| %>
14
12
  <%
15
- show = "document.getElementById('#{name.gsub(/\s/, '-')}').style.display='block';"
16
- hide = (names - [name]).collect {|hide_name| "document.getElementById('#{hide_name.gsub(/\s/, '-')}').style.display='none';"}
13
+ show = "show('#{name.gsub(/\s/, '-')}');"
14
+ hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}');"}
17
15
  %>
18
16
  <a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
19
17
  <% end %>
20
18
 
21
19
  <% traces.each do |name, trace| %>
22
20
  <div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == "Application Trace") ? 'block' : 'none' %>;">
23
- <pre><code><%=h trace.join "\n" %></code></pre>
21
+ <pre><code><%= trace.join "\n" %></code></pre>
24
22
  </div>
25
23
  <% end %>
26
24
  </div>
@@ -1,10 +1,16 @@
1
- <h1>
2
- <%=h @exception.class.to_s %>
3
- <% if @request.parameters['controller'] %>
4
- in <%=h @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>
5
- <% end %>
6
- </h1>
7
- <pre><%=h @exception.message %></pre>
1
+ <header>
2
+ <h1>
3
+ <%= @exception.class.to_s %>
4
+ <% if @request.parameters['controller'] %>
5
+ in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
6
+ <% end %>
7
+ </h1>
8
+ </header>
8
9
 
9
- <%= render :template => "rescues/_trace" %>
10
- <%= render :template => "rescues/_request_and_response" %>
10
+ <div id="container">
11
+ <h2><%= @exception.message %></h2>
12
+
13
+ <%= render template: "rescues/_source" %>
14
+ <%= render template: "rescues/_trace" %>
15
+ <%= render template: "rescues/_request_and_response" %>
16
+ </div>