class Sqreen::SafeJSON
Safely dump datastructure in json (more resilient to encoding errors)
Public Class Methods
dump(data)
click to toggle source
# File lib/sqreen/safe_json.rb, line 13 def self.dump(data) JSON.generate(data) rescue JSON::GeneratorError, Encoding::UndefinedConversionError Sqreen.log.debug('Payload could not be encoded enforcing recode') JSON.generate(rencode_payload(data)) end
enforce_encoding(str)
click to toggle source
# File lib/sqreen/safe_json.rb, line 47 def self.enforce_encoding(str) return str unless str.is_a?(String) return str if str.ascii_only? encoded8bit = str.encoding.name == 'ASCII-8BIT' return str if !encoded8bit && str.valid_encoding? r = str.chars.map do |v| if !v.valid_encoding? || (encoded8bit && !v.ascii_only?) v.bytes.map { |c| "\\x#{c.to_s(16).upcase}" }.join else v end end.join "SqBytes[#{r}]" end
rencode_array(array, max_depth)
click to toggle source
# File lib/sqreen/safe_json.rb, line 42 def self.rencode_array(array, max_depth) array.map! { |e| rencode_payload(e, max_depth - 1) } array end
rencode_payload(obj, max_depth = 20)
click to toggle source
# File lib/sqreen/safe_json.rb, line 20 def self.rencode_payload(obj, max_depth = 20) max_depth -= 1 return obj if max_depth < 0 return rencode_array(obj, max_depth) if obj.is_a?(Array) return enforce_encoding(obj) unless obj.is_a?(Hash) nobj = {} obj.each do |k, v| safe_k = rencode_payload(k, max_depth) nobj[safe_k] = case v when Array rencode_array(v, max_depth) when Hash rencode_payload(v, max_depth) when String enforce_encoding(v) else # for example integers v end end nobj end