sqreen 1.18.5 → 1.19.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/lib/sqreen/actions.rb +2 -0
  4. data/lib/sqreen/actions/actions_index.rb +16 -0
  5. data/lib/sqreen/actions/base.rb +4 -10
  6. data/lib/sqreen/actions/block_ip.rb +2 -0
  7. data/lib/sqreen/actions/block_user.rb +2 -0
  8. data/lib/sqreen/actions/ip_range_indexed_action_class.rb +4 -24
  9. data/lib/sqreen/actions/ip_ranges_index.rb +32 -11
  10. data/lib/sqreen/actions/redirect_ip.rb +2 -0
  11. data/lib/sqreen/actions/redirect_user.rb +2 -0
  12. data/lib/sqreen/actions/repository.rb +27 -8
  13. data/lib/sqreen/actions/unknown_action_type.rb +4 -0
  14. data/lib/sqreen/actions/user_action_class.rb +5 -30
  15. data/lib/sqreen/actions/users_index.rb +35 -0
  16. data/lib/sqreen/agent.rb +2 -1
  17. data/lib/sqreen/attack_blocked.rb +2 -0
  18. data/lib/sqreen/backport.rb +2 -0
  19. data/lib/sqreen/backport/clock_gettime.rb +74 -0
  20. data/lib/sqreen/backport/original_name.rb +2 -0
  21. data/lib/sqreen/binding_accessor.rb +2 -0
  22. data/lib/sqreen/binding_accessor/path_elem.rb +2 -0
  23. data/lib/sqreen/binding_accessor/transforms.rb +8 -1
  24. data/lib/sqreen/call_countable.rb +2 -0
  25. data/lib/sqreen/capped_queue.rb +2 -0
  26. data/lib/sqreen/cb.rb +2 -0
  27. data/lib/sqreen/cb_tree.rb +2 -0
  28. data/lib/sqreen/condition_evaluator.rb +2 -0
  29. data/lib/sqreen/conditionable.rb +2 -0
  30. data/lib/sqreen/configuration.rb +14 -0
  31. data/lib/sqreen/context.rb +2 -0
  32. data/lib/sqreen/default_cb.rb +2 -0
  33. data/lib/sqreen/deferred_logger.rb +2 -0
  34. data/lib/sqreen/deliveries.rb +2 -0
  35. data/lib/sqreen/deliveries/batch.rb +2 -0
  36. data/lib/sqreen/deliveries/simple.rb +2 -0
  37. data/lib/sqreen/dependency.rb +3 -1
  38. data/lib/sqreen/dependency/detector.rb +22 -14
  39. data/lib/sqreen/dependency/libsqreen.rb +4 -0
  40. data/lib/sqreen/dependency/new_relic.rb +2 -0
  41. data/lib/sqreen/dependency/rack.rb +10 -5
  42. data/lib/sqreen/dependency/rails.rb +4 -0
  43. data/lib/sqreen/dependency/sentry.rb +2 -0
  44. data/lib/sqreen/dependency/sinatra.rb +12 -1
  45. data/lib/sqreen/encoding_sanitizer.rb +2 -0
  46. data/lib/sqreen/error_handling_middleware.rb +2 -0
  47. data/lib/sqreen/event.rb +2 -0
  48. data/lib/sqreen/events/attack.rb +2 -0
  49. data/lib/sqreen/events/remote_exception.rb +2 -0
  50. data/lib/sqreen/events/request_record.rb +2 -0
  51. data/lib/sqreen/exception.rb +2 -0
  52. data/lib/sqreen/formatter_with_tid.rb +2 -0
  53. data/lib/sqreen/framework_cb.rb +2 -0
  54. data/lib/sqreen/frameworks.rb +2 -0
  55. data/lib/sqreen/frameworks/generic.rb +2 -0
  56. data/lib/sqreen/frameworks/rails.rb +1 -0
  57. data/lib/sqreen/frameworks/rails3.rb +2 -0
  58. data/lib/sqreen/frameworks/request_recorder.rb +2 -0
  59. data/lib/sqreen/frameworks/sinatra.rb +2 -0
  60. data/lib/sqreen/frameworks/sqreen_test.rb +2 -0
  61. data/lib/sqreen/graft.rb +12 -0
  62. data/lib/sqreen/graft/call.rb +150 -0
  63. data/lib/sqreen/{dependency → graft}/callback.rb +12 -4
  64. data/lib/sqreen/graft/hook.rb +316 -0
  65. data/lib/sqreen/{dependency → graft}/hook_point.rb +152 -33
  66. data/lib/sqreen/graft/hook_point_error.rb +10 -0
  67. data/lib/sqreen/invalid_signature_exception.rb +2 -0
  68. data/lib/sqreen/js.rb +2 -0
  69. data/lib/sqreen/js/call_context.rb +2 -0
  70. data/lib/sqreen/js/context_pool.rb +2 -0
  71. data/lib/sqreen/js/exec_js_runnable.rb +2 -0
  72. data/lib/sqreen/js/execjs_adapter.rb +2 -0
  73. data/lib/sqreen/js/executable_js.rb +2 -0
  74. data/lib/sqreen/js/js_service.rb +2 -0
  75. data/lib/sqreen/js/js_service_adapter.rb +2 -0
  76. data/lib/sqreen/js/mini_racer_adapter.rb +2 -0
  77. data/lib/sqreen/js/mini_racer_executable_js.rb +2 -0
  78. data/lib/sqreen/js/thread_local_exec_js_runnable.rb +2 -0
  79. data/lib/sqreen/legacy.rb +8 -0
  80. data/lib/sqreen/{instrumentation.rb → legacy/instrumentation.rb} +31 -2
  81. data/lib/sqreen/log.rb +2 -0
  82. data/lib/sqreen/log/loggable.rb +28 -0
  83. data/lib/sqreen/logger.rb +2 -0
  84. data/lib/sqreen/metrics.rb +2 -0
  85. data/lib/sqreen/metrics/average.rb +2 -0
  86. data/lib/sqreen/metrics/base.rb +2 -0
  87. data/lib/sqreen/metrics/binning.rb +2 -0
  88. data/lib/sqreen/metrics/collect.rb +2 -0
  89. data/lib/sqreen/metrics/sum.rb +2 -0
  90. data/lib/sqreen/metrics_store.rb +2 -0
  91. data/lib/sqreen/metrics_store/already_registered_metric.rb +2 -0
  92. data/lib/sqreen/metrics_store/unknown_metric.rb +2 -0
  93. data/lib/sqreen/metrics_store/unregistered_metric.rb +2 -0
  94. data/lib/sqreen/middleware.rb +2 -0
  95. data/lib/sqreen/mono_time.rb +2 -0
  96. data/lib/sqreen/node.rb +2 -0
  97. data/lib/sqreen/not_implemented_yet.rb +2 -0
  98. data/lib/sqreen/null_logger.rb +2 -0
  99. data/lib/sqreen/payload_creator.rb +2 -0
  100. data/lib/sqreen/payload_creator/header_section.rb +2 -0
  101. data/lib/sqreen/performance_notifications.rb +2 -0
  102. data/lib/sqreen/performance_notifications/binned_metrics.rb +2 -0
  103. data/lib/sqreen/performance_notifications/log.rb +2 -0
  104. data/lib/sqreen/performance_notifications/log_performance.rb +2 -0
  105. data/lib/sqreen/performance_notifications/metrics.rb +2 -0
  106. data/lib/sqreen/performance_notifications/newrelic.rb +2 -0
  107. data/lib/sqreen/prefix.rb +2 -0
  108. data/lib/sqreen/rails_middleware.rb +2 -0
  109. data/lib/sqreen/remote_command.rb +2 -0
  110. data/lib/sqreen/remote_command/failure_output.rb +5 -0
  111. data/lib/sqreen/rules.rb +2 -0
  112. data/lib/sqreen/rules/attrs.rb +2 -0
  113. data/lib/sqreen/rules/auth_track_cb.rb +2 -0
  114. data/lib/sqreen/rules/binding_accessor_matcher_cb.rb +2 -0
  115. data/lib/sqreen/rules/binding_accessor_metrics.rb +2 -0
  116. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -0
  117. data/lib/sqreen/rules/count_http_codes.rb +2 -0
  118. data/lib/sqreen/rules/crawler_user_agent_matches_cb.rb +2 -0
  119. data/lib/sqreen/rules/crawler_user_agent_matches_metrics_cb.rb +2 -0
  120. data/lib/sqreen/rules/custom_error_cb.rb +2 -0
  121. data/lib/sqreen/rules/devise_auth_track_cb.rb +2 -0
  122. data/lib/sqreen/rules/devise_signup_track_cb.rb +2 -0
  123. data/lib/sqreen/rules/execjs_cb.rb +2 -0
  124. data/lib/sqreen/rules/headers_insert_cb.rb +7 -0
  125. data/lib/sqreen/rules/matcher_rule.rb +2 -0
  126. data/lib/sqreen/rules/not_found_cb.rb +7 -0
  127. data/lib/sqreen/rules/rails_parameters_cb.rb +2 -0
  128. data/lib/sqreen/rules/record_request_context.rb +2 -0
  129. data/lib/sqreen/rules/regexp_rule_cb.rb +2 -0
  130. data/lib/sqreen/rules/rule_cb.rb +2 -0
  131. data/lib/sqreen/rules/run_req_start_actions.rb +3 -1
  132. data/lib/sqreen/rules/run_user_actions.rb +3 -1
  133. data/lib/sqreen/rules/shell_env_cb.rb +2 -0
  134. data/lib/sqreen/rules/signup_track_cb.rb +2 -0
  135. data/lib/sqreen/rules/update_request_context.rb +2 -0
  136. data/lib/sqreen/rules/url_matches_cb.rb +2 -0
  137. data/lib/sqreen/rules/user_agent_matches_cb.rb +2 -0
  138. data/lib/sqreen/rules/waf_cb.rb +28 -5
  139. data/lib/sqreen/rules/xss_cb.rb +2 -0
  140. data/lib/sqreen/run_when_called_cb.rb +2 -0
  141. data/lib/sqreen/runner.rb +25 -7
  142. data/lib/sqreen/runtime_infos.rb +2 -0
  143. data/lib/sqreen/safe_json.rb +2 -0
  144. data/lib/sqreen/sdk.rb +4 -0
  145. data/lib/sqreen/sensitive_data_redactor.rb +2 -0
  146. data/lib/sqreen/serializer.rb +2 -0
  147. data/lib/sqreen/session.rb +2 -0
  148. data/lib/sqreen/shared_storage.rb +2 -0
  149. data/lib/sqreen/shared_storage23.rb +2 -0
  150. data/lib/sqreen/shrink_wrap.rb +16 -0
  151. data/lib/sqreen/signature_verifier.rb +2 -0
  152. data/lib/sqreen/sinatra_middleware.rb +2 -0
  153. data/lib/sqreen/sqreen_signed_verifier.rb +2 -0
  154. data/lib/sqreen/token_invalid_exception.rb +2 -0
  155. data/lib/sqreen/token_not_found_exception.rb +2 -0
  156. data/lib/sqreen/trie.rb +2 -0
  157. data/lib/sqreen/unauthorized.rb +2 -0
  158. data/lib/sqreen/util.rb +5 -0
  159. data/lib/sqreen/util/capped_array.rb +2 -0
  160. data/lib/sqreen/util/capped_hash.rb +2 -0
  161. data/lib/sqreen/util/capped_string.rb +2 -0
  162. data/lib/sqreen/util/capper.rb +2 -0
  163. data/lib/sqreen/version.rb +3 -1
  164. data/lib/sqreen/waf_error.rb +2 -0
  165. data/lib/sqreen/weave.rb +12 -0
  166. data/lib/sqreen/weave/hardcoded.rb +19 -0
  167. data/lib/sqreen/weave/instrumentor.rb +48 -0
  168. data/lib/sqreen/weave/legacy.rb +12 -0
  169. data/lib/sqreen/weave/legacy/instrumentation.rb +406 -0
  170. data/lib/sqreen/web_server.rb +2 -0
  171. data/lib/sqreen/web_server/generic.rb +2 -0
  172. data/lib/sqreen/web_server/passenger.rb +2 -0
  173. data/lib/sqreen/web_server/puma.rb +2 -0
  174. data/lib/sqreen/web_server/rainbows.rb +2 -0
  175. data/lib/sqreen/web_server/thin.rb +2 -0
  176. data/lib/sqreen/web_server/unicorn.rb +2 -0
  177. data/lib/sqreen/web_server/webrick.rb +2 -0
  178. data/lib/sqreen/worker.rb +2 -0
  179. metadata +28 -9
  180. data/lib/sqreen/dependency/hook.rb +0 -102
@@ -1,3 +1,5 @@
1
+ # typed: ignore
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
 
@@ -1,3 +1,5 @@
1
+ # typed: ignore
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
 
@@ -1,3 +1,4 @@
1
+ # typed: ignore
1
2
  # frozen_string_literal: true
2
3
 
3
4
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
@@ -1,3 +1,5 @@
1
+ # typed: ignore
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
 
@@ -1,3 +1,5 @@
1
+ # typed: ignore
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
 
@@ -1,3 +1,5 @@
1
+ # typed: ignore
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
 
@@ -1,3 +1,5 @@
1
+ # typed: true
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
 
@@ -0,0 +1,12 @@
1
+ # typed: strong
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/log/loggable'
7
+
8
+ module Sqreen
9
+ module Graft
10
+ include Sqreen::Log::Loggable
11
+ end
12
+ end
@@ -0,0 +1,150 @@
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/backport/clock_gettime'
7
+ require 'sqreen/graft'
8
+
9
+ module Sqreen
10
+ module Graft
11
+ CallbackCall = Struct.new(:callback, :remaining, :instance, :args, :raised, :returned)
12
+ HookedCall = Struct.new(:instance, :args_passed, :args_pass, :raised, :returned, :return, :returning, :retrying, :args_passing, :raising, :raise)
13
+
14
+ class Ball
15
+ def return(value)
16
+ Flow.return(value)
17
+ end
18
+
19
+ def args(value)
20
+ Flow.args(value)
21
+ end
22
+
23
+ def retry
24
+ Flow.retry
25
+ end
26
+
27
+ def raise(value)
28
+ Flow.raise(value)
29
+ end
30
+ end
31
+
32
+ class Flow
33
+ class << self
34
+ def return(value)
35
+ new(:return, value)
36
+ end
37
+
38
+ def args(value)
39
+ new(:args, value)
40
+ end
41
+
42
+ def retry
43
+ new(:retry)
44
+ end
45
+
46
+ def raise(value)
47
+ new(:raise, value)
48
+ end
49
+ end
50
+
51
+ def initialize(action, value, brk = false)
52
+ @action = action
53
+ @value = value
54
+ @break = brk
55
+ end
56
+
57
+ def return?
58
+ @action == :return
59
+ end
60
+
61
+ def return
62
+ @value if return?
63
+ end
64
+
65
+ def raise?
66
+ @action == :raise
67
+ end
68
+
69
+ def raise
70
+ @value if raise?
71
+ end
72
+
73
+ def args?
74
+ @action == :args
75
+ end
76
+
77
+ def args
78
+ @value if args?
79
+ end
80
+
81
+ def retry?
82
+ @action == :retry
83
+ end
84
+
85
+ def break!
86
+ @break = true
87
+
88
+ self
89
+ end
90
+
91
+ def break?
92
+ @break ? true : false
93
+ end
94
+ end
95
+
96
+ class Timer
97
+ def self.read
98
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
99
+ end
100
+
101
+ attr_reader :tag
102
+
103
+ def initialize(tag, &block)
104
+ @tag = tag
105
+ @blips = []
106
+ @block = block
107
+ end
108
+
109
+ def duration
110
+ @blips.each_with_index.reduce(0) { |a, (e, i)| i.even? ? a - e : a + e }
111
+ end
112
+
113
+ def elapsed
114
+ @blips.each_with_index.reduce(0) { |a, (e, i)| i.even? ? a - e : a + e } + Timer.read
115
+ end
116
+
117
+ def ignore
118
+ @blips << Timer.read
119
+ yield(self)
120
+ ensure
121
+ @blips << Timer.read
122
+ end
123
+
124
+ def measure
125
+ @blips << Timer.read
126
+ yield(self)
127
+ ensure
128
+ @blips << Timer.read
129
+ @block.call(self) if @block
130
+ Sqreen::Graft.logger.debug { "#{@tag}: time=%.03fus" % (duration * 1_000_000) }
131
+ end
132
+
133
+ def start
134
+ @blips << Timer.read
135
+ end
136
+
137
+ def stop
138
+ @blips << Timer.read
139
+ end
140
+
141
+ def size
142
+ @blips.size
143
+ end
144
+
145
+ def to_s
146
+ "#{@tag}: time=%.03fus" % (duration * 1_000_000)
147
+ end
148
+ end
149
+ end
150
+ end
@@ -1,19 +1,27 @@
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
 
6
+ require 'sqreen/graft'
7
+
4
8
  module Sqreen
5
- module Dependency
9
+ module Graft
6
10
  class Callback
7
- attr_reader :name
11
+ attr_reader :name, :rank, :mandatory, :flow, :ignore
8
12
 
9
- def initialize(name = nil, &block)
13
+ def initialize(name = nil, opts = {}, &block)
10
14
  @name = name
15
+ @rank = opts[:rank] || 0
16
+ @mandatory = opts[:mandatory] || false
17
+ @flow = opts[:flow] || false
18
+ @ignore = opts[:ignore] || false
11
19
  @block = block
12
20
  @disabled = false
13
21
  end
14
22
 
15
23
  def call(*args, &block)
16
- Sqreen.log.debug "[#{Process.pid}] Callback #{@name} disabled:#{disabled?}"
24
+ Sqreen::Graft.logger.debug { "[#{Process.pid}] Callback #{@name} disabled:#{disabled?}" }
17
25
  return if @disabled
18
26
  @block.call(*args, &block)
19
27
  end
@@ -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