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());

Reply via email to