Skip to content

Commit 366c59c

Browse files
authored
Merge pull request #1429 from WebFuzzing/phg/objectMapper-v2
Add ObjectMapper unescaping ASCII control characters when using DTOs
2 parents d91bd0f + 386f715 commit 366c59c

File tree

6 files changed

+38
-24
lines changed

6 files changed

+38
-24
lines changed

core/src/main/kotlin/org/evomaster/core/output/dto/DtoOutput.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.evomaster.core.output.dto
22

3-
import org.evomaster.core.output.Lines
43
import org.evomaster.core.output.OutputFormat
54
import java.nio.file.Path
65

@@ -12,12 +11,14 @@ import java.nio.file.Path
1211
interface DtoOutput {
1312

1413
/**
14+
* Writes a DTO class in the corresponding [org.evomaster.core.output.OutputFormat].
15+
*
16+
* @param outputFormat under which the java class must be written
1517
* @param testSuitePath under which the java class must be written
1618
* @param testSuitePackage under which the java class must be written
17-
* @param outputFormat forwarded to the [Lines] helper class and for setting the .java extension in the generated file
1819
* @param dtoClass to be written to filesystem
1920
*/
20-
fun writeClass(testSuitePath: Path, testSuitePackage: String, outputFormat: OutputFormat, dtoClass: DtoClass)
21+
fun writeClass(outputFormat: OutputFormat, testSuitePath: Path, testSuitePackage: String, dtoClass: DtoClass)
2122

2223
/**
2324
* @param dtoName that will be instantiated for payload

core/src/main/kotlin/org/evomaster/core/output/dto/DtoWriter.kt

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,24 +49,13 @@ class DtoWriter(
4949

5050
fun write(testSuitePath: Path, testSuitePackage: String, solution: Solution<*>) {
5151
calculateDtos(solution)
52+
val dtoOutput = when {
53+
outputFormat.isJava() -> JavaDtoOutput()
54+
outputFormat.isKotlin() -> KotlinDtoOutput()
55+
else -> throw IllegalStateException("$outputFormat output format does not support DTOs as request payloads.")
56+
}
5257
dtoCollector.forEach {
53-
when {
54-
outputFormat.isJava() -> JavaDtoOutput().writeClass(
55-
testSuitePath,
56-
testSuitePackage,
57-
outputFormat,
58-
it.value
59-
)
60-
61-
outputFormat.isKotlin() -> KotlinDtoOutput().writeClass(
62-
testSuitePath,
63-
testSuitePackage,
64-
outputFormat,
65-
it.value
66-
)
67-
68-
else -> throw IllegalStateException("$outputFormat output format does not support DTOs as request payloads.")
69-
}
58+
dtoOutput.writeClass(outputFormat, testSuitePath, testSuitePackage, it.value)
7059
}
7160
}
7261

core/src/main/kotlin/org/evomaster/core/output/dto/JavaDtoOutput.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import java.nio.file.Path
88

99
class JavaDtoOutput: JvmDtoOutput() {
1010

11-
override fun writeClass(testSuitePath: Path, testSuitePackage: String, outputFormat: OutputFormat, dtoClass: DtoClass) {
11+
override fun writeClass(outputFormat: OutputFormat, testSuitePath: Path, testSuitePackage: String, dtoClass: DtoClass) {
1212
val dtoFilename = TestSuiteFileName(appendDtoPackage(dtoClass.name))
1313
val lines = Lines(outputFormat)
1414
setPackage(lines, testSuitePackage)
@@ -81,4 +81,5 @@ class JavaDtoOutput: JvmDtoOutput() {
8181
lines.addEmpty()
8282
}
8383
}
84+
8485
}

core/src/main/kotlin/org/evomaster/core/output/dto/KotlinDtoOutput.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import java.nio.file.Path
77

88
class KotlinDtoOutput: JvmDtoOutput() {
99

10-
override fun writeClass(testSuitePath: Path, testSuitePackage: String, outputFormat: OutputFormat, dtoClass: DtoClass) {
10+
override fun writeClass(outputFormat: OutputFormat, testSuitePath: Path, testSuitePackage: String, dtoClass: DtoClass) {
1111
val dtoFilename = TestSuiteFileName(appendDtoPackage(dtoClass.name))
1212
val lines = Lines(outputFormat)
1313
setPackage(lines, testSuitePackage)

core/src/main/kotlin/org/evomaster/core/output/service/HttpWsTestCaseWriter.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import org.evomaster.core.output.auth.CookieWriter
1111
import org.evomaster.core.output.auth.TokenWriter
1212
import org.evomaster.core.output.dto.DtoCall
1313
import org.evomaster.core.output.dto.GeneToDto
14+
import org.evomaster.core.output.formatter.OutputFormatter
1415
import org.evomaster.core.problem.enterprise.EnterpriseActionGroup
1516
import org.evomaster.core.problem.externalservice.httpws.HttpExternalServiceAction
1617
import org.evomaster.core.problem.httpws.HttpWsAction
@@ -123,8 +124,7 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
123124

124125
private fun writeDto(call: HttpWsAction, lines: Lines): String {
125126
val bodyParam = call.parameters.find { p -> p is BodyParam } as BodyParam?
126-
if (bodyParam != null && bodyParam.isJson()) {
127-
127+
if (bodyParam != null && bodyParam.isJson() && payloadIsValidJson(bodyParam)) {
128128
val primaryGene = bodyParam.primaryGene()
129129
val choiceGene = primaryGene.getWrappedGene(ChoiceGene::class.java)
130130
val actionName = call.getName()
@@ -147,6 +147,15 @@ abstract class HttpWsTestCaseWriter : ApiTestCaseWriter() {
147147
return ""
148148
}
149149

150+
/*
151+
* Control characters break JSON and transform it into an invalid payload. If there's any invalid character
152+
* then we'll avoid using DTOs and have the payload in the test case be represented by the raw JSON string.
153+
*/
154+
private fun payloadIsValidJson(bodyParam: BodyParam): Boolean {
155+
val json = bodyParam.getValueAsPrintableString(mode = GeneUtils.EscapeMode.JSON, targetFormat = format)
156+
return OutputFormatter.JSON_FORMATTER.isValid(json)
157+
}
158+
150159
private fun generateDtoCall(gene: Gene, actionName: String, lines: Lines): DtoCall {
151160
val geneToDto = GeneToDto(format)
152161

core/src/test/kotlin/org/evomaster/core/output/formatter/OutputFormatterTest.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,5 +151,19 @@ class OutputFormatterTest {
151151
assertFalse(isValid)
152152
}
153153

154+
@Test
155+
fun testInvalidJsonWithAsciiControlCharacter() {
156+
val json = " {\"s0\":\"This is a long string\", \"s1\":\"This isa long string\", \"s2\":\"_EM_3149_XYZ_\"} "
157+
val isValid = OutputFormatter.JSON_FORMATTER.isValid(json)
158+
assertFalse(isValid)
159+
}
160+
161+
@Test
162+
fun testValidJsonWithEscapedAsciiControlCharacter() {
163+
val json = " {\"s0\":\"This is a long string\", \"s1\":\"This is\\u001Fa long string\", \"s2\":\"_EM_3149_XYZ_\"} "
164+
val isValid = OutputFormatter.JSON_FORMATTER.isValid(json)
165+
assertTrue(isValid)
166+
}
167+
154168

155169
}

0 commit comments

Comments
 (0)