sqreen 1.16.2 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 424c794c9315a7e1a0544fd6be427194ec7d7155e665ba86c1c3413306078941
4
- data.tar.gz: 815fa9b893dd2577360a0408cc44194879c9fb1bbe5074cdce6c8c8629e82704
3
+ metadata.gz: edfd8cc358ff6408be042a8d11d473b85b00c2a1cf80c97cf5b154a6fa7da037
4
+ data.tar.gz: f558c9aef036f11b3e20fe0f8d41d7020b7d302233a4385d7cb760a983e91116
5
5
  SHA512:
6
- metadata.gz: 9bc336364648476b1e6a0b6a3955215646c008a418b35f39abacc1cee9fccd5bab9374e8e90b444bc2a1482eebc25ddf463526154479acca14acc7605e438bdf
7
- data.tar.gz: 53433d834097073f8ec98dd4396243029fb55e60c675bb6da379d12090000cbb31be0a23e736a9cc70615dd5fe7991559cc4a3c3c884d02cbbe6e5c787e5b415
6
+ metadata.gz: aa39b3c2a3af1e2b2135dd735b736dce973eab3810cbbe7dc7d017d25ca69d7f309f9029e9f0281d51cd523f996f86c75963d83b77a2294f6a359f847305f100
7
+ data.tar.gz: daa34349243dc5a56abadff975c776098db0e1d520f15720bae17443b157cc586ba77bc954ab4c7687866dab4bd4b8607cb6fee4c2e9e3bd68cc9f7b46b78faf
data/README.md CHANGED
@@ -75,3 +75,8 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
75
75
  ## Contributing
76
76
 
77
77
  Bug reports and pull requests are welcome on GitHub at https://github.com/sqreen/RubyAgent. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
78
+
79
+ ## LICENSE
80
+
81
+ Sqreen for Ruby is free-to-use, proprietary software.
82
+
@@ -18,14 +18,21 @@ require 'thread'
18
18
 
19
19
  Sqreen.framework.on_start do |framework|
20
20
  if Sqreen.framework.on_pre_fork_preload?
21
+ Sqreen.log.debug "Sqreen detected a forking server with preloading"
21
22
  next
23
+ else
24
+ Sqreen.log.debug "Sqreen detected a single-process server"
22
25
  end
23
26
  Thread.new do
24
27
  begin
25
28
  runner = nil
29
+ Sqreen.log.debug("Reading configuration")
26
30
  configuration = Sqreen.config_init(framework)
27
- Sqreen.log.debug("Starting Sqreen #{Sqreen::VERSION}")
28
31
  framework.sqreen_configuration = configuration
32
+ Sqreen.log.debug("Initializing logs")
33
+ Sqreen.log_init
34
+ Sqreen.log.debug("Starting Sqreen #{Sqreen::VERSION}")
35
+ warn "[#{Process.pid}] Sqreen logging at level #{Sqreen.log.instance_eval { @logger }.level} to #{Sqreen.log.instance_eval { @logger }.instance_eval { @logdev.filename }}"
29
36
  prevent_startup = Sqreen.framework.prevent_startup
30
37
  if !prevent_startup
31
38
  runner = Sqreen::Runner.new(configuration, framework)
@@ -38,33 +45,33 @@ Sqreen.framework.on_start do |framework|
38
45
  rescue Sqreen::TokenInvalidException
39
46
  Sqreen.log.error "Sorry but your Sqreen token appears to be invalid.\nYour application is NOT currently protected by Sqreen.\n\nHave you correctly filled your config/sqreen.yml?\n\n"
40
47
  rescue Exception => e
41
- Sqreen.log.error e.inspect
42
- Sqreen.log.debug e.backtrace.join("\n")
48
+ Sqreen.log.debug("General exception caught: #{e.inspect}")
49
+ Sqreen.log.debug e.backtrace
43
50
  if runner
44
- # immediately post exception
51
+ Sqreen.log.debug("Immediately posting exception for runner #{runner.inspect}")
45
52
  runner.session.post_sqreen_exception(Sqreen::RemoteException.new(e))
46
- Sqreen.log.debug("runner = #{runner.inspect}")
47
53
  begin
48
54
  runner.remove_instrumentation
49
- rescue => remove_exception
50
- Sqreen.log.debug(remove_exception.inspect)
51
- # We did not manage to remove instrumentation, state is unclear:
52
- # terminate thread
55
+ rescue => e
56
+ Sqreen.log.debug("Unexpected exception when removing instrumentation: #{e.inspect}")
57
+ Sqreen.log.debug e.backtrace
58
+ Sqreen.log.error("Terminating Sqreen thread")
53
59
  return nil
54
60
  end
55
61
  begin
56
62
  runner.logout(false)
57
- rescue => logout_exception
58
- Sqreen.log.debug(logout_exception.inspect)
63
+ rescue StandardError => e
64
+ Sqreen.log.debug("Unexpected exception when logging out: #{remove_exception.inspect}")
65
+ Sqreen.log.debug(e.backtrace)
59
66
  nil
60
67
  end
61
68
  end
62
69
  # Wait a few seconds before retrying
63
70
  delay = rand(120)
64
- Sqreen.log.debug("Sleeping #{delay} seconds before retry")
71
+ Sqreen.log.debug("Sleeping #{delay} seconds before restarting Sqreen thread")
65
72
  sleep(delay)
66
73
  retry
67
74
  end
68
- Sqreen.log.debug("shutting down Sqreen #{Sqreen::VERSION}")
75
+ Sqreen.log.debug("Shutting down Sqreen #{Sqreen::VERSION}")
69
76
  end
70
77
  end unless Sqreen::to_bool(ENV['SQREEN_DISABLE'])
@@ -96,6 +96,8 @@ module Sqreen
96
96
  if path
97
97
  file_config = parse_configuration_file(path)
98
98
  @config.merge!(file_config)
99
+ else
100
+ Sqreen.log.warn("could not find sqreen configuration file")
99
101
  end
100
102
 
101
103
  env_config = from_environment
@@ -162,8 +164,17 @@ module Sqreen
162
164
  protected
163
165
 
164
166
  def config_file_from_env
165
- path = ENV[Sqreen::CONFIG_FILE_BY_ENV]
166
- return path if path && File.exist?(path)
167
+ return unless (path = ENV[Sqreen::CONFIG_FILE_BY_ENV])
168
+
169
+ path = File.expand_path(path)
170
+
171
+ unless File.exist?(path)
172
+ Sqreen.log.warn("could not find sqreen configuration file provided by #{Sqreen::CONFIG_FILE_BY_ENV}: '#{path}'")
173
+ end
174
+
175
+ Sqreen.log.info("using config file provided by #{Sqreen::CONFIG_FILE_BY_ENV}: '#{path}'")
176
+
177
+ path
167
178
  end
168
179
 
169
180
  def local_config_file
@@ -57,10 +57,17 @@ module Sqreen
57
57
  else
58
58
  res[:request] = {}
59
59
  end
60
+ if payload['response']
61
+ res[:response] = payload['response'].dup
62
+ else
63
+ res[:response] = {}
64
+ end
60
65
 
61
66
  res[:request][:parameters] = payload['params'] if payload['params']
62
67
  res[:request][:headers] = payload['headers'] if payload['headers']
63
68
 
69
+ res = Sqreen::EncodingSanitizer.sanitize(res)
70
+
64
71
  if @redactor
65
72
  res[:request] = @redactor.redact(res[:request])
66
73
  end
@@ -108,6 +115,27 @@ module Sqreen
108
115
  end
109
116
  end
110
117
 
118
+ class EncodingSanitizer
119
+ def self.sanitize(obj)
120
+ case obj
121
+ when String
122
+ sanitize_string(obj)
123
+ when Array
124
+ obj.map { |e| sanitize(e) }
125
+ when Hash
126
+ obj.each_with_object({}) { |(k, v), h| h[k] = sanitize(v) }
127
+ else
128
+ obj
129
+ end
130
+ end
131
+
132
+ def self.sanitize_string(s)
133
+ return s if s.encoding.name == 'UTF-8' && s.valid_encoding?
134
+
135
+ s.encode('UTF-16', :invalid => :replace, :undef => :replace).encode('UTF-8')
136
+ end
137
+ end
138
+
111
139
  # For redacting sensitive data and avoid having it sent to our servers
112
140
  class SensitiveDataRedactor
113
141
  DEFAULT_SENSITIVE_KEYS = Set.new(%w[password secret passwd authorization api_key apikey access_token]).freeze
@@ -20,7 +20,9 @@ module Sqreen
20
20
  require 'sqreen/frameworks/rails3'
21
21
  Sqreen::Frameworks::Rails3Framework
22
22
  else
23
- raise "Rails version #{Rails.version} not supported"
23
+ Sqreen.log.warn "Detected unsupported Rails version #{Rails.version}, but continuing"
24
+ require 'sqreen/frameworks/rails'
25
+ Sqreen::Frameworks::RailsFramework
24
26
  end
25
27
  when defined?(::Sinatra)
26
28
  require 'sqreen/frameworks/sinatra'
@@ -29,8 +31,7 @@ module Sqreen
29
31
  require 'sqreen/frameworks/sqreen_test'
30
32
  Sqreen::Frameworks::SqreenTestFramework
31
33
  else
32
- # FIXME: use sqreen logger before configuration?
33
- STDERR.puts "Error: cannot find any framework\n"
34
+ Sqreen.log.error "Error: cannot find any framework\n"
34
35
  require 'sqreen/frameworks/generic'
35
36
  Sqreen::Frameworks::GenericFramework
36
37
  end
@@ -44,6 +44,10 @@ module Sqreen
44
44
  ENV['RACK_ENV'] == 'development'
45
45
  end
46
46
 
47
+ def test?
48
+ ENV['RACK_ENV'] == 'test'
49
+ end
50
+
47
51
  PREFERRED_IP_HEADERS = %w[HTTP_X_FORWARDED_FOR HTTP_X_REAL_IP
48
52
  HTTP_CLIENT_IP HTTP_X_FORWARDED
49
53
  HTTP_X_CLUSTER_CLIENT_IP HTTP_FORWARDED_FOR
@@ -161,6 +165,23 @@ module Sqreen
161
165
  }
162
166
  end
163
167
 
168
+ def response_infos
169
+ return {} if response.nil?
170
+
171
+ content_type = response.header['Content-Type']
172
+ content_length = begin
173
+ Integer(response.header['Content-Length'])
174
+ rescue ArgumentError, TypeError
175
+ nil
176
+ end
177
+
178
+ {
179
+ :status => response.status,
180
+ :content_type => content_type,
181
+ :content_length => content_length,
182
+ }
183
+ end
184
+
164
185
  # Request URL path
165
186
  def request_path
166
187
  req = request
@@ -257,17 +278,26 @@ module Sqreen
257
278
  SharedStorage.set(:request_overtime, nil)
258
279
  end
259
280
 
281
+ def store_response(rv, _env)
282
+ SharedStorage.set(:response, Rack::Response.new([], rv[0], rv[1]))
283
+ end
284
+
260
285
  # Get the currently stored request
261
286
  def request
262
287
  SharedStorage.get(:request)
263
288
  end
264
289
 
290
+ def response
291
+ SharedStorage.get(:response)
292
+ end
293
+
265
294
  # Cleanup request context
266
295
  def clean_request
267
296
  payload_creator = Sqreen::PayloadCreator.new(self)
268
297
  close_request_record(Sqreen.queue, Sqreen.observations_queue, payload_creator)
269
298
  self.remaining_perf_budget = nil
270
299
  SharedStorage.set(:request, nil)
300
+ SharedStorage.set(:response, nil)
271
301
  SharedStorage.set(:xss_params, nil)
272
302
  SharedStorage.set(:whitelisted, nil)
273
303
  SharedStorage.set(:request_overtime, nil)
@@ -397,7 +427,7 @@ module Sqreen
397
427
  each_key_value_for_hash(p) do |value|
398
428
  next unless value.is_a?(String)
399
429
  next if value.size < 5
400
- value = value.force_encoding(Encoding::ISO_8859_1).encode(Encoding::UTF_8) unless value.valid_encoding?
430
+ value = value.dup.force_encoding(Encoding::ISO_8859_1).encode(Encoding::UTF_8) unless value.valid_encoding?
401
431
  next if regexp && !regexp.match?(value)
402
432
  parm << value
403
433
  end
@@ -415,7 +445,7 @@ module Sqreen
415
445
  each_key_value_for_hash(p) do |value|
416
446
  next unless value.is_a?(String)
417
447
  next if value.size < 5
418
- value = value.force_encoding(Encoding::ISO_8859_1).encode(Encoding::UTF_8) unless value.valid_encoding?
448
+ value = value.dup.force_encoding(Encoding::ISO_8859_1).encode(Encoding::UTF_8) unless value.valid_encoding?
419
449
  next if regexp && !regexp.match(value)
420
450
  parm << value
421
451
  end
@@ -564,7 +594,13 @@ module Sqreen
564
594
  end
565
595
 
566
596
  def split_ip_addresses(ip_addresses)
567
- ip_addresses ? ip_addresses.strip.split(/[,\s]+/) : []
597
+ return [] unless ip_addresses
598
+
599
+ r = ip_addresses.strip.split(/[,\s]+/)
600
+ r.map! do |ip|
601
+ m = /^(?:(?<ip>.*\..*)\:|\[(?<ip>.*)\]\:)/.match(ip)
602
+ m ? m[:ip] : ip
603
+ end
568
604
  end
569
605
 
570
606
  def valid_ip?(ip)
@@ -415,36 +415,31 @@ module Sqreen
415
415
  end
416
416
 
417
417
  def override_class_method(klass, meth)
418
- # FIXME: This is somehow ugly. We should reduce the amount of
419
- # `evaled` code.
420
- str = " class << #{klass}
418
+ original = meth.to_sym
419
+ saved_meth_name = get_saved_method_name(meth).to_sym
420
+ new_method = "#{meth}_modified".to_sym
421
421
 
422
- original = '#{meth}'.to_sym
423
- saved_meth_name = '#{get_saved_method_name(meth)}'.to_sym
424
- new_method = '#{meth}_modified'.to_sym
422
+ klass.singleton_class.instance_eval do
423
+ alias_method saved_meth_name, original
425
424
 
426
- alias_method saved_meth_name, original
425
+ p = Instrumentation.define_callback_method(original, saved_meth_name, klass)
426
+ define_method(new_method, p)
427
427
 
428
- p = Instrumentation.define_callback_method(original, saved_meth_name,
429
- #{klass})
430
- define_method(new_method, p)
428
+ private new_method
431
429
 
432
- private new_method
430
+ method_kind = nil
431
+ if public_method_defined?(original)
432
+ method_kind = :public
433
+ elsif protected_method_defined?(original)
434
+ method_kind = :protected
435
+ elsif private_method_defined?(original)
436
+ method_kind = :private
437
+ end
433
438
 
434
- method_kind = nil
435
- case
436
- when public_method_defined?(original)
437
- method_kind = :public
438
- when protected_method_defined?(original)
439
- method_kind = :protected
440
- when private_method_defined?(original)
441
- method_kind = :private
439
+ alias_method original, new_method
440
+ send(method_kind, original)
441
+ private saved_meth_name
442
442
  end
443
- alias_method original, new_method
444
- send(method_kind, original)
445
- private saved_meth_name
446
- end "
447
- eval str
448
443
  end
449
444
 
450
445
  def unoverride_instance_method(obj, meth)
@@ -516,19 +511,19 @@ module Sqreen
516
511
  # WARNING We do not actually remove `meth`
517
512
  def unoverride_class_method(klass, meth)
518
513
  saved_meth_name = get_saved_method_name(meth)
514
+ method_kind = nil
519
515
 
520
- eval "method_kind = nil; class << #{klass}
521
- case
522
- when public_method_defined?(#{meth.to_sym.inspect})
523
- method_kind = :public
524
- when protected_method_defined?(original)
525
- method_kind = :protected
526
- when private_method_defined?(#{meth.to_sym.inspect})
527
- method_kind = :private
528
- end
529
- alias_method #{meth.to_sym.inspect}, #{saved_meth_name.to_sym.inspect}
530
- send(method_kind, #{meth.to_sym.inspect})
531
- end "
516
+ klass.singleton_class.instance_eval do
517
+ if public_method_defined?(meth.to_sym)
518
+ method_kind = :public
519
+ elsif protected_method_defined?(original)
520
+ method_kind = :protected
521
+ elsif private_method_defined?(meth.to_sym)
522
+ method_kind = :private
523
+ end
524
+ alias_method meth.to_sym, saved_meth_name.to_sym
525
+ send(method_kind, meth.to_sym)
526
+ end
532
527
  end
533
528
 
534
529
  if RUBY_VERSION < '1.9'
@@ -9,18 +9,20 @@ require 'sqreen/performance_notifications/log_performance'
9
9
  require 'sqreen/configuration'
10
10
 
11
11
  module Sqreen
12
- def self::log
13
- @logger ||= nil
14
- return @logger unless @logger.nil?
15
- return NoopLogger.instance unless Sqreen.configured?
12
+ def self.log_init
16
13
  @logger = Logger.new(
17
14
  Sqreen.config_get(:log_level).to_s.upcase,
18
15
  Sqreen.config_get(:log_location)
19
16
  )
17
+ DeferredLogger.instance.flush_to(@logger.instance_eval { @logger })
20
18
  rescue => e
21
19
  warn "Sqreen logger exception: #{e}"
22
20
  end
23
21
 
22
+ def self::log
23
+ @logger || DeferredLogger.instance
24
+ end
25
+
24
26
  # Ruby default formatter modified to display current thread_id
25
27
  class FormatterWithTid
26
28
  Format = "%s, [%s#%d.%s] %5s -- %s: %s\n".freeze
@@ -113,7 +115,7 @@ module Sqreen
113
115
  end
114
116
 
115
117
  def create_error_logger
116
- @error_logger = ::Logger.new(STDERR)
118
+ @error_logger = Kernel.const_defined?('MiniTest') ? NullLogger.instance : ::Logger.new(STDERR)
117
119
  enforce_log_format(@error_logger)
118
120
  end
119
121
 
@@ -122,7 +124,7 @@ module Sqreen
122
124
  end
123
125
  end
124
126
 
125
- class NoopLogger
127
+ class NullLogger
126
128
  include Singleton
127
129
 
128
130
  def debug(_msg = nil); end
@@ -132,5 +134,54 @@ module Sqreen
132
134
  def warn(_msg = nil); end
133
135
 
134
136
  def error(_msg = nil); end
137
+
138
+ def formatter=(_); end
139
+ end
140
+
141
+ class DeferredLogger
142
+ include Singleton
143
+
144
+ def initialize
145
+ @buffer = StringIO.new
146
+ @logger = ::Logger.new(@buffer)
147
+ end
148
+
149
+ def debug(msg = nil, &block)
150
+ @logger.debug(msg, &block)
151
+ end
152
+
153
+ def info(msg = nil, &block)
154
+ @logger.info(msg, &block)
155
+ end
156
+
157
+ def warn(msg = nil, &block)
158
+ @logger.warn(msg, &block)
159
+ end
160
+
161
+ def error(msg = nil, &block)
162
+ @logger.error(msg, &block)
163
+ end
164
+
165
+ def formatter=(value)
166
+ @logger.formatter = value
167
+ end
168
+
169
+ def flush_to(logger)
170
+ logger.instance_eval { @logdev }.write(read).tap { reset }
171
+ end
172
+
173
+ private
174
+
175
+ def read
176
+ @buffer.rewind
177
+ @buffer.read
178
+ end
179
+
180
+ def reset
181
+ buffer = StringIO.new
182
+ logger = ::Logger.new(buffer)
183
+ logger.formatter = @logger.formatter
184
+ @buffer, @logger = buffer, logger
185
+ end
135
186
  end
136
187
  end
@@ -54,6 +54,7 @@ module Sqreen
54
54
 
55
55
  FULL_SECTIONS = {
56
56
  'request' => 'request_infos',
57
+ 'response' => 'response_infos',
57
58
  'params' => 'filtered_request_params',
58
59
  'headers' => 'ip_headers',
59
60
  'local' => 'local_infos',
@@ -64,6 +65,9 @@ module Sqreen
64
65
  'addr' => 'client_ip',
65
66
  'rid' => 'request_id',
66
67
  },
68
+ 'response' => {
69
+ 'status' => 'status',
70
+ },
67
71
  'local' => {
68
72
  'name' => 'hostname',
69
73
  },
@@ -30,7 +30,8 @@ module Sqreen
30
30
  advise_action(nil)
31
31
  end
32
32
 
33
- def post(_rv, _inst, _args, _budget = nil, &_block)
33
+ def post(rv, _inst, args, _budget = nil, &_block)
34
+ framework.store_response(rv, args[0])
34
35
  framework.clean_request
35
36
  advise_action(nil)
36
37
  end
@@ -228,16 +228,18 @@ module Sqreen
228
228
 
229
229
 
230
230
  def setup_instrumentation(context_infos = {})
231
- Sqreen.log.info 'setup instrumentation'
231
+ Sqreen.log.info 'Setting up instrumentation'
232
232
  rulespack_id, rules = load_rules(context_infos)
233
233
  @framework.instrument_when_ready!(instrumenter, rules)
234
+ Sqreen.log.info 'Instrumentation set up'
234
235
  rulespack_id.to_s
235
236
  end
236
237
 
237
238
  def remove_instrumentation(_context_infos = {})
238
- Sqreen.log.debug 'removing instrumentation'
239
+ Sqreen.log.debug 'Removing instrumentation'
239
240
  instrumenter.remove_all_callbacks
240
241
  Sqreen::Actions::Repository.instance.clear
242
+ Sqreen.log.debug 'Instrumentation removed'
241
243
  true
242
244
  end
243
245
 
@@ -419,6 +421,7 @@ module Sqreen
419
421
 
420
422
  def logout(retrying = true)
421
423
  return unless session
424
+ Sqreen.log.debug("Logging out")
422
425
  if @framework.development?
423
426
  @running = false
424
427
  return
@@ -440,7 +443,13 @@ module Sqreen
440
443
  if exit_from_sinatra_startup? && try_again
441
444
  register_exit_cb(false)
442
445
  else
443
- logout
446
+ begin
447
+ logout
448
+ rescue StandardError => e
449
+ Sqreen.log.debug(e.inspect)
450
+ Sqreen.log.debug(e.backtrace)
451
+ nil
452
+ end
444
453
  end
445
454
  end
446
455
  end
@@ -89,16 +89,6 @@ module Sqreen
89
89
  @http.finish if connected?
90
90
  end
91
91
 
92
- NET_ERRORS = [Timeout::Error,
93
- Errno::EINVAL,
94
- Errno::ECONNRESET,
95
- Errno::ECONNREFUSED,
96
- EOFError,
97
- Net::HTTPBadResponse,
98
- Net::HTTPHeaderSyntaxError,
99
- SocketError,
100
- Net::ProtocolError].freeze
101
-
102
92
  def connect
103
93
  return if connected?
104
94
  Sqreen.log.warn "connection to #{@server_url}..."
@@ -106,7 +96,9 @@ module Sqreen
106
96
  @conn_retry = 0
107
97
  begin
108
98
  @con = @http.start
109
- rescue *NET_ERRORS
99
+ rescue StandardError => e
100
+ Sqreen.log.debug { "Caught exception during request: #{e.inspect}" }
101
+ Sqreen.log.debug { e.backtrace }
110
102
  Sqreen.log.debug "Cannot connect, retry in #{RETRY_CONNECT_SECONDS} seconds"
111
103
  sleep RETRY_CONNECT_SECONDS
112
104
  @conn_retry += 1
@@ -133,16 +125,18 @@ module Sqreen
133
125
  end
134
126
 
135
127
  def resiliently(retry_request_seconds, max_retry, current_retry = 0)
128
+ connect unless connected?
136
129
  return yield
137
130
  rescue => e
138
- Sqreen.log.debug { e.inspect }
131
+ Sqreen.log.debug { "Caught exception during request: #{e.inspect}" }
132
+ Sqreen.log.debug { e.backtrace }
139
133
 
140
134
  current_retry += 1
141
135
 
142
136
  raise e if current_retry >= max_retry || e.is_a?(Sqreen::NotImplementedYet)
143
137
 
144
138
  sleep_delay = [MAX_DELAY, retry_request_seconds * current_retry].min
145
- Sqreen.log.debug format('Sleeping %ds', sleep_delay)
139
+ Sqreen.log.debug format("Sleeping %ds before retry #{current_retry}/#{max_retry}", sleep_delay)
146
140
  sleep(sleep_delay)
147
141
 
148
142
  retry
@@ -159,7 +153,6 @@ module Sqreen
159
153
  end
160
154
 
161
155
  def do_http_request(method, path, data, headers = {}, max_retry = 2)
162
- connect unless connected?
163
156
  now = Time.now.utc
164
157
  headers['X-Session-Key'] = @session_id if @session_id
165
158
  headers['X-Sqreen-Time'] = now.to_f.to_s
@@ -170,6 +163,7 @@ module Sqreen
170
163
  @req_nb,
171
164
  Time.now.utc.to_f)
172
165
  headers['Content-Type'] = 'application/json'
166
+ headers['Accept'] = 'application/json'
173
167
  if request_compression && !method.casecmp(:GET).zero?
174
168
  headers['Content-Encoding'] = 'gzip'
175
169
  end
@@ -198,11 +192,15 @@ module Sqreen
198
192
  raise Sqreen::NotImplementedYet
199
193
  end
200
194
  end
201
-
202
195
  if json && json.body
203
- res = JSON.parse(json.body)
204
- unless res['status']
205
- Sqreen.log.debug(format('Cannot %s %s.', method, path))
196
+ if json['Content-Type'] && json['Content-Type'].start_with?('application/json')
197
+ res = JSON.parse(json.body)
198
+ unless res['status']
199
+ Sqreen.log.debug(format('Cannot %s %s. Parsed response body was: %s', method, path, res.inspect))
200
+ end
201
+ else
202
+ Sqreen.log.debug "Unexpected response Content-Type: #{json['Content-Type']}"
203
+ Sqreen.log.debug "Unexpected response body: #{json.body.inspect}"
206
204
  end
207
205
  else
208
206
  Sqreen.log.debug 'warning: empty return value'
@@ -283,7 +281,7 @@ module Sqreen
283
281
  # @param exception [RemoteException] Exception and context to be sent over
284
282
  def post_sqreen_exception(exception)
285
283
  post('sqreen_exception', exception.to_hash, {}, 5)
286
- rescue *NET_ERRORS => e
284
+ rescue StandardError => e
287
285
  Sqreen.log.warn(format('Could not post exception (network down? %s) %s',
288
286
  e.inspect,
289
287
  exception.to_hash.inspect))
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
  module Sqreen
4
- VERSION = '1.16.2'.freeze
4
+ VERSION = '1.17.0'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqreen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.16.2
4
+ version: 1.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sqreen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-14 00:00:00.000000000 Z
11
+ date: 2019-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sq_mini_racer