This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/commons-secure-xml.git
The following commit(s) were added to refs/heads/main by this push:
new a06bb68 Forward getExternalSubset to a caller EntityResolver2 (#68)
a06bb68 is described below
commit a06bb687673c218053c5075ce6fb3a06948e3770
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Tue Sep 1 13:23:41 2026 +0200
Forward getExternalSubset to a caller EntityResolver2 (#68)
The entity-resolver floor inherited DefaultHandler2's always-null
getExternalSubset, so a caller resolver installed through
setEntityResolver never had its synthetic external subset consulted and
DOCTYPE-less documents parsed without the declarations the caller
supplied. Forward the call to an EntityResolver2 delegate; without one
the "no synthetic subset" default stands. A null return means the parse
continues without a subset, not that a resource went unresolved, so the
ignore fallback stays out of this path.
Assisted-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CLnTBsvmYtxzNTWVGNyz33
---
.../xml/secure/FallbackIgnoreEntityResolver2.java | 11 ++++++-----
.../xml/secure/FallbackIgnoreEntityResolver2Test.java | 18 ++++++++++++++++++
2 files changed, 24 insertions(+), 5 deletions(-)
diff --git
a/src/main/java/org/apache/commons/xml/secure/FallbackIgnoreEntityResolver2.java
b/src/main/java/org/apache/commons/xml/secure/FallbackIgnoreEntityResolver2.java
index aa840a6..5fc2575 100644
---
a/src/main/java/org/apache/commons/xml/secure/FallbackIgnoreEntityResolver2.java
+++
b/src/main/java/org/apache/commons/xml/secure/FallbackIgnoreEntityResolver2.java
@@ -47,11 +47,6 @@
* resolver; anything they leave unresolved (a {@code null} return, or no
caller resolver at all) goes to {@link #onUnresolved}, which returns empty
content by
* default.
* </p>
- * <p>
- * It extends {@link DefaultHandler2} so it is also usable as a {@link
org.xml.sax.ext.LexicalHandler}; {@link #getExternalSubset} therefore inherits
the
- * {@code DefaultHandler2} "no synthetic subset" default. Only {@link
#resolveEntity(String, String, String, String) resolveEntity} (the actual
external fetch)
- * reaches the ignore fallback.
- * </p>
*/
class FallbackIgnoreEntityResolver2 extends DefaultHandler2 {
@@ -99,6 +94,12 @@ final EntityResolver getDelegate() {
return delegate;
}
+ @Override
+ public final InputSource getExternalSubset(final String name, final String
baseURI) throws SAXException, IOException {
+ // A null return means "no synthetic subset", not "unresolved",
nothing is fetched.
+ return delegate instanceof EntityResolver2 ? ((EntityResolver2)
delegate).getExternalSubset(name, baseURI) : null;
+ }
+
/**
* Outcome when neither the caller delegate nor this resolver provides the
entity. Resolves to empty content by default, so the external resource is
neither
* fetched nor leaked and the parse continues with no replacement text.
The returned source echoes the requested identifiers (with {@code systemId}
diff --git
a/src/test/java/org/apache/commons/xml/secure/FallbackIgnoreEntityResolver2Test.java
b/src/test/java/org/apache/commons/xml/secure/FallbackIgnoreEntityResolver2Test.java
index 2148ae4..18b71f3 100644
---
a/src/test/java/org/apache/commons/xml/secure/FallbackIgnoreEntityResolver2Test.java
+++
b/src/test/java/org/apache/commons/xml/secure/FallbackIgnoreEntityResolver2Test.java
@@ -19,6 +19,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -31,6 +32,23 @@
class FallbackIgnoreEntityResolver2Test {
+ @Test
+ void forwardsGetExternalSubsetOnlyToExtendedDelegates() throws Exception {
+ final FallbackIgnoreEntityResolver2 floor = new
FallbackIgnoreEntityResolver2(null);
+ assertNull(floor.getExternalSubset("name",
"https://example.test/base/"));
+ floor.setDelegate((publicId, systemId) -> new InputSource());
+ assertNull(floor.getExternalSubset("name",
"https://example.test/base/"));
+ final InputSource expected = new InputSource();
+ floor.setDelegate(new DefaultHandler2() {
+
+ @Override
+ public InputSource getExternalSubset(final String name, final
String baseURI) {
+ return expected;
+ }
+ });
+ assertSame(expected, floor.getExternalSubset("name",
"https://example.test/base/"));
+ }
+
@Test
void resolvesDelegatesAndAllFallbackPaths() throws Exception {
final FallbackIgnoreEntityResolver2 floor = new
FallbackIgnoreEntityResolver2(null);