Skip to content

Commit 70613e3

Browse files
committed
fix(soap): respond with custom fault if status is 500 and content set.
1 parent ae29129 commit 70613e3

File tree

3 files changed

+91
-35
lines changed

3 files changed

+91
-35
lines changed

mock/soap/src/main/java/io/gatehill/imposter/plugin/soap/SoapPluginImpl.kt

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,9 @@ import io.gatehill.imposter.service.ResponseRoutingService
7272
import io.gatehill.imposter.service.ResponseService
7373
import io.gatehill.imposter.service.ResponseService.ResponseSender
7474
import io.gatehill.imposter.util.HttpUtil
75-
import io.gatehill.imposter.util.LogUtil
75+
import io.gatehill.imposter.util.LogUtil.describeRequestShort
7676
import io.gatehill.imposter.util.ResourceUtil
7777
import io.gatehill.imposter.util.completedUnitFuture
78-
import io.gatehill.imposter.util.makeFuture
7978
import io.vertx.core.Vertx
8079
import org.apache.logging.log4j.LogManager
8180
import java.io.File
@@ -229,26 +228,25 @@ class SoapPluginImpl @Inject constructor(
229228

230229
val defaultBehaviourHandler: DefaultBehaviourHandler = { responseBehaviour: ResponseBehaviour ->
231230
// set status code regardless of response strategy
232-
val response = httpExchange.response
233-
.setStatusCode(responseBehaviour.statusCode)
231+
httpExchange.response.setStatusCode(responseBehaviour.statusCode)
234232

235-
determineResponseMessage(responseBehaviour, operation)?.let { message ->
236-
LOGGER.trace("Using output schema type: {}", message)
233+
// build a response from the XSD
234+
val exampleSender = ResponseSender { httpExchange: HttpExchange, _: ResponseBehaviour ->
235+
determineResponseMessage(responseBehaviour, operation)?.let { message ->
236+
LOGGER.trace("Using output schema type: {}", message)
237237

238-
if (!responseBehaviour.responseHeaders.containsKey(HttpUtil.CONTENT_TYPE)) {
239-
responseBehaviour.responseHeaders[HttpUtil.CONTENT_TYPE] = when (bodyHolder) {
240-
is ParsedSoapMessage -> when (parser.version) {
241-
WsdlParser.WsdlVersion.V1 -> SoapUtil.soap11ContentType
242-
WsdlParser.WsdlVersion.V2 -> SoapUtil.soap12ContentType
243-
}
238+
if (!responseBehaviour.responseHeaders.containsKey(HttpUtil.CONTENT_TYPE)) {
239+
responseBehaviour.responseHeaders[HttpUtil.CONTENT_TYPE] = when (bodyHolder) {
240+
is ParsedSoapMessage -> when (parser.version) {
241+
WsdlParser.WsdlVersion.V1 -> SoapUtil.soap11ContentType
242+
WsdlParser.WsdlVersion.V2 -> SoapUtil.soap12ContentType
243+
}
244244

245-
is ParsedRawBody -> SoapUtil.textXmlContentType
246-
else -> throw IllegalStateException("Unsupported request body: ${bodyHolder::class.java.canonicalName}")
245+
is ParsedRawBody -> SoapUtil.textXmlContentType
246+
else -> throw IllegalStateException("Unsupported request body: ${bodyHolder::class.java.canonicalName}")
247+
}
247248
}
248-
}
249249

250-
// build a response from the XSD
251-
val exampleSender = ResponseSender { httpExchange: HttpExchange, _: ResponseBehaviour ->
252250
soapExampleService.serveExample(
253251
httpExchange,
254252
parser.schemaContext,
@@ -257,25 +255,18 @@ class SoapPluginImpl @Inject constructor(
257255
message,
258256
bodyHolder
259257
)
260-
}
261-
262-
// attempt to serve the example, falling back if not present
263-
return@let responseService.sendResponse(
264-
pluginConfig,
265-
resourceConfig,
266-
httpExchange,
267-
responseBehaviour,
268-
exampleSender,
269-
)
270-
271-
} ?: run {
272-
LOGGER.warn(
273-
"No output or fault definition found in WSDL for {} and status code {}",
274-
LogUtil.describeRequestShort(httpExchange),
275-
responseBehaviour.statusCode,
276-
)
277-
makeFuture { response.end() }
258+
} ?: return@ResponseSender false
278259
}
260+
261+
// attempt to serve the example, falling back if not present
262+
responseService.sendResponse(
263+
pluginConfig,
264+
resourceConfig,
265+
httpExchange,
266+
responseBehaviour,
267+
exampleSender,
268+
this::fallback,
269+
)
279270
}
280271

281272
val context = mutableMapOf(
@@ -305,4 +296,21 @@ class SoapPluginImpl @Inject constructor(
305296
else -> operation.outputRef
306297
}
307298
}
299+
300+
/**
301+
* Handles the scenario when no example is found.
302+
*
303+
* @param httpExchange the HTTP exchange
304+
* @param responseBehaviour the response behaviour
305+
*/
306+
private fun fallback(httpExchange: HttpExchange, responseBehaviour: ResponseBehaviour): Boolean {
307+
LOGGER.warn(
308+
"No output or fault definition found in WSDL for {} with status code {} and no response file or content set - sending empty response",
309+
describeRequestShort(httpExchange),
310+
responseBehaviour.statusCode,
311+
)
312+
// should this be a 400, as it's not in the WSDL?
313+
httpExchange.response.end()
314+
return true
315+
}
308316
}

mock/soap/src/test/java/io/gatehill/imposter/plugin/soap/FaultExampleTest.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,37 @@ class FaultExampleTest : BaseVerticleTest() {
9999
)
100100
}
101101

102+
@Test
103+
fun `respond with a custom fault if status is 500 and content set`() {
104+
val getPetByIdEnv = SoapUtil.wrapInEnv(
105+
"""
106+
<getPetByIdRequest xmlns="urn:com:example:petstore">
107+
<id>2</id>
108+
</getPetByIdRequest>
109+
""".trim(), soapEnvNamespace
110+
)
111+
112+
RestAssured.given()
113+
.log().ifValidationFails()
114+
.accept(soapContentType)
115+
.contentType(soapContentType)
116+
.`when`()
117+
.body(getPetByIdEnv)
118+
.post("/pets/")
119+
.then()
120+
.log().ifValidationFails()
121+
.statusCode(HttpUtil.HTTP_INTERNAL_ERROR)
122+
.body(
123+
Matchers.allOf(
124+
Matchers.containsString("Envelope"),
125+
Matchers.containsString("soap:Fault"),
126+
Matchers.containsString("code"),
127+
Matchers.containsString("description"),
128+
Matchers.containsString("Custom fault"),
129+
)
130+
)
131+
}
132+
102133
@Test
103134
fun `respond with a fault generated from the schema if response configuration set`() {
104135
val getPetByIdEnv = SoapUtil.wrapInEnv(

mock/soap/src/test/resources/fault-example/imposter-config.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@ resources:
77
response:
88
statusCode: 500
99

10+
- binding: SoapBinding
11+
operation: getPetById
12+
requestBody:
13+
xPath: //pets:id
14+
value: 2
15+
response:
16+
statusCode: 500
17+
content: |
18+
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
19+
<soap:Body>
20+
<soap:Fault>
21+
<code>2</code>
22+
<description>Custom fault</description>
23+
</soap:Fault>
24+
</soap:Body>
25+
</soap:Envelope>
26+
1027
- binding: SoapBinding
1128
operation: getPetById
1229
requestBody:

0 commit comments

Comments
 (0)