This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 0557edc90a89 CAMEL-24110: camel-xslt-saxon - fix saxonReaderProperties
null-guard, DOMSource URIResolver, unhardened SAXParser (#24779)
0557edc90a89 is described below
commit 0557edc90a89c7c123e47e4e8e5a1cda01478d46
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jul 16 15:39:18 2026 +0200
CAMEL-24110: camel-xslt-saxon - fix saxonReaderProperties null-guard,
DOMSource URIResolver, unhardened SAXParser (#24779)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
.../component/xslt/saxon/XsltSaxonEndpoint.java | 29 +++----
.../saxon/XsltSaxonUriResolverDomSourceTest.java | 92 ++++++++++++++++++++++
2 files changed, 107 insertions(+), 14 deletions(-)
diff --git
a/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonEndpoint.java
b/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonEndpoint.java
index 433c5bce381b..9f118760d367 100644
---
a/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonEndpoint.java
+++
b/components/camel-xslt-saxon/src/main/java/org/apache/camel/component/xslt/saxon/XsltSaxonEndpoint.java
@@ -270,9 +270,7 @@ public class XsltSaxonEndpoint extends XsltEndpoint {
InputStream is =
getCamelContext().getTypeConverter().mandatoryConvertTo(InputStream.class,
exchange, template);
XsltBuilder builder = createXsltBuilder();
Source source = new StreamSource(is);
- if (this.saxonReaderProperties != null) {
- //for Saxon we need to create XMLReader for the coming source
- //so that the features configuration can take effect
+ if (!this.saxonReaderProperties.isEmpty()) {
source = createReaderForSource(source);
}
builder.setTransformerSource(source);
@@ -290,23 +288,27 @@ public class XsltSaxonEndpoint extends XsltEndpoint {
protected void loadResource(String resourceUri, XsltBuilder xslt) throws
TransformerException, IOException {
LOG.trace("{} loading schema resource: {}", this, resourceUri);
Source source = xslt.getUriResolver().resolve(resourceUri, null);
- if (this.saxonReaderProperties != null) {
- //for Saxon we need to create XMLReader for the coming source
- //so that the features configuration can take effect
- source = createReaderForSource(source);
- }
if (source == null) {
throw new IOException("Cannot load schema resource " +
resourceUri);
- } else {
- xslt.setTransformerSource(source);
}
- // now loaded so clear flag
+ if (!this.saxonReaderProperties.isEmpty()) {
+ source = createReaderForSource(source);
+ }
+ xslt.setTransformerSource(source);
setCacheCleared(false);
}
private Source createReaderForSource(Source source) {
+ InputSource inputSource = SAXSource.sourceToInputSource(source);
+ if (inputSource == null) {
+ return source;
+ }
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl",
true);
+
factory.setFeature("http://xml.org/sax/features/external-general-entities",
false);
+
factory.setFeature("http://xml.org/sax/features/external-parameter-entities",
false);
SAXParser saxParser = factory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
@@ -317,7 +319,7 @@ public class XsltSaxonEndpoint extends XsltEndpoint {
URI uri = new URI(key);
if (value != null
&& (value.toString().equals("true") ||
(value.toString().equals("false")))) {
- xmlReader.setFeature(uri.toString(),
Boolean.valueOf(value.toString()));
+ xmlReader.setFeature(uri.toString(),
Boolean.parseBoolean(value.toString()));
} else if (value != null) {
xmlReader.setProperty(uri.toString(), value);
}
@@ -325,11 +327,10 @@ public class XsltSaxonEndpoint extends XsltEndpoint {
LOG.debug("{} isn't a valid URI, so ignore it", key);
}
}
- InputSource inputSource = SAXSource.sourceToInputSource(source);
return new SAXSource(xmlReader, inputSource);
} catch (SAXException | ParserConfigurationException e) {
LOG.info("Can't create XMLReader for source ", e);
- return null;
+ return source;
}
}
diff --git
a/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonUriResolverDomSourceTest.java
b/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonUriResolverDomSourceTest.java
new file mode 100644
index 000000000000..d147735b0025
--- /dev/null
+++
b/components/camel-xslt-saxon/src/test/java/org/apache/camel/component/xslt/saxon/XsltSaxonUriResolverDomSourceTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.xslt.saxon;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.dom.DOMSource;
+
+import org.w3c.dom.Document;
+
+import org.xml.sax.InputSource;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class XsltSaxonUriResolverDomSourceTest extends CamelTestSupport {
+
+ private static final String XSL = "<?xml version='1.0'?>"
+ + "<xsl:stylesheet
xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='2.0'>"
+ + " <xsl:output method='xml'
indent='yes'/>"
+ + " <xsl:template match='/'>"
+ + " <transformed><xsl:copy-of
select='*'/></transformed>"
+ + " </xsl:template>"
+ + "</xsl:stylesheet>";
+
+ @Test
+ public void testUriResolverReturningDomSource() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMessageCount(1);
+
+ template.sendBody("direct:start", "<hello>world</hello>");
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ String xml =
mock.getReceivedExchanges().get(0).getIn().getBody(String.class);
+ assertTrue(xml.contains("<transformed"), "Should contain transformed
element");
+ assertTrue(xml.contains("<hello>world</hello>"), "Should contain
original content");
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:start")
+ .to("xslt-saxon:dummy.xsl?uriResolver=#domResolver")
+ .to("mock:result");
+ }
+ };
+ }
+
+ @Override
+ protected void bindToRegistry(Registry registry) throws Exception {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document xslDoc = db.parse(new InputSource(new StringReader(XSL)));
+
+ URIResolver domResolver = new URIResolver() {
+ @Override
+ public Source resolve(String href, String base) throws
TransformerException {
+ return new DOMSource(xslDoc);
+ }
+ };
+
+ registry.bind("domResolver", domResolver);
+ }
+}