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

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.

Related

Add cookie to HTTP header for SOAP call in ColdFusion

I basically want to add the ASP.NET_SessionId cookie to my HTTP request header when calling a SOAP web service through ColdFusion.
The web service is registered in the OnApplicationStart function of the Application.cfc component in ColdFusion.
<cfscript>
objSoapHeader = XmlParse("<wsse:Security mustUnderstand=""true"" xmlns:wsse=""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""><wsse:UsernameToken><wsse:Username>MY_USERNAME</wsse:Username><wsse:Password>MY_PASSWORD</wsse:Password></wsse:UsernameToken></wsse:Security>");
Application.UserWebService = CreateObject("webservice","MY_URL/UserService.asmx?WSDL");
addSOAPRequestHeader(Application.UserWebService,"","",objSoapHeader,true);
</cfscript>
My web service is called as such:
<cfset Result = "#Application.UserWebService.SomeFunction("1", "DATA")#">
In order for the .Net server (where the web services are located) to remember my session state, I must pass the ASP.NET_SessionId cookie in the HTTP request header, but have no idea if this is even possible in ColdFusion.
I've researched for several hours but nothing has come of it as of yet, so has anyone successfully managed to pull this off?
Short Answer:
For CF9 / Axis1 try enabling sessions on the web service object.
ws = createObject("webservice", "http://localhost/MyWebService.asmx?wsdl");
ws.setMaintainSession( true );
For CF10+ / Axis2, see longer answer below:
(Disclaimer: Using cfhttp might be simpler, but I was curious and did some digging ..)
From what I have read, since CF10+ uses Axis2 for web services it should be possible to use the underlying methods to maintain session state through HTTP cookies.
How to set Cookies in ColdFusion SOAP requests - (circa 2006) - Written for a much older version of CF/Axis, so some of it is outdated, but it still provides a good overview of the general concept.
Maintain session in Axis2
Java axis web service client setMaintainSession on multiple services (cookies?)
Axis2 Manage Session Cookie Manually
Using the the links above, I put together a quick POC using a basic web service and was able to extract the cookie header from the web service client response:
// make initial request
ws = createObject("webservice", "http://localhost/MyWebService.asmx?wsdl");
ws.firstMethod();
// For maintainability, use constants instead of hard coded strings
wsdlConstants = createObject("java", "org.apache.axis2.wsdl.WSDLConstants");
// Extract headers
operation = ws._getServiceClient().getLastOperationContext();
context = operation.getMessageContext( wsdlConstants.MESSAGE_LABEL_IN_VALUE );
headers = context.getProperty( context.TRANSPORT_HEADERS );
Then set the cookie and instruct the web service client to send it with subsequent requests:
if ( structKeyExists(headers, "Set-Cookie") ) {
// include http cookies with request
httpConstants = createObject("java", "org.apache.axis2.transport.http.HTTPConstants");
options = ws._getServiceClient().getOptions();
options.setManageSession( true );
options.setProperty( httpConstants.COOKIE_STRING, headers["Set-Cookie"] );
}
// ... more requests
ws.secondMethod();
ws.thirdMethod();
NB: Side note, I noticed you are storing the instance in the shared Application scope. Just keep in mind web service instances are probably NOT thread safe.
Inside your CFHPPT tags, set the cookie with CFHTTPPARAM

Make MTOM Optional

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.

Monitoring HTTP requests and responses (no web browser)

I'm creating web services to make an Android app talk to a server.
I'm using Tomcat for the server and a JAX RS lib to convert data between Java objects and JSON during the transfers.
What I want is to be able to view the actual HTTP requests and responses the framework is creating.
A web browser (like Firefox with Firebug) won't do because I also need to check the request bodies generated by the Android app.
With the Servlet API I could intercept and get the request data with a filter, but not the response (I believe) after it was written by the framework.
Wireshark might be a solution (I'm trying it right now), but seems to be a bit to much. I need to worry about properly filtering my messages and didn't figure out yet how to get my HTTP messages properly formatted (plain text w/o the hexa content).
I wonder if there is a simpler way to do this from inside my application or from tomcat.
Try Tomcat's AccessLogValve. You can configure it to log incoming request headers as well as outgoing response headers. Here's an example:
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_headers_access_log." suffix=".txt"
pattern="%t "%r" %s ||| %{Content-Length}o ||| %{User-Agent}i" />
Notice the %{xxx}o pattern - that's for response header. You might want to use it as %{X-JSON}o. Also notice the %{xxx}i pattern - that's for request headers.
Nest the <Valve/> element within a <Context/>, <Host/> or <Engine/> elements and you'll be all set.
I ended up using Wireshark with the following filter:
http.content_type == "application/json" || http.accept ==
"application/json"
To get the content decoded, right click on the json part of you package ("JavaScript Object Notation: application/json") > Copy > Bytes > Printable text only

Stub generated using Axis2 Webservice forming new connection for redirect URL...Need same TCP connection...!

I am badly stuck with a SOAP based integration using Axis2 framework for generation of client stubs from the Server WSDL. The scenario is as follows :
There is always a login API call first, which gives a Success response in SOAP body and Temporary Redirect in HTTP header. Also provides a URL which contains the session ID in the Location field of HTTP Header.
The next API call is required to be made at this redirect location. IN THE SAME TCP CONNECTION, for getting a proper response.
Now, the problem is, as a part of Webservice implementation using Axis2 generated stubs, I need to reload this redirect URL and re-instantiate it as --- "stub=new Stub(newurl)"
As soon as this is done, it creates a new TCP connection and so, the next request gives the response as "session ID invalid" because it goes out-of-sync with login API.
I have tried everything mentioned as a solution in this forum and nothing is working out.
For e.g --
MultiThreadedHttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
HttpClient httpClient = new HttpClient(httpConnectionManager);
ServiceClient serviceClient = stub._getServiceClient();
Options opts = stub._getServiceClient().getOptions();
opts.setTo(new EndpointReference(prop.getProperty("target_end_point_url")));
opts.setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Constants.VALUE_TRUE);
opts.setProperty(HTTPConstants.CACHED_HTTP_CLIENT, httpClient);
serviceClient.setOptions(opts);
stub._setServiceClient(serviceClient);
Similarly, I have tried many other options too. But it's not helpful at all.
Faced exactly the same issue.
Following steps solved the issue.
1. Using HttpClient, perform login. Don't use stub object to perform login.
2. Use the Location Header URL, to create new stub object i.e. stub = new Stub(locationURL). (Your existing options setting should be retained.)
3. There is a default timeout, by which server disconnects the TCP connection. In my case it was 50 seconds. Hence as soon as i performed login in step 1, i execute a timer every 40 seconds, to send an empty requests to new Location URL using HeadMethod of same HttpClient object.

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);