summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordanielsdeleo <dan@opscode.com>2013-02-12 10:57:07 -0800
committerdanielsdeleo <dan@opscode.com>2013-02-12 10:57:07 -0800
commit453e99906edb6a737768b69bc74262b37e266bd6 (patch)
treecb53909a8bbd773fa5d98989734ecd5e839d2d77
parentc7e99e50b1b9bba72b3fd907e1fb3748b901eeee (diff)
downloadchef-453e99906edb6a737768b69bc74262b37e266bd6.tar.gz
[CHEF-3863] improve error compat with old impl.
-rw-r--r--lib/chef/json_compat.rb20
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