diff options
author | danielsdeleo <dan@opscode.com> | 2013-02-12 10:57:07 -0800 |
---|---|---|
committer | danielsdeleo <dan@opscode.com> | 2013-02-12 10:57:07 -0800 |
commit | 453e99906edb6a737768b69bc74262b37e266bd6 (patch) | |
tree | cb53909a8bbd773fa5d98989734ecd5e839d2d77 | |
parent | c7e99e50b1b9bba72b3fd907e1fb3748b901eeee (diff) | |
download | chef-453e99906edb6a737768b69bc74262b37e266bd6.tar.gz |
[CHEF-3863] improve error compat with old impl.
-rw-r--r-- | lib/chef/json_compat.rb | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/lib/chef/json_compat.rb b/lib/chef/json_compat.rb index 80afc163e7..e8f8a75162 100644 --- a/lib/chef/json_compat.rb +++ b/lib/chef/json_compat.rb @@ -38,6 +38,7 @@ class Chef CHEF_RESOURCECOLLECTION = "Chef::ResourceCollection".freeze class <<self + # See CHEF-1292/PL-538. Increase the max nesting for JSON, which defaults # to 19, and isn't enough for some (for example, a Node within a Node) # structures. @@ -53,6 +54,13 @@ class Chef def from_json(source, opts = {}) obj = ::Yajl::Parser.parse(source) + # JSON gem requires top level object to be a Hash or Array (otherwise + # you get the "must contain two octets" error). Yajl doesn't impose the + # same limitation. For compatibility, we re-impose this condition. + unless obj.kind_of?(Hash) or obj.kind_of?(Array) + raise JSON::ParserError, "Top level JSON object must be a Hash or Array. (actual: #{obj.class})" + end + # The old default in the json gem (which we are mimicing because we # sadly rely on this misfeature) is to "create additions" i.e., convert # JSON objects into ruby objects. Explicit :create_additions => false @@ -67,7 +75,7 @@ class Chef # Look at an object that's a basic type (from json parse) and convert it # to an instance of Chef classes if desired. def map_to_rb_obj(json_obj) - res = case json_obj + case json_obj when Hash mapped_hash = map_hash_to_rb_obj(json_obj) if json_obj.has_key?(JSON_CLASS) && (class_to_inflate = class_for_json_class(json_obj[JSON_CLASS])) @@ -80,7 +88,6 @@ class Chef else json_obj end - res end def map_hash_to_rb_obj(json_hash) @@ -99,6 +106,10 @@ class Chef end + # Map +json_class+ to a Class object. We use a +case+ instead of a Hash + # assigned to a constant because otherwise this file could not be loaded + # until all the constants were defined, which means you'd have to load + # the world to get json, which would make knife very slow. def class_for_json_class(json_class) case json_class when CHEF_APICLIENT @@ -116,6 +127,9 @@ class Chef when CHEF_ROLE Chef::Role when CHEF_SANDBOX + # a falsey return here will disable object inflation/"create + # additions" in the caller. In Chef 11 this is correct, we just have + # a dummy Chef::Sandbox class for compat with Chef 10 servers. false when CHEF_RESOURCE Chef::Resource @@ -124,7 +138,7 @@ class Chef when /^Chef::Resource/ Chef::Resource.find_subclass_by_name(json_class) else - raise ArgumentError, "Unsupported `json_class` type '#{json_class}'" + raise JSON::ParserError, "Unsupported `json_class` type '#{json_class}'" end end |