I'm using WSS4j CXF Out Interceptor in MULE to sign the SOAP response but if there is an error in this interceptor the SOAPFault is not generated properly. In fact the result is a blank body with status 200.
Problem:
If the out interceptor used to sign (WSS4JOutInterceptor) fails, it does not generates a proper SOAPFault (with status code 400/500) due to is executed in PRE_PROTOCOL and the http.status and response headers have already been written in the HttpResponse.
Cause The SOAPFault is generated in a last phase in the interceptor chain (interceptor chain) so the HttpConnection is already open and the HttpResponse is being written, headers and status are set.
Detail
Mule version: 3.6.1 CE CXF version: 2.5.9 WSS4j: 1.6.9
JVM: JDK7
The CXF inbound enpoint in mule calls to CxfInboundMessageProcessor. This class create the Exchange to execute the input interceptor chain , the mule flow and finally the output interceptor chain .
The most important phases that causes this error are the following:
- PREPARE_SEND Opening of the connection
- PRE_STREAM
- PRE_PROTOCOL Misc protocol actions.->Here is executed *WSS4jOutInterceptor**
The output interceptor chain is executed in two phases, the mule interceptor MuleProtocolHeadersOutInterceptor (PRE_STREAM) pauses it. The rest of the output interceptor chain is executed when the HttpResponse is fully created.
When it is paused the execution return back to the first class CxfInboundMessageProcessor.
it is after that when the response is going to be created:
MuleMessage muleResMsg = responseEvent.getMessage(); muleResMsg.setPayload(getResponseOutputHandler(m));
The interface org.mule.api.transport.OutputHandler is used to delegate the SOAP object creation until the org.mule.transport.http.ResponseWriter is executed:
OutputHandler: Here it can see how the method write continues with the output chain:
public void write(MuleEvent event, OutputStream out) throws IOException
{
Message outFaultMessage = m.getExchange().getOutFaultMessage();
Message outMessage = m.getExchange().getOutMessage();
Message contentMsg = null;
if (outFaultMessage != null && outFaultMessage.getContent(OutputStream.class) != null)
{
contentMsg = outFaultMessage;
}
else if (outMessage != null)
{
contentMsg = outMessage;
}
if (contentMsg == null)
{
return;
}
DelegatingOutputStream delegate = contentMsg.getContent(DelegatingOutputStream.class);
if (delegate.getOutputStream() instanceof ByteArrayOutputStream)
{
out.write(((ByteArrayOutputStream) delegate.getOutputStream()).toByteArray());
}
delegate.setOutputStream(out);
out.flush();
contentMsg.getInterceptorChain().resume();
}
org.mule.transport.http.HttpServerConnection
public void writeResponse(final HttpResponse response, Map<String,String> headers) throws IOException
{
if (response == null)
{
return;
}
if (!response.isKeepAlive())
{
Header header = new Header(HttpConstants.HEADER_CONNECTION, "close");
response.setHeader(header);
}
setKeepAlive(response.isKeepAlive());
addHeadersToHttpResponse(response, headers);
ResponseWriter writer = new ResponseWriter(this.out, encoding);
OutputStream outstream = this.out;
writer.println(response.getStatusLine());
Iterator item = response.getHeaderIterator();
while (item.hasNext())
{
Header header = (Header) item.next();
writer.print(header.toExternalForm());
}
writer.println();
writer.flush();
OutputHandler content = response.getBody();
if (content != null)
{
Header transferenc = response.getFirstHeader(HttpConstants.HEADER_TRANSFER_ENCODING);
if (transferenc != null)
{
response.removeHeaders(HttpConstants.HEADER_CONTENT_LENGTH);
if (transferenc.getValue().indexOf(HttpConstants.TRANSFER_ENCODING_CHUNKED) != -1)
{
outstream = new ChunkedOutputStream(outstream);
}
}
content.write(RequestContext.getEvent(), outstream);
if (outstream instanceof ChunkedOutputStream)
{
((ChunkedOutputStream) outstream).finish();
}
}
outstream.flush();
}
And here after httpResponse creation and set the headers is when the "body" is generated: