sqreen 1.18.2-java → 1.19.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -0
  3. data/LICENSE +3 -0
  4. data/lib/sqreen.rb +2 -0
  5. data/lib/sqreen/actions.rb +13 -337
  6. data/lib/sqreen/actions/actions_index.rb +16 -0
  7. data/lib/sqreen/actions/base.rb +104 -0
  8. data/lib/sqreen/actions/block_ip.rb +34 -0
  9. data/lib/sqreen/actions/block_user.rb +46 -0
  10. data/lib/sqreen/actions/ip_range_indexed_action_class.rb +16 -0
  11. data/lib/sqreen/actions/ip_ranges_index.rb +57 -0
  12. data/lib/sqreen/actions/redirect_ip.rb +42 -0
  13. data/lib/sqreen/actions/redirect_user.rb +47 -0
  14. data/lib/sqreen/actions/repository.rb +43 -0
  15. data/lib/sqreen/actions/unknown_action_type.rb +20 -0
  16. data/lib/sqreen/actions/user_action_class.rb +16 -0
  17. data/lib/sqreen/actions/users_index.rb +35 -0
  18. data/lib/sqreen/agent.rb +6 -2
  19. data/lib/sqreen/attack_blocked.rb +19 -0
  20. data/lib/sqreen/backport.rb +2 -0
  21. data/lib/sqreen/backport/clock_gettime.rb +74 -0
  22. data/lib/sqreen/backport/original_name.rb +2 -0
  23. data/lib/sqreen/binding_accessor.rb +11 -102
  24. data/lib/sqreen/binding_accessor/path_elem.rb +10 -0
  25. data/lib/sqreen/binding_accessor/transforms.rb +114 -0
  26. data/lib/sqreen/call_countable.rb +2 -0
  27. data/lib/sqreen/capped_queue.rb +4 -0
  28. data/lib/sqreen/{callbacks.rb → cb.rb} +3 -53
  29. data/lib/sqreen/{callback_tree.rb → cb_tree.rb} +4 -2
  30. data/lib/sqreen/condition_evaluator.rb +24 -5
  31. data/lib/sqreen/conditionable.rb +2 -0
  32. data/lib/sqreen/configuration.rb +19 -0
  33. data/lib/sqreen/context.rb +2 -0
  34. data/lib/sqreen/default_cb.rb +22 -0
  35. data/lib/sqreen/deferred_logger.rb +65 -0
  36. data/lib/sqreen/deliveries.rb +12 -0
  37. data/lib/sqreen/deliveries/batch.rb +9 -1
  38. data/lib/sqreen/deliveries/simple.rb +7 -0
  39. data/lib/sqreen/dependency.rb +3 -1
  40. data/lib/sqreen/dependency/detector.rb +22 -14
  41. data/lib/sqreen/dependency/libsqreen.rb +32 -0
  42. data/lib/sqreen/dependency/new_relic.rb +2 -0
  43. data/lib/sqreen/dependency/rack.rb +10 -5
  44. data/lib/sqreen/dependency/rails.rb +8 -0
  45. data/lib/sqreen/dependency/sentry.rb +2 -0
  46. data/lib/sqreen/dependency/sinatra.rb +58 -14
  47. data/lib/sqreen/encoding_sanitizer.rb +2 -0
  48. data/lib/sqreen/error_handling_middleware.rb +32 -0
  49. data/lib/sqreen/event.rb +4 -0
  50. data/lib/sqreen/events/attack.rb +4 -0
  51. data/lib/sqreen/events/remote_exception.rb +2 -0
  52. data/lib/sqreen/events/request_record.rb +13 -56
  53. data/lib/sqreen/exception.rb +11 -40
  54. data/lib/sqreen/formatter_with_tid.rb +47 -0
  55. data/lib/sqreen/framework_cb.rb +30 -0
  56. data/lib/sqreen/frameworks.rb +9 -0
  57. data/lib/sqreen/frameworks/generic.rb +22 -2
  58. data/lib/sqreen/frameworks/rails.rb +3 -0
  59. data/lib/sqreen/frameworks/rails3.rb +2 -0
  60. data/lib/sqreen/frameworks/request_recorder.rb +5 -0
  61. data/lib/sqreen/frameworks/sinatra.rb +4 -0
  62. data/lib/sqreen/frameworks/sqreen_test.rb +4 -0
  63. data/lib/sqreen/graft.rb +12 -0
  64. data/lib/sqreen/graft/call.rb +150 -0
  65. data/lib/sqreen/{dependency → graft}/callback.rb +12 -4
  66. data/lib/sqreen/graft/hook.rb +316 -0
  67. data/lib/sqreen/{dependency → graft}/hook_point.rb +152 -33
  68. data/lib/sqreen/graft/hook_point_error.rb +10 -0
  69. data/lib/sqreen/invalid_signature_exception.rb +10 -0
  70. data/lib/sqreen/js.rb +11 -0
  71. data/lib/sqreen/js/call_context.rb +12 -0
  72. data/lib/sqreen/js/context_pool.rb +62 -0
  73. data/lib/sqreen/js/exec_js_runnable.rb +22 -0
  74. data/lib/sqreen/js/execjs_adapter.rb +8 -47
  75. data/lib/sqreen/js/executable_js.rb +14 -0
  76. data/lib/sqreen/js/js_service.rb +4 -22
  77. data/lib/sqreen/js/js_service_adapter.rb +20 -0
  78. data/lib/sqreen/js/mini_racer_adapter.rb +8 -180
  79. data/lib/sqreen/js/mini_racer_executable_js.rb +144 -0
  80. data/lib/sqreen/js/thread_local_exec_js_runnable.rb +49 -0
  81. data/lib/{sqreen-alt.rb → sqreen/legacy.rb} +5 -1
  82. data/lib/sqreen/{instrumentation.rb → legacy/instrumentation.rb} +44 -15
  83. data/lib/sqreen/log.rb +10 -188
  84. data/lib/sqreen/log/loggable.rb +28 -0
  85. data/lib/sqreen/logger.rb +85 -0
  86. data/lib/sqreen/metrics.rb +2 -0
  87. data/lib/sqreen/metrics/average.rb +2 -0
  88. data/lib/sqreen/metrics/base.rb +2 -0
  89. data/lib/sqreen/metrics/binning.rb +2 -0
  90. data/lib/sqreen/metrics/collect.rb +2 -0
  91. data/lib/sqreen/metrics/sum.rb +2 -0
  92. data/lib/sqreen/metrics_store.rb +5 -11
  93. data/lib/sqreen/metrics_store/already_registered_metric.rb +13 -0
  94. data/lib/sqreen/metrics_store/unknown_metric.rb +13 -0
  95. data/lib/sqreen/metrics_store/unregistered_metric.rb +13 -0
  96. data/lib/sqreen/middleware.rb +2 -34
  97. data/lib/sqreen/mono_time.rb +4 -0
  98. data/lib/sqreen/node.rb +46 -0
  99. data/lib/sqreen/not_implemented_yet.rb +10 -0
  100. data/lib/sqreen/null_logger.rb +26 -0
  101. data/lib/sqreen/payload_creator.rb +4 -19
  102. data/lib/sqreen/payload_creator/header_section.rb +30 -0
  103. data/lib/sqreen/performance_notifications.rb +2 -0
  104. data/lib/sqreen/performance_notifications/binned_metrics.rb +2 -0
  105. data/lib/sqreen/performance_notifications/log.rb +2 -0
  106. data/lib/sqreen/performance_notifications/log_performance.rb +2 -0
  107. data/lib/sqreen/performance_notifications/metrics.rb +2 -0
  108. data/lib/sqreen/performance_notifications/newrelic.rb +2 -0
  109. data/lib/sqreen/prefix.rb +35 -0
  110. data/lib/sqreen/rails_middleware.rb +16 -0
  111. data/lib/sqreen/remote_command.rb +3 -8
  112. data/lib/sqreen/remote_command/failure_output.rb +16 -0
  113. data/lib/sqreen/rules.rb +34 -2
  114. data/lib/sqreen/{rule_attributes.rb → rules/attrs.rb} +2 -0
  115. data/lib/sqreen/{rules_callbacks/sdk_auth_track.rb → rules/auth_track_cb.rb} +4 -2
  116. data/lib/sqreen/{rules_callbacks/binding_accessor_matcher.rb → rules/binding_accessor_matcher_cb.rb} +6 -8
  117. data/lib/sqreen/{rules_callbacks → rules}/binding_accessor_metrics.rb +3 -1
  118. data/lib/sqreen/{rules_callbacks/blacklist_ips.rb → rules/blacklist_ips_cb.rb} +5 -2
  119. data/lib/sqreen/{rules_callbacks → rules}/count_http_codes.rb +4 -2
  120. data/lib/sqreen/{rules_callbacks/crawler_user_agent_matches.rb → rules/crawler_user_agent_matches_cb.rb} +3 -1
  121. data/lib/sqreen/{rules_callbacks/crawler_user_agent_matches_metrics.rb → rules/crawler_user_agent_matches_metrics_cb.rb} +3 -1
  122. data/lib/sqreen/{rules_callbacks/custom_error.rb → rules/custom_error_cb.rb} +3 -1
  123. data/lib/sqreen/{rules_callbacks/devise_auth_track.rb → rules/devise_auth_track_cb.rb} +4 -2
  124. data/lib/sqreen/{rules_callbacks/devise_signup_track.rb → rules/devise_signup_track_cb.rb} +4 -2
  125. data/lib/sqreen/{rules_callbacks/execjs.rb → rules/execjs_cb.rb} +51 -50
  126. data/lib/sqreen/{rules_callbacks/headers_insert.rb → rules/headers_insert_cb.rb} +8 -1
  127. data/lib/sqreen/{rules_callbacks → rules}/matcher_rule.rb +4 -2
  128. data/lib/sqreen/{rules_callbacks/not_found.rb → rules/not_found_cb.rb} +7 -2
  129. data/lib/sqreen/{rules_callbacks/rails_parameters.rb → rules/rails_parameters_cb.rb} +3 -1
  130. data/lib/sqreen/{rules_callbacks → rules}/record_request_context.rb +3 -1
  131. data/lib/sqreen/{rules_callbacks/regexp_rule.rb → rules/regexp_rule_cb.rb} +3 -1
  132. data/lib/sqreen/{rule_callback.rb → rules/rule_cb.rb} +4 -2
  133. data/lib/sqreen/{rules_callbacks → rules}/run_req_start_actions.rb +7 -3
  134. data/lib/sqreen/{rules_callbacks → rules}/run_user_actions.rb +4 -2
  135. data/lib/sqreen/{rules_callbacks/shell_env.rb → rules/shell_env_cb.rb} +3 -1
  136. data/lib/sqreen/{rules_callbacks/sdk_signup_track.rb → rules/signup_track_cb.rb} +4 -2
  137. data/lib/sqreen/rules/update_request_context.rb +22 -0
  138. data/lib/sqreen/{rules_callbacks/url_matches.rb → rules/url_matches_cb.rb} +3 -1
  139. data/lib/sqreen/{rules_callbacks/user_agent_matches.rb → rules/user_agent_matches_cb.rb} +3 -1
  140. data/lib/sqreen/{rules_callbacks/waf.rb → rules/waf_cb.rb} +41 -21
  141. data/lib/sqreen/{rules_callbacks/reflected_xss.rb → rules/xss_cb.rb} +12 -7
  142. data/lib/sqreen/run_when_called_cb.rb +23 -0
  143. data/lib/sqreen/runner.rb +25 -7
  144. data/lib/sqreen/runtime_infos.rb +4 -9
  145. data/lib/sqreen/safe_json.rb +2 -0
  146. data/lib/sqreen/sdk.rb +4 -0
  147. data/lib/sqreen/sensitive_data_redactor.rb +113 -0
  148. data/lib/sqreen/serializer.rb +2 -0
  149. data/lib/sqreen/session.rb +2 -0
  150. data/lib/sqreen/shared_storage.rb +2 -0
  151. data/lib/sqreen/shared_storage23.rb +2 -0
  152. data/lib/sqreen/shrink_wrap.rb +16 -0
  153. data/lib/sqreen/signature_verifier.rb +22 -0
  154. data/lib/sqreen/sinatra_middleware.rb +16 -0
  155. data/lib/sqreen/{rules_signature.rb → sqreen_signed_verifier.rb} +7 -17
  156. data/lib/sqreen/token_invalid_exception.rb +10 -0
  157. data/lib/sqreen/token_not_found_exception.rb +11 -0
  158. data/lib/sqreen/trie.rb +5 -64
  159. data/lib/sqreen/unauthorized.rb +10 -0
  160. data/lib/sqreen/util.rb +7 -0
  161. data/lib/sqreen/util/capped_array.rb +35 -0
  162. data/lib/sqreen/util/capped_hash.rb +41 -0
  163. data/lib/sqreen/util/capped_string.rb +26 -0
  164. data/lib/sqreen/util/capper.rb +67 -0
  165. data/lib/sqreen/version.rb +3 -1
  166. data/lib/sqreen/waf_error.rb +20 -0
  167. data/lib/sqreen/weave.rb +12 -0
  168. data/lib/sqreen/weave/hardcoded.rb +19 -0
  169. data/lib/sqreen/weave/instrumentor.rb +48 -0
  170. data/lib/sqreen/weave/legacy.rb +12 -0
  171. data/lib/sqreen/weave/legacy/instrumentation.rb +406 -0
  172. data/lib/sqreen/web_server.rb +2 -0
  173. data/lib/sqreen/web_server/generic.rb +2 -0
  174. data/lib/sqreen/web_server/passenger.rb +2 -0
  175. data/lib/sqreen/web_server/puma.rb +2 -0
  176. data/lib/sqreen/web_server/rainbows.rb +2 -0
  177. data/lib/sqreen/web_server/thin.rb +2 -0
  178. data/lib/sqreen/web_server/unicorn.rb +2 -0
  179. data/lib/sqreen/web_server/webrick.rb +2 -0
  180. data/lib/sqreen/worker.rb +2 -0
  181. metadata +105 -39
  182. data/lib/sqreen/dependency/hook.rb +0 -102
  183. data/lib/sqreen/rules_callbacks.rb +0 -35
  184. data/lib/sqreen/rules_callbacks/inspect_rule.rb +0 -25
@@ -1,3 +1,4 @@
1
+ # typed: ignore
1
2
  # frozen_string_literal: true
2
3
 
3
4
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
@@ -5,6 +6,8 @@
5
6
 
6
7
  require 'sqreen/frameworks/generic'
7
8
  require 'sqreen/middleware'
9
+ require 'sqreen/error_handling_middleware'
10
+ require 'sqreen/rails_middleware'
8
11
 
9
12
  module Sqreen
10
13
  module Frameworks
@@ -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,6 +1,11 @@
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
 
6
+ # TODO: Sqreen::Framework::RequestRecorder misnamed/misplaced?
7
+ # TODO: deps?
8
+
4
9
  require 'set'
5
10
  require 'sqreen/shared_storage'
6
11
  require 'sqreen/events/request_record'
@@ -1,8 +1,12 @@
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
 
4
6
  require 'sqreen/frameworks/generic'
5
7
  require 'sqreen/middleware'
8
+ require 'sqreen/error_handling_middleware'
9
+ require 'sqreen/sinatra_middleware'
6
10
 
7
11
  module Sqreen
8
12
  module Frameworks
@@ -1,6 +1,10 @@
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
 
6
+ # TODO: drop
7
+
4
8
  require 'sqreen/frameworks/generic'
5
9
 
6
10
  module Sqreen
@@ -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