omg-actionpack 8.0.0.alpha1

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 (187) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +129 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +57 -0
  5. data/lib/abstract_controller/asset_paths.rb +14 -0
  6. data/lib/abstract_controller/base.rb +299 -0
  7. data/lib/abstract_controller/caching/fragments.rb +149 -0
  8. data/lib/abstract_controller/caching.rb +68 -0
  9. data/lib/abstract_controller/callbacks.rb +265 -0
  10. data/lib/abstract_controller/collector.rb +44 -0
  11. data/lib/abstract_controller/deprecator.rb +9 -0
  12. data/lib/abstract_controller/error.rb +8 -0
  13. data/lib/abstract_controller/helpers.rb +243 -0
  14. data/lib/abstract_controller/logger.rb +16 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +25 -0
  16. data/lib/abstract_controller/rendering.rb +126 -0
  17. data/lib/abstract_controller/translation.rb +42 -0
  18. data/lib/abstract_controller/url_for.rb +37 -0
  19. data/lib/abstract_controller.rb +36 -0
  20. data/lib/action_controller/api/api_rendering.rb +18 -0
  21. data/lib/action_controller/api.rb +155 -0
  22. data/lib/action_controller/base.rb +332 -0
  23. data/lib/action_controller/caching.rb +49 -0
  24. data/lib/action_controller/deprecator.rb +9 -0
  25. data/lib/action_controller/form_builder.rb +55 -0
  26. data/lib/action_controller/log_subscriber.rb +96 -0
  27. data/lib/action_controller/metal/allow_browser.rb +123 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
  29. data/lib/action_controller/metal/conditional_get.rb +341 -0
  30. data/lib/action_controller/metal/content_security_policy.rb +86 -0
  31. data/lib/action_controller/metal/cookies.rb +20 -0
  32. data/lib/action_controller/metal/data_streaming.rb +154 -0
  33. data/lib/action_controller/metal/default_headers.rb +21 -0
  34. data/lib/action_controller/metal/etag_with_flash.rb +22 -0
  35. data/lib/action_controller/metal/etag_with_template_digest.rb +59 -0
  36. data/lib/action_controller/metal/exceptions.rb +106 -0
  37. data/lib/action_controller/metal/flash.rb +67 -0
  38. data/lib/action_controller/metal/head.rb +67 -0
  39. data/lib/action_controller/metal/helpers.rb +129 -0
  40. data/lib/action_controller/metal/http_authentication.rb +565 -0
  41. data/lib/action_controller/metal/implicit_render.rb +67 -0
  42. data/lib/action_controller/metal/instrumentation.rb +120 -0
  43. data/lib/action_controller/metal/live.rb +398 -0
  44. data/lib/action_controller/metal/logging.rb +22 -0
  45. data/lib/action_controller/metal/mime_responds.rb +337 -0
  46. data/lib/action_controller/metal/parameter_encoding.rb +84 -0
  47. data/lib/action_controller/metal/params_wrapper.rb +312 -0
  48. data/lib/action_controller/metal/permissions_policy.rb +38 -0
  49. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  50. data/lib/action_controller/metal/redirecting.rb +251 -0
  51. data/lib/action_controller/metal/renderers.rb +181 -0
  52. data/lib/action_controller/metal/rendering.rb +260 -0
  53. data/lib/action_controller/metal/request_forgery_protection.rb +667 -0
  54. data/lib/action_controller/metal/rescue.rb +33 -0
  55. data/lib/action_controller/metal/streaming.rb +183 -0
  56. data/lib/action_controller/metal/strong_parameters.rb +1546 -0
  57. data/lib/action_controller/metal/testing.rb +25 -0
  58. data/lib/action_controller/metal/url_for.rb +65 -0
  59. data/lib/action_controller/metal.rb +339 -0
  60. data/lib/action_controller/railtie.rb +149 -0
  61. data/lib/action_controller/railties/helpers.rb +26 -0
  62. data/lib/action_controller/renderer.rb +161 -0
  63. data/lib/action_controller/template_assertions.rb +13 -0
  64. data/lib/action_controller/test_case.rb +691 -0
  65. data/lib/action_controller.rb +80 -0
  66. data/lib/action_dispatch/constants.rb +34 -0
  67. data/lib/action_dispatch/deprecator.rb +9 -0
  68. data/lib/action_dispatch/http/cache.rb +249 -0
  69. data/lib/action_dispatch/http/content_disposition.rb +47 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +365 -0
  71. data/lib/action_dispatch/http/filter_parameters.rb +80 -0
  72. data/lib/action_dispatch/http/filter_redirect.rb +50 -0
  73. data/lib/action_dispatch/http/headers.rb +134 -0
  74. data/lib/action_dispatch/http/mime_negotiation.rb +187 -0
  75. data/lib/action_dispatch/http/mime_type.rb +389 -0
  76. data/lib/action_dispatch/http/mime_types.rb +54 -0
  77. data/lib/action_dispatch/http/parameters.rb +119 -0
  78. data/lib/action_dispatch/http/permissions_policy.rb +189 -0
  79. data/lib/action_dispatch/http/rack_cache.rb +67 -0
  80. data/lib/action_dispatch/http/request.rb +498 -0
  81. data/lib/action_dispatch/http/response.rb +556 -0
  82. data/lib/action_dispatch/http/upload.rb +107 -0
  83. data/lib/action_dispatch/http/url.rb +344 -0
  84. data/lib/action_dispatch/journey/formatter.rb +226 -0
  85. data/lib/action_dispatch/journey/gtg/builder.rb +149 -0
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +50 -0
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +217 -0
  88. data/lib/action_dispatch/journey/nfa/dot.rb +27 -0
  89. data/lib/action_dispatch/journey/nodes/node.rb +208 -0
  90. data/lib/action_dispatch/journey/parser.rb +103 -0
  91. data/lib/action_dispatch/journey/path/pattern.rb +209 -0
  92. data/lib/action_dispatch/journey/route.rb +189 -0
  93. data/lib/action_dispatch/journey/router/utils.rb +105 -0
  94. data/lib/action_dispatch/journey/router.rb +151 -0
  95. data/lib/action_dispatch/journey/routes.rb +82 -0
  96. data/lib/action_dispatch/journey/scanner.rb +70 -0
  97. data/lib/action_dispatch/journey/visitors.rb +267 -0
  98. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  99. data/lib/action_dispatch/journey/visualizer/fsm.js +159 -0
  100. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  101. data/lib/action_dispatch/journey.rb +7 -0
  102. data/lib/action_dispatch/log_subscriber.rb +25 -0
  103. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  104. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  105. data/lib/action_dispatch/middleware/callbacks.rb +38 -0
  106. data/lib/action_dispatch/middleware/cookies.rb +719 -0
  107. data/lib/action_dispatch/middleware/debug_exceptions.rb +206 -0
  108. data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
  109. data/lib/action_dispatch/middleware/debug_view.rb +73 -0
  110. data/lib/action_dispatch/middleware/exception_wrapper.rb +350 -0
  111. data/lib/action_dispatch/middleware/executor.rb +32 -0
  112. data/lib/action_dispatch/middleware/flash.rb +318 -0
  113. data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
  114. data/lib/action_dispatch/middleware/public_exceptions.rb +64 -0
  115. data/lib/action_dispatch/middleware/reloader.rb +16 -0
  116. data/lib/action_dispatch/middleware/remote_ip.rb +199 -0
  117. data/lib/action_dispatch/middleware/request_id.rb +50 -0
  118. data/lib/action_dispatch/middleware/server_timing.rb +78 -0
  119. data/lib/action_dispatch/middleware/session/abstract_store.rb +112 -0
  120. data/lib/action_dispatch/middleware/session/cache_store.rb +66 -0
  121. data/lib/action_dispatch/middleware/session/cookie_store.rb +129 -0
  122. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +34 -0
  123. data/lib/action_dispatch/middleware/show_exceptions.rb +88 -0
  124. data/lib/action_dispatch/middleware/ssl.rb +180 -0
  125. data/lib/action_dispatch/middleware/stack.rb +194 -0
  126. data/lib/action_dispatch/middleware/static.rb +192 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +17 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +35 -0
  139. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  140. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
  141. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
  142. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +284 -0
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
  144. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  145. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  146. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  147. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  148. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  149. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  150. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  151. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  152. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  153. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +19 -0
  154. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +232 -0
  155. data/lib/action_dispatch/railtie.rb +77 -0
  156. data/lib/action_dispatch/request/session.rb +283 -0
  157. data/lib/action_dispatch/request/utils.rb +109 -0
  158. data/lib/action_dispatch/routing/endpoint.rb +19 -0
  159. data/lib/action_dispatch/routing/inspector.rb +323 -0
  160. data/lib/action_dispatch/routing/mapper.rb +2372 -0
  161. data/lib/action_dispatch/routing/polymorphic_routes.rb +363 -0
  162. data/lib/action_dispatch/routing/redirection.rb +218 -0
  163. data/lib/action_dispatch/routing/route_set.rb +958 -0
  164. data/lib/action_dispatch/routing/routes_proxy.rb +66 -0
  165. data/lib/action_dispatch/routing/url_for.rb +244 -0
  166. data/lib/action_dispatch/routing.rb +262 -0
  167. data/lib/action_dispatch/system_test_case.rb +206 -0
  168. data/lib/action_dispatch/system_testing/browser.rb +75 -0
  169. data/lib/action_dispatch/system_testing/driver.rb +85 -0
  170. data/lib/action_dispatch/system_testing/server.rb +33 -0
  171. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
  172. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
  173. data/lib/action_dispatch/testing/assertion_response.rb +48 -0
  174. data/lib/action_dispatch/testing/assertions/response.rb +114 -0
  175. data/lib/action_dispatch/testing/assertions/routing.rb +343 -0
  176. data/lib/action_dispatch/testing/assertions.rb +25 -0
  177. data/lib/action_dispatch/testing/integration.rb +694 -0
  178. data/lib/action_dispatch/testing/request_encoder.rb +60 -0
  179. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  180. data/lib/action_dispatch/testing/test_process.rb +57 -0
  181. data/lib/action_dispatch/testing/test_request.rb +73 -0
  182. data/lib/action_dispatch/testing/test_response.rb +58 -0
  183. data/lib/action_dispatch.rb +147 -0
  184. data/lib/action_pack/gem_version.rb +19 -0
  185. data/lib/action_pack/version.rb +12 -0
  186. data/lib/action_pack.rb +27 -0
  187. metadata +375 -0
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "action_dispatch/middleware/exception_wrapper"
6
+ require "action_dispatch/routing/inspector"
7
+
8
+ require "action_view"
9
+
10
+ module ActionDispatch
11
+ # # Action Dispatch DebugExceptions
12
+ #
13
+ # This middleware is responsible for logging exceptions and showing a debugging
14
+ # page in case the request is local.
15
+ class DebugExceptions
16
+ cattr_reader :interceptors, instance_accessor: false, default: []
17
+
18
+ def self.register_interceptor(object = nil, &block)
19
+ interceptor = object || block
20
+ interceptors << interceptor
21
+ end
22
+
23
+ def initialize(app, routes_app = nil, response_format = :default, interceptors = self.class.interceptors)
24
+ @app = app
25
+ @routes_app = routes_app
26
+ @response_format = response_format
27
+ @interceptors = interceptors
28
+ end
29
+
30
+ def call(env)
31
+ _, headers, body = response = @app.call(env)
32
+
33
+ if headers[Constants::X_CASCADE] == "pass"
34
+ body.close if body.respond_to?(:close)
35
+ raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
36
+ end
37
+
38
+ response
39
+ rescue Exception => exception
40
+ request = ActionDispatch::Request.new env
41
+ backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
42
+ wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
43
+
44
+ invoke_interceptors(request, exception, wrapper)
45
+ raise exception unless wrapper.show?(request)
46
+ render_exception(request, exception, wrapper)
47
+ end
48
+
49
+ private
50
+ def invoke_interceptors(request, exception, wrapper)
51
+ @interceptors.each do |interceptor|
52
+ interceptor.call(request, exception)
53
+ rescue Exception
54
+ log_error(request, wrapper)
55
+ end
56
+ end
57
+
58
+ def render_exception(request, exception, wrapper)
59
+ log_error(request, wrapper)
60
+
61
+ if request.get_header("action_dispatch.show_detailed_exceptions")
62
+ begin
63
+ content_type = request.formats.first
64
+ rescue ActionDispatch::Http::MimeNegotiation::InvalidType
65
+ content_type = Mime[:text]
66
+ end
67
+
68
+ if api_request?(content_type)
69
+ render_for_api_request(content_type, wrapper)
70
+ else
71
+ render_for_browser_request(request, wrapper)
72
+ end
73
+ else
74
+ raise exception
75
+ end
76
+ end
77
+
78
+ def render_for_browser_request(request, wrapper)
79
+ template = create_template(request, wrapper)
80
+ file = "rescues/#{wrapper.rescue_template}"
81
+
82
+ if request.xhr?
83
+ body = template.render(template: file, layout: false, formats: [:text])
84
+ format = "text/plain"
85
+ else
86
+ body = template.render(template: file, layout: "rescues/layout")
87
+ format = "text/html"
88
+ end
89
+ render(wrapper.status_code, body, format)
90
+ end
91
+
92
+ def render_for_api_request(content_type, wrapper)
93
+ body = {
94
+ status: wrapper.status_code,
95
+ error: Rack::Utils::HTTP_STATUS_CODES.fetch(
96
+ wrapper.status_code,
97
+ Rack::Utils::HTTP_STATUS_CODES[500]
98
+ ),
99
+ exception: wrapper.exception_inspect,
100
+ traces: wrapper.traces
101
+ }
102
+
103
+ to_format = "to_#{content_type.to_sym}"
104
+
105
+ if content_type && body.respond_to?(to_format)
106
+ formatted_body = body.public_send(to_format)
107
+ format = content_type
108
+ else
109
+ formatted_body = body.to_json
110
+ format = Mime[:json]
111
+ end
112
+
113
+ render(wrapper.status_code, formatted_body, format)
114
+ end
115
+
116
+ def create_template(request, wrapper)
117
+ DebugView.new(
118
+ request: request,
119
+ exception_wrapper: wrapper,
120
+ # Everything should use the wrapper, but we need to pass `exception` for legacy
121
+ # code.
122
+ exception: wrapper.exception,
123
+ traces: wrapper.traces,
124
+ show_source_idx: wrapper.source_to_show_id,
125
+ trace_to_show: wrapper.trace_to_show,
126
+ routes_inspector: routes_inspector(wrapper),
127
+ source_extracts: wrapper.source_extracts,
128
+ )
129
+ end
130
+
131
+ def render(status, body, format)
132
+ [status, { Rack::CONTENT_TYPE => "#{format}; charset=#{Response.default_charset}", Rack::CONTENT_LENGTH => body.bytesize.to_s }, [body]]
133
+ end
134
+
135
+ def log_error(request, wrapper)
136
+ logger = logger(request)
137
+
138
+ return unless logger
139
+ return if !log_rescued_responses?(request) && wrapper.rescue_response?
140
+
141
+ trace = wrapper.exception_trace
142
+
143
+ message = []
144
+ message << " "
145
+ if wrapper.has_cause?
146
+ message << "#{wrapper.exception_class_name} (#{wrapper.message})"
147
+ wrapper.wrapped_causes.each do |wrapped_cause|
148
+ message << "Caused by: #{wrapped_cause.exception_class_name} (#{wrapped_cause.message})"
149
+ end
150
+
151
+ message << "\nInformation for: #{wrapper.exception_class_name} (#{wrapper.message}):"
152
+ else
153
+ message << "#{wrapper.exception_class_name} (#{wrapper.message}):"
154
+ end
155
+
156
+ message.concat(wrapper.annotated_source_code)
157
+ message << " "
158
+ message.concat(trace)
159
+
160
+ if wrapper.has_cause?
161
+ wrapper.wrapped_causes.each do |wrapped_cause|
162
+ message << "\nInformation for cause: #{wrapped_cause.exception_class_name} (#{wrapped_cause.message}):"
163
+ message.concat(wrapped_cause.annotated_source_code)
164
+ message << " "
165
+ message.concat(wrapped_cause.exception_trace)
166
+ end
167
+ end
168
+
169
+ log_array(logger, message, request)
170
+ end
171
+
172
+ def log_array(logger, lines, request)
173
+ return if lines.empty?
174
+
175
+ level = request.get_header("action_dispatch.debug_exception_log_level")
176
+
177
+ if logger.formatter && logger.formatter.respond_to?(:tags_text)
178
+ logger.add(level, lines.join("\n#{logger.formatter.tags_text}"))
179
+ else
180
+ logger.add(level, lines.join("\n"))
181
+ end
182
+ end
183
+
184
+ def logger(request)
185
+ request.logger || ActionView::Base.logger || stderr_logger
186
+ end
187
+
188
+ def stderr_logger
189
+ @stderr_logger ||= ActiveSupport::Logger.new($stderr)
190
+ end
191
+
192
+ def routes_inspector(exception)
193
+ if @routes_app.respond_to?(:routes) && (exception.routing_error? || exception.template_error?)
194
+ ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes)
195
+ end
196
+ end
197
+
198
+ def api_request?(content_type)
199
+ @response_format == :api && !content_type.html?
200
+ end
201
+
202
+ def log_rescued_responses?(request)
203
+ request.get_header("action_dispatch.log_rescued_responses")
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionDispatch
6
+ # # Action Dispatch DebugLocks
7
+ #
8
+ # This middleware can be used to diagnose deadlocks in the autoload interlock.
9
+ #
10
+ # To use it, insert it near the top of the middleware stack, using
11
+ # `config/application.rb`:
12
+ #
13
+ # config.middleware.insert_before Rack::Sendfile, ActionDispatch::DebugLocks
14
+ #
15
+ # After restarting the application and re-triggering the deadlock condition, the
16
+ # route `/rails/locks` will show a summary of all threads currently known to the
17
+ # interlock, which lock level they are holding or awaiting, and their current
18
+ # backtrace.
19
+ #
20
+ # Generally a deadlock will be caused by the interlock conflicting with some
21
+ # other external lock or blocking I/O call. These cannot be automatically
22
+ # identified, but should be visible in the displayed backtraces.
23
+ #
24
+ # NOTE: The formatting and content of this middleware's output is intended for
25
+ # human consumption, and should be expected to change between releases.
26
+ #
27
+ # This middleware exposes operational details of the server, with no access
28
+ # control. It should only be enabled when in use, and removed thereafter.
29
+ class DebugLocks
30
+ def initialize(app, path = "/rails/locks")
31
+ @app = app
32
+ @path = path
33
+ end
34
+
35
+ def call(env)
36
+ req = ActionDispatch::Request.new env
37
+
38
+ if req.get?
39
+ path = req.path_info.chomp("/")
40
+ if path == @path
41
+ return render_details(req)
42
+ end
43
+ end
44
+
45
+ @app.call(env)
46
+ end
47
+
48
+ private
49
+ def render_details(req)
50
+ threads = ActiveSupport::Dependencies.interlock.raw_state do |raw_threads|
51
+ # The Interlock itself comes to a complete halt as long as this block is
52
+ # executing. That gives us a more consistent picture of everything, but creates
53
+ # a pretty strong Observer Effect.
54
+ #
55
+ # Most directly, that means we need to do as little as possible in this block.
56
+ # More widely, it means this middleware should remain a strictly diagnostic tool
57
+ # (to be used when something has gone wrong), and not for any sort of general
58
+ # monitoring.
59
+
60
+ raw_threads.each.with_index do |(thread, info), idx|
61
+ info[:index] = idx
62
+ info[:backtrace] = thread.backtrace
63
+ end
64
+
65
+ raw_threads
66
+ end
67
+
68
+ str = threads.map do |thread, info|
69
+ if info[:exclusive]
70
+ lock_state = +"Exclusive"
71
+ elsif info[:sharing] > 0
72
+ lock_state = +"Sharing"
73
+ lock_state << " x#{info[:sharing]}" if info[:sharing] > 1
74
+ else
75
+ lock_state = +"No lock"
76
+ end
77
+
78
+ if info[:waiting]
79
+ lock_state << " (yielded share)"
80
+ end
81
+
82
+ msg = +"Thread #{info[:index]} [0x#{thread.__id__.to_s(16)} #{thread.status || 'dead'}] #{lock_state}\n"
83
+
84
+ if info[:sleeper]
85
+ msg << " Waiting in #{info[:sleeper]}"
86
+ msg << " to #{info[:purpose].to_s.inspect}" unless info[:purpose].nil?
87
+ msg << "\n"
88
+
89
+ if info[:compatible]
90
+ compat = info[:compatible].map { |c| c == false ? "share" : c.to_s.inspect }
91
+ msg << " may be pre-empted for: #{compat.join(', ')}\n"
92
+ end
93
+
94
+ blockers = threads.values.select { |binfo| blocked_by?(info, binfo, threads.values) }
95
+ msg << " blocked by: #{blockers.map { |i| i[:index] }.join(', ')}\n" if blockers.any?
96
+ end
97
+
98
+ blockees = threads.values.select { |binfo| blocked_by?(binfo, info, threads.values) }
99
+ msg << " blocking: #{blockees.map { |i| i[:index] }.join(', ')}\n" if blockees.any?
100
+
101
+ msg << "\n#{info[:backtrace].join("\n")}\n" if info[:backtrace]
102
+ end.join("\n\n---\n\n\n")
103
+
104
+ [200, { Rack::CONTENT_TYPE => "text/plain; charset=#{ActionDispatch::Response.default_charset}",
105
+ Rack::CONTENT_LENGTH => str.size.to_s }, [str]]
106
+ end
107
+
108
+ def blocked_by?(victim, blocker, all_threads)
109
+ return false if victim.equal?(blocker)
110
+
111
+ case victim[:sleeper]
112
+ when :start_sharing
113
+ blocker[:exclusive] ||
114
+ (!victim[:waiting] && blocker[:compatible] && !blocker[:compatible].include?(false))
115
+ when :start_exclusive
116
+ blocker[:sharing] > 0 ||
117
+ blocker[:exclusive] ||
118
+ (blocker[:compatible] && !blocker[:compatible].include?(victim[:purpose]))
119
+ when :yield_shares
120
+ blocker[:exclusive]
121
+ when :stop_exclusive
122
+ blocker[:exclusive] ||
123
+ victim[:compatible] &&
124
+ victim[:compatible].include?(blocker[:purpose]) &&
125
+ all_threads.all? { |other| !other[:compatible] || blocker.equal?(other) || other[:compatible].include?(blocker[:purpose]) }
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "pp"
6
+
7
+ require "action_view"
8
+ require "action_view/base"
9
+
10
+ module ActionDispatch
11
+ class DebugView < ActionView::Base # :nodoc:
12
+ RESCUES_TEMPLATE_PATHS = [File.expand_path("templates", __dir__)]
13
+
14
+ def initialize(assigns)
15
+ paths = RESCUES_TEMPLATE_PATHS.dup
16
+ lookup_context = ActionView::LookupContext.new(paths)
17
+ super(lookup_context, assigns, nil)
18
+ @exception_wrapper = assigns[:exception_wrapper]
19
+ end
20
+
21
+ def compiled_method_container
22
+ self.class
23
+ end
24
+
25
+ def error_highlight_available?
26
+ @exception_wrapper.error_highlight_available?
27
+ end
28
+
29
+ def debug_params(params)
30
+ clean_params = params.clone
31
+ clean_params.delete("action")
32
+ clean_params.delete("controller")
33
+
34
+ if clean_params.empty?
35
+ "None"
36
+ else
37
+ PP.pp(clean_params, +"", 200)
38
+ end
39
+ end
40
+
41
+ def debug_headers(headers)
42
+ if headers.present?
43
+ headers.inspect.gsub(",", ",\n")
44
+ else
45
+ "None"
46
+ end
47
+ end
48
+
49
+ def debug_hash(object)
50
+ object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
51
+ end
52
+
53
+ def render(*)
54
+ logger = ActionView::Base.logger
55
+
56
+ if logger && logger.respond_to?(:silence)
57
+ logger.silence { super }
58
+ else
59
+ super
60
+ end
61
+ end
62
+
63
+ def protect_against_forgery?
64
+ false
65
+ end
66
+
67
+ def params_valid?
68
+ @request.parameters
69
+ rescue ActionController::BadRequest
70
+ false
71
+ end
72
+ end
73
+ end