1 /* 2 * Copyright (c) 2024 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.networknt.schema; 17 18 import java.net.URI; 19 import java.net.URISyntaxException; 20 21 /** 22 * Validator for validating the correctness of $id. 23 */ 24 public interface JsonSchemaIdValidator { 25 /** 26 * Validates if the $id value is valid. 27 * 28 * @param id the $id or id 29 * @param rootSchema true if this is a root schema 30 * @param schemaLocation the schema location 31 * @param resolvedSchemaLocation the schema location after resolving with the id 32 * @param validationContext the validation context for instance to get the 33 * meta schema 34 * @return true if valid 35 */ validate(String id, boolean rootSchema, SchemaLocation schemaLocation, SchemaLocation resolvedSchemaLocation, ValidationContext validationContext)36 boolean validate(String id, boolean rootSchema, SchemaLocation schemaLocation, 37 SchemaLocation resolvedSchemaLocation, ValidationContext validationContext); 38 39 public static final JsonSchemaIdValidator DEFAULT = new DefaultJsonSchemaIdValidator(); 40 41 /** 42 * Implementation of {@link JsonSchemaIdValidator}. 43 * <p> 44 * Note that this does not strictly follow the specification. 45 * <p> 46 * This allows an $id that isn't an absolute-IRI on the root schema but it must 47 * resolve to an absolute-IRI given a base-IRI. 48 * <p> 49 * This also allows non-empty fragments. 50 */ 51 public static class DefaultJsonSchemaIdValidator implements JsonSchemaIdValidator { 52 @Override validate(String id, boolean rootSchema, SchemaLocation schemaLocation, SchemaLocation resolvedSchemaLocation, ValidationContext validationContext)53 public boolean validate(String id, boolean rootSchema, SchemaLocation schemaLocation, 54 SchemaLocation resolvedSchemaLocation, ValidationContext validationContext) { 55 if (hasNoContext(schemaLocation)) { 56 // The following are non-standard 57 if (isFragment(id) || startsWithSlash(id)) { 58 return true; 59 } 60 } 61 return resolvedSchemaLocation.getAbsoluteIri() != null 62 && isAbsoluteIri(resolvedSchemaLocation.getAbsoluteIri().toString()); 63 } 64 startsWithSlash(String id)65 protected boolean startsWithSlash(String id) { 66 return id.startsWith("/"); 67 } 68 isFragment(String id)69 protected boolean isFragment(String id) { 70 return id.startsWith("#"); 71 } 72 hasNoContext(SchemaLocation schemaLocation)73 protected boolean hasNoContext(SchemaLocation schemaLocation) { 74 return schemaLocation.getAbsoluteIri() == null || schemaLocation.toString().startsWith("#"); 75 } 76 isAbsoluteIri(String iri)77 protected boolean isAbsoluteIri(String iri) { 78 if (!iri.contains(":")) { 79 return false; // quick check 80 } 81 try { 82 new URI(iri); 83 } catch (URISyntaxException e) { 84 return false; 85 } 86 return true; 87 } 88 } 89 } 90