diff --git a/lib/json-schema/schema.rb b/lib/json-schema/schema.rb index 2bafd18a..d7fc482f 100644 --- a/lib/json-schema/schema.rb +++ b/lib/json-schema/schema.rb @@ -2,23 +2,11 @@ module JSON class Schema - attr_accessor :schema, :uri, :validator - def initialize(schema,uri,parent_validator=nil) + def initialize(schema, uri, parent_validator = nil) @schema = self.class.stringify(schema) - @uri = uri - - # If there is an ID on this schema, use it to generate the URI - if @schema['id'] && @schema['id'].kind_of?(String) - temp_uri = URI.parse(@schema['id']) - if temp_uri.relative? - uri = uri.merge(@schema['id']) - temp_uri = uri - end - @uri = temp_uri - end - @uri.fragment = '' + @uri = generate_schema_uri(uri) # If there is a $schema on this schema, use it to determine which validator to use if @schema['$schema'] @@ -50,14 +38,23 @@ def self.stringify(schema) end def base_uri - parts = @uri.to_s.split('/') - parts.pop - parts.join('/') + '/' + @uri.merge(File.dirname(@uri.path)).to_s end def to_s @schema.to_json end + + private + + def generate_schema_uri(uri) + schema_uri = uri.merge('#') # Drop fragment if present + return schema_uri unless @schema['id'] && @schema['id'].kind_of?(String) + + id_uri = URI.parse(@schema['id']) + return id_uri unless id_uri.relative? + + schema_uri.merge(id_uri.path) + end end end - diff --git a/lib/json-schema/validator.rb b/lib/json-schema/validator.rb index da880290..0fc2f0b7 100644 --- a/lib/json-schema/validator.rb +++ b/lib/json-schema/validator.rb @@ -499,10 +499,14 @@ def serialize schema end end - def fake_uuid schema + def fake_uuid(schema) @@fake_uuid_generator.call(schema) end + def fake_uri_for_schema(schema) + URI::Generic.build(:scheme => "urn", :opaque => "uuid:#{fake_uuid(schema)}") + end + def schema_to_list(schema) new_schema = {"type" => "array", "items" => schema} if !schema["$schema"].nil? @@ -516,7 +520,7 @@ def initialize_schema(schema) if schema.is_a?(String) begin # Build a fake URI for this - schema_uri = URI.parse(fake_uuid(schema)) + schema_uri = fake_uri_for_schema(schema) schema = JSON::Validator.parse(schema) if @options[:list] && @options[:fragment].nil? schema = schema_to_list(schema) @@ -537,7 +541,7 @@ def initialize_schema(schema) schema = Validator.schemas[schema_uri.to_s] if @options[:list] && @options[:fragment].nil? schema = schema_to_list(schema.schema) - schema_uri = URI.parse(fake_uuid(serialize(schema))) + schema_uri = fake_uri_for_schema(serialize(schema)) schema = JSON::Schema.new(schema, schema_uri, @options[:version]) Validator.add_schema(schema) end @@ -548,7 +552,7 @@ def initialize_schema(schema) if @options[:list] && @options[:fragment].nil? schema = schema_to_list(schema) end - schema_uri = URI.parse(fake_uuid(serialize(schema))) + schema_uri = fake_uri_for_schema(serialize(schema)) schema = JSON::Schema.new(schema,schema_uri,@options[:version]) Validator.add_schema(schema) else diff --git a/test/test_bad_schema_ref.rb b/test/test_bad_schema_ref.rb index af004eec..b1d4761d 100644 --- a/test/test_bad_schema_ref.rb +++ b/test/test_bad_schema_ref.rb @@ -16,12 +16,12 @@ def test_bad_uri_ref schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "type" => "array", - "items" => { "$ref" => "../google.json"} + "items" => { "$ref" => "{bad-scheme}://foo.com"} } data = [1,2,3] - assert_raises(URI::BadURIError) do - JSON::Validator.validate(schema,data) + assert_raises(URI::InvalidURIError) do + JSON::Validator.validate(schema, data) end end diff --git a/test/test_list_option.rb b/test/test_list_option.rb index 47da250b..64cb41e6 100644 --- a/test/test_list_option.rb +++ b/test/test_list_option.rb @@ -8,7 +8,7 @@ def test_list_option_reusing_schemas "properties" => { "a" => { "type" => "integer" } } } - uri = URI.parse('http://example.com/item') + uri = URI.parse('http://example.com/item#') schema = JSON::Schema.new(schema_hash, uri) JSON::Validator.add_schema(schema) diff --git a/test/test_schema_validation.rb b/test/test_schema_validation.rb index 940715e4..39132561 100644 --- a/test/test_schema_validation.rb +++ b/test/test_schema_validation.rb @@ -36,6 +36,14 @@ def valid_schema_v4 } end + def valid_schema_v4_with_fragment_id + valid_schema_v4.merge("id" => "#/foo") + end + + def valid_schema_v4_with_absolute_uri_id + valid_schema_v4.merge("id" => "http://www.example.invalid/#/foo") + end + def invalid_schema_v4 { "$schema" => "http://json-schema.org/draft-04/schema#", @@ -142,6 +150,8 @@ def test_draft04_validation data = {"b" => {"a" => 5}} assert(JSON::Validator.validate(valid_schema_v4,data,:validate_schema => true, :version => :draft4)) assert(!JSON::Validator.validate(invalid_schema_v4,data,:validate_schema => true, :version => :draft4)) + assert(JSON::Validator.validate(valid_schema_v4_with_fragment_id,data,:validate_schema => true, :version => :draft4)) + assert(JSON::Validator.validate(valid_schema_v4_with_absolute_uri_id,data,:validate_schema => true, :version => :draft4)) end def test_validate_just_schema_draft04