sqreen-alt 1.11.0 → 1.11.1

Sign up to get free protection for your applications and to get access to all the features.
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.