This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch coheigea/relative in repository https://gitbox.apache.org/repos/asf/ws-xmlschema.git
commit 1c3fcaf6c67f394dcac75315e44b8c8807c72c8d Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Thu Sep 24 12:37:29 2026 +0100 Check the file the parser opens for a relative schema location --- .../schema/resolver/DefaultURIResolver.java | 25 ++++++++++++++++++++-- .../test/java/tests/DefaultURIResolverTest.java | 19 ++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/DefaultURIResolver.java b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/DefaultURIResolver.java index 7ad19405..24d60ba4 100644 --- a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/DefaultURIResolver.java +++ b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/resolver/DefaultURIResolver.java @@ -31,6 +31,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; +import java.net.URLDecoder; import java.net.UnknownHostException; import java.security.AccessController; import java.security.PrivilegedAction; @@ -237,8 +238,8 @@ public class DefaultURIResolver implements CollectionURIResolver { + ALLOW_FILE_SYSTEM_PROPERTY + " has turned off."); } // The parser opens this against the working directory, so it is as much a local read - // as a file: URL and needs the same check. - verifyRegularFile(new File(schemaLocation), schemaLocation); + // as a file: URL and needs the same check, made on the file the parser will open. + verifyRegularFile(relativeLocationFile(schemaLocation), schemaLocation); return new InputSource(schemaLocation); } return null; @@ -587,6 +588,26 @@ public class DefaultURIResolver implements CollectionURIResolver { } } + /** + * The file the parser opens for a relative location with no base URI. It resolves the location + * as a URI against the working directory and opens the path of the result, so escapes are + * decoded and a query or fragment is dropped: <code>pip%65.xsd</code>, + * <code>pipe.xsd#x</code> and <code>pipe.xsd?x</code> all name the file <code>pipe.xsd</code>. + * Taking the location as a file name instead would check a file the parser never opens. + */ + private static File relativeLocationFile(String location) { + try { + final URL workingDirectory = new File("").getAbsoluteFile().toURI().toURL(); + // The parser takes a backslash in a system id as a path separator. + final URL resolved = new URL(workingDirectory, location.replace('\\', '/')); + // URLDecoder would read '+' as a space, which a URL path does not. + return new File(URLDecoder.decode(resolved.getPath().replace("+", "%2B"), "UTF-8")); + } catch (IOException | IllegalArgumentException e) { + // A malformed escape: the parser cannot open the location either. + return new File(location); + } + } + /** * The local file a <code>file:</code> URL names, or <code>null</code> if it cannot be mapped to * one. Null means the check above does not apply rather than that the location is safe; the diff --git a/xmlschema-core/src/test/java/tests/DefaultURIResolverTest.java b/xmlschema-core/src/test/java/tests/DefaultURIResolverTest.java index 0d76ea21..55eb7c4c 100644 --- a/xmlschema-core/src/test/java/tests/DefaultURIResolverTest.java +++ b/xmlschema-core/src/test/java/tests/DefaultURIResolverTest.java @@ -464,6 +464,25 @@ public class DefaultURIResolverTest extends Assert { assertSchemeRefused(".", null, "not a regular file"); } + /** + * The parser resolves a relative location as a URI, decoding escapes and dropping a query or + * fragment, so each of these names the directory "src" and must be checked as that. + */ + @Test + public void testARelativeLocationIsCheckedAsTheParserReadsIt() { + assertTrue(new File("src").isDirectory()); + assertSchemeRefused("sr%63", null, "not a regular file"); + assertSchemeRefused("src#fragment", null, "not a regular file"); + assertSchemeRefused("src?query", null, "not a regular file"); + } + + @Test + public void testARelativeRegularFileWithAFragmentStillResolves() { + assertEquals("pom.xml#fragment", + new DefaultURIResolver().resolveEntity("urn:x", "pom.xml#fragment", null) + .getSystemId()); + } + @Test public void testARelativeRegularOrMissingFileStillResolves() { assertTrue(new File("pom.xml").isFile());
