actionpack 3.2.19 → 4.2.11.3

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 (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +412 -503
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +11 -294
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +52 -18
  7. data/lib/abstract_controller/callbacks.rb +87 -89
  8. data/lib/abstract_controller/collector.rb +17 -3
  9. data/lib/abstract_controller/helpers.rb +41 -14
  10. data/lib/abstract_controller/logger.rb +1 -2
  11. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  12. data/lib/abstract_controller/rendering.rb +65 -118
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +7 -7
  15. data/lib/abstract_controller.rb +2 -10
  16. data/lib/action_controller/base.rb +61 -28
  17. data/lib/action_controller/caching/fragments.rb +30 -54
  18. data/lib/action_controller/caching.rb +38 -35
  19. data/lib/action_controller/log_subscriber.rb +35 -18
  20. data/lib/action_controller/metal/conditional_get.rb +103 -34
  21. data/lib/action_controller/metal/data_streaming.rb +20 -26
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  23. data/lib/action_controller/metal/exceptions.rb +19 -6
  24. data/lib/action_controller/metal/flash.rb +41 -9
  25. data/lib/action_controller/metal/force_ssl.rb +70 -12
  26. data/lib/action_controller/metal/head.rb +30 -7
  27. data/lib/action_controller/metal/helpers.rb +11 -11
  28. data/lib/action_controller/metal/hide_actions.rb +0 -1
  29. data/lib/action_controller/metal/http_authentication.rb +140 -94
  30. data/lib/action_controller/metal/implicit_render.rb +1 -1
  31. data/lib/action_controller/metal/instrumentation.rb +11 -7
  32. data/lib/action_controller/metal/live.rb +328 -0
  33. data/lib/action_controller/metal/mime_responds.rb +161 -152
  34. data/lib/action_controller/metal/params_wrapper.rb +126 -81
  35. data/lib/action_controller/metal/rack_delegation.rb +10 -4
  36. data/lib/action_controller/metal/redirecting.rb +44 -41
  37. data/lib/action_controller/metal/renderers.rb +48 -19
  38. data/lib/action_controller/metal/rendering.rb +46 -11
  39. data/lib/action_controller/metal/request_forgery_protection.rb +250 -29
  40. data/lib/action_controller/metal/streaming.rb +30 -38
  41. data/lib/action_controller/metal/strong_parameters.rb +669 -0
  42. data/lib/action_controller/metal/testing.rb +12 -18
  43. data/lib/action_controller/metal/url_for.rb +31 -29
  44. data/lib/action_controller/metal.rb +31 -40
  45. data/lib/action_controller/model_naming.rb +12 -0
  46. data/lib/action_controller/railtie.rb +38 -18
  47. data/lib/action_controller/railties/helpers.rb +22 -0
  48. data/lib/action_controller/test_case.rb +359 -173
  49. data/lib/action_controller.rb +9 -16
  50. data/lib/action_dispatch/http/cache.rb +64 -11
  51. data/lib/action_dispatch/http/filter_parameters.rb +20 -10
  52. data/lib/action_dispatch/http/filter_redirect.rb +38 -0
  53. data/lib/action_dispatch/http/headers.rb +85 -17
  54. data/lib/action_dispatch/http/mime_negotiation.rb +55 -5
  55. data/lib/action_dispatch/http/mime_type.rb +167 -114
  56. data/lib/action_dispatch/http/mime_types.rb +2 -1
  57. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  58. data/lib/action_dispatch/http/parameters.rb +30 -46
  59. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  60. data/lib/action_dispatch/http/request.rb +108 -45
  61. data/lib/action_dispatch/http/response.rb +247 -48
  62. data/lib/action_dispatch/http/upload.rb +60 -29
  63. data/lib/action_dispatch/http/url.rb +135 -45
  64. data/lib/action_dispatch/journey/backwards.rb +5 -0
  65. data/lib/action_dispatch/journey/formatter.rb +166 -0
  66. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  67. data/lib/action_dispatch/journey/gtg/simulator.rb +47 -0
  68. data/lib/action_dispatch/journey/gtg/transition_table.rb +157 -0
  69. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  70. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  71. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  72. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  73. data/lib/action_dispatch/journey/nodes/node.rb +128 -0
  74. data/lib/action_dispatch/journey/parser.rb +198 -0
  75. data/lib/action_dispatch/journey/parser.y +49 -0
  76. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  77. data/lib/action_dispatch/journey/path/pattern.rb +193 -0
  78. data/lib/action_dispatch/journey/route.rb +125 -0
  79. data/lib/action_dispatch/journey/router/strexp.rb +27 -0
  80. data/lib/action_dispatch/journey/router/utils.rb +93 -0
  81. data/lib/action_dispatch/journey/router.rb +144 -0
  82. data/lib/action_dispatch/journey/routes.rb +80 -0
  83. data/lib/action_dispatch/journey/scanner.rb +61 -0
  84. data/lib/action_dispatch/journey/visitors.rb +221 -0
  85. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  86. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  87. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  88. data/lib/action_dispatch/journey.rb +5 -0
  89. data/lib/action_dispatch/middleware/callbacks.rb +16 -11
  90. data/lib/action_dispatch/middleware/cookies.rb +346 -125
  91. data/lib/action_dispatch/middleware/debug_exceptions.rb +52 -24
  92. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -9
  93. data/lib/action_dispatch/middleware/flash.rb +85 -72
  94. data/lib/action_dispatch/middleware/params_parser.rb +16 -31
  95. data/lib/action_dispatch/middleware/public_exceptions.rb +39 -14
  96. data/lib/action_dispatch/middleware/reloader.rb +16 -7
  97. data/lib/action_dispatch/middleware/remote_ip.rb +132 -40
  98. data/lib/action_dispatch/middleware/request_id.rb +3 -7
  99. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  100. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  101. data/lib/action_dispatch/middleware/session/cookie_store.rb +84 -29
  102. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  103. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -44
  104. data/lib/action_dispatch/middleware/ssl.rb +72 -0
  105. data/lib/action_dispatch/middleware/stack.rb +6 -1
  106. data/lib/action_dispatch/middleware/static.rb +80 -23
  107. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +34 -0
  108. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +27 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +133 -5
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  125. data/lib/action_dispatch/railtie.rb +19 -6
  126. data/lib/action_dispatch/request/session.rb +193 -0
  127. data/lib/action_dispatch/request/utils.rb +35 -0
  128. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  129. data/lib/action_dispatch/routing/inspector.rb +234 -0
  130. data/lib/action_dispatch/routing/mapper.rb +897 -436
  131. data/lib/action_dispatch/routing/polymorphic_routes.rb +213 -92
  132. data/lib/action_dispatch/routing/redirection.rb +97 -37
  133. data/lib/action_dispatch/routing/route_set.rb +432 -239
  134. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  135. data/lib/action_dispatch/routing/url_for.rb +63 -34
  136. data/lib/action_dispatch/routing.rb +57 -89
  137. data/lib/action_dispatch/testing/assertions/dom.rb +2 -36
  138. data/lib/action_dispatch/testing/assertions/response.rb +24 -38
  139. data/lib/action_dispatch/testing/assertions/routing.rb +55 -54
  140. data/lib/action_dispatch/testing/assertions/selector.rb +2 -434
  141. data/lib/action_dispatch/testing/assertions/tag.rb +2 -137
  142. data/lib/action_dispatch/testing/assertions.rb +11 -7
  143. data/lib/action_dispatch/testing/integration.rb +88 -72
  144. data/lib/action_dispatch/testing/test_process.rb +9 -6
  145. data/lib/action_dispatch/testing/test_request.rb +13 -9
  146. data/lib/action_dispatch/testing/test_response.rb +1 -5
  147. data/lib/action_dispatch.rb +24 -21
  148. data/lib/action_pack/gem_version.rb +15 -0
  149. data/lib/action_pack/version.rb +5 -7
  150. data/lib/action_pack.rb +1 -1
  151. metadata +181 -292
  152. data/lib/abstract_controller/layouts.rb +0 -423
  153. data/lib/abstract_controller/view_paths.rb +0 -96
  154. data/lib/action_controller/caching/actions.rb +0 -185
  155. data/lib/action_controller/caching/pages.rb +0 -187
  156. data/lib/action_controller/caching/sweeping.rb +0 -97
  157. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  158. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  159. data/lib/action_controller/deprecated.rb +0 -3
  160. data/lib/action_controller/metal/compatibility.rb +0 -65
  161. data/lib/action_controller/metal/responder.rb +0 -286
  162. data/lib/action_controller/metal/session_management.rb +0 -14
  163. data/lib/action_controller/railties/paths.rb +0 -25
  164. data/lib/action_controller/record_identifier.rb +0 -85
  165. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  166. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  167. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  168. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  169. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  170. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  171. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  172. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  173. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  174. data/lib/action_dispatch/middleware/head.rb +0 -18
  175. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  176. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  177. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  178. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  179. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  180. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  181. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  182. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  183. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  184. data/lib/action_view/asset_paths.rb +0 -142
  185. data/lib/action_view/base.rb +0 -220
  186. data/lib/action_view/buffers.rb +0 -43
  187. data/lib/action_view/context.rb +0 -36
  188. data/lib/action_view/flows.rb +0 -79
  189. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  190. data/lib/action_view/helpers/asset_paths.rb +0 -7
  191. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  192. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  193. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  194. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  195. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  196. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  197. data/lib/action_view/helpers/cache_helper.rb +0 -64
  198. data/lib/action_view/helpers/capture_helper.rb +0 -203
  199. data/lib/action_view/helpers/controller_helper.rb +0 -25
  200. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  201. data/lib/action_view/helpers/date_helper.rb +0 -1062
  202. data/lib/action_view/helpers/debug_helper.rb +0 -40
  203. data/lib/action_view/helpers/form_helper.rb +0 -1486
  204. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  205. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  206. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  207. data/lib/action_view/helpers/number_helper.rb +0 -622
  208. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  209. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  210. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  211. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  212. data/lib/action_view/helpers/tag_helper.rb +0 -160
  213. data/lib/action_view/helpers/text_helper.rb +0 -426
  214. data/lib/action_view/helpers/translation_helper.rb +0 -91
  215. data/lib/action_view/helpers/url_helper.rb +0 -693
  216. data/lib/action_view/helpers.rb +0 -60
  217. data/lib/action_view/locale/en.yml +0 -160
  218. data/lib/action_view/log_subscriber.rb +0 -28
  219. data/lib/action_view/lookup_context.rb +0 -254
  220. data/lib/action_view/path_set.rb +0 -89
  221. data/lib/action_view/railtie.rb +0 -55
  222. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  223. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  224. data/lib/action_view/renderer/renderer.rb +0 -54
  225. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  226. data/lib/action_view/renderer/template_renderer.rb +0 -94
  227. data/lib/action_view/template/error.rb +0 -128
  228. data/lib/action_view/template/handlers/builder.rb +0 -26
  229. data/lib/action_view/template/handlers/erb.rb +0 -125
  230. data/lib/action_view/template/handlers.rb +0 -50
  231. data/lib/action_view/template/resolver.rb +0 -272
  232. data/lib/action_view/template/text.rb +0 -30
  233. data/lib/action_view/template.rb +0 -337
  234. data/lib/action_view/test_case.rb +0 -245
  235. data/lib/action_view/testing/resolvers.rb +0 -50
  236. data/lib/action_view.rb +0 -84
  237. data/lib/sprockets/assets.rake +0 -99
  238. data/lib/sprockets/bootstrap.rb +0 -37
  239. data/lib/sprockets/compressors.rb +0 -83
  240. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  241. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  242. data/lib/sprockets/helpers.rb +0 -6
  243. data/lib/sprockets/railtie.rb +0 -62
  244. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,77 +1,48 @@
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
30
+ @app.call(env)
31
+ rescue Exception => exception
32
+ if env['action_dispatch.show_exceptions'] == false
33
+ raise exception
34
+ else
35
+ render_exception(env, exception)
59
36
  end
60
-
61
- response || render_exception(env, exception)
62
37
  end
63
38
 
64
39
  private
65
40
 
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
41
  def render_exception(env, exception)
72
42
  wrapper = ExceptionWrapper.new(env, exception)
73
43
  status = wrapper.status_code
74
44
  env["action_dispatch.exception"] = wrapper.exception
45
+ env["action_dispatch.original_path"] = env["PATH_INFO"]
75
46
  env["PATH_INFO"] = "/#{status}"
76
47
  response = @exceptions_app.call(env)
77
48
  response[1]['X-Cascade'] == 'pass' ? pass_response(status) : response
@@ -0,0 +1,72 @@
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.reverse_merge!(hsts_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
+ host = @host || request.host
36
+ port = @port || request.port
37
+
38
+ location = "https://#{host}"
39
+ location << ":#{port}" if port != 80
40
+ location << request.fullpath
41
+
42
+ headers = { 'Content-Type' => 'text/html', 'Location' => location }
43
+
44
+ [301, headers, []]
45
+ end
46
+
47
+ # http://tools.ietf.org/html/draft-hodges-strict-transport-sec-02
48
+ def hsts_headers
49
+ if @hsts
50
+ value = "max-age=#{@hsts[:expires].to_i}"
51
+ value += "; includeSubDomains" if @hsts[:subdomains]
52
+ { 'Strict-Transport-Security' => value }
53
+ else
54
+ {}
55
+ end
56
+ end
57
+
58
+ def flag_cookies_as_secure!(headers)
59
+ if cookies = headers['Set-Cookie']
60
+ cookies = cookies.split("\n")
61
+
62
+ headers['Set-Cookie'] = cookies.map { |cookie|
63
+ if cookie !~ /;\s*secure\s*(;|$)/i
64
+ "#{cookie}; secure"
65
+ else
66
+ cookie
67
+ end
68
+ }.join("\n")
69
+ end
70
+ end
71
+ end
72
+ 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,49 +1,106 @@
1
1
  require 'rack/utils'
2
+ require 'active_support/core_ext/uri'
2
3
 
3
4
  module ActionDispatch
5
+ # This middleware returns a file's contents from disk in the body response.
6
+ # When initialized it can accept an optional 'Cache-Control' header which
7
+ # will be set when a response containing a file's contents is delivered.
8
+ #
9
+ # This middleware will render the file specified in `env["PATH_INFO"]`
10
+ # where the base path is in the +root+ directory. For example if the +root+
11
+ # is set to `public/` then a request with `env["PATH_INFO"]` of
12
+ # `assets/application.js` will return a response with contents of a file
13
+ # located at `public/assets/application.js` if the file exists. If the file
14
+ # does not exist a 404 "File not Found" response will be returned.
4
15
  class FileHandler
5
16
  def initialize(root, cache_control)
6
17
  @root = root.chomp('/')
7
18
  @compiled_root = /^#{Regexp.escape(root)}/
8
- headers = cache_control && { 'Cache-Control' => cache_control }
9
- @file_server = ::Rack::File.new(@root, headers)
19
+ headers = cache_control && { 'Cache-Control' => cache_control }
20
+ @file_server = ::Rack::File.new(@root, headers)
10
21
  end
11
22
 
12
23
  def match?(path)
13
- path = path.dup
24
+ path = URI.parser.unescape(path)
25
+ return false unless valid_path?(path)
14
26
 
15
- full_path = path.empty? ? @root : File.join(@root, escape_glob_chars(unescape_path(path)))
16
- paths = "#{full_path}#{ext}"
27
+ paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"].map { |v|
28
+ Rack::Utils.clean_path_info v
29
+ }
17
30
 
18
- matches = Dir[paths]
19
- match = matches.detect { |m| File.file?(m) }
20
- if match
21
- match.sub!(@compiled_root, '')
22
- ::Rack::Utils.escape(match)
31
+ if match = paths.detect { |p|
32
+ path = File.join(@root, p.force_encoding('UTF-8'))
33
+ begin
34
+ File.file?(path) && File.readable?(path)
35
+ rescue SystemCallError
36
+ false
37
+ end
38
+
39
+ }
40
+ return ::Rack::Utils.escape(match)
23
41
  end
24
42
  end
25
43
 
26
44
  def call(env)
27
- @file_server.call(env)
28
- end
45
+ path = env['PATH_INFO']
46
+ gzip_path = gzip_file_path(path)
29
47
 
30
- def ext
31
- @ext ||= begin
32
- ext = ::ActionController::Base.page_cache_extension
33
- "{,#{ext},/index#{ext}}"
48
+ if gzip_path && gzip_encoding_accepted?(env)
49
+ env['PATH_INFO'] = gzip_path
50
+ status, headers, body = @file_server.call(env)
51
+ if status == 304
52
+ return [status, headers, body]
53
+ end
54
+ headers['Content-Encoding'] = 'gzip'
55
+ headers['Content-Type'] = content_type(path)
56
+ else
57
+ status, headers, body = @file_server.call(env)
34
58
  end
35
- end
36
59
 
37
- def unescape_path(path)
38
- URI.parser.unescape(path)
39
- end
60
+ headers['Vary'] = 'Accept-Encoding' if gzip_path
40
61
 
41
- def escape_glob_chars(path)
42
- path.force_encoding('binary') if path.respond_to? :force_encoding
43
- path.gsub(/[*?{}\[\]]/, "\\\\\\&")
62
+ return [status, headers, body]
63
+ ensure
64
+ env['PATH_INFO'] = path
44
65
  end
66
+
67
+ private
68
+ def ext
69
+ ::ActionController::Base.default_static_extension
70
+ end
71
+
72
+ def content_type(path)
73
+ ::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
74
+ end
75
+
76
+ def gzip_encoding_accepted?(env)
77
+ env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/i
78
+ end
79
+
80
+ def gzip_file_path(path)
81
+ can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
82
+ gzip_path = "#{path}.gz"
83
+ if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape(gzip_path)))
84
+ gzip_path
85
+ else
86
+ false
87
+ end
88
+ end
89
+
90
+ def valid_path?(path)
91
+ path.valid_encoding? && !path.include?("\0")
92
+ end
45
93
  end
46
94
 
95
+ # This middleware will attempt to return the contents of a file's body from
96
+ # disk in the response. If a file is not found on disk, the request will be
97
+ # delegated to the application stack. This middleware is commonly initialized
98
+ # to serve assets from a server's `public/` directory.
99
+ #
100
+ # This middleware verifies the path to ensure that only files
101
+ # living in the root directory can be rendered. A request cannot
102
+ # produce a directory traversal using this middleware. Only 'GET' and 'HEAD'
103
+ # requests will result in a file being returned.
47
104
  class Static
48
105
  def initialize(app, path, cache_control=nil)
49
106
  @app = app
@@ -0,0 +1,34 @@
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
+ <%
9
+ clean_params = @request.filtered_parameters.clone
10
+ clean_params.delete("action")
11
+ clean_params.delete("controller")
12
+
13
+ request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
14
+
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
+ end unless self.class.method_defined?(:debug_hash)
18
+ %>
19
+
20
+ <h2 style="margin-top: 30px">Request</h2>
21
+ <p><b>Parameters</b>:</p> <pre><%= request_dump %></pre>
22
+
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>
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>
32
+
33
+ <h2 style="margin-top: 30px">Response</h2>
34
+ <p><b>Headers</b>:</p> <pre><%= defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></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' %>
@@ -0,0 +1,27 @@
1
+ <% @source_extracts.each_with_index do |source_extract, index| %>
2
+ <% if source_extract[:code] %>
3
+ <div class="source <%="hidden" if @show_source_idx != index%>" id="frame-source-<%=index%>">
4
+ <div class="info">
5
+ Extracted source (around line <strong>#<%= source_extract[:line_number] %></strong>):
6
+ </div>
7
+ <div class="data">
8
+ <table cellpadding="0" cellspacing="0" class="lines">
9
+ <tr>
10
+ <td>
11
+ <pre class="line_numbers">
12
+ <% source_extract[:code].each_key do |line_number| %>
13
+ <span><%= line_number -%></span>
14
+ <% end %>
15
+ </pre>
16
+ </td>
17
+ <td width="100%">
18
+ <pre>
19
+ <% source_extract[:code].each do |line, source| -%><div class="line<%= " active" if line == source_extract[:line_number] -%>"><%= source -%></div><% end -%>
20
+ </pre>
21
+ </td>
22
+ </tr>
23
+ </table>
24
+ </div>
25
+ </div>
26
+ <% end %>
27
+ <% end %>
@@ -0,0 +1,52 @@
1
+ <% names = @traces.keys %>
2
+
3
+ <p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p>
4
+
5
+ <div id="traces">
6
+ <% names.each do |name| %>
7
+ <%
8
+ show = "show('#{name.gsub(/\s/, '-')}');"
9
+ hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}');"}
10
+ %>
11
+ <a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
12
+ <% end %>
13
+
14
+ <% @traces.each do |name, trace| %>
15
+ <div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == @trace_to_show) ? 'block' : 'none' %>;">
16
+ <pre><code><% trace.each do |frame| %><a class="trace-frames" data-frame-id="<%= frame[:id] %>" href="#"><%= frame[:trace] %></a><br><% end %></code></pre>
17
+ </div>
18
+ <% end %>
19
+
20
+ <script type="text/javascript">
21
+ var traceFrames = document.getElementsByClassName('trace-frames');
22
+ var selectedFrame, currentSource = document.getElementById('frame-source-0');
23
+
24
+ // Add click listeners for all stack frames
25
+ for (var i = 0; i < traceFrames.length; i++) {
26
+ traceFrames[i].addEventListener('click', function(e) {
27
+ e.preventDefault();
28
+ var target = e.target;
29
+ var frame_id = target.dataset.frameId;
30
+
31
+ if (selectedFrame) {
32
+ selectedFrame.className = selectedFrame.className.replace("selected", "");
33
+ }
34
+
35
+ target.className += " selected";
36
+ selectedFrame = target;
37
+
38
+ // Change the extracted source code
39
+ changeSourceExtract(frame_id);
40
+ });
41
+
42
+ function changeSourceExtract(frame_id) {
43
+ var el = document.getElementById('frame-source-' + frame_id);
44
+ if (currentSource && el) {
45
+ currentSource.className += " hidden";
46
+ el.className = el.className.replace(" hidden", "");
47
+ currentSource = el;
48
+ }
49
+ }
50
+ }
51
+ </script>
52
+ </div>
@@ -0,0 +1,9 @@
1
+ Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %>
2
+
3
+ <% @traces.each do |name, trace| %>
4
+ <% if trace.any? %>
5
+ <%= name %>
6
+ <%= trace.map { |t| t[:trace] }.join("\n") %>
7
+
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,16 @@
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>
9
+
10
+ <div id="container">
11
+ <h2><%= h @exception.message %></h2>
12
+
13
+ <%= render template: "rescues/_source" %>
14
+ <%= render template: "rescues/_trace" %>
15
+ <%= render template: "rescues/_request_and_response" %>
16
+ </div>
@@ -0,0 +1,9 @@
1
+ <%= @exception.class.to_s %><%
2
+ if @request.parameters['controller']
3
+ %> in <%= @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%= @request.parameters['action'] %><% end %>
4
+ <% end %>
5
+
6
+ <%= @exception.message %>
7
+ <%= render template: "rescues/_source" %>
8
+ <%= render template: "rescues/_trace" %>
9
+ <%= render template: "rescues/_request_and_response" %>
@@ -4,7 +4,11 @@
4
4
  <meta charset="utf-8" />
5
5
  <title>Action Controller: Exception caught</title>
6
6
  <style>
7
- body { background-color: #fff; color: #333; }
7
+ body {
8
+ background-color: #FAFAFA;
9
+ color: #333;
10
+ margin: 0px;
11
+ }
8
12
 
9
13
  body, p, ol, ul, td {
10
14
  font-family: helvetica, verdana, arial, sans-serif;
@@ -13,16 +17,140 @@
13
17
  }
14
18
 
15
19
  pre {
16
- background-color: #eee;
17
- padding: 10px;
18
20
  font-size: 11px;
19
21
  white-space: pre-wrap;
20
22
  }
21
23
 
22
- a { color: #000; }
24
+ pre.box {
25
+ border: 1px solid #EEE;
26
+ padding: 10px;
27
+ margin: 0px;
28
+ width: 958px;
29
+ }
30
+
31
+ header {
32
+ color: #F0F0F0;
33
+ background: #C52F24;
34
+ padding: 0.5em 1.5em;
35
+ }
36
+
37
+ h1 {
38
+ margin: 0.2em 0;
39
+ line-height: 1.1em;
40
+ font-size: 2em;
41
+ }
42
+
43
+ h2 {
44
+ color: #C52F24;
45
+ line-height: 25px;
46
+ }
47
+
48
+ .details {
49
+ border: 1px solid #D0D0D0;
50
+ border-radius: 4px;
51
+ margin: 1em 0px;
52
+ display: block;
53
+ width: 978px;
54
+ }
55
+
56
+ .summary {
57
+ padding: 8px 15px;
58
+ border-bottom: 1px solid #D0D0D0;
59
+ display: block;
60
+ }
61
+
62
+ .details pre {
63
+ margin: 5px;
64
+ border: none;
65
+ }
66
+
67
+ #container {
68
+ box-sizing: border-box;
69
+ width: 100%;
70
+ padding: 0 1.5em;
71
+ }
72
+
73
+ .source * {
74
+ margin: 0px;
75
+ padding: 0px;
76
+ }
77
+
78
+ .source {
79
+ border: 1px solid #D9D9D9;
80
+ background: #ECECEC;
81
+ width: 978px;
82
+ }
83
+
84
+ .source pre {
85
+ padding: 10px 0px;
86
+ border: none;
87
+ }
88
+
89
+ .source .data {
90
+ font-size: 80%;
91
+ overflow: auto;
92
+ background-color: #FFF;
93
+ }
94
+
95
+ .info {
96
+ padding: 0.5em;
97
+ }
98
+
99
+ .source .data .line_numbers {
100
+ background-color: #ECECEC;
101
+ color: #AAA;
102
+ padding: 1em .5em;
103
+ border-right: 1px solid #DDD;
104
+ text-align: right;
105
+ }
106
+
107
+ .line {
108
+ padding-left: 10px;
109
+ }
110
+
111
+ .line:hover {
112
+ background-color: #F6F6F6;
113
+ }
114
+
115
+ .line.active {
116
+ background-color: #FFCCCC;
117
+ }
118
+
119
+ .hidden {
120
+ display: none;
121
+ }
122
+
123
+ a { color: #980905; }
23
124
  a:visited { color: #666; }
24
- a:hover { color: #fff; background-color:#000; }
125
+ a.trace-frames { color: #666; }
126
+ a:hover { color: #C52F24; }
127
+ a.trace-frames.selected { color: #C52F24 }
128
+
129
+ <%= yield :style %>
25
130
  </style>
131
+
132
+ <script>
133
+ var toggle = function(id) {
134
+ var s = document.getElementById(id).style;
135
+ s.display = s.display == 'none' ? 'block' : 'none';
136
+ return false;
137
+ }
138
+ var show = function(id) {
139
+ document.getElementById(id).style.display = 'block';
140
+ }
141
+ var hide = function(id) {
142
+ document.getElementById(id).style.display = 'none';
143
+ }
144
+ var toggleTrace = function() {
145
+ return toggle('blame_trace');
146
+ }
147
+ var toggleSessionDump = function() {
148
+ return toggle('session_dump');
149
+ }
150
+ var toggleEnvDump = function() {
151
+ return toggle('env_dump');
152
+ }
153
+ </script>
26
154
  </head>
27
155
  <body>
28
156
 
@@ -0,0 +1,11 @@
1
+ <header>
2
+ <h1>Template is missing</h1>
3
+ </header>
4
+
5
+ <div id="container">
6
+ <h2><%= h @exception.message %></h2>
7
+
8
+ <%= render template: "rescues/_source" %>
9
+ <%= render template: "rescues/_trace" %>
10
+ <%= render template: "rescues/_request_and_response" %>
11
+ </div>
@@ -0,0 +1,3 @@
1
+ Template is missing
2
+
3
+ <%= @exception.message %>