actionpack 3.2.22.5 → 5.2.4

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 (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +279 -603
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -297
  5. data/lib/abstract_controller/asset_paths.rb +4 -2
  6. data/lib/abstract_controller/base.rb +82 -52
  7. data/lib/abstract_controller/caching/fragments.rb +166 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +117 -103
  10. data/lib/abstract_controller/collector.rb +18 -7
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +65 -38
  13. data/lib/abstract_controller/logger.rb +3 -2
  14. data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
  15. data/lib/abstract_controller/rendering.rb +77 -129
  16. data/lib/abstract_controller/translation.rb +21 -3
  17. data/lib/abstract_controller/url_for.rb +9 -7
  18. data/lib/abstract_controller.rb +12 -13
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +81 -40
  22. data/lib/action_controller/caching.rb +22 -62
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +30 -18
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +190 -47
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +40 -65
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  32. data/lib/action_controller/metal/exceptions.rb +19 -12
  33. data/lib/action_controller/metal/flash.rb +42 -9
  34. data/lib/action_controller/metal/force_ssl.rb +79 -19
  35. data/lib/action_controller/metal/head.rb +35 -10
  36. data/lib/action_controller/metal/helpers.rb +31 -21
  37. data/lib/action_controller/metal/http_authentication.rb +182 -134
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +28 -26
  40. data/lib/action_controller/metal/live.rb +312 -0
  41. data/lib/action_controller/metal/mime_responds.rb +159 -163
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +146 -93
  44. data/lib/action_controller/metal/redirecting.rb +80 -56
  45. data/lib/action_controller/metal/renderers.rb +119 -47
  46. data/lib/action_controller/metal/rendering.rb +89 -32
  47. data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +39 -45
  50. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  51. data/lib/action_controller/metal/testing.rb +8 -29
  52. data/lib/action_controller/metal/url_for.rb +43 -32
  53. data/lib/action_controller/metal.rb +112 -106
  54. data/lib/action_controller/railtie.rb +56 -18
  55. data/lib/action_controller/railties/helpers.rb +24 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +402 -347
  59. data/lib/action_controller.rb +31 -30
  60. data/lib/action_dispatch/http/cache.rb +133 -34
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +40 -24
  63. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  64. data/lib/action_dispatch/http/headers.rb +117 -16
  65. data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
  66. data/lib/action_dispatch/http/mime_type.rb +198 -146
  67. data/lib/action_dispatch/http/mime_types.rb +22 -7
  68. data/lib/action_dispatch/http/parameter_filter.rb +61 -49
  69. data/lib/action_dispatch/http/parameters.rb +94 -51
  70. data/lib/action_dispatch/http/rack_cache.rb +4 -3
  71. data/lib/action_dispatch/http/request.rb +262 -117
  72. data/lib/action_dispatch/http/response.rb +400 -86
  73. data/lib/action_dispatch/http/upload.rb +66 -29
  74. data/lib/action_dispatch/http/url.rb +232 -60
  75. data/lib/action_dispatch/journey/formatter.rb +189 -0
  76. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  79. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  80. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  83. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  84. data/lib/action_dispatch/journey/parser.rb +199 -0
  85. data/lib/action_dispatch/journey/parser.y +50 -0
  86. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  87. data/lib/action_dispatch/journey/path/pattern.rb +199 -0
  88. data/lib/action_dispatch/journey/route.rb +203 -0
  89. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  90. data/lib/action_dispatch/journey/router.rb +156 -0
  91. data/lib/action_dispatch/journey/routes.rb +82 -0
  92. data/lib/action_dispatch/journey/scanner.rb +64 -0
  93. data/lib/action_dispatch/journey/visitors.rb +268 -0
  94. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  95. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  96. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  97. data/lib/action_dispatch/journey.rb +7 -0
  98. data/lib/action_dispatch/middleware/callbacks.rb +17 -13
  99. data/lib/action_dispatch/middleware/cookies.rb +494 -162
  100. data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
  101. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  102. data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
  103. data/lib/action_dispatch/middleware/executor.rb +21 -0
  104. data/lib/action_dispatch/middleware/flash.rb +128 -91
  105. data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
  106. data/lib/action_dispatch/middleware/reloader.rb +6 -83
  107. data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
  108. data/lib/action_dispatch/middleware/request_id.rb +19 -15
  109. data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
  110. data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
  111. data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
  112. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
  113. data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
  114. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  115. data/lib/action_dispatch/middleware/stack.rb +33 -41
  116. data/lib/action_dispatch/middleware/static.rb +92 -48
  117. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +134 -5
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  136. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  138. data/lib/action_dispatch/railtie.rb +29 -8
  139. data/lib/action_dispatch/request/session.rb +234 -0
  140. data/lib/action_dispatch/request/utils.rb +78 -0
  141. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  142. data/lib/action_dispatch/routing/inspector.rb +225 -0
  143. data/lib/action_dispatch/routing/mapper.rb +1329 -582
  144. data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
  145. data/lib/action_dispatch/routing/redirection.rb +120 -50
  146. data/lib/action_dispatch/routing/route_set.rb +545 -322
  147. data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
  148. data/lib/action_dispatch/routing/url_for.rb +103 -34
  149. data/lib/action_dispatch/routing.rb +66 -99
  150. data/lib/action_dispatch/system_test_case.rb +147 -0
  151. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  152. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  153. data/lib/action_dispatch/system_testing/server.rb +31 -0
  154. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  157. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  158. data/lib/action_dispatch/testing/assertions/response.rb +53 -42
  159. data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
  160. data/lib/action_dispatch/testing/assertions.rb +15 -9
  161. data/lib/action_dispatch/testing/integration.rb +361 -207
  162. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  163. data/lib/action_dispatch/testing/test_process.rb +28 -19
  164. data/lib/action_dispatch/testing/test_request.rb +30 -33
  165. data/lib/action_dispatch/testing/test_response.rb +35 -11
  166. data/lib/action_dispatch.rb +42 -32
  167. data/lib/action_pack/gem_version.rb +17 -0
  168. data/lib/action_pack/version.rb +7 -7
  169. data/lib/action_pack.rb +4 -2
  170. metadata +116 -175
  171. data/lib/abstract_controller/layouts.rb +0 -423
  172. data/lib/abstract_controller/view_paths.rb +0 -96
  173. data/lib/action_controller/caching/actions.rb +0 -185
  174. data/lib/action_controller/caching/fragments.rb +0 -127
  175. data/lib/action_controller/caching/pages.rb +0 -187
  176. data/lib/action_controller/caching/sweeping.rb +0 -97
  177. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  178. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  179. data/lib/action_controller/deprecated.rb +0 -3
  180. data/lib/action_controller/metal/compatibility.rb +0 -65
  181. data/lib/action_controller/metal/hide_actions.rb +0 -41
  182. data/lib/action_controller/metal/rack_delegation.rb +0 -26
  183. data/lib/action_controller/metal/responder.rb +0 -286
  184. data/lib/action_controller/metal/session_management.rb +0 -14
  185. data/lib/action_controller/middleware.rb +0 -39
  186. data/lib/action_controller/railties/paths.rb +0 -25
  187. data/lib/action_controller/record_identifier.rb +0 -85
  188. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  189. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  190. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  191. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  192. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  193. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  194. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  195. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  196. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  197. data/lib/action_dispatch/middleware/head.rb +0 -18
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -75
  199. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  200. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  201. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  202. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  203. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  204. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  205. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  206. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  207. data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
  208. data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
  209. data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
  210. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  211. data/lib/action_view/asset_paths.rb +0 -142
  212. data/lib/action_view/base.rb +0 -220
  213. data/lib/action_view/buffers.rb +0 -43
  214. data/lib/action_view/context.rb +0 -36
  215. data/lib/action_view/flows.rb +0 -79
  216. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  217. data/lib/action_view/helpers/asset_paths.rb +0 -7
  218. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  219. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  220. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  221. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  222. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  223. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  224. data/lib/action_view/helpers/cache_helper.rb +0 -64
  225. data/lib/action_view/helpers/capture_helper.rb +0 -203
  226. data/lib/action_view/helpers/controller_helper.rb +0 -25
  227. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  228. data/lib/action_view/helpers/date_helper.rb +0 -1062
  229. data/lib/action_view/helpers/debug_helper.rb +0 -40
  230. data/lib/action_view/helpers/form_helper.rb +0 -1486
  231. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  232. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  233. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  234. data/lib/action_view/helpers/number_helper.rb +0 -622
  235. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  236. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  237. data/lib/action_view/helpers/rendering_helper.rb +0 -92
  238. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  239. data/lib/action_view/helpers/tag_helper.rb +0 -167
  240. data/lib/action_view/helpers/text_helper.rb +0 -426
  241. data/lib/action_view/helpers/translation_helper.rb +0 -91
  242. data/lib/action_view/helpers/url_helper.rb +0 -693
  243. data/lib/action_view/helpers.rb +0 -60
  244. data/lib/action_view/locale/en.yml +0 -160
  245. data/lib/action_view/log_subscriber.rb +0 -28
  246. data/lib/action_view/lookup_context.rb +0 -258
  247. data/lib/action_view/path_set.rb +0 -101
  248. data/lib/action_view/railtie.rb +0 -55
  249. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  250. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  251. data/lib/action_view/renderer/renderer.rb +0 -61
  252. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  253. data/lib/action_view/renderer/template_renderer.rb +0 -95
  254. data/lib/action_view/template/error.rb +0 -128
  255. data/lib/action_view/template/handlers/builder.rb +0 -26
  256. data/lib/action_view/template/handlers/erb.rb +0 -125
  257. data/lib/action_view/template/handlers.rb +0 -50
  258. data/lib/action_view/template/resolver.rb +0 -298
  259. data/lib/action_view/template/text.rb +0 -30
  260. data/lib/action_view/template.rb +0 -337
  261. data/lib/action_view/test_case.rb +0 -246
  262. data/lib/action_view/testing/resolvers.rb +0 -49
  263. data/lib/action_view.rb +0 -84
  264. data/lib/sprockets/assets.rake +0 -99
  265. data/lib/sprockets/bootstrap.rb +0 -37
  266. data/lib/sprockets/compressors.rb +0 -83
  267. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  268. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  269. data/lib/sprockets/helpers.rb +0 -6
  270. data/lib/sprockets/railtie.rb +0 -62
  271. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,14 +1,25 @@
1
- require 'action_dispatch/middleware/session/abstract_store'
2
- require 'rack/session/memcache'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/middleware/session/abstract_store"
4
+ begin
5
+ require "rack/session/dalli"
6
+ rescue LoadError => e
7
+ $stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
8
+ raise e
9
+ end
3
10
 
4
11
  module ActionDispatch
5
12
  module Session
6
- class MemCacheStore < Rack::Session::Memcache
13
+ # A session store that uses MemCache to implement storage.
14
+ #
15
+ # ==== Options
16
+ # * <tt>expire_after</tt> - The length of time a session will be stored before automatically expiring.
17
+ class MemCacheStore < Rack::Session::Dalli
7
18
  include Compatibility
8
19
  include StaleSessionCheck
20
+ include SessionObject
9
21
 
10
22
  def initialize(app, options = {})
11
- require 'memcache'
12
23
  options[:expire_after] ||= options[:expires]
13
24
  super
14
25
  end
@@ -1,87 +1,62 @@
1
- require 'action_dispatch/http/request'
2
- require 'action_dispatch/middleware/exception_wrapper'
3
- require 'active_support/deprecation'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/http/request"
4
+ require "action_dispatch/middleware/exception_wrapper"
4
5
 
5
6
  module ActionDispatch
6
7
  # This middleware rescues any exception returned by the application
7
8
  # and calls an exceptions app that will wrap it in a format for the end user.
8
9
  #
9
10
  # The exceptions app should be passed as parameter on initialization
10
- # of ShowExceptions. Everytime there is an exception, ShowExceptions will
11
+ # of ShowExceptions. Every time there is an exception, ShowExceptions will
11
12
  # store the exception in env["action_dispatch.exception"], rewrite the
12
- # PATH_INFO to the exception status code and call the rack app.
13
- #
13
+ # PATH_INFO to the exception status code and call the Rack app.
14
+ #
14
15
  # If the application returns a "X-Cascade" pass response, this middleware
15
16
  # will send an empty response as result with the correct status code.
16
17
  # If any exception happens inside the exceptions app, this middleware
17
18
  # catches the exceptions and returns a FAILSAFE_RESPONSE.
18
19
  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
20
+ FAILSAFE_RESPONSE = [500, { "Content-Type" => "text/plain" },
21
+ ["500 Internal Server Error\n" \
22
+ "If you are the administrator of this website, then please read this web " \
23
+ "application's log file and/or the web server's log file to find out what " \
24
+ "went wrong."]]
49
25
 
26
+ def initialize(app, exceptions_app)
50
27
  @app = app
51
28
  @exceptions_app = exceptions_app
52
29
  end
53
30
 
54
31
  def call(env)
55
- begin
56
- response = @app.call(env)
57
- rescue Exception => exception
58
- raise exception if env['action_dispatch.show_exceptions'] == false
32
+ request = ActionDispatch::Request.new env
33
+ @app.call(env)
34
+ rescue Exception => exception
35
+ if request.show_exceptions?
36
+ render_exception(request, exception)
37
+ else
38
+ raise exception
59
39
  end
60
-
61
- response || render_exception(env, exception)
62
40
  end
63
41
 
64
42
  private
65
43
 
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
- def render_exception(env, exception)
72
- wrapper = ExceptionWrapper.new(env, exception)
73
- status = wrapper.status_code
74
- env["action_dispatch.exception"] = wrapper.exception
75
- env["PATH_INFO"] = "/#{status}"
76
- response = @exceptions_app.call(env)
77
- response[1]['X-Cascade'] == 'pass' ? pass_response(status) : response
78
- rescue Exception => failsafe_error
79
- $stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}"
80
- FAILSAFE_RESPONSE
81
- end
44
+ def render_exception(request, exception)
45
+ backtrace_cleaner = request.get_header "action_dispatch.backtrace_cleaner"
46
+ wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
47
+ status = wrapper.status_code
48
+ request.set_header "action_dispatch.exception", wrapper.exception
49
+ request.set_header "action_dispatch.original_path", request.path_info
50
+ request.path_info = "/#{status}"
51
+ response = @exceptions_app.call(request.env)
52
+ response[1]["X-Cascade"] == "pass" ? pass_response(status) : response
53
+ rescue Exception => failsafe_error
54
+ $stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}"
55
+ FAILSAFE_RESPONSE
56
+ end
82
57
 
83
- def pass_response(status)
84
- [status, {"Content-Type" => "text/html; charset=#{Response.default_charset}", "Content-Length" => "0"}, []]
85
- end
58
+ def pass_response(status)
59
+ [status, { "Content-Type" => "text/html; charset=#{Response.default_charset}", "Content-Length" => "0" }, []]
60
+ end
86
61
  end
87
62
  end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ # This middleware is added to the stack when <tt>config.force_ssl = true</tt>, and is passed
5
+ # the options set in +config.ssl_options+. It does three jobs to enforce secure HTTP
6
+ # requests:
7
+ #
8
+ # 1. <b>TLS redirect</b>: Permanently redirects +http://+ requests to +https://+
9
+ # with the same URL host, path, etc. Enabled by default. Set +config.ssl_options+
10
+ # to modify the destination URL
11
+ # (e.g. <tt>redirect: { host: "secure.widgets.com", port: 8080 }</tt>), or set
12
+ # <tt>redirect: false</tt> to disable this feature.
13
+ #
14
+ # Requests can opt-out of redirection with +exclude+:
15
+ #
16
+ # config.ssl_options = { redirect: { exclude: -> request { request.path =~ /healthcheck/ } } }
17
+ #
18
+ # Cookies will not be flagged as secure for excluded requests.
19
+ #
20
+ # 2. <b>Secure cookies</b>: Sets the +secure+ flag on cookies to tell browsers they
21
+ # must not be sent along with +http://+ requests. Enabled by default. Set
22
+ # +config.ssl_options+ with <tt>secure_cookies: false</tt> to disable this feature.
23
+ #
24
+ # 3. <b>HTTP Strict Transport Security (HSTS)</b>: Tells the browser to remember
25
+ # this site as TLS-only and automatically redirect non-TLS requests.
26
+ # Enabled by default. Configure +config.ssl_options+ with <tt>hsts: false</tt> to disable.
27
+ #
28
+ # Set +config.ssl_options+ with <tt>hsts: { ... }</tt> to configure HSTS:
29
+ #
30
+ # * +expires+: How long, in seconds, these settings will stick. The minimum
31
+ # required to qualify for browser preload lists is 1 year. Defaults to
32
+ # 1 year (recommended).
33
+ #
34
+ # * +subdomains+: Set to +true+ to tell the browser to apply these settings
35
+ # to all subdomains. This protects your cookies from interception by a
36
+ # vulnerable site on a subdomain. Defaults to +true+.
37
+ #
38
+ # * +preload+: Advertise that this site may be included in browsers'
39
+ # preloaded HSTS lists. HSTS protects your site on every visit <i>except the
40
+ # first visit</i> since it hasn't seen your HSTS header yet. To close this
41
+ # gap, browser vendors include a baked-in list of HSTS-enabled sites.
42
+ # Go to https://hstspreload.org to submit your site for inclusion.
43
+ # Defaults to +false+.
44
+ #
45
+ # To turn off HSTS, omitting the header is not enough. Browsers will remember the
46
+ # original HSTS directive until it expires. Instead, use the header to tell browsers to
47
+ # expire HSTS immediately. Setting <tt>hsts: false</tt> is a shortcut for
48
+ # <tt>hsts: { expires: 0 }</tt>.
49
+ class SSL
50
+ # :stopdoc:
51
+
52
+ # Default to 1 year, the minimum for browser preload lists.
53
+ HSTS_EXPIRES_IN = 31536000
54
+
55
+ def self.default_hsts_options
56
+ { expires: HSTS_EXPIRES_IN, subdomains: true, preload: false }
57
+ end
58
+
59
+ def initialize(app, redirect: {}, hsts: {}, secure_cookies: true)
60
+ @app = app
61
+
62
+ @redirect = redirect
63
+
64
+ @exclude = @redirect && @redirect[:exclude] || proc { !@redirect }
65
+ @secure_cookies = secure_cookies
66
+
67
+ @hsts_header = build_hsts_header(normalize_hsts_options(hsts))
68
+ end
69
+
70
+ def call(env)
71
+ request = Request.new env
72
+
73
+ if request.ssl?
74
+ @app.call(env).tap do |status, headers, body|
75
+ set_hsts_header! headers
76
+ flag_cookies_as_secure! headers if @secure_cookies && !@exclude.call(request)
77
+ end
78
+ else
79
+ return redirect_to_https request unless @exclude.call(request)
80
+ @app.call(env)
81
+ end
82
+ end
83
+
84
+ private
85
+ def set_hsts_header!(headers)
86
+ headers["Strict-Transport-Security".freeze] ||= @hsts_header
87
+ end
88
+
89
+ def normalize_hsts_options(options)
90
+ case options
91
+ # Explicitly disabling HSTS clears the existing setting from browsers
92
+ # by setting expiry to 0.
93
+ when false
94
+ self.class.default_hsts_options.merge(expires: 0)
95
+ # Default to enabled, with default options.
96
+ when nil, true
97
+ self.class.default_hsts_options
98
+ else
99
+ self.class.default_hsts_options.merge(options)
100
+ end
101
+ end
102
+
103
+ # https://tools.ietf.org/html/rfc6797#section-6.1
104
+ def build_hsts_header(hsts)
105
+ value = "max-age=#{hsts[:expires].to_i}".dup
106
+ value << "; includeSubDomains" if hsts[:subdomains]
107
+ value << "; preload" if hsts[:preload]
108
+ value
109
+ end
110
+
111
+ def flag_cookies_as_secure!(headers)
112
+ if cookies = headers["Set-Cookie".freeze]
113
+ cookies = cookies.split("\n".freeze)
114
+
115
+ headers["Set-Cookie".freeze] = cookies.map { |cookie|
116
+ if cookie !~ /;\s*secure\s*(;|$)/i
117
+ "#{cookie}; secure"
118
+ else
119
+ cookie
120
+ end
121
+ }.join("\n".freeze)
122
+ end
123
+ end
124
+
125
+ def redirect_to_https(request)
126
+ [ @redirect.fetch(:status, redirection_status(request)),
127
+ { "Content-Type" => "text/html",
128
+ "Location" => https_location_for(request) },
129
+ @redirect.fetch(:body, []) ]
130
+ end
131
+
132
+ def redirection_status(request)
133
+ if request.get? || request.head?
134
+ 301 # Issue a permanent redirect via a GET request.
135
+ else
136
+ 307 # Issue a fresh request redirect to preserve the HTTP method.
137
+ end
138
+ end
139
+
140
+ def https_location_for(request)
141
+ host = @redirect[:host] || request.host
142
+ port = @redirect[:port] || request.port
143
+
144
+ location = "https://#{host}".dup
145
+ location << ":#{port}" if port != 80 && port != 443
146
+ location << request.fullpath
147
+ location
148
+ end
149
+ end
150
+ end
@@ -1,28 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/inflector/methods"
2
4
  require "active_support/dependencies"
3
5
 
4
6
  module ActionDispatch
5
7
  class MiddlewareStack
6
8
  class Middleware
7
- attr_reader :args, :block, :name, :classcache
8
-
9
- def initialize(klass_or_name, *args, &block)
10
- @klass = nil
11
-
12
- if klass_or_name.respond_to?(:name)
13
- @klass = klass_or_name
14
- @name = @klass.name
15
- else
16
- @name = klass_or_name.to_s
17
- end
9
+ attr_reader :args, :block, :klass
18
10
 
19
- @classcache = ActiveSupport::Dependencies::Reference
20
- @args, @block = args, block
11
+ def initialize(klass, args, block)
12
+ @klass = klass
13
+ @args = args
14
+ @block = block
21
15
  end
22
16
 
23
- def klass
24
- @klass || classcache[@name]
25
- end
17
+ def name; klass.name; end
26
18
 
27
19
  def ==(middleware)
28
20
  case middleware
@@ -30,24 +22,20 @@ module ActionDispatch
30
22
  klass == middleware.klass
31
23
  when Class
32
24
  klass == middleware
33
- else
34
- normalize(@name) == normalize(middleware)
35
25
  end
36
26
  end
37
27
 
38
28
  def inspect
39
- klass.to_s
29
+ if klass.is_a?(Class)
30
+ klass.to_s
31
+ else
32
+ klass.class.to_s
33
+ end
40
34
  end
41
35
 
42
36
  def build(app)
43
37
  klass.new(app, *args, &block)
44
38
  end
45
-
46
- private
47
-
48
- def normalize(object)
49
- object.to_s.strip.sub(/^::/, '')
50
- end
51
39
  end
52
40
 
53
41
  include Enumerable
@@ -75,14 +63,17 @@ module ActionDispatch
75
63
  middlewares[i]
76
64
  end
77
65
 
66
+ def unshift(klass, *args, &block)
67
+ middlewares.unshift(build_middleware(klass, args, block))
68
+ end
69
+
78
70
  def initialize_copy(other)
79
71
  self.middlewares = other.middlewares.dup
80
72
  end
81
73
 
82
- def insert(index, *args, &block)
74
+ def insert(index, klass, *args, &block)
83
75
  index = assert_index(index, :before)
84
- middleware = self.class::Middleware.new(*args, &block)
85
- middlewares.insert(index, middleware)
76
+ middlewares.insert(index, build_middleware(klass, args, block))
86
77
  end
87
78
 
88
79
  alias_method :insert_before, :insert
@@ -99,26 +90,27 @@ module ActionDispatch
99
90
  end
100
91
 
101
92
  def delete(target)
102
- middlewares.delete target
93
+ middlewares.delete_if { |m| m.klass == target }
103
94
  end
104
95
 
105
- def use(*args, &block)
106
- middleware = self.class::Middleware.new(*args, &block)
107
- middlewares.push(middleware)
96
+ def use(klass, *args, &block)
97
+ middlewares.push(build_middleware(klass, args, block))
108
98
  end
109
99
 
110
100
  def build(app = nil, &block)
111
- app ||= block
112
- raise "MiddlewareStack#build requires an app" unless app
113
- middlewares.reverse.inject(app) { |a, e| e.build(a) }
101
+ middlewares.freeze.reverse.inject(app || block) { |a, e| e.build(a) }
114
102
  end
115
103
 
116
- protected
104
+ private
117
105
 
118
- def assert_index(index, where)
119
- i = index.is_a?(Integer) ? index : middlewares.index(index)
120
- raise "No such middleware to insert #{where}: #{index.inspect}" unless i
121
- i
122
- end
106
+ def assert_index(index, where)
107
+ i = index.is_a?(Integer) ? index : middlewares.index { |m| m.klass == index }
108
+ raise "No such middleware to insert #{where}: #{index.inspect}" unless i
109
+ i
110
+ end
111
+
112
+ def build_middleware(klass, args, block)
113
+ Middleware.new(klass, args, block)
114
+ end
123
115
  end
124
116
  end
@@ -1,86 +1,130 @@
1
- require 'rack/utils'
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/utils"
4
+ require "active_support/core_ext/uri"
2
5
 
3
6
  module ActionDispatch
7
+ # This middleware returns a file's contents from disk in the body response.
8
+ # When initialized, it can accept optional HTTP headers, which will be set
9
+ # when a response containing a file's contents is delivered.
10
+ #
11
+ # This middleware will render the file specified in <tt>env["PATH_INFO"]</tt>
12
+ # where the base path is in the +root+ directory. For example, if the +root+
13
+ # is set to +public/+, then a request with <tt>env["PATH_INFO"]</tt> of
14
+ # +assets/application.js+ will return a response with the contents of a file
15
+ # located at +public/assets/application.js+ if the file exists. If the file
16
+ # does not exist, a 404 "File not Found" response will be returned.
4
17
  class FileHandler
5
- def initialize(root, cache_control)
6
- @root = root.chomp('/')
7
- @compiled_root = /^#{Regexp.escape(root)}/
8
- headers = cache_control && { 'Cache-Control' => cache_control }
18
+ def initialize(root, index: "index", headers: {})
19
+ @root = root.chomp("/").b
9
20
  @file_server = ::Rack::File.new(@root, headers)
21
+ @index = index
10
22
  end
11
23
 
24
+ # Takes a path to a file. If the file is found, has valid encoding, and has
25
+ # correct read permissions, the return value is a URI-escaped string
26
+ # representing the filename. Otherwise, false is returned.
27
+ #
28
+ # Used by the +Static+ class to check the existence of a valid file
29
+ # in the server's +public/+ directory (see Static#call).
12
30
  def match?(path)
13
- path = path.dup
14
-
15
- full_path = path.empty? ? @root : File.join(@root, escape_glob_chars(clean_path_info(unescape_path(path))))
16
- paths = "#{full_path}#{ext}"
31
+ path = ::Rack::Utils.unescape_path path
32
+ return false unless ::Rack::Utils.valid_path? path
33
+ path = ::Rack::Utils.clean_path_info path
34
+
35
+ paths = [path, "#{path}#{ext}", "#{path}/#{@index}#{ext}"]
36
+
37
+ if match = paths.detect { |p|
38
+ path = File.join(@root, p.b)
39
+ begin
40
+ File.file?(path) && File.readable?(path)
41
+ rescue SystemCallError
42
+ false
43
+ end
17
44
 
18
- matches = Dir[paths]
19
- match = matches.detect { |m| File.file?(m) && File.readable?(m) }
20
- if match
21
- match.sub!(@compiled_root, '')
22
- ::Rack::Utils.escape(match)
45
+ }
46
+ return ::Rack::Utils.escape_path(match).b
23
47
  end
24
48
  end
25
49
 
26
50
  def call(env)
27
- @file_server.call(env)
51
+ serve(Rack::Request.new(env))
28
52
  end
29
53
 
30
- def ext
31
- @ext ||= begin
32
- ext = ::ActionController::Base.page_cache_extension
33
- "{,#{ext},/index#{ext}}"
54
+ def serve(request)
55
+ path = request.path_info
56
+ gzip_path = gzip_file_path(path)
57
+
58
+ if gzip_path && gzip_encoding_accepted?(request)
59
+ request.path_info = gzip_path
60
+ status, headers, body = @file_server.call(request.env)
61
+ if status == 304
62
+ return [status, headers, body]
63
+ end
64
+ headers["Content-Encoding"] = "gzip"
65
+ headers["Content-Type"] = content_type(path)
66
+ else
67
+ status, headers, body = @file_server.call(request.env)
34
68
  end
35
- end
36
69
 
37
- def unescape_path(path)
38
- URI.parser.unescape(path)
39
- end
70
+ headers["Vary"] = "Accept-Encoding" if gzip_path
40
71
 
41
- def escape_glob_chars(path)
42
- path.force_encoding('binary') if path.respond_to? :force_encoding
43
- path.gsub(/[*?{}\[\]\\]/, "\\\\\\&")
72
+ return [status, headers, body]
73
+ ensure
74
+ request.path_info = path
44
75
  end
45
76
 
46
77
  private
78
+ def ext
79
+ ::ActionController::Base.default_static_extension
80
+ end
47
81
 
48
- PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact)
49
-
50
- def clean_path_info(path_info)
51
- path_info.force_encoding('binary') if path_info.respond_to? :force_encoding
52
- parts = path_info.split PATH_SEPS
53
-
54
- clean = []
55
-
56
- parts.each do |part|
57
- next if part.empty? || part == '.'
58
- part == '..' ? clean.pop : clean << part
82
+ def content_type(path)
83
+ ::Rack::Mime.mime_type(::File.extname(path), "text/plain".freeze)
59
84
  end
60
85
 
61
- clean.unshift '/' if parts.empty? || parts.first.empty?
86
+ def gzip_encoding_accepted?(request)
87
+ request.accept_encoding.any? { |enc, quality| enc =~ /\bgzip\b/i }
88
+ end
62
89
 
63
- ::File.join(*clean)
64
- end
90
+ def gzip_file_path(path)
91
+ can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
92
+ gzip_path = "#{path}.gz"
93
+ if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path).b))
94
+ gzip_path.b
95
+ else
96
+ false
97
+ end
98
+ end
65
99
  end
66
100
 
101
+ # This middleware will attempt to return the contents of a file's body from
102
+ # disk in the response. If a file is not found on disk, the request will be
103
+ # delegated to the application stack. This middleware is commonly initialized
104
+ # to serve assets from a server's +public/+ directory.
105
+ #
106
+ # This middleware verifies the path to ensure that only files
107
+ # living in the root directory can be rendered. A request cannot
108
+ # produce a directory traversal using this middleware. Only 'GET' and 'HEAD'
109
+ # requests will result in a file being returned.
67
110
  class Static
68
- def initialize(app, path, cache_control=nil)
111
+ def initialize(app, path, index: "index", headers: {})
69
112
  @app = app
70
- @file_handler = FileHandler.new(path, cache_control)
113
+ @file_handler = FileHandler.new(path, index: index, headers: headers)
71
114
  end
72
115
 
73
116
  def call(env)
74
- case env['REQUEST_METHOD']
75
- when 'GET', 'HEAD'
76
- path = env['PATH_INFO'].chomp('/')
117
+ req = Rack::Request.new env
118
+
119
+ if req.get? || req.head?
120
+ path = req.path_info.chomp("/".freeze)
77
121
  if match = @file_handler.match?(path)
78
- env["PATH_INFO"] = match
79
- return @file_handler.call(env)
122
+ req.path_info = match
123
+ return @file_handler.serve(req)
80
124
  end
81
125
  end
82
126
 
83
- @app.call(env)
127
+ @app.call(req.env)
84
128
  end
85
129
  end
86
130
  end
@@ -0,0 +1,22 @@
1
+ <% unless @exception.blamed_files.blank? %>
2
+ <% if (hide = @exception.blamed_files.length > 8) %>
3
+ <a href="#" onclick="return toggleTrace()">Toggle blamed files</a>
4
+ <% end %>
5
+ <pre id="blame_trace" <%='style="display:none"' if hide %>><code><%= @exception.describe_blame %></code></pre>
6
+ <% end %>
7
+
8
+ <h2 style="margin-top: 30px">Request</h2>
9
+ <p><b>Parameters</b>:</p> <pre><%= debug_params(@request.filtered_parameters) %></pre>
10
+
11
+ <div class="details">
12
+ <div class="summary"><a href="#" onclick="return toggleSessionDump()">Toggle session dump</a></div>
13
+ <div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div>
14
+ </div>
15
+
16
+ <div class="details">
17
+ <div class="summary"><a href="#" onclick="return toggleEnvDump()">Toggle env dump</a></div>
18
+ <div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>
19
+ </div>
20
+
21
+ <h2 style="margin-top: 30px">Response</h2>
22
+ <p><b>Headers</b>:</p> <pre><%= debug_headers(defined?(@response) ? @response.headers : {}) %></pre>
@@ -0,0 +1,23 @@
1
+ <%
2
+ clean_params = @request.filtered_parameters.clone
3
+ clean_params.delete("action")
4
+ clean_params.delete("controller")
5
+
6
+ request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
7
+
8
+ def debug_hash(object)
9
+ object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
10
+ end unless self.class.method_defined?(:debug_hash)
11
+ %>
12
+
13
+ Request parameters
14
+ <%= request_dump %>
15
+
16
+ Session dump
17
+ <%= debug_hash @request.session %>
18
+
19
+ Env dump
20
+ <%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %>
21
+
22
+ Response headers
23
+ <%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %>