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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +129 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +57 -0
- data/lib/abstract_controller/asset_paths.rb +14 -0
- data/lib/abstract_controller/base.rb +299 -0
- data/lib/abstract_controller/caching/fragments.rb +149 -0
- data/lib/abstract_controller/caching.rb +68 -0
- data/lib/abstract_controller/callbacks.rb +265 -0
- data/lib/abstract_controller/collector.rb +44 -0
- data/lib/abstract_controller/deprecator.rb +9 -0
- data/lib/abstract_controller/error.rb +8 -0
- data/lib/abstract_controller/helpers.rb +243 -0
- data/lib/abstract_controller/logger.rb +16 -0
- data/lib/abstract_controller/railties/routes_helpers.rb +25 -0
- data/lib/abstract_controller/rendering.rb +126 -0
- data/lib/abstract_controller/translation.rb +42 -0
- data/lib/abstract_controller/url_for.rb +37 -0
- data/lib/abstract_controller.rb +36 -0
- data/lib/action_controller/api/api_rendering.rb +18 -0
- data/lib/action_controller/api.rb +155 -0
- data/lib/action_controller/base.rb +332 -0
- data/lib/action_controller/caching.rb +49 -0
- data/lib/action_controller/deprecator.rb +9 -0
- data/lib/action_controller/form_builder.rb +55 -0
- data/lib/action_controller/log_subscriber.rb +96 -0
- data/lib/action_controller/metal/allow_browser.rb +123 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
- data/lib/action_controller/metal/conditional_get.rb +341 -0
- data/lib/action_controller/metal/content_security_policy.rb +86 -0
- data/lib/action_controller/metal/cookies.rb +20 -0
- data/lib/action_controller/metal/data_streaming.rb +154 -0
- data/lib/action_controller/metal/default_headers.rb +21 -0
- data/lib/action_controller/metal/etag_with_flash.rb +22 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +59 -0
- data/lib/action_controller/metal/exceptions.rb +106 -0
- data/lib/action_controller/metal/flash.rb +67 -0
- data/lib/action_controller/metal/head.rb +67 -0
- data/lib/action_controller/metal/helpers.rb +129 -0
- data/lib/action_controller/metal/http_authentication.rb +565 -0
- data/lib/action_controller/metal/implicit_render.rb +67 -0
- data/lib/action_controller/metal/instrumentation.rb +120 -0
- data/lib/action_controller/metal/live.rb +398 -0
- data/lib/action_controller/metal/logging.rb +22 -0
- data/lib/action_controller/metal/mime_responds.rb +337 -0
- data/lib/action_controller/metal/parameter_encoding.rb +84 -0
- data/lib/action_controller/metal/params_wrapper.rb +312 -0
- data/lib/action_controller/metal/permissions_policy.rb +38 -0
- data/lib/action_controller/metal/rate_limiting.rb +62 -0
- data/lib/action_controller/metal/redirecting.rb +251 -0
- data/lib/action_controller/metal/renderers.rb +181 -0
- data/lib/action_controller/metal/rendering.rb +260 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +667 -0
- data/lib/action_controller/metal/rescue.rb +33 -0
- data/lib/action_controller/metal/streaming.rb +183 -0
- data/lib/action_controller/metal/strong_parameters.rb +1546 -0
- data/lib/action_controller/metal/testing.rb +25 -0
- data/lib/action_controller/metal/url_for.rb +65 -0
- data/lib/action_controller/metal.rb +339 -0
- data/lib/action_controller/railtie.rb +149 -0
- data/lib/action_controller/railties/helpers.rb +26 -0
- data/lib/action_controller/renderer.rb +161 -0
- data/lib/action_controller/template_assertions.rb +13 -0
- data/lib/action_controller/test_case.rb +691 -0
- data/lib/action_controller.rb +80 -0
- data/lib/action_dispatch/constants.rb +34 -0
- data/lib/action_dispatch/deprecator.rb +9 -0
- data/lib/action_dispatch/http/cache.rb +249 -0
- data/lib/action_dispatch/http/content_disposition.rb +47 -0
- data/lib/action_dispatch/http/content_security_policy.rb +365 -0
- data/lib/action_dispatch/http/filter_parameters.rb +80 -0
- data/lib/action_dispatch/http/filter_redirect.rb +50 -0
- data/lib/action_dispatch/http/headers.rb +134 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +187 -0
- data/lib/action_dispatch/http/mime_type.rb +389 -0
- data/lib/action_dispatch/http/mime_types.rb +54 -0
- data/lib/action_dispatch/http/parameters.rb +119 -0
- data/lib/action_dispatch/http/permissions_policy.rb +189 -0
- data/lib/action_dispatch/http/rack_cache.rb +67 -0
- data/lib/action_dispatch/http/request.rb +498 -0
- data/lib/action_dispatch/http/response.rb +556 -0
- data/lib/action_dispatch/http/upload.rb +107 -0
- data/lib/action_dispatch/http/url.rb +344 -0
- data/lib/action_dispatch/journey/formatter.rb +226 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +149 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +50 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +217 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +27 -0
- data/lib/action_dispatch/journey/nodes/node.rb +208 -0
- data/lib/action_dispatch/journey/parser.rb +103 -0
- data/lib/action_dispatch/journey/path/pattern.rb +209 -0
- data/lib/action_dispatch/journey/route.rb +189 -0
- data/lib/action_dispatch/journey/router/utils.rb +105 -0
- data/lib/action_dispatch/journey/router.rb +151 -0
- data/lib/action_dispatch/journey/routes.rb +82 -0
- data/lib/action_dispatch/journey/scanner.rb +70 -0
- data/lib/action_dispatch/journey/visitors.rb +267 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +159 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/journey.rb +7 -0
- data/lib/action_dispatch/log_subscriber.rb +25 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
- data/lib/action_dispatch/middleware/callbacks.rb +38 -0
- data/lib/action_dispatch/middleware/cookies.rb +719 -0
- data/lib/action_dispatch/middleware/debug_exceptions.rb +206 -0
- data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
- data/lib/action_dispatch/middleware/debug_view.rb +73 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +350 -0
- data/lib/action_dispatch/middleware/executor.rb +32 -0
- data/lib/action_dispatch/middleware/flash.rb +318 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +64 -0
- data/lib/action_dispatch/middleware/reloader.rb +16 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +199 -0
- data/lib/action_dispatch/middleware/request_id.rb +50 -0
- data/lib/action_dispatch/middleware/server_timing.rb +78 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +112 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +66 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +129 -0
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +34 -0
- data/lib/action_dispatch/middleware/show_exceptions.rb +88 -0
- data/lib/action_dispatch/middleware/ssl.rb +180 -0
- data/lib/action_dispatch/middleware/stack.rb +194 -0
- data/lib/action_dispatch/middleware/static.rb +192 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +35 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +284 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +232 -0
- data/lib/action_dispatch/railtie.rb +77 -0
- data/lib/action_dispatch/request/session.rb +283 -0
- data/lib/action_dispatch/request/utils.rb +109 -0
- data/lib/action_dispatch/routing/endpoint.rb +19 -0
- data/lib/action_dispatch/routing/inspector.rb +323 -0
- data/lib/action_dispatch/routing/mapper.rb +2372 -0
- data/lib/action_dispatch/routing/polymorphic_routes.rb +363 -0
- data/lib/action_dispatch/routing/redirection.rb +218 -0
- data/lib/action_dispatch/routing/route_set.rb +958 -0
- data/lib/action_dispatch/routing/routes_proxy.rb +66 -0
- data/lib/action_dispatch/routing/url_for.rb +244 -0
- data/lib/action_dispatch/routing.rb +262 -0
- data/lib/action_dispatch/system_test_case.rb +206 -0
- data/lib/action_dispatch/system_testing/browser.rb +75 -0
- data/lib/action_dispatch/system_testing/driver.rb +85 -0
- data/lib/action_dispatch/system_testing/server.rb +33 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
- data/lib/action_dispatch/testing/assertion_response.rb +48 -0
- data/lib/action_dispatch/testing/assertions/response.rb +114 -0
- data/lib/action_dispatch/testing/assertions/routing.rb +343 -0
- data/lib/action_dispatch/testing/assertions.rb +25 -0
- data/lib/action_dispatch/testing/integration.rb +694 -0
- data/lib/action_dispatch/testing/request_encoder.rb +60 -0
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +57 -0
- data/lib/action_dispatch/testing/test_request.rb +73 -0
- data/lib/action_dispatch/testing/test_response.rb +58 -0
- data/lib/action_dispatch.rb +147 -0
- data/lib/action_pack/gem_version.rb +19 -0
- data/lib/action_pack/version.rb +12 -0
- data/lib/action_pack.rb +27 -0
- metadata +375 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
5
|
+
require "active_support/core_ext/module/attribute_accessors"
|
|
6
|
+
require "active_support/syntax_error_proxy"
|
|
7
|
+
require "active_support/core_ext/thread/backtrace/location"
|
|
8
|
+
require "rack/utils"
|
|
9
|
+
|
|
10
|
+
module ActionDispatch
|
|
11
|
+
class ExceptionWrapper
|
|
12
|
+
cattr_accessor :rescue_responses, default: Hash.new(:internal_server_error).merge!(
|
|
13
|
+
"ActionController::RoutingError" => :not_found,
|
|
14
|
+
"AbstractController::ActionNotFound" => :not_found,
|
|
15
|
+
"ActionController::MethodNotAllowed" => :method_not_allowed,
|
|
16
|
+
"ActionController::UnknownHttpMethod" => :method_not_allowed,
|
|
17
|
+
"ActionController::NotImplemented" => :not_implemented,
|
|
18
|
+
"ActionController::UnknownFormat" => :not_acceptable,
|
|
19
|
+
"ActionDispatch::Http::MimeNegotiation::InvalidType" => :not_acceptable,
|
|
20
|
+
"ActionController::MissingExactTemplate" => :not_acceptable,
|
|
21
|
+
"ActionController::InvalidAuthenticityToken" => :unprocessable_entity,
|
|
22
|
+
"ActionController::InvalidCrossOriginRequest" => :unprocessable_entity,
|
|
23
|
+
"ActionDispatch::Http::Parameters::ParseError" => :bad_request,
|
|
24
|
+
"ActionController::BadRequest" => :bad_request,
|
|
25
|
+
"ActionController::ParameterMissing" => :bad_request,
|
|
26
|
+
"Rack::QueryParser::ParameterTypeError" => :bad_request,
|
|
27
|
+
"Rack::QueryParser::InvalidParameterError" => :bad_request
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
cattr_accessor :rescue_templates, default: Hash.new("diagnostics").merge!(
|
|
31
|
+
"ActionView::MissingTemplate" => "missing_template",
|
|
32
|
+
"ActionController::RoutingError" => "routing_error",
|
|
33
|
+
"AbstractController::ActionNotFound" => "unknown_action",
|
|
34
|
+
"ActiveRecord::StatementInvalid" => "invalid_statement",
|
|
35
|
+
"ActionView::Template::Error" => "template_error",
|
|
36
|
+
"ActionController::MissingExactTemplate" => "missing_exact_template",
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
cattr_accessor :wrapper_exceptions, default: [
|
|
40
|
+
"ActionView::Template::Error"
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
cattr_accessor :silent_exceptions, default: [
|
|
44
|
+
"ActionController::RoutingError",
|
|
45
|
+
"ActionDispatch::Http::MimeNegotiation::InvalidType"
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
attr_reader :backtrace_cleaner, :wrapped_causes, :exception_class_name, :exception
|
|
49
|
+
|
|
50
|
+
def initialize(backtrace_cleaner, exception)
|
|
51
|
+
@backtrace_cleaner = backtrace_cleaner
|
|
52
|
+
@exception_class_name = exception.class.name
|
|
53
|
+
@wrapped_causes = wrapped_causes_for(exception, backtrace_cleaner)
|
|
54
|
+
@exception = exception
|
|
55
|
+
if exception.is_a?(SyntaxError)
|
|
56
|
+
@exception = ActiveSupport::SyntaxErrorProxy.new(exception)
|
|
57
|
+
end
|
|
58
|
+
@backtrace = build_backtrace
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def routing_error?
|
|
62
|
+
@exception.is_a?(ActionController::RoutingError)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def template_error?
|
|
66
|
+
@exception.is_a?(ActionView::Template::Error)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def sub_template_message
|
|
70
|
+
@exception.sub_template_message
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def has_cause?
|
|
74
|
+
@exception.cause
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def failures
|
|
78
|
+
@exception.failures
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def has_corrections?
|
|
82
|
+
@exception.respond_to?(:original_message) && @exception.respond_to?(:corrections)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def original_message
|
|
86
|
+
@exception.original_message
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def corrections
|
|
90
|
+
@exception.corrections
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def file_name
|
|
94
|
+
@exception.file_name
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def line_number
|
|
98
|
+
@exception.line_number
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def actions
|
|
102
|
+
ActiveSupport::ActionableError.actions(@exception)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def unwrapped_exception
|
|
106
|
+
if wrapper_exceptions.include?(@exception_class_name)
|
|
107
|
+
@exception.cause
|
|
108
|
+
else
|
|
109
|
+
@exception
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def annotated_source_code
|
|
114
|
+
if exception.respond_to?(:annotated_source_code)
|
|
115
|
+
exception.annotated_source_code
|
|
116
|
+
else
|
|
117
|
+
[]
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def rescue_template
|
|
122
|
+
@@rescue_templates[@exception_class_name]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def status_code
|
|
126
|
+
self.class.status_code_for_exception(unwrapped_exception.class.name)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def exception_trace
|
|
130
|
+
trace = application_trace
|
|
131
|
+
trace = framework_trace if trace.empty? && !silent_exceptions.include?(@exception_class_name)
|
|
132
|
+
trace
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def application_trace
|
|
136
|
+
clean_backtrace(:silent)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def framework_trace
|
|
140
|
+
clean_backtrace(:noise)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def full_trace
|
|
144
|
+
clean_backtrace(:all)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def traces
|
|
148
|
+
application_trace_with_ids = []
|
|
149
|
+
framework_trace_with_ids = []
|
|
150
|
+
full_trace_with_ids = []
|
|
151
|
+
|
|
152
|
+
full_trace.each_with_index do |trace, idx|
|
|
153
|
+
trace_with_id = {
|
|
154
|
+
exception_object_id: @exception.object_id,
|
|
155
|
+
id: idx,
|
|
156
|
+
trace: trace
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if application_trace.include?(trace)
|
|
160
|
+
application_trace_with_ids << trace_with_id
|
|
161
|
+
else
|
|
162
|
+
framework_trace_with_ids << trace_with_id
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
full_trace_with_ids << trace_with_id
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
{
|
|
169
|
+
"Application Trace" => application_trace_with_ids,
|
|
170
|
+
"Framework Trace" => framework_trace_with_ids,
|
|
171
|
+
"Full Trace" => full_trace_with_ids
|
|
172
|
+
}
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def self.status_code_for_exception(class_name)
|
|
176
|
+
Rack::Utils.status_code(@@rescue_responses[class_name])
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def show?(request)
|
|
180
|
+
# We're treating `nil` as "unset", and we want the default setting to be `:all`.
|
|
181
|
+
# This logic should be extracted to `env_config` and calculated once.
|
|
182
|
+
config = request.get_header("action_dispatch.show_exceptions")
|
|
183
|
+
|
|
184
|
+
case config
|
|
185
|
+
when :none
|
|
186
|
+
false
|
|
187
|
+
when :rescuable
|
|
188
|
+
rescue_response?
|
|
189
|
+
else
|
|
190
|
+
true
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def rescue_response?
|
|
195
|
+
@@rescue_responses.key?(exception.class.name)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def source_extracts
|
|
199
|
+
backtrace.map do |trace|
|
|
200
|
+
extract_source(trace)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def error_highlight_available?
|
|
205
|
+
# ErrorHighlight.spot with backtrace_location keyword is available since
|
|
206
|
+
# error_highlight 0.4.0
|
|
207
|
+
defined?(ErrorHighlight) && Gem::Version.new(ErrorHighlight::VERSION) >= Gem::Version.new("0.4.0")
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def trace_to_show
|
|
211
|
+
if traces["Application Trace"].empty? && rescue_template != "routing_error"
|
|
212
|
+
"Full Trace"
|
|
213
|
+
else
|
|
214
|
+
"Application Trace"
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def source_to_show_id
|
|
219
|
+
(traces[trace_to_show].first || {})[:id]
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def exception_name
|
|
223
|
+
exception.cause.class.to_s
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def message
|
|
227
|
+
exception.message
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def exception_inspect
|
|
231
|
+
exception.inspect
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def exception_id
|
|
235
|
+
exception.object_id
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
private
|
|
239
|
+
class SourceMapLocation < DelegateClass(Thread::Backtrace::Location) # :nodoc:
|
|
240
|
+
def initialize(location, template)
|
|
241
|
+
super(location)
|
|
242
|
+
@template = template
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def spot(exc)
|
|
246
|
+
if RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location) && __getobj__.is_a?(Thread::Backtrace::Location)
|
|
247
|
+
location = @template.spot(__getobj__)
|
|
248
|
+
else
|
|
249
|
+
location = super
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
if location
|
|
253
|
+
@template.translate_location(__getobj__, location)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
attr_reader :backtrace
|
|
259
|
+
|
|
260
|
+
def build_backtrace
|
|
261
|
+
built_methods = {}
|
|
262
|
+
|
|
263
|
+
ActionView::PathRegistry.all_resolvers.each do |resolver|
|
|
264
|
+
resolver.built_templates.each do |template|
|
|
265
|
+
built_methods[template.method_name] = template
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
(@exception.backtrace_locations || []).map do |loc|
|
|
270
|
+
if built_methods.key?(loc.label.to_s)
|
|
271
|
+
thread_backtrace_location = if loc.respond_to?(:__getobj__)
|
|
272
|
+
loc.__getobj__
|
|
273
|
+
else
|
|
274
|
+
loc
|
|
275
|
+
end
|
|
276
|
+
SourceMapLocation.new(thread_backtrace_location, built_methods[loc.label.to_s])
|
|
277
|
+
else
|
|
278
|
+
loc
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def causes_for(exception)
|
|
284
|
+
return enum_for(__method__, exception) unless block_given?
|
|
285
|
+
|
|
286
|
+
yield exception while exception = exception.cause
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def wrapped_causes_for(exception, backtrace_cleaner)
|
|
290
|
+
causes_for(exception).map { |cause| self.class.new(backtrace_cleaner, cause) }
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def clean_backtrace(*args)
|
|
294
|
+
if backtrace_cleaner
|
|
295
|
+
backtrace_cleaner.clean(backtrace, *args)
|
|
296
|
+
else
|
|
297
|
+
backtrace
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def extract_source(trace)
|
|
302
|
+
spot = trace.spot(@exception)
|
|
303
|
+
|
|
304
|
+
if spot
|
|
305
|
+
line = spot[:first_lineno]
|
|
306
|
+
code = extract_source_fragment_lines(spot[:script_lines], line)
|
|
307
|
+
|
|
308
|
+
if line == spot[:last_lineno]
|
|
309
|
+
code[line] = [
|
|
310
|
+
code[line][0, spot[:first_column]],
|
|
311
|
+
code[line][spot[:first_column]...spot[:last_column]],
|
|
312
|
+
code[line][spot[:last_column]..-1],
|
|
313
|
+
]
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
code: code,
|
|
318
|
+
line_number: line
|
|
319
|
+
}
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
file, line_number = extract_file_and_line_number(trace)
|
|
323
|
+
|
|
324
|
+
{
|
|
325
|
+
code: source_fragment(file, line_number),
|
|
326
|
+
line_number: line_number
|
|
327
|
+
}
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def extract_source_fragment_lines(source_lines, line)
|
|
331
|
+
start = [line - 3, 0].max
|
|
332
|
+
lines = source_lines.drop(start).take(6)
|
|
333
|
+
Hash[*(start + 1..(lines.count + start)).zip(lines).flatten]
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def source_fragment(path, line)
|
|
337
|
+
return unless Rails.respond_to?(:root) && Rails.root
|
|
338
|
+
full_path = Rails.root.join(path)
|
|
339
|
+
if File.exist?(full_path)
|
|
340
|
+
File.open(full_path, "r") do |file|
|
|
341
|
+
extract_source_fragment_lines(file.each_line, line)
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def extract_file_and_line_number(trace)
|
|
347
|
+
[trace.path, trace.lineno]
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
5
|
+
require "rack/body_proxy"
|
|
6
|
+
|
|
7
|
+
module ActionDispatch
|
|
8
|
+
class Executor
|
|
9
|
+
def initialize(app, executor)
|
|
10
|
+
@app, @executor = app, executor
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call(env)
|
|
14
|
+
state = @executor.run!(reset: true)
|
|
15
|
+
begin
|
|
16
|
+
response = @app.call(env)
|
|
17
|
+
|
|
18
|
+
if env["action_dispatch.report_exception"]
|
|
19
|
+
error = env["action_dispatch.exception"]
|
|
20
|
+
@executor.error_reporter.report(error, handled: false, source: "application.action_dispatch")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
returned = response << ::Rack::BodyProxy.new(response.pop) { state.complete! }
|
|
24
|
+
rescue => error
|
|
25
|
+
@executor.error_reporter.report(error, handled: false, source: "application.action_dispatch")
|
|
26
|
+
raise
|
|
27
|
+
ensure
|
|
28
|
+
state.complete! unless returned
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
5
|
+
require "active_support/core_ext/hash/keys"
|
|
6
|
+
|
|
7
|
+
module ActionDispatch
|
|
8
|
+
# # Action Dispatch Flash
|
|
9
|
+
#
|
|
10
|
+
# The flash provides a way to pass temporary primitive-types (String, Array,
|
|
11
|
+
# Hash) between actions. Anything you place in the flash will be exposed to the
|
|
12
|
+
# very next action and then cleared out. This is a great way of doing notices
|
|
13
|
+
# and alerts, such as a create action that sets `flash[:notice] = "Post
|
|
14
|
+
# successfully created"` before redirecting to a display action that can then
|
|
15
|
+
# expose the flash to its template. Actually, that exposure is automatically
|
|
16
|
+
# done.
|
|
17
|
+
#
|
|
18
|
+
# class PostsController < ActionController::Base
|
|
19
|
+
# def create
|
|
20
|
+
# # save post
|
|
21
|
+
# flash[:notice] = "Post successfully created"
|
|
22
|
+
# redirect_to @post
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# def show
|
|
26
|
+
# # doesn't need to assign the flash notice to the template, that's done automatically
|
|
27
|
+
# end
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# Then in `show.html.erb`:
|
|
31
|
+
#
|
|
32
|
+
# <% if flash[:notice] %>
|
|
33
|
+
# <div class="notice"><%= flash[:notice] %></div>
|
|
34
|
+
# <% end %>
|
|
35
|
+
#
|
|
36
|
+
# Since the `notice` and `alert` keys are a common idiom, convenience accessors
|
|
37
|
+
# are available:
|
|
38
|
+
#
|
|
39
|
+
# flash.alert = "You must be logged in"
|
|
40
|
+
# flash.notice = "Post successfully created"
|
|
41
|
+
#
|
|
42
|
+
# This example places a string in the flash. And of course, you can put as many
|
|
43
|
+
# as you like at a time too. If you want to pass non-primitive types, you will
|
|
44
|
+
# have to handle that in your application. Example: To show messages with links,
|
|
45
|
+
# you will have to use sanitize helper.
|
|
46
|
+
#
|
|
47
|
+
# Just remember: They'll be gone by the time the next action has been performed.
|
|
48
|
+
#
|
|
49
|
+
# See docs on the FlashHash class for more details about the flash.
|
|
50
|
+
class Flash
|
|
51
|
+
KEY = "action_dispatch.request.flash_hash"
|
|
52
|
+
|
|
53
|
+
module RequestMethods
|
|
54
|
+
# Access the contents of the flash. Returns a ActionDispatch::Flash::FlashHash.
|
|
55
|
+
#
|
|
56
|
+
# See ActionDispatch::Flash for example usage.
|
|
57
|
+
def flash
|
|
58
|
+
flash = flash_hash
|
|
59
|
+
return flash if flash
|
|
60
|
+
self.flash = Flash::FlashHash.from_session_value(session["flash"])
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def flash=(flash)
|
|
64
|
+
set_header Flash::KEY, flash
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def flash_hash # :nodoc:
|
|
68
|
+
get_header Flash::KEY
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def commit_flash # :nodoc:
|
|
72
|
+
return unless session.enabled?
|
|
73
|
+
|
|
74
|
+
if flash_hash && (flash_hash.present? || session.key?("flash"))
|
|
75
|
+
session["flash"] = flash_hash.to_session_value
|
|
76
|
+
self.flash = flash_hash.dup
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
if session.loaded? && session.key?("flash") && session["flash"].nil?
|
|
80
|
+
session.delete("flash")
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def reset_session # :nodoc:
|
|
85
|
+
super
|
|
86
|
+
self.flash = nil
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class FlashNow # :nodoc:
|
|
91
|
+
attr_accessor :flash
|
|
92
|
+
|
|
93
|
+
def initialize(flash)
|
|
94
|
+
@flash = flash
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def []=(k, v)
|
|
98
|
+
k = k.to_s
|
|
99
|
+
@flash[k] = v
|
|
100
|
+
@flash.discard(k)
|
|
101
|
+
v
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def [](k)
|
|
105
|
+
@flash[k.to_s]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Convenience accessor for `flash.now[:alert]=`.
|
|
109
|
+
def alert=(message)
|
|
110
|
+
self[:alert] = message
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Convenience accessor for `flash.now[:notice]=`.
|
|
114
|
+
def notice=(message)
|
|
115
|
+
self[:notice] = message
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
class FlashHash
|
|
120
|
+
include Enumerable
|
|
121
|
+
|
|
122
|
+
def self.from_session_value(value) # :nodoc:
|
|
123
|
+
case value
|
|
124
|
+
when FlashHash # Rails 3.1, 3.2
|
|
125
|
+
flashes = value.instance_variable_get(:@flashes)
|
|
126
|
+
if discard = value.instance_variable_get(:@used)
|
|
127
|
+
flashes.except!(*discard)
|
|
128
|
+
end
|
|
129
|
+
new(flashes, flashes.keys)
|
|
130
|
+
when Hash # Rails 4.0
|
|
131
|
+
flashes = value["flashes"]
|
|
132
|
+
if discard = value["discard"]
|
|
133
|
+
flashes.except!(*discard)
|
|
134
|
+
end
|
|
135
|
+
new(flashes, flashes.keys)
|
|
136
|
+
else
|
|
137
|
+
new
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Builds a hash containing the flashes to keep for the next request. If there
|
|
142
|
+
# are none to keep, returns `nil`.
|
|
143
|
+
def to_session_value # :nodoc:
|
|
144
|
+
flashes_to_keep = @flashes.except(*@discard)
|
|
145
|
+
return nil if flashes_to_keep.empty?
|
|
146
|
+
{ "discard" => [], "flashes" => flashes_to_keep }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def initialize(flashes = {}, discard = []) # :nodoc:
|
|
150
|
+
@discard = Set.new(stringify_array(discard))
|
|
151
|
+
@flashes = flashes.stringify_keys
|
|
152
|
+
@now = nil
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def initialize_copy(other)
|
|
156
|
+
if other.now_is_loaded?
|
|
157
|
+
@now = other.now.dup
|
|
158
|
+
@now.flash = self
|
|
159
|
+
end
|
|
160
|
+
super
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def []=(k, v)
|
|
164
|
+
k = k.to_s
|
|
165
|
+
@discard.delete k
|
|
166
|
+
@flashes[k] = v
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def [](k)
|
|
170
|
+
@flashes[k.to_s]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def update(h) # :nodoc:
|
|
174
|
+
@discard.subtract stringify_array(h.keys)
|
|
175
|
+
@flashes.update h.stringify_keys
|
|
176
|
+
self
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def keys
|
|
180
|
+
@flashes.keys
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def key?(name)
|
|
184
|
+
@flashes.key? name.to_s
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Immediately deletes the single flash entry. Use this method when you want
|
|
188
|
+
# remove the message within the current action. See also #discard.
|
|
189
|
+
def delete(key)
|
|
190
|
+
key = key.to_s
|
|
191
|
+
@discard.delete key
|
|
192
|
+
@flashes.delete key
|
|
193
|
+
self
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def to_hash
|
|
197
|
+
@flashes.dup
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def empty?
|
|
201
|
+
@flashes.empty?
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def clear
|
|
205
|
+
@discard.clear
|
|
206
|
+
@flashes.clear
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def each(&block)
|
|
210
|
+
@flashes.each(&block)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
alias :merge! :update
|
|
214
|
+
|
|
215
|
+
def replace(h) # :nodoc:
|
|
216
|
+
@discard.clear
|
|
217
|
+
@flashes.replace h.stringify_keys
|
|
218
|
+
self
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Sets a flash that will not be available to the next action, only to the
|
|
222
|
+
# current.
|
|
223
|
+
#
|
|
224
|
+
# flash.now[:message] = "Hello current action"
|
|
225
|
+
#
|
|
226
|
+
# This method enables you to use the flash as a central messaging system in your
|
|
227
|
+
# app. When you need to pass an object to the next action, you use the standard
|
|
228
|
+
# flash assign (`[]=`). When you need to pass an object to the current action,
|
|
229
|
+
# you use `now`, and your object will vanish when the current action is done.
|
|
230
|
+
#
|
|
231
|
+
# Entries set via `now` are accessed the same way as standard entries:
|
|
232
|
+
# `flash['my-key']`.
|
|
233
|
+
#
|
|
234
|
+
# Also, brings two convenience accessors:
|
|
235
|
+
#
|
|
236
|
+
# flash.now.alert = "Beware now!"
|
|
237
|
+
# # Equivalent to flash.now[:alert] = "Beware now!"
|
|
238
|
+
#
|
|
239
|
+
# flash.now.notice = "Good luck now!"
|
|
240
|
+
# # Equivalent to flash.now[:notice] = "Good luck now!"
|
|
241
|
+
def now
|
|
242
|
+
@now ||= FlashNow.new(self)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Keeps either the entire current flash or a specific flash entry available for
|
|
246
|
+
# the next action:
|
|
247
|
+
#
|
|
248
|
+
# flash.keep # keeps the entire flash
|
|
249
|
+
# flash.keep(:notice) # keeps only the "notice" entry, the rest of the flash is discarded
|
|
250
|
+
def keep(k = nil)
|
|
251
|
+
k = k.to_s if k
|
|
252
|
+
@discard.subtract Array(k || keys)
|
|
253
|
+
k ? self[k] : self
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Marks the entire flash or a single flash entry to be discarded by the end of
|
|
257
|
+
# the current action:
|
|
258
|
+
#
|
|
259
|
+
# flash.discard # discard the entire flash at the end of the current action
|
|
260
|
+
# flash.discard(:warning) # discard only the "warning" entry at the end of the current action
|
|
261
|
+
#
|
|
262
|
+
# Use this method when you want to display the message in the current action but
|
|
263
|
+
# not in the next one. See also #delete.
|
|
264
|
+
def discard(k = nil)
|
|
265
|
+
k = k.to_s if k
|
|
266
|
+
@discard.merge Array(k || keys)
|
|
267
|
+
k ? self[k] : self
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Mark for removal entries that were kept, and delete unkept ones.
|
|
271
|
+
#
|
|
272
|
+
# This method is called automatically by filters, so you generally don't need to
|
|
273
|
+
# care about it.
|
|
274
|
+
def sweep # :nodoc:
|
|
275
|
+
@discard.each { |k| @flashes.delete k }
|
|
276
|
+
@discard.replace @flashes.keys
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Convenience accessor for `flash[:alert]`.
|
|
280
|
+
def alert
|
|
281
|
+
self[:alert]
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Convenience accessor for `flash[:alert]=`.
|
|
285
|
+
def alert=(message)
|
|
286
|
+
self[:alert] = message
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Convenience accessor for `flash[:notice]`.
|
|
290
|
+
def notice
|
|
291
|
+
self[:notice]
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Convenience accessor for `flash[:notice]=`.
|
|
295
|
+
def notice=(message)
|
|
296
|
+
self[:notice] = message
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
protected
|
|
300
|
+
def now_is_loaded?
|
|
301
|
+
@now
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
private
|
|
305
|
+
def stringify_array(array) # :doc:
|
|
306
|
+
array.map do |item|
|
|
307
|
+
item.kind_of?(Symbol) ? item.to_s : item
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def self.new(app) app; end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
class Request
|
|
316
|
+
prepend Flash::RequestMethods
|
|
317
|
+
end
|
|
318
|
+
end
|