XmlTransform() uses wrong working directory

Description

When using XmlTransform(), any relative paths in the XSL file (<xsl;include> or <xsl:import>) should be treated as relative to the XSL file's location.

In reality they are treated as relative to the installation location of Tomcat, which effectively breaks XSL includes, which in turn severely limits the usefulness of the XmlTransform().

(This relates to LDEV-228, where a similar issue was reported, but it was reported years ago for an older version of Lucee, without pointing out the reason for the error, and not much became of the ticket.)

Environment

Reproduced with Lucee 5.2.9.31 w/ Tomcat 8.5 on Windows
(I'm pretty sure this affects all versions on all Platforms though)

Activity

Martin Böhm 6 February 2019 at 14:15
Edited

After skimming the code that does this in the Lucee GitHub repository:

/src/main/java/lucee/runtime/text/xml/XMLUtil.java:1068

The point where it all goes wrong is in toInputSource().

When the code sees an XSL document referenced through as a File or file path, it opens this file, reads its text and constructs an InputSource from that text. After that the Transformer has no way to resolve any paths inside the XSL anymore, because there is no indication that the XSL code once was a file. Lacking any better context it uses the working directory of the parent process/thread instead as the root for any relative paths.

What needs to happen instead: Construct an InputSource from the file and set its system ID to that file. Simplified example:

File inputFile = new File(path); StringWriter sw = new StringWriter(); StreamSource ss = new StreamSource(new FileInputStream(inputFile)); ss.setSystemId(inputFile); transformer.transform(ss, new StreamResult(sw));

This way the context is maintained and the Transformer will do the right thing on its own. For org.xml.sax.InputSource instances that refer to files, the system ID must be the absolute URI (string) of the file.

There is a tightly related bug in there which should be fixed the same go. This is wrong:

if (value instanceof InputStream) { InputStream is = (InputStream)value; try { String str = IOUtil.toString(is, (Charset)null); return new InputSource(new StringReader(str)); }

It's impossible to read text files into a string safely without knowing their encoding. This is guaranteed to go wrong for all but the simplest cases.

File-based InputSource objects must be constructed using a byte stream. The XSL processor will determine the byte encoding on its own.

Details

Assignee

Reporter

Priority

Labels

New Issue warning screen

Before you create a new Issue, please post to the mailing list first https://dev.lucee.org

Once the issue has been verified, one of the Lucee team will ask you to file an issue

Affects versions

Created 6 February 2019 at 12:40
Updated 19 May 2021 at 11:19