Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,27 @@

package org.apache.jmeter.save

import com.ctc.wstx.api.InvalidCharHandler
import com.ctc.wstx.api.WstxOutputProperties
import com.thoughtworks.xstream.io.xml.StaxDriver
import javax.xml.stream.XMLOutputFactory

public class JMeterStaxDriver(
public val xmlHeader: Boolean = true,
public val indent: Boolean = true,
) : StaxDriver() {
override fun createOutputFactory(): XMLOutputFactory =
XMLOutputFactoryDelegate(super.createOutputFactory(), xmlHeader = xmlHeader, indent = indent)
override fun createOutputFactory(): XMLOutputFactory {
val factory = super.createOutputFactory()
// Woodstox rejects XML 1.0-illegal characters (NUL, C0 controls) by default.
// Replace them so JTL/JMX save of binary payloads does not fail (#6761).
factory.setProperty(
WstxOutputProperties.P_OUTPUT_INVALID_CHAR_HANDLER,
InvalidCharHandler.ReplacingHandler(INVALID_XML_CHAR_REPLACEMENT)
)
return XMLOutputFactoryDelegate(factory, xmlHeader = xmlHeader, indent = indent)
}

private companion object {
const val INVALID_XML_CHAR_REPLACEMENT = ' '
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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.jmeter.save;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;

import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;

import org.apache.jmeter.junit.JMeterTestCase;
import org.apache.jmeter.samplers.SampleEvent;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.SampleSaveConfiguration;
import org.apache.jmeter.testelement.property.StringProperty;
import org.junit.jupiter.api.Test;

/**
* Regression for <a href="https://github.com/apache/jmeter/issues/6761">#6761</a>:
* Woodstox rejects characters that are illegal in XML 1.0 when saving JTL/JMX.
*/
public class SaveServiceInvalidXmlCharTest extends JMeterTestCase {

private static final String ILLEGAL_XML_CHARS = "pre\u0000mid\u001fsuf";

@Test
void saveSampleResultAllowsIllegalXmlCharsInSamplerData() {
SampleSaveConfiguration saveConfig = new SampleSaveConfiguration();
saveConfig.setSamplerData(true);

SampleResult result = new SampleResult();
result.setSaveConfig(saveConfig);
result.setSampleLabel("binary-body");
result.setSamplerData(ILLEGAL_XML_CHARS);

StringWriter writer = new StringWriter();
assertDoesNotThrow(() -> SaveService.saveSampleResult(new SampleEvent(result, "tg"), writer));

String xml = writer.toString();
assertFalse(xml.isEmpty(), "JTL output should not be empty");
assertFalse(xml.indexOf('\u0000') >= 0, "NUL must not appear in well-formed XML");
assertFalse(xml.indexOf('\u001f') >= 0, "C1 control 0x1F must not appear in XML 1.0");
}

@Test
void saveElementAllowsNulInStringProperty() {
StringProperty property = new StringProperty("bin", ILLEGAL_XML_CHARS);
ByteArrayOutputStream out = new ByteArrayOutputStream();
assertDoesNotThrow(() -> SaveService.saveElement(property, out));

String xml = out.toString(StandardCharsets.UTF_8);
assertFalse(xml.isEmpty(), "JMX fragment should not be empty");
assertFalse(xml.indexOf('\u0000') >= 0, "NUL must not appear in well-formed XML");
assertFalse(xml.indexOf('\u001f') >= 0, "C1 control 0x1F must not appear in XML 1.0");
}
}
1 change: 1 addition & 0 deletions xdocs/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ Summary
<li><issue>5937</issue>Remove deprecated Log4j package scanning and configure plugin metadata processing to improve startup time and avoid deprecation warnings. Contributed by Piotr P. Karwasz (github.com/piotrgithub)</li>
<li><pr>6620</pr>Fix report generation paths so dashboard output files are created in the correct location after internal refactoring.</li>
<li><bug>6456</bug>Handle malformed percent-encoded URLs gracefully when recording HTTP traffic, logging a warning instead of failing the recording.</li>
<li><issue>6761</issue>Allow XML save of sample results and test plans that contain characters illegal in XML 1.0 (NUL and C0 controls) after the Woodstox migration.</li>
</ul>
<!-- =================== Thanks =================== -->

Expand Down