From 1aeea15fce3a8cb37db620b3e86c14c07089ebfb Mon Sep 17 00:00:00 2001 From: Justin Tay <49700559+justin-tay@users.noreply.github.com> Date: Tue, 28 Jan 2025 11:35:46 +0800 Subject: [PATCH] Fix relative iris with colons --- .../com/networknt/schema/AbsoluteIri.java | 23 +++++++++++- .../com/networknt/schema/AbsoluteIriTest.java | 36 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/networknt/schema/AbsoluteIri.java b/src/main/java/com/networknt/schema/AbsoluteIri.java index 3c4075c08..1ade74363 100644 --- a/src/main/java/com/networknt/schema/AbsoluteIri.java +++ b/src/main/java/com/networknt/schema/AbsoluteIri.java @@ -76,6 +76,27 @@ protected String getSchemeAuthority() { return getSchemeAuthority(this.value); } + /** + * Determines if the iri is absolute or relative. + * + * @param iri to determine + * @return true if absolute + */ + private static boolean isAbsoluteIri(String iri) { + int length = iri.length(); + for (int x = 0; x < length; x++) { + char ch = iri.charAt(x); + if (ch == ':') { + // if the first segment is relative with a colon it must be a dot path segment + // ie. ./foo:bar + return true; + } else if (ch == '/' || ch == '?' || ch == '#') { + return false; + } + } + return false; + } + /** * Constructs a new IRI by parsing the given string and then resolving it * against this IRI. @@ -85,7 +106,7 @@ protected String getSchemeAuthority() { * @return the new absolute IRI */ public static String resolve(String parent, String iri) { - if (iri.contains(":")) { + if (isAbsoluteIri(iri)) { // IRI is absolute return iri; } else { diff --git a/src/test/java/com/networknt/schema/AbsoluteIriTest.java b/src/test/java/com/networknt/schema/AbsoluteIriTest.java index 172883150..c07860d82 100644 --- a/src/test/java/com/networknt/schema/AbsoluteIriTest.java +++ b/src/test/java/com/networknt/schema/AbsoluteIriTest.java @@ -33,6 +33,30 @@ void resolveNull() { assertEquals("test.json", iri.resolve("test.json").toString()); } + @Test + void relativeColonDotPathSegment() { + AbsoluteIri iri = new AbsoluteIri("http://www.example.org/foo/bar.json"); + assertEquals("http://www.example.org/foo/foo:bar", iri.resolve("./foo:bar").toString()); + } + + @Test + void relativeColonSecondSegment() { + AbsoluteIri iri = new AbsoluteIri("http://www.example.org/foo/bar.json"); + assertEquals("http://www.example.org/foo/bar/foo:bar", iri.resolve("bar/foo:bar").toString()); + } + + @Test + void relativeColonQueryString() { + AbsoluteIri iri = new AbsoluteIri("http://www.example.org/foo/bar.json"); + assertEquals("http://www.example.org/foo/test.json?queryParam=foo:bar", iri.resolve("test.json?queryParam=foo:bar").toString()); + } + + @Test + void relativeColonAnchor() { + AbsoluteIri iri = new AbsoluteIri("http://www.example.org/foo/bar.json"); + assertEquals("http://www.example.org/foo/test.json#foo:bar", iri.resolve("test.json#foo:bar").toString()); + } + @Test void relativeAtDocument() { AbsoluteIri iri = new AbsoluteIri("http://www.example.org/foo/bar.json"); @@ -93,6 +117,18 @@ void relativeParentWithSchemeSpecificPart() { assertEquals("classpath:resource/test.json", iri.resolve("../../test.json").toString()); } + @Test + void rootColonDotPathSegment() { + AbsoluteIri iri = new AbsoluteIri("http://www.example.org/foo/bar.json"); + assertEquals("http://www.example.org/foo:bar", iri.resolve("/foo:bar").toString()); + } + + @Test + void rootColonSecondSegment() { + AbsoluteIri iri = new AbsoluteIri("http://www.example.org/foo/bar.json"); + assertEquals("http://www.example.org/bar/foo:bar", iri.resolve("/bar/foo:bar").toString()); + } + @Test void rootAbsoluteAtDocument() { AbsoluteIri iri = new AbsoluteIri("http://www.example.org/foo/bar.json");