The writePayload method (reproduced below) can be asked to pretty print XML of any size, causing (I think) at least three copies of potentially huge XML in memory. The problem is that the limit is applied after the XML is formatted (which it has to be, otherwise the data wouldn't be valid XML and wouldn't be formattable). Also, swriter.toString is called twice - which I assume means two more copies of the data.

Would it be safer to disable pretty printing if cos.size() > limit ?
Or even to have a separate limit just for this purpose (i.e. never pretty print more than 10MB unless the user has set limit >10MB).

As a side issue, two copies of the data could be removed by accessing the StringBuffer directly rather than calling toString (example at the end of this email), but I think the danger is with doing any pretty printing of an unknown size.

Happy to submit a patch if folks agree it's an issue.

Jim

protected void writePayload(StringBuilder builder, CachedOutputStream cos, String encoding, String contentType)
        throws Exception {
        // Just transform the XML message when the cos has content
if (isPrettyLogging() && (contentType != null && contentType.indexOf("xml") >= 0) && cos.size() > 0) {
            Transformer serializer = XMLUtils.newTransformer(2);
            // Setup indenting to "pretty print"
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount";, "2");

            StringWriter swriter = new StringWriter();
serializer.transform(new StreamSource(cos.getInputStream()), new StreamResult(swriter));
            String result = swriter.toString();
            if (result.length() < limit || limit == -1) {
                builder.append(swriter.toString());
            } else {
                builder.append(swriter.toString().substring(0, limit));
            }
        } else {
            if (StringUtils.isEmpty(encoding)) {
                cos.writeCacheTo(builder, limit);
            } else {
                cos.writeCacheTo(builder, encoding, limit);
            }
        }
    }


Change to remove calls to toString():
            StringBuffer swBuffer = swriter.getBuffer();
            if (swBuffer.length() < limit || limit == -1) {
                builder.append(swBuffer.toString());
            } else {
                builder.append(swBuffer.substring(0, limit));
            }

Reply via email to