sqreen 1.18.6-java → 1.20.0-java
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 +4 -4
- data/CHANGELOG.md +27 -0
- data/lib/sqreen/actions.rb +2 -0
- data/lib/sqreen/actions/actions_index.rb +16 -0
- data/lib/sqreen/actions/base.rb +4 -10
- data/lib/sqreen/actions/block_ip.rb +2 -0
- data/lib/sqreen/actions/block_user.rb +2 -0
- data/lib/sqreen/actions/ip_range_indexed_action_class.rb +4 -24
- data/lib/sqreen/actions/ip_ranges_index.rb +32 -11
- data/lib/sqreen/actions/redirect_ip.rb +2 -0
- data/lib/sqreen/actions/redirect_user.rb +2 -0
- data/lib/sqreen/actions/repository.rb +27 -8
- data/lib/sqreen/actions/unknown_action_type.rb +4 -0
- data/lib/sqreen/actions/user_action_class.rb +5 -30
- data/lib/sqreen/actions/users_index.rb +35 -0
- data/lib/sqreen/agent.rb +2 -1
- data/lib/sqreen/aggregated_metric.rb +25 -0
- data/lib/sqreen/attack_blocked.rb +2 -0
- data/lib/sqreen/binding_accessor.rb +2 -0
- data/lib/sqreen/binding_accessor/path_elem.rb +2 -0
- data/lib/sqreen/binding_accessor/transforms.rb +8 -1
- data/lib/sqreen/call_countable.rb +2 -0
- data/lib/sqreen/capped_queue.rb +2 -0
- data/lib/sqreen/cb.rb +2 -0
- data/lib/sqreen/cb_tree.rb +2 -0
- data/lib/sqreen/condition_evaluator.rb +2 -0
- data/lib/sqreen/conditionable.rb +2 -0
- data/lib/sqreen/configuration.rb +19 -1
- data/lib/sqreen/context.rb +2 -0
- data/lib/sqreen/default_cb.rb +2 -0
- data/lib/sqreen/deferred_logger.rb +2 -0
- data/lib/sqreen/deliveries.rb +2 -0
- data/lib/sqreen/deliveries/batch.rb +6 -1
- data/lib/sqreen/deliveries/simple.rb +6 -0
- data/lib/sqreen/dependency.rb +3 -1
- data/lib/sqreen/dependency/detector.rb +22 -14
- data/lib/sqreen/dependency/libsqreen.rb +4 -0
- data/lib/sqreen/dependency/new_relic.rb +2 -0
- data/lib/sqreen/dependency/rack.rb +10 -5
- data/lib/sqreen/dependency/rails.rb +4 -0
- data/lib/sqreen/dependency/sentry.rb +2 -0
- data/lib/sqreen/dependency/sinatra.rb +12 -1
- data/lib/sqreen/encoding_sanitizer.rb +2 -0
- data/lib/sqreen/error_handling_middleware.rb +2 -0
- data/lib/sqreen/event.rb +9 -5
- data/lib/sqreen/events/attack.rb +25 -18
- data/lib/sqreen/events/remote_exception.rb +2 -22
- data/lib/sqreen/events/request_record.rb +17 -70
- data/lib/sqreen/exception.rb +2 -0
- data/lib/sqreen/formatter_with_tid.rb +2 -0
- data/lib/sqreen/framework_cb.rb +2 -0
- data/lib/sqreen/frameworks.rb +2 -0
- data/lib/sqreen/frameworks/generic.rb +2 -0
- data/lib/sqreen/frameworks/rails.rb +1 -0
- data/lib/sqreen/frameworks/rails3.rb +2 -0
- data/lib/sqreen/frameworks/request_recorder.rb +15 -2
- data/lib/sqreen/frameworks/sinatra.rb +2 -0
- data/lib/sqreen/frameworks/sqreen_test.rb +2 -0
- data/lib/sqreen/graft.rb +12 -0
- data/lib/sqreen/graft/call.rb +150 -0
- data/lib/sqreen/{dependency → graft}/callback.rb +12 -4
- data/lib/sqreen/graft/hook.rb +316 -0
- data/lib/sqreen/{dependency → graft}/hook_point.rb +152 -33
- data/lib/sqreen/graft/hook_point_error.rb +10 -0
- data/lib/sqreen/invalid_signature_exception.rb +2 -0
- data/lib/sqreen/js.rb +2 -0
- data/lib/sqreen/js/call_context.rb +2 -0
- data/lib/sqreen/js/context_pool.rb +2 -0
- data/lib/sqreen/js/exec_js_runnable.rb +2 -0
- data/lib/sqreen/js/execjs_adapter.rb +2 -0
- data/lib/sqreen/js/executable_js.rb +2 -0
- data/lib/sqreen/js/js_service.rb +2 -0
- data/lib/sqreen/js/js_service_adapter.rb +2 -0
- data/lib/sqreen/js/mini_racer_adapter.rb +2 -0
- data/lib/sqreen/js/mini_racer_executable_js.rb +2 -0
- data/lib/sqreen/js/thread_local_exec_js_runnable.rb +2 -0
- data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
- data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
- data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
- data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
- data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
- data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
- data/lib/sqreen/{backport.rb → legacy.rb} +3 -2
- data/lib/sqreen/{instrumentation.rb → legacy/instrumentation.rb} +31 -2
- data/lib/sqreen/legacy/old_event_submission_strategy.rb +221 -0
- data/lib/sqreen/legacy/waf_redactions.rb +49 -0
- data/lib/sqreen/log.rb +2 -0
- data/lib/sqreen/log/loggable.rb +28 -0
- data/lib/sqreen/logger.rb +2 -0
- data/lib/sqreen/metrics.rb +2 -0
- data/lib/sqreen/metrics/average.rb +2 -0
- data/lib/sqreen/metrics/base.rb +5 -0
- data/lib/sqreen/metrics/binning.rb +2 -0
- data/lib/sqreen/metrics/collect.rb +2 -0
- data/lib/sqreen/metrics/sum.rb +2 -0
- data/lib/sqreen/metrics_store.rb +24 -12
- data/lib/sqreen/metrics_store/already_registered_metric.rb +2 -0
- data/lib/sqreen/metrics_store/unknown_metric.rb +2 -0
- data/lib/sqreen/metrics_store/unregistered_metric.rb +2 -0
- data/lib/sqreen/middleware.rb +2 -0
- data/lib/sqreen/mono_time.rb +2 -0
- data/lib/sqreen/node.rb +2 -0
- data/lib/sqreen/not_implemented_yet.rb +2 -0
- data/lib/sqreen/null_logger.rb +2 -0
- data/lib/sqreen/payload_creator.rb +2 -0
- data/lib/sqreen/payload_creator/header_section.rb +2 -0
- data/lib/sqreen/performance_notifications.rb +2 -0
- data/lib/sqreen/performance_notifications/binned_metrics.rb +10 -2
- data/lib/sqreen/performance_notifications/log.rb +2 -0
- data/lib/sqreen/performance_notifications/log_performance.rb +2 -0
- data/lib/sqreen/performance_notifications/metrics.rb +2 -0
- data/lib/sqreen/performance_notifications/newrelic.rb +2 -0
- data/lib/sqreen/prefix.rb +2 -0
- data/lib/sqreen/rails_middleware.rb +2 -0
- data/lib/sqreen/remote_command.rb +2 -0
- data/lib/sqreen/remote_command/failure_output.rb +5 -0
- data/lib/sqreen/rules.rb +6 -2
- data/lib/sqreen/rules/attrs.rb +2 -0
- data/lib/sqreen/rules/auth_track_cb.rb +2 -0
- data/lib/sqreen/rules/binding_accessor_matcher_cb.rb +2 -0
- data/lib/sqreen/rules/binding_accessor_metrics.rb +2 -0
- data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -0
- data/lib/sqreen/rules/count_http_codes.rb +2 -0
- data/lib/sqreen/rules/crawler_user_agent_matches_cb.rb +2 -0
- data/lib/sqreen/rules/crawler_user_agent_matches_metrics_cb.rb +2 -0
- data/lib/sqreen/rules/custom_error_cb.rb +2 -0
- data/lib/sqreen/rules/devise_auth_track_cb.rb +2 -0
- data/lib/sqreen/rules/devise_signup_track_cb.rb +2 -0
- data/lib/sqreen/rules/execjs_cb.rb +2 -0
- data/lib/sqreen/rules/headers_insert_cb.rb +7 -0
- data/lib/sqreen/rules/matcher_rule.rb +2 -0
- data/lib/sqreen/rules/not_found_cb.rb +7 -0
- data/lib/sqreen/rules/rails_parameters_cb.rb +2 -0
- data/lib/sqreen/rules/record_request_context.rb +2 -0
- data/lib/sqreen/rules/regexp_rule_cb.rb +2 -0
- data/lib/sqreen/rules/rule_cb.rb +4 -0
- data/lib/sqreen/rules/run_req_start_actions.rb +3 -1
- data/lib/sqreen/rules/run_user_actions.rb +3 -1
- data/lib/sqreen/rules/shell_env_cb.rb +2 -0
- data/lib/sqreen/rules/signup_track_cb.rb +2 -0
- data/lib/sqreen/rules/update_request_context.rb +2 -0
- data/lib/sqreen/rules/url_matches_cb.rb +2 -0
- data/lib/sqreen/rules/user_agent_matches_cb.rb +2 -0
- data/lib/sqreen/rules/waf_cb.rb +41 -16
- data/lib/sqreen/rules/xss_cb.rb +2 -0
- data/lib/sqreen/run_when_called_cb.rb +2 -0
- data/lib/sqreen/runner.rb +68 -12
- data/lib/sqreen/runtime_infos.rb +2 -0
- data/lib/sqreen/safe_json.rb +2 -0
- data/lib/sqreen/sdk.rb +4 -0
- data/lib/sqreen/sensitive_data_redactor.rb +21 -31
- data/lib/sqreen/serializer.rb +2 -0
- data/lib/sqreen/session.rb +41 -37
- data/lib/sqreen/shared_storage.rb +2 -0
- data/lib/sqreen/shared_storage23.rb +2 -0
- data/lib/sqreen/shrink_wrap.rb +16 -0
- data/lib/sqreen/signals/conversions.rb +283 -0
- data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
- data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
- data/lib/sqreen/signature_verifier.rb +2 -0
- data/lib/sqreen/sinatra_middleware.rb +2 -0
- data/lib/sqreen/sqreen_signed_verifier.rb +2 -0
- data/lib/sqreen/token_invalid_exception.rb +2 -0
- data/lib/sqreen/token_not_found_exception.rb +2 -0
- data/lib/sqreen/trie.rb +2 -0
- data/lib/sqreen/unauthorized.rb +2 -0
- data/lib/sqreen/util.rb +5 -0
- data/lib/sqreen/util/capped_array.rb +2 -0
- data/lib/sqreen/util/capped_hash.rb +2 -0
- data/lib/sqreen/util/capped_string.rb +2 -0
- data/lib/sqreen/util/capper.rb +2 -0
- data/lib/sqreen/version.rb +3 -1
- data/lib/sqreen/waf_error.rb +2 -0
- data/lib/sqreen/weave.rb +12 -0
- data/lib/sqreen/weave/hardcoded.rb +19 -0
- data/lib/sqreen/weave/instrumentor.rb +48 -0
- data/lib/sqreen/weave/legacy.rb +12 -0
- data/lib/sqreen/weave/legacy/instrumentation.rb +406 -0
- data/lib/sqreen/web_server.rb +2 -0
- data/lib/sqreen/web_server/generic.rb +2 -0
- data/lib/sqreen/web_server/passenger.rb +2 -0
- data/lib/sqreen/web_server/puma.rb +2 -0
- data/lib/sqreen/web_server/rainbows.rb +2 -0
- data/lib/sqreen/web_server/thin.rb +2 -0
- data/lib/sqreen/web_server/unicorn.rb +2 -0
- data/lib/sqreen/web_server/webrick.rb +2 -0
- data/lib/sqreen/worker.rb +2 -0
- metadata +65 -9
- data/lib/sqreen/backport/original_name.rb +0 -86
- data/lib/sqreen/dependency/hook.rb +0 -102
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
# typed: false
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
|
4
|
+
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
|
5
|
+
|
|
6
|
+
require 'sqreen/graft'
|
|
7
|
+
require 'sqreen/graft/call'
|
|
8
|
+
require 'sqreen/graft/callback'
|
|
9
|
+
require 'sqreen/graft/hook_point'
|
|
10
|
+
|
|
11
|
+
module Sqreen
|
|
12
|
+
module Graft
|
|
13
|
+
class Hook
|
|
14
|
+
@hooks = {}
|
|
15
|
+
|
|
16
|
+
def self.[](hook_point, strategy = :chain)
|
|
17
|
+
@hooks[hook_point] ||= new(hook_point, nil, strategy)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.add(hook_point, strategy = :chain, &block)
|
|
21
|
+
self[hook_point, strategy].add(&block)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
attr_reader :point
|
|
25
|
+
|
|
26
|
+
def initialize(hook_point, dependency_test = nil, strategy = :chain)
|
|
27
|
+
@disabled = false
|
|
28
|
+
@point = hook_point.is_a?(HookPoint) ? hook_point : HookPoint.new(hook_point, strategy)
|
|
29
|
+
@before = []
|
|
30
|
+
@after = []
|
|
31
|
+
@raised = []
|
|
32
|
+
@ensured = []
|
|
33
|
+
@dependency_test = dependency_test || Proc.new { point.exist? }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def dependency?
|
|
37
|
+
@dependency_test.call if @dependency_test
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add(&block)
|
|
41
|
+
tap { instance_eval(&block) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def callback_name(whence, tag = nil)
|
|
45
|
+
"#{point}@#{whence}" << (tag ? ":#{tag}" : "")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def before(tag = nil, opts = {}, &block)
|
|
49
|
+
return @before.sort_by(&:rank) if block.nil?
|
|
50
|
+
|
|
51
|
+
@before << Callback.new(callback_name(:before, tag), opts, &block)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def after(tag = nil, opts = {}, &block)
|
|
55
|
+
return @after.sort_by(&:rank) if block.nil?
|
|
56
|
+
|
|
57
|
+
@after << Callback.new(callback_name(:after, tag), opts, &block)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def raised(tag = nil, opts = {}, &block)
|
|
61
|
+
return @raised.sort_by(&:rank) if block.nil?
|
|
62
|
+
|
|
63
|
+
@raised << Callback.new(callback_name(:raised, tag), opts, &block)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def ensured(tag = nil, opts = {}, &block)
|
|
67
|
+
return @ensured.sort_by(&:rank) if block.nil?
|
|
68
|
+
|
|
69
|
+
@ensured << Callback.new(callback_name(:ensured, tag), opts, &block)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def depends_on(&block)
|
|
73
|
+
@dependency_test = block
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def enable
|
|
77
|
+
@disabled = false
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def disable
|
|
81
|
+
@disabled = true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def disabled?
|
|
85
|
+
@disabled
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def install
|
|
89
|
+
unless point.exist?
|
|
90
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] #{point} not found" }
|
|
91
|
+
return
|
|
92
|
+
end
|
|
93
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] Hook #{point}: installing" }
|
|
94
|
+
|
|
95
|
+
point.install('sqreen_hook', &Sqreen::Graft::Hook.wrapper(self))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def uninstall
|
|
99
|
+
unless point.exist?
|
|
100
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] #{point} not found" }
|
|
101
|
+
return
|
|
102
|
+
end
|
|
103
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] Hook #{point}: uninstalling" }
|
|
104
|
+
|
|
105
|
+
point.uninstall('sqreen_hook', &Sqreen::Graft::Hook.wrapper(self))
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def clear
|
|
109
|
+
@before = []
|
|
110
|
+
@after = []
|
|
111
|
+
@raised = []
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.wrapper(hook)
|
|
115
|
+
Proc.new do |*args, &block|
|
|
116
|
+
if Thread.current[:sqreen_hook_entered] || Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:time_budget_expended]
|
|
117
|
+
if hook.point.super?
|
|
118
|
+
return super(*args, &block)
|
|
119
|
+
else
|
|
120
|
+
return hook.point.apply(self, 'sqreen_hook', *args, &block)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
Timer.new(hook.point) do |t|
|
|
125
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks] << t
|
|
126
|
+
end.measure do |chrono|
|
|
127
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} caller:#{Kernel.caller[2].inspect}" }
|
|
128
|
+
|
|
129
|
+
budget = Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:time_budget]
|
|
130
|
+
timer = Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timer] if budget
|
|
131
|
+
hooked_call = HookedCall.new(self, args)
|
|
132
|
+
|
|
133
|
+
begin
|
|
134
|
+
timer.start if timer
|
|
135
|
+
Thread.current[:sqreen_hook_entered] = true
|
|
136
|
+
|
|
137
|
+
# TODO: make Call have #ball to throw by cb
|
|
138
|
+
# TODO: can Call be the ball? r = catch(Call.new, &c)
|
|
139
|
+
# TODO: is catch return value a Call? a #dispatch?
|
|
140
|
+
# TODO: make before/after/raised return a CallbackCollection << Array (or extend with module)
|
|
141
|
+
# TODO: add CallbackCollection#each_with_call(instance, args) { |call| ... } ?
|
|
142
|
+
# TODO: HookCall x CallbackCollection#each_with_call x Flow
|
|
143
|
+
# TODO: TimedHookCall TimedCallbackCall
|
|
144
|
+
# TODO: TimeBoundHookCall TimeBoundCallbackCall TimeBoundFlow?
|
|
145
|
+
|
|
146
|
+
Timer.new("#{hook.point}@before") do |t|
|
|
147
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks_before] << t
|
|
148
|
+
end.measure do |before_chrono|
|
|
149
|
+
hook.before.each do |c|
|
|
150
|
+
next if c.ignore && c.ignore.call
|
|
151
|
+
|
|
152
|
+
if timer && !c.mandatory
|
|
153
|
+
remaining = budget - timer.elapsed
|
|
154
|
+
unless remaining > 0
|
|
155
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:skipped_callbacks] << c && Thread.current[:sqreen_http_request][:time_budget_expended] = true
|
|
156
|
+
next
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
flow = catch(Ball.new) do |ball|
|
|
161
|
+
Timer.new(c.name) do |t|
|
|
162
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_callbacks] << t
|
|
163
|
+
end.measure do
|
|
164
|
+
before_chrono.ignore do
|
|
165
|
+
c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passed), ball)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
next unless c.flow && flow.is_a?(Flow)
|
|
171
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
|
172
|
+
hooked_call.args_pass = flow.args and hooked_call.args_passing = true if flow.args?
|
|
173
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
|
174
|
+
break if flow.break?
|
|
175
|
+
end unless hook.disabled?
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
raise hooked_call.raise if hooked_call.raising
|
|
179
|
+
return hooked_call.return if hooked_call.returning
|
|
180
|
+
ensure
|
|
181
|
+
Thread.current[:sqreen_hook_entered] = false
|
|
182
|
+
timer.stop if timer
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
begin
|
|
186
|
+
chrono.ignore do
|
|
187
|
+
if hook.point.super?
|
|
188
|
+
hooked_call.returned = super(*(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
|
|
189
|
+
else
|
|
190
|
+
hooked_call.returned = hook.point.apply(hooked_call.instance, 'sqreen_hook', *(hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed), &block)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
rescue ::Exception => e # rubocop:disable Lint/RescueException
|
|
194
|
+
timer.start if timer
|
|
195
|
+
Thread.current[:sqreen_hook_entered] = true
|
|
196
|
+
hooked_call.raised = e
|
|
197
|
+
|
|
198
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] Hook #{hook.point} disabled:#{hook.disabled?} exception:#{e}" }
|
|
199
|
+
raise if hook.raised.empty?
|
|
200
|
+
|
|
201
|
+
Timer.new("#{hook.point}@raised") do |t|
|
|
202
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks_raised] << t
|
|
203
|
+
end.measure do |raised_chrono|
|
|
204
|
+
hook.raised.each do |c|
|
|
205
|
+
next if c.ignore && c.ignore.call
|
|
206
|
+
|
|
207
|
+
if timer && !c.mandatory
|
|
208
|
+
remaining = budget - timer.elapsed
|
|
209
|
+
unless remaining > 0
|
|
210
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:skipped_callbacks] << c && Thread.current[:sqreen_http_request][:time_budget_expended] = true
|
|
211
|
+
next
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
flow = catch(Ball.new) do |ball|
|
|
216
|
+
Timer.new(c.name) do |t|
|
|
217
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_callbacks] << t
|
|
218
|
+
end.measure do
|
|
219
|
+
raised_chrono.ignore do
|
|
220
|
+
c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, hooked_call.raised), ball)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
next unless c.flow && flow.is_a?(Flow)
|
|
226
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
|
227
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
|
228
|
+
hooked_call.retrying = true if flow.retry?
|
|
229
|
+
break if flow.break?
|
|
230
|
+
end unless hook.disabled?
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
retry if hooked_call.retrying
|
|
234
|
+
raise hooked_call.raise if hooked_call.raising
|
|
235
|
+
return hooked_call.return if hooked_call.returning
|
|
236
|
+
raise
|
|
237
|
+
else
|
|
238
|
+
timer.start if timer
|
|
239
|
+
Thread.current[:sqreen_hook_entered] = true
|
|
240
|
+
|
|
241
|
+
Timer.new("#{hook.point}@after") do |t|
|
|
242
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks_after] << t
|
|
243
|
+
end.measure do |after_chrono|
|
|
244
|
+
hook.after.each do |c|
|
|
245
|
+
next if c.ignore && c.ignore.call
|
|
246
|
+
|
|
247
|
+
if timer && !c.mandatory
|
|
248
|
+
remaining = budget - timer.elapsed
|
|
249
|
+
unless remaining > 0
|
|
250
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:skipped_callbacks] << c && Thread.current[:sqreen_http_request][:time_budget_expended] = true
|
|
251
|
+
next
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
flow = catch(Ball.new) do |ball|
|
|
256
|
+
Timer.new(c.name) do |t|
|
|
257
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_callbacks] << t
|
|
258
|
+
end.measure do
|
|
259
|
+
after_chrono.ignore do
|
|
260
|
+
c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
next unless c.flow && flow.is_a?(Flow)
|
|
266
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
|
267
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
|
268
|
+
break if flow.break?
|
|
269
|
+
end unless hook.disabled?
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
raise hooked_call.raise if hooked_call.raising
|
|
273
|
+
return hooked_call.returning ? hooked_call.return : hooked_call.returned
|
|
274
|
+
ensure
|
|
275
|
+
# TODO: timer.start if someone has thrown?
|
|
276
|
+
|
|
277
|
+
Timer.new("#{hook.point}@ensured") do |t|
|
|
278
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_hooks_ensured] << t
|
|
279
|
+
end.measure do |ensured_chrono|
|
|
280
|
+
hook.ensured.each do |c|
|
|
281
|
+
next if c.ignore && c.ignore.call
|
|
282
|
+
|
|
283
|
+
if timer && !c.mandatory
|
|
284
|
+
remaining = budget - timer.elapsed
|
|
285
|
+
unless remaining > 0
|
|
286
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:skipped_callbacks] << c && Thread.current[:sqreen_http_request][:time_budget_expended] = true
|
|
287
|
+
next
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
flow = catch(Ball.new) do |ball|
|
|
292
|
+
Timer.new(c.name) do |t|
|
|
293
|
+
Thread.current[:sqreen_http_request] && Thread.current[:sqreen_http_request][:timed_callbacks] << t
|
|
294
|
+
end.measure do
|
|
295
|
+
ensured_chrono.ignore do
|
|
296
|
+
c.call(CallbackCall.new(c, remaining, hooked_call.instance, hooked_call.args_passing ? hooked_call.args_pass : hooked_call.args_passed, nil, hooked_call.returned), ball)
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
next unless c.flow && flow.is_a?(Flow)
|
|
302
|
+
hooked_call.raise = flow.raise and hooked_call.raising = true if flow.raise?
|
|
303
|
+
hooked_call.return = flow.return and hooked_call.returning = true if flow.return?
|
|
304
|
+
break if flow.break?
|
|
305
|
+
end unless hook.disabled?
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
Thread.current[:sqreen_hook_entered] = false
|
|
309
|
+
timer.stop if timer
|
|
310
|
+
end
|
|
311
|
+
end # chrono
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
@@ -1,12 +1,26 @@
|
|
|
1
|
+
# typed: false
|
|
2
|
+
|
|
1
3
|
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
|
2
4
|
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
|
3
5
|
|
|
4
6
|
require 'sqreen/dependency'
|
|
5
7
|
require 'sqreen/backport/original_name'
|
|
8
|
+
require 'sqreen/graft'
|
|
9
|
+
require 'sqreen/graft/hook_point_error'
|
|
6
10
|
|
|
7
11
|
module Sqreen
|
|
8
|
-
module
|
|
9
|
-
class
|
|
12
|
+
module Graft
|
|
13
|
+
class HookSpot < Module
|
|
14
|
+
def initialize(key)
|
|
15
|
+
@key = key
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
attr_reader :key
|
|
19
|
+
|
|
20
|
+
def inspect
|
|
21
|
+
"#<#{self.class.name}: #{@key.inspect}>"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
10
24
|
|
|
11
25
|
class HookPoint
|
|
12
26
|
def self.parse(hook_point)
|
|
@@ -22,8 +36,9 @@ module Sqreen
|
|
|
22
36
|
|
|
23
37
|
attr_reader :klass_name, :method_kind, :method_name
|
|
24
38
|
|
|
25
|
-
def initialize(hook_point)
|
|
26
|
-
@klass_name, @method_kind, @method_name = Sqreen::
|
|
39
|
+
def initialize(hook_point, strategy = :chain)
|
|
40
|
+
@klass_name, @method_kind, @method_name = Sqreen::Graft::HookPoint.parse(hook_point)
|
|
41
|
+
@strategy = strategy
|
|
27
42
|
end
|
|
28
43
|
|
|
29
44
|
def to_s
|
|
@@ -34,11 +49,12 @@ module Sqreen
|
|
|
34
49
|
return false unless Sqreen::Dependency.const_exist?(@klass_name)
|
|
35
50
|
|
|
36
51
|
if klass_method?
|
|
37
|
-
(klass.
|
|
52
|
+
(klass.singleton_class.public_instance_methods(false) + klass.singleton_class.protected_instance_methods(false) + klass.singleton_class.private_instance_methods(false)).include?(@method_name)
|
|
38
53
|
elsif instance_method?
|
|
39
|
-
(klass.
|
|
54
|
+
(klass.public_instance_methods(false) + klass.protected_instance_methods(false) + klass.private_instance_methods(false)).include?(@method_name)
|
|
40
55
|
else
|
|
41
|
-
|
|
56
|
+
Sqreen::Graft.logger.error { "[#{Process.pid}] #{self} unknown hook point kind" }
|
|
57
|
+
raise HookPointError, "#{self} unknown hook point kind"
|
|
42
58
|
end
|
|
43
59
|
end
|
|
44
60
|
|
|
@@ -56,7 +72,8 @@ module Sqreen
|
|
|
56
72
|
elsif instance_method?
|
|
57
73
|
klass.private_instance_methods.include?(@method_name)
|
|
58
74
|
else
|
|
59
|
-
|
|
75
|
+
Sqreen::Graft.logger.error { "[#{Process.pid}] #{self} unknown hook point kind" }
|
|
76
|
+
raise HookPointError, "#{self} unknown hook point kind"
|
|
60
77
|
end
|
|
61
78
|
end
|
|
62
79
|
|
|
@@ -66,7 +83,8 @@ module Sqreen
|
|
|
66
83
|
elsif instance_method?
|
|
67
84
|
klass.protected_instance_methods.include?(@method_name)
|
|
68
85
|
else
|
|
69
|
-
|
|
86
|
+
Sqreen::Graft.logger.error { "[#{Process.pid}] #{self} unknown hook point kind" }
|
|
87
|
+
raise HookPointError, "#{self} unknown hook point kind"
|
|
70
88
|
end
|
|
71
89
|
end
|
|
72
90
|
|
|
@@ -74,58 +92,159 @@ module Sqreen
|
|
|
74
92
|
@method_kind == :instance_method
|
|
75
93
|
end
|
|
76
94
|
|
|
77
|
-
def installed?(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
(klass.instance_methods + klass.protected_instance_methods + klass.private_instance_methods).include?(:"#{method_name}_with_#{suffix}")
|
|
82
|
-
else
|
|
83
|
-
raise HookPointError, 'unknown hook point kind'
|
|
95
|
+
def installed?(key)
|
|
96
|
+
case @strategy
|
|
97
|
+
when :chain then defined(key)
|
|
98
|
+
when :prepend then prepended?(key) && overridden?(key)
|
|
84
99
|
end
|
|
85
100
|
end
|
|
86
101
|
|
|
102
|
+
def super?
|
|
103
|
+
@strategy == :prepend
|
|
104
|
+
end
|
|
105
|
+
|
|
87
106
|
def apply(obj, suffix, *args, &block)
|
|
107
|
+
raise 'use super' if super?
|
|
108
|
+
|
|
88
109
|
obj.send("#{method_name}_without_#{suffix}", *args, &block)
|
|
89
110
|
end
|
|
90
111
|
|
|
91
|
-
def install(
|
|
92
|
-
if installed?(
|
|
93
|
-
Sqreen.
|
|
112
|
+
def install(key, &block)
|
|
113
|
+
if installed?(key)
|
|
114
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] #{self} already installed" }
|
|
115
|
+
return
|
|
94
116
|
end
|
|
95
117
|
unless exist?
|
|
96
|
-
Sqreen.
|
|
118
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] #{self} hook point not found" }
|
|
119
|
+
return
|
|
97
120
|
end
|
|
98
121
|
|
|
99
|
-
|
|
100
|
-
|
|
122
|
+
case @strategy
|
|
123
|
+
when :chain
|
|
124
|
+
define(key, &block)
|
|
125
|
+
chain(key)
|
|
126
|
+
when :prepend
|
|
127
|
+
prepend(key)
|
|
128
|
+
override(key, &block)
|
|
129
|
+
end
|
|
101
130
|
end
|
|
102
131
|
|
|
103
|
-
def uninstall(
|
|
104
|
-
|
|
105
|
-
|
|
132
|
+
def uninstall(key)
|
|
133
|
+
unless installed?(key)
|
|
134
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] #{self} not installed" }
|
|
135
|
+
return
|
|
136
|
+
end
|
|
137
|
+
unless exist?
|
|
138
|
+
Sqreen::Graft.logger.debug { "[#{Process.pid}] #{self} hook point not found" }
|
|
139
|
+
return
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
case @strategy
|
|
143
|
+
when :chain
|
|
144
|
+
disable(key)
|
|
145
|
+
remove(key)
|
|
146
|
+
when :prepend
|
|
147
|
+
unoverride(key) if overridden?(key)
|
|
148
|
+
end
|
|
106
149
|
end
|
|
107
150
|
|
|
108
|
-
def enable(
|
|
109
|
-
|
|
151
|
+
def enable(key)
|
|
152
|
+
case @strategy
|
|
153
|
+
when :chain
|
|
154
|
+
chain(key)
|
|
155
|
+
when :prepend
|
|
156
|
+
raise HookPointError, "enable called on prepend mode"
|
|
157
|
+
end
|
|
110
158
|
end
|
|
111
159
|
|
|
112
|
-
def disable(
|
|
113
|
-
|
|
160
|
+
def disable(key)
|
|
161
|
+
case @strategy
|
|
162
|
+
when :chain
|
|
163
|
+
unchain(key)
|
|
164
|
+
when :prepend
|
|
165
|
+
unoverride(key)
|
|
166
|
+
end
|
|
114
167
|
end
|
|
115
168
|
|
|
116
|
-
def disabled?(
|
|
117
|
-
|
|
169
|
+
def disabled?(key)
|
|
170
|
+
case @strategy
|
|
171
|
+
when :chain
|
|
172
|
+
!chained?(key)
|
|
173
|
+
when :prepend
|
|
174
|
+
!overridden?(key)
|
|
175
|
+
end
|
|
118
176
|
end
|
|
119
177
|
|
|
120
178
|
private
|
|
121
179
|
|
|
180
|
+
def prepend(key)
|
|
181
|
+
target = klass_method? ? klass.singleton_class : klass
|
|
182
|
+
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
|
183
|
+
mod ||= HookSpot.new(key)
|
|
184
|
+
target.instance_eval { prepend(mod) }
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def prepended?(key)
|
|
188
|
+
target = klass_method? ? klass.singleton_class : klass
|
|
189
|
+
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
|
190
|
+
|
|
191
|
+
mod != nil
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def overridden?(key)
|
|
195
|
+
target = klass_method? ? klass.singleton_class : klass
|
|
196
|
+
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
|
197
|
+
|
|
198
|
+
(mod.instance_methods(false) + mod.protected_instance_methods(false) + mod.private_instance_methods(false)).include?(method_name)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def override(key, &block)
|
|
202
|
+
hook_point = self
|
|
203
|
+
method_name = @method_name
|
|
204
|
+
|
|
205
|
+
target = klass_method? ? klass.singleton_class : klass
|
|
206
|
+
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
|
207
|
+
|
|
208
|
+
mod.instance_eval do
|
|
209
|
+
if hook_point.private_method?
|
|
210
|
+
private
|
|
211
|
+
elsif hook_point.protected_method?
|
|
212
|
+
protected
|
|
213
|
+
else
|
|
214
|
+
public
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
define_method(:"#{method_name}", &block)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def unoverride(key)
|
|
222
|
+
method_name = @method_name
|
|
223
|
+
|
|
224
|
+
target = klass_method? ? klass.singleton_class : klass
|
|
225
|
+
mod = target.ancestors.each { |e| break if e == target; break(e) if e.class == HookSpot && e.key == key }
|
|
226
|
+
|
|
227
|
+
mod.instance_eval { remove_method(method_name) }
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def defined(suffix)
|
|
231
|
+
if klass_method?
|
|
232
|
+
(klass.methods + klass.protected_methods + klass.private_methods).include?(:"#{method_name}_with_#{suffix}")
|
|
233
|
+
elsif instance_method?
|
|
234
|
+
(klass.instance_methods + klass.protected_instance_methods + klass.private_instance_methods).include?(:"#{method_name}_with_#{suffix}")
|
|
235
|
+
else
|
|
236
|
+
Sqreen::Graft.logger.error { "[#{Process.pid}] #{self} unknown hook point kind" }
|
|
237
|
+
raise HookPointError, "#{self} unknown hook point kind"
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
122
241
|
def define(suffix, &block)
|
|
123
242
|
hook_point = self
|
|
124
243
|
method_name = @method_name
|
|
125
244
|
|
|
126
245
|
if klass_method?
|
|
127
246
|
klass.singleton_class.instance_eval do
|
|
128
|
-
if hook_point.
|
|
247
|
+
if hook_point.private_method?
|
|
129
248
|
private
|
|
130
249
|
elsif hook_point.protected_method?
|
|
131
250
|
protected
|
|
@@ -137,7 +256,7 @@ module Sqreen
|
|
|
137
256
|
end
|
|
138
257
|
elsif instance_method?
|
|
139
258
|
klass.class_eval do
|
|
140
|
-
if hook_point.
|
|
259
|
+
if hook_point.private_method?
|
|
141
260
|
private
|
|
142
261
|
elsif hook_point.protected_method?
|
|
143
262
|
protected
|