Make MTOM Optional - web-services

I am exposing a SOAP service using Tomcat, Apache CXF and Spring Boot. The web service has MTOM enabled and it works as expected when testing it from SOAP UI.
The problem is that when I try to get the message with MTOM disabled from SOAP UI, I still get the message with an XOP attachment. The options from SOAP UI that I use are: Enable MTOM: false; Force MTOM: false.
I have tried to set the Accept header on the request to application/xml instead of application/xop+xml, but I still get the same thing.
The only time when I get the Byte64 stream is when I test with a file which is smaller than the threshold that I've set:
#MTOM(enabled = true, threshold = 2048)
What I would need is MTOM to be optional when it is set to enabled and to depend on the request, not only on the threshold, could this be a problem with SOAP UI or does my current configuration ignore the request parameters?
I need this because some clients of the web service don't support MTOM.
Here is the object I return from the exposed method:
public class Document {
private DataHandler fileData;
public DataHandler getFileData() {
return fileData;
}
public void setFileData(DataHandler fileData) {
this.fileData = fileData;
}
}

You can't control from the client whether you want the server to respond with an xop attachment or without.
JAX-WS, and I think none of its implementations such as CXF for example, care about the Accept header since it's not specified in the SOAP specifications that the server has to read if from the request, nor which value it should write on the response. So it makes no difference if you put application/xml or text/xml or any other.
If the server has MTOM enabled it must always (as long as it falls into the threshold range) send back a soap response using MTOM.
The options from SOAP UI that I use are: Enable MTOM: false; Force MTOM: false
These are options for the request message, so in case you are sending a file in your request it would be encoded as a base64 attachment, meaning you are just disabling MTOM for the request.
It's a bummer but basically you are just left with two options:
Modify the server and disable MTOM or try to do something with interceptors like reading a value from the request and enabling/disabling mtom programatically for that single message based on that value. It's like implementing yourself a mechanism to decide wether that client supports MTOM or not.
Modify the clients that don's support MTOM which probably you can't do if you are asking this question.

Related

Handling soap+msbin1 content type in Jmeter

I am trying to use Jmeter for performance testing of a WPF app that uses WCF Web Service. I see that the service is using msbin1 encoding format. Hence i am no able to make out what the request parameters are. How to handle this in Jmeter
In order to make the request you need to just add HTTP Header Manager and configure it to send Content-Type header with the value of soap-msbin1. In order to send the actual payload you can use i.e. HTTP Raw Request sampler.
If you need extended functionality, i.e. to be able to build requests from text and perform correlation of responses you will have to use the code from WCF-Binary-SOAP-Plug-In in JSR223 Test Elements and perform payload encoding/decoding using Groovy language

AWS API Gateway with Lambda proxy always produces base64 string response

I'm using API Gateway Lambda proxy integration and trying to return a binary application/protobuf response. No matter what I do, the response body is always a base64 encoded string
I have application/protobuf setup as a binary media types in APIG
My client (javascript) is sending following headers in the POST:
Accept: application/protobuf
Content-Type: application/protobuf
My lambda is responing with content-type: application/protobuf, and correctly setting the IsBase64Encoded Lambda response to true
How do you get APIG to base64 decode the string? I swear I had this working a few months ago when I 1st tried this.
Note: I've also tried */* as a binary media types
Some related posts to add background:
https://github.com/twitchtv/twirp/issues/81
https://github.com/awslabs/aws-serverless-express/issues/39#issuecomment-276019222
Update:
Turns out I can only get it working if binary media type is set to */*. The client Accept header has no impact once it is set to this.
Many bad side effects of using */* because every response is attempted to get decoded (even when IsBase64Encoded is false or not set)
I thought it wasn't decoding because Chrome network inspect tools will always show binary data as base64 encoded in the Preview tab. You can see the protobuf in the Response tab.
The problem was I'm using CloudFront in front of API Gateway, and I was not passing the Accept header to the origin (APIG).
The docs on handling binary with Lambda proxy are not great, so here is a quick summary:
Your client must send an Accept header who's 1st media type matches what you have set as a binary media types in API Gateway
Your Lambda, if serving a binary media type, must set IsBase64Encoded to true AND the body must be base64 encoded
If the clients Accept header matches an entry in API Gateway's binary media types and these conditions are met, API Gateway will transform (base64 decode) before sending a response to the client.
This blog post walks you through step-by-step on how to get it working (without CloudFront).
This is a full blown aws-blueprint for getting a production grade ci/cd with CloudFront.

Why dont we have GET call in SOAP?

Why don't we have a GET call in SOAP?
We only send POST requests with SOAP.Why..?
In RESTful APIs, GET, POST, etc. are part of the "method call," so to speak.
However, in SOAP all of the information about the method call is specified in XML.
POST is just more practical for transmittng XML objects in the body of a HTTP request or response. The query string in a GET request would be awkward and has limitations.
However, SOAP 1.2 supports GET for certain requests. This means you can take advantage of caching responses.
SOAP is also not bound to any underlying transport architecture (like HTTP). That means it could be used on top of SMTP for example.
See the section on http binding for more info: https://www.w3.org/TR/soap12-part2/#soapinhttp

How to disable chunking in cxf webservice on server-side?

I need to disable chunking in cxf webservice on server-side as some clients need 'Content-Length' header in response. Now i can see 'Transfer-Encoding' is 'chunked' in server response and no 'Content-Length' header is sent.
I've found that chunkins can be disabled in spring's context like this:
<http-conf:conduit name="*.http-conduit">
<http-conf:client ReceiveTimeout=“300000“ AllowChunking="false"/>
</http-conf:conduit>
Since i'm creating services programmatically like this:
// media service
Object mediaService = new MediaService();
System.out.println("Starting media service #1 ...");
EndpointImpl mediaEP = (EndpointImpl)Endpoint.create(mediaService);
mediaEP.publish("http://localhost:8081/onvif/media_service");
How can i do it?
Actually, you can't easyly specified to not allow chuncking from server side.
Indeed, it's a client pb! What I understand is that you have a client of your ws who can't modify his code to desactivate chunking?
You have to do that : write a CXF interceptor that would replace the servlets OutputStream in the message with a buffer of some sort (ByteArrayOutputStream or CachedOutputStream) at the beginning of the output chain and then at the end of the chain, use that to set the Content-Length header on the response and copy that data to the real output stream.
Indeed, the content lenght will force the framework to not use the chunking.
I did it once before. I'll try to post you maybe tomorrow a code of such interceptor.

Setting HTTP headers through Axis2 API

I am using apache axis2 server webservies, Basically I am sending xml response to android client through webservices. Here I need to maintain the session since the services per user basis. I know maintaining session in webservices is bad idea, but cant avoid it.
Actually I need to generate random unique string when user invoke first service from android client, that random string going to be used as session id. This session id, i need to set in http custom header, so that android client can able to get it and can send it subsequent requests as well.
I want to know whether any API is available in axis2 to set custom header information on http headers. Same way I need to read the http header, so that next request I can get the session id from header.
Can anyone advice me regarding this?? Thanks
-Ravi
Dead link on #Martin Dürrmeier's answer, here's a snapshot of the webpage that i've found on web.archive.org : Axis2 - Setting custom HTTP Headers on a response, it helped me.
Here's the lines needed :
MessageContext responseMessageContext =
MessageContext.getCurrentMessageContext().getOperationContext().getMessageContext(
WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
List<Header> headers = new ArrayList<Header>();
headers.add(new Header(HTTPConstants.HEADER_CONTENT_ENCODING, "identity"));
responseMessageContext.setProperty(HTTPConstants.HTTP_HEADERS, headers);