sqreen-alt 1.11.0 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sqreen.rb +0 -1
  3. data/lib/sqreen/callback_tree.rb +38 -20
  4. data/lib/sqreen/callbacks.rb +6 -4
  5. data/lib/sqreen/conditionable.rb +3 -3
  6. data/lib/sqreen/frameworks/generic.rb +38 -18
  7. data/lib/sqreen/frameworks/request_recorder.rb +0 -2
  8. data/lib/sqreen/instrumentation.rb +217 -160
  9. data/lib/sqreen/performance_notifications.rb +10 -36
  10. data/lib/sqreen/performance_notifications/log.rb +1 -2
  11. data/lib/sqreen/performance_notifications/log_performance.rb +1 -2
  12. data/lib/sqreen/performance_notifications/metrics.rb +1 -2
  13. data/lib/sqreen/performance_notifications/newrelic.rb +1 -2
  14. data/lib/sqreen/remote_command.rb +7 -7
  15. data/lib/sqreen/rule_callback.rb +4 -0
  16. data/lib/sqreen/rules.rb +2 -2
  17. data/lib/sqreen/rules_callbacks/binding_accessor_matcher.rb +7 -1
  18. data/lib/sqreen/rules_callbacks/binding_accessor_metrics.rb +3 -3
  19. data/lib/sqreen/rules_callbacks/blacklist_ips.rb +1 -1
  20. data/lib/sqreen/rules_callbacks/count_http_codes.rb +7 -6
  21. data/lib/sqreen/rules_callbacks/crawler_user_agent_matches.rb +1 -1
  22. data/lib/sqreen/rules_callbacks/crawler_user_agent_matches_metrics.rb +1 -1
  23. data/lib/sqreen/rules_callbacks/custom_error.rb +2 -5
  24. data/lib/sqreen/rules_callbacks/execjs.rb +76 -37
  25. data/lib/sqreen/rules_callbacks/headers_insert.rb +1 -1
  26. data/lib/sqreen/rules_callbacks/inspect_rule.rb +3 -3
  27. data/lib/sqreen/rules_callbacks/matcher_rule.rb +18 -17
  28. data/lib/sqreen/rules_callbacks/rails_parameters.rb +1 -1
  29. data/lib/sqreen/rules_callbacks/record_request_context.rb +9 -8
  30. data/lib/sqreen/rules_callbacks/reflected_xss.rb +40 -34
  31. data/lib/sqreen/rules_callbacks/regexp_rule.rb +13 -4
  32. data/lib/sqreen/rules_callbacks/shell_env.rb +2 -2
  33. data/lib/sqreen/rules_callbacks/url_matches.rb +1 -1
  34. data/lib/sqreen/rules_callbacks/user_agent_matches.rb +1 -1
  35. data/lib/sqreen/session.rb +1 -1
  36. data/lib/sqreen/shared_storage.rb +16 -12
  37. data/lib/sqreen/{stats.rb → shared_storage23.rb} +3 -11
  38. data/lib/sqreen/version.rb +1 -1
  39. metadata +4 -4
@@ -15,22 +15,13 @@ module Sqreen
15
15
  #
16
16
  module PerformanceNotifications
17
17
  @subscriptions_all = {}
18
- @subscriptions_regexp = {}
19
- @subscriptions_val = Hash.new { |h, k| h[k] = [] }
20
18
  @subscription_id = 0
21
19
  class << self
22
20
  # Subsribe to receive notificiations about an event
23
21
  # returns a subscription indentitifcation
24
- def subscribe(pattern = nil, &block)
22
+ def subscribe(&block)
25
23
  id = (@subscription_id += 1)
26
- case pattern
27
- when NilClass
28
- @subscriptions_all[id] = block
29
- when Regexp
30
- @subscriptions_regexp[id] = [pattern, block]
31
- else
32
- @subscriptions_val[pattern].push([id, block])
33
- end
24
+ @subscriptions_all[id] = block
34
25
  id
35
26
  end
36
27
 
@@ -44,22 +35,20 @@ module Sqreen
44
35
  end
45
36
  end
46
37
 
47
- # Is there a subscriber for this key
48
- def listen_for?(key)
49
- return true unless @subscriptions_all.empty?
50
- return true if @subscriptions_val.key?(key)
51
- @subscriptions_regexp.values.any? { |r| r.first.match(key) }
38
+ # Is there a subscriber
39
+ def listen_for?
40
+ !@subscriptions_all.empty?
52
41
  end
53
42
 
54
43
  # Instrument a call identified by key
55
44
  def instrument(key, meta = {}, &block)
56
- return yield unless listen_for?(key)
45
+ return yield unless listen_for?
57
46
  _instrument(key, meta, &block)
58
47
  end
59
48
 
60
49
  def notify(key, start, stop, meta = {})
61
- return unless listen_for?(key)
62
- notifiers_for(key).each do |callable|
50
+ return unless listen_for?
51
+ notifiers.each do |callable|
63
52
  callable.call(key, start, stop, meta)
64
53
  end
65
54
  end
@@ -67,33 +56,18 @@ module Sqreen
67
56
  # Unsubscrube for a given subscription
68
57
  def unsubscribe(subscription)
69
58
  return unless @subscriptions_all.delete(subscription).nil?
70
- return unless @subscriptions_regexp.delete(subscription).nil?
71
- @subscriptions_val.delete_if do |_, v|
72
- v.delete_if { |r| r.first == subscription }
73
- v.empty?
74
- end
75
59
  end
76
60
 
77
61
  # Unsubscribe from everything
78
62
  # not threadsafe
79
63
  def unsubscribe_all!
80
64
  @subscriptions_all.clear
81
- @subscriptions_regexp.clear
82
- @subscriptions_val.clear
83
65
  end
84
66
 
85
67
  private
86
68
 
87
- def notifiers_for(key)
88
- reg = @subscriptions_regexp.values.map do |r|
89
- r.first.match(key) && r.last
90
- end
91
- reg.compact!
92
- str = []
93
- if @subscriptions_val.key?(key)
94
- str = @subscriptions_val[key].map(&:last)
95
- end
96
- @subscriptions_all.values + str + reg
69
+ def notifiers
70
+ @subscriptions_all.values
97
71
  end
98
72
 
99
73
  if SQREEN_MONO_TIME
@@ -21,8 +21,7 @@ module Sqreen
21
21
  def enable(facility = nil)
22
22
  return unless @subid.nil?
23
23
  @facility = facility
24
- @subid = Sqreen::PerformanceNotifications.subscribe(nil,
25
- &method(:log))
24
+ @subid = Sqreen::PerformanceNotifications.subscribe(&method(:log))
26
25
  end
27
26
 
28
27
  def disable
@@ -55,8 +55,7 @@ module Sqreen
55
55
  def enable(facility = nil)
56
56
  return unless @subid.nil?
57
57
  @facility = facility
58
- @subid = Sqreen::PerformanceNotifications.subscribe(nil,
59
- &method(:log))
58
+ @subid = Sqreen::PerformanceNotifications.subscribe(&method(:log))
60
59
  end
61
60
 
62
61
  def disable
@@ -21,8 +21,7 @@ module Sqreen
21
21
  metrics_engine.create_metric('name' => EVENT_CAT,
22
22
  'period' => period,
23
23
  'kind' => 'Average')
24
- @subid = Sqreen::PerformanceNotifications.subscribe(nil,
25
- &method(:log))
24
+ @subid = Sqreen::PerformanceNotifications.subscribe(&method(:log))
26
25
  end
27
26
 
28
27
  def disable
@@ -76,8 +76,7 @@ module Sqreen
76
76
  return unless level > 0
77
77
  @level = level
78
78
  Sqreen.log.debug('Enabling New Relic reporting')
79
- @subid = Sqreen::PerformanceNotifications.subscribe(nil,
80
- &method(:log))
79
+ @subid = Sqreen::PerformanceNotifications.subscribe(&method(:log))
81
80
  end
82
81
 
83
82
  def disable
@@ -30,7 +30,7 @@ module Sqreen
30
30
  def process(runner, context_infos = {})
31
31
  failing = validate_command(runner)
32
32
  return failing if failing
33
- Sqreen.log.debug format('processing command %s', @name)
33
+ Sqreen.log.debug { format('processing command %s', @name) }
34
34
  begin
35
35
  output = runner.send(KNOWN_COMMANDS[@name], *@params, context_infos)
36
36
  rescue => e
@@ -46,14 +46,14 @@ module Sqreen
46
46
  return res_list unless commands
47
47
 
48
48
  unless commands.is_a? Array
49
- Sqreen.log.debug format('Wrong commands type %s', commands.class)
50
- Sqreen.log.debug commands.inspect
49
+ Sqreen.log.debug { format('Wrong commands type %s', commands.class) }
50
+ Sqreen.log.debug { commands.inspect }
51
51
  return res_list
52
52
  end
53
53
  commands.each do |cmd_json|
54
- Sqreen.log.debug cmd_json
54
+ Sqreen.log.debug { cmd_json }
55
55
  cmd = RemoteCommand.new(cmd_json)
56
- Sqreen.log.debug cmd.inspect
56
+ Sqreen.log.debug { cmd.inspect }
57
57
  uuid = cmd.uuid
58
58
  res_list[uuid] = cmd.process(runner, context_infos)
59
59
  end
@@ -71,12 +71,12 @@ module Sqreen
71
71
  def validate_command(runner)
72
72
  unless KNOWN_COMMANDS.include?(@name)
73
73
  msg = format("unknown command name '%s'", @name)
74
- Sqreen.log.debug msg
74
+ Sqreen.log.debug { msg }
75
75
  return { :status => false, :reason => msg }
76
76
  end
77
77
  return nil if runner.respond_to?(KNOWN_COMMANDS[@name])
78
78
  msg = format("not implemented '%s'", @name)
79
- Sqreen.log.debug msg
79
+ Sqreen.log.debug { msg }
80
80
  { :status => false, :reason => msg }
81
81
  end
82
82
 
@@ -35,6 +35,7 @@ module Sqreen
35
35
  @data = rule_hash[Attrs::DATA]
36
36
  @rule = rule_hash
37
37
  @payload_tpl = @rule[Attrs::PAYLOAD] || DEFAULT_PAYLOAD
38
+ @overtimeable = true
38
39
  condition_callbacks(@rule[Attrs::CONDITIONS])
39
40
  count_callback_calls(@rule[Attrs::CALL_COUNT_INTERVAL])
40
41
  end
@@ -48,6 +49,8 @@ module Sqreen
48
49
  end
49
50
 
50
51
  def whitelisted?
52
+ whitelisted = SharedStorage.get(:whitelisted)
53
+ return whitelisted unless whitelisted.nil?
51
54
  framework && !framework.whitelisted_match.nil?
52
55
  end
53
56
 
@@ -105,6 +108,7 @@ module Sqreen
105
108
  end
106
109
 
107
110
  def overtime!
111
+ return false unless @overtimeable
108
112
  Sqreen.log.debug { "rulecb #{self} is overtime!" }
109
113
  return true if framework.nil? || !framework.mark_request_overtime!
110
114
  record_observation(
data/lib/sqreen/rules.rb CHANGED
@@ -83,7 +83,7 @@ module Sqreen
83
83
  end
84
84
 
85
85
  if cb_class.nil?
86
- Sqreen.log.debug "Cannot setup #{cbname.inspect} [#{rule_name}]"
86
+ Sqreen.log.debug { "Cannot setup #{cbname.inspect} [#{rule_name}]" }
87
87
  return nil
88
88
  end
89
89
 
@@ -110,7 +110,7 @@ module Sqreen
110
110
  'exception' => e,
111
111
  'rulespack_id' => rulespack_id,
112
112
  'rule_name' => rule_name)
113
- Sqreen.log.debug("Creating cb from rule #{rule_name} failed (#{e.inspect})")
113
+ Sqreen.log.debug { "Creating cb from rule #{rule_name} failed (#{e.inspect})" }
114
114
  nil
115
115
  end
116
116
 
@@ -47,7 +47,10 @@ module Sqreen
47
47
  end
48
48
  end
49
49
 
50
- def pre(inst, *args, &_block)
50
+ def pre(inst, args, budget = nil, &_block)
51
+ unless budget.nil?
52
+ finish = budget + Sqreen::PerformanceNotifications.time.to_f
53
+ end
51
54
  resol_cache = Hash.new do |hash, accessor|
52
55
  hash[accessor] = accessor.resolve(binding, framework, inst, args)
53
56
  end
@@ -58,6 +61,9 @@ module Sqreen
58
61
  next unless val.respond_to?(:each)
59
62
  next if val.respond_to?(:seek)
60
63
  val.each do |v|
64
+ if !budget.nil? && Sqreen::PerformanceNotifications.time.to_f > finish
65
+ return nil
66
+ end
61
67
  next if !v.is_a?(String) || (!matcher.min_size.nil? && v.size < matcher.min_size)
62
68
  next if v.size > MAX_LENGTH
63
69
  next if matcher.match(v).nil?
@@ -38,19 +38,19 @@ module Sqreen
38
38
  @expr[FAILING_CB]
39
39
  end
40
40
 
41
- def pre(inst, *args, &_block)
41
+ def pre(inst, args, _budget = nil, &_block)
42
42
  return unless pre?
43
43
 
44
44
  add_metrics(PRE_CB, inst, args)
45
45
  end
46
46
 
47
- def post(rv, inst, *args, &_block)
47
+ def post(rv, inst, args, _budget = nil, &_block)
48
48
  return unless post?
49
49
 
50
50
  add_metrics(POST_CB, inst, args, rv)
51
51
  end
52
52
 
53
- def failing(exception, inst, *args, &_block)
53
+ def failing(exception, inst, args, _budget = nil, &_block)
54
54
  return unless failing?
55
55
 
56
56
  add_metrics(FAILING_CB, inst, args, exception)
@@ -15,7 +15,7 @@ module Sqreen
15
15
  raise ArgumentError.new("no ips given") if @ips.empty?
16
16
  end
17
17
 
18
- def pre(_inst, *_args, &_block)
18
+ def pre(_inst, _args, _budget = nil, &_block)
19
19
  return unless framework
20
20
  ip = framework.client_ip
21
21
  return unless ip
@@ -10,15 +10,16 @@ module Sqreen
10
10
  # Save request context for handling further down
11
11
  class CountHTTPCodes < RuleCB
12
12
  METRIC_CATEGORY = 'http_code'.freeze
13
- def post(rv, _inst, *_args, &_block)
13
+ def initialize(*args)
14
+ super(*args)
15
+ @overtimeable = false
16
+ end
17
+
18
+ def post(rv, _inst, _args, _budget = nil, &_block)
14
19
  return unless rv.is_a?(Array) && !rv.empty?
15
20
  record_observation(METRIC_CATEGORY, rv[0], 1)
16
21
  advise_action(nil)
17
22
  end
18
-
19
- def overtime!
20
- false
21
- end
22
23
  end
23
24
 
24
25
  # Count 1 for each things located by the binding accessor
@@ -31,7 +32,7 @@ module Sqreen
31
32
  @metric_category = rule_hash[Attrs::METRICS].first['name']
32
33
  end
33
34
 
34
- def post(rv, inst, *args, &_block)
35
+ def post(rv, inst, args, _budget = nil, &_block)
35
36
  return unless rv.is_a?(Array) && !rv.empty?
36
37
  key = @accessors.map do |accessor|
37
38
  accessor.resolve(binding, framework, inst, args, @data, rv)
@@ -9,7 +9,7 @@ module Sqreen
9
9
  # FIXME: Factor with UserAgentMatchesCB
10
10
  # Look for crawlers
11
11
  class CrawlerUserAgentMatchesCB < MatcherRuleCB
12
- def pre(_inst, *_args, &_block)
12
+ def pre(_inst, _args, _budget = nil, &_block)
13
13
  ua = framework.client_user_agent
14
14
  return unless ua
15
15
  found = match(ua)
@@ -10,7 +10,7 @@ module Sqreen
10
10
  class CrawlerUserAgentMatchesMetricsCB < MatcherRuleCB
11
11
  CRAWLER_CATEGORY = 'crawler'.freeze
12
12
 
13
- def pre(_inst, *_args, &_block)
13
+ def pre(_inst, _args, _budget = nil, &_block)
14
14
  ua = framework.client_user_agent
15
15
  return unless ua
16
16
  found = match(ua)
@@ -17,6 +17,7 @@ module Sqreen
17
17
  raise Sqreen::Exception, 'No data'
18
18
  end
19
19
  configure_custom_error(@data['values'][0])
20
+ @overtimeable = false
20
21
  end
21
22
 
22
23
  def configure_custom_error(custom_error)
@@ -31,7 +32,7 @@ module Sqreen
31
32
  end
32
33
  end
33
34
 
34
- def failing(except, _inst, *_args, &_block)
35
+ def failing(except, _inst, _args, _budget = nil, &_block)
35
36
  oexcept = nil
36
37
  if except.respond_to?(:original_exception)
37
38
  oexcept = except.original_exception
@@ -59,10 +60,6 @@ module Sqreen
59
60
  }
60
61
  [@status_code, headers, page]
61
62
  end
62
-
63
- def overtime!
64
- false
65
- end
66
63
  end
67
64
  end
68
65
  end
@@ -8,7 +8,7 @@ else
8
8
  begin
9
9
  require 'mini_racer'
10
10
  SQREEN_MINI_RACER = true
11
- GC_MINI_RACER = 10000
11
+ GC_MINI_RACER = 10_000
12
12
  rescue LoadError
13
13
  require 'therubyracer'
14
14
  SQREEN_MINI_RACER = false
@@ -25,10 +25,43 @@ require 'sqreen/binding_accessor'
25
25
  require 'sqreen/events/remote_exception'
26
26
 
27
27
  module Sqreen
28
+ if SQREEN_MINI_RACER
29
+ # Context specialized for Sqreen usage
30
+ class SqreenContext < MiniRacer::Context
31
+ def eval_unsafe(str, filename = nil, timeoutv = nil)
32
+ # Beware, timeout could be kept in the context
33
+ # if perf cap is removed after having been activated
34
+ # As it's unused by execjscb we are not cleaning it
35
+ return super(str, filename) if timeoutv.nil?
36
+ return if timeoutv <= 0.0
37
+ timeoutv *= 1000 # Timeout are currently expressed in seconds
38
+ @timeout = timeoutv
39
+ @eval_thread = Thread.current
40
+ timeout do
41
+ super(str, filename)
42
+ end
43
+ end
44
+ end
45
+
46
+ # Weak ref to a context
47
+ # enables us to skip a method missing call
48
+ class WeakCtx < WeakRef
49
+ def initialize(*args)
50
+ super(*args)
51
+ end
52
+
53
+ def eval_unsafe(str, filename, timeoutv)
54
+ __getobj__.eval_unsafe(str, filename, timeoutv)
55
+ end
56
+ end
57
+ end
28
58
  module Rules
29
59
  # Exec js callbacks
30
60
  class ExecJSCB < RuleCB
31
61
  attr_accessor :restrict_max_depth
62
+ attr_reader :runtimes
63
+ attr_accessor :recycle_runtime_every
64
+
32
65
  def initialize(klass, method, rule_hash)
33
66
  super(klass, method, rule_hash)
34
67
  callbacks = @rule[Attrs::CALLBACKS]
@@ -41,13 +74,15 @@ module Sqreen
41
74
  end
42
75
 
43
76
  build_runnable(callbacks)
44
- if !SQREEN_MINI_RACER
77
+ @restrict_max_depth = 20
78
+ unless SQREEN_MINI_RACER
45
79
  @compiled = ExecJS.compile(@source)
46
- else
47
- @snapshot = MiniRacer::Snapshot.new(@source)
48
- @runtimes = []
80
+ return
49
81
  end
50
- @restrict_max_depth = 20
82
+ @recycle_runtime_every = GC_MINI_RACER
83
+ @snapshot = MiniRacer::Snapshot.new(@source)
84
+ @runtimes = []
85
+ @key = "SQREEN_MINI_RACER_CONTEXT_#{object_id}".freeze
51
86
  end
52
87
 
53
88
  def pre?
@@ -62,22 +97,22 @@ module Sqreen
62
97
  @js_failing
63
98
  end
64
99
 
65
- def pre(inst, *args, &_block)
100
+ def pre(inst, args, budget = nil, &_block)
66
101
  return unless pre?
67
102
 
68
- call_callback('pre', inst, args)
103
+ call_callback('pre', inst, budget, args)
69
104
  end
70
105
 
71
- def post(rv, inst, *args, &_block)
106
+ def post(rv, inst, args, budget = nil, &_block)
72
107
  return unless post?
73
108
 
74
- call_callback('post', inst, args, rv)
109
+ call_callback('post', inst, budget, args, rv)
75
110
  end
76
111
 
77
- def failing(rv, inst, *args, &_block)
112
+ def failing(rv, inst, args, budget = nil, &_block)
78
113
  return unless failing?
79
114
 
80
- call_callback('failing', inst, args, rv)
115
+ call_callback('failing', inst, budget, args, rv)
81
116
  end
82
117
 
83
118
  def self.hash_val_included(needed, haystack, min_length = 8, max_depth = 20)
@@ -86,7 +121,7 @@ module Sqreen
86
121
  to_do = haystack.map { |k, v| [new_obj, k, v, 0] }
87
122
  until to_do.empty?
88
123
  where, key, value, deepness = to_do.pop
89
- safe_key = key.kind_of?(Integer) ? key : key.to_s
124
+ safe_key = key.is_a?(Integer) ? key : key.to_s
90
125
  if value.is_a?(Hash) && deepness < max_depth
91
126
  val = {}
92
127
  insert << [where, safe_key, val]
@@ -126,12 +161,12 @@ module Sqreen
126
161
  def record_and_continue?(ret)
127
162
  case ret
128
163
  when NilClass
129
- return false
164
+ false
130
165
  when Hash
131
166
  ret.keys.each do |k|
132
167
  ret[(begin
133
168
  k.to_sym
134
- rescue
169
+ rescue StandardError
135
170
  k
136
171
  end)] = ret[k] end
137
172
  record_event(ret[:record]) unless ret[:record].nil?
@@ -141,15 +176,17 @@ module Sqreen
141
176
  record_observation(*obs)
142
177
  end
143
178
  end
144
- return !ret[:call].nil?
179
+ !ret[:call].nil?
145
180
  else
146
181
  raise Sqreen::Exception, "Invalid return type #{ret.inspect}"
147
182
  end
148
183
  end
149
184
 
150
185
  def push_runtime(runtime)
151
- @runtimes.delete_if do |th, _runt|
152
- th.nil? || !th.weakref_alive? || !th.alive?
186
+ @runtimes.delete_if do |th, runt, _thid|
187
+ del = th.nil? || !th.weakref_alive? || !th.alive?
188
+ runt.dispose if del
189
+ del
153
190
  end
154
191
  @runtimes.push [WeakRef.new(Thread.current), runtime, Thread.current.object_id]
155
192
  end
@@ -159,39 +196,41 @@ module Sqreen
159
196
  runtime.dispose
160
197
  end
161
198
 
162
- def call_callback(name, inst, args, rv = nil)
199
+ def call_callback(name, inst, budget, args, rv = nil)
200
+ mini_racer_context = nil
163
201
  if SQREEN_MINI_RACER
164
- mini_racer_context = Thread.current["SQREEN_MINI_RACER_CONTEXT_#{object_id}"]
165
- if mini_racer_context.nil? || mini_racer_context[:r].nil? || !mini_racer_context[:r].weakref_alive?
166
- new_runtime = MiniRacer::Context.new(:snapshot => @snapshot)
167
- push_runtime new_runtime
168
- Thread.current["SQREEN_MINI_RACER_CONTEXT_#{object_id}"] = {
169
- :c => 0,
170
- :r => WeakRef.new(new_runtime),
171
- }
172
- elsif mini_racer_context[:c] >= GC_MINI_RACER
202
+ mini_racer_context = Thread.current[@key]
203
+ dead_runtime = !mini_racer_context || !mini_racer_context[:r] || !mini_racer_context[:r].weakref_alive?
204
+ if !dead_runtime && mini_racer_context[:c] >= @recycle_runtime_every
173
205
  dispose_runtime(mini_racer_context[:r])
174
- new_runtime = MiniRacer::Context.new(:snapshot => @snapshot)
206
+ dead_runtime = true
207
+ end
208
+ if dead_runtime
209
+ new_runtime = SqreenContext.new(:snapshot => @snapshot)
175
210
  push_runtime new_runtime
176
- Thread.current["SQREEN_MINI_RACER_CONTEXT_#{object_id}"] = {
211
+ mini_racer_context = {
177
212
  :c => 0,
178
- :r => WeakRef.new(new_runtime),
213
+ :r => WeakCtx.new(new_runtime),
179
214
  }
215
+ Thread.current[@key] = mini_racer_context
180
216
  end
181
217
  end
182
218
  ret = nil
183
219
  args_override = nil
184
220
  arguments = nil
185
- loop do
221
+ while true
186
222
  arguments = (args_override || @argument_requirements[name]).map do |accessor|
187
223
  accessor.resolve(binding, framework, inst, args, @data, rv)
188
224
  end
189
225
  arguments = restrict(name, arguments) if @conditions.key?(name)
190
226
  Sqreen.log.debug { [name, arguments].inspect }
191
227
  if SQREEN_MINI_RACER
192
- mini_racer_context = Thread.current["SQREEN_MINI_RACER_CONTEXT_#{object_id}"]
193
228
  mini_racer_context[:c] += 1
194
- ret = mini_racer_context[:r].eval("#{name}.apply(this, #{::JSON.generate(arguments)})")
229
+ begin
230
+ ret = mini_racer_context[:r].eval_unsafe("#{name}.apply(this, #{::JSON.generate(arguments)})", nil, budget)
231
+ rescue MiniRacer::ScriptTerminatedError
232
+ ret = nil
233
+ end
195
234
  else
196
235
  ret = @compiled.call(name, *arguments)
197
236
  end
@@ -204,8 +243,8 @@ module Sqreen
204
243
  args_override = ret[:args]
205
244
  args_override = build_accessor(args_override) if args_override
206
245
  end
207
- rescue => e
208
- Sqreen.log.warn "we catch a JScb exception: #{e.inspect}"
246
+ rescue StandardError => e
247
+ Sqreen.log.warn { "we catch a JScb exception: #{e.inspect}" }
209
248
  Sqreen.log.debug e.backtrace
210
249
  record_exception(e, :cb => name, :args => arguments)
211
250
  nil
@@ -226,7 +265,7 @@ module Sqreen
226
265
 
227
266
  def restrict(cbname, arguments)
228
267
  condition = @conditions[cbname]
229
- return arguments if condition.nil? or @argument_requirements[cbname].nil?
268
+ return arguments if condition.nil? || @argument_requirements[cbname].nil?
230
269
 
231
270
  each_hash_val_include(condition) do |needle, haystack, min_length|
232
271
  # We could actually run the binding accessor expression here.