Sha256: 9a53edde41398e0a162fb1899a0c6dfdfaebe479c6eb1358278053cf3284958d

Contents?: true

Size: 1.82 KB

Versions: 10

Compression:

Stored size: 1.82 KB

Contents

# typed: ignore

# Copyright (c) 2015 Sqreen. All Rights Reserved.
# Please refer to our terms for more information: https://www.sqreen.com/terms.html

require 'json'

require 'sqreen/log'

module Sqreen
  # Safely dump datastructure in json (more resilient to encoding errors)
  class SafeJSON
    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

    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

    def self.rencode_array(array, max_depth)
      array.map! { |e| rencode_payload(e, max_depth - 1) }
      array
    end

    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
  end
end

Version data entries

10 entries across 10 versions & 1 rubygems

Version Path
sqreen-1.25.1 lib/sqreen/safe_json.rb
sqreen-1.25.0 lib/sqreen/safe_json.rb
sqreen-1.24.3 lib/sqreen/safe_json.rb
sqreen-1.24.2 lib/sqreen/safe_json.rb
sqreen-1.24.1 lib/sqreen/safe_json.rb
sqreen-1.24.0 lib/sqreen/safe_json.rb
sqreen-1.23.2 lib/sqreen/safe_json.rb
sqreen-1.23.1 lib/sqreen/safe_json.rb
sqreen-1.23.0 lib/sqreen/safe_json.rb
sqreen-1.22.1 lib/sqreen/safe_json.rb