Monday, February 18, 2008

How to debug SOAP on Mac with tcpdump

I’ve been using several tools to debug SOAP on Mac and Windows. I would like to share my experience in using some of the tools and show some examples.

So far I found four major categories of tools that are useful in debugging SOAP:
  1. Interface listeners such as tcpdump and others
  2. Proxy tools such as TCPMonitor
  3. Servlet filters
  4. Application server logging. For example, Weblogic has a special logging option that dumps SOAP requests and responses to the sever log.
All of these tools have their own advantages and disadvantages. In this article, I will describe the first type - an interface listener tool called tcpdump. I am planning to describe other three categories in the future posts.

The tcpdump is a tool that sniffs IP traffic and dumps it to a file or a standard output stream. It was originally developed by Van Jacobson, Craig Leres and Steven McCanne from the Lawrence Berkeley National Laboratory, University of California, Berkeley, CA. It is open source. The tcpdump documentation and source code is available at http://www.tcpdump.org/. The tcpdump has been ported to many platforms. The version for Mac comes with MacPorts ( http://www.macports.org/).

Here is an example of capturing SOAP traffic where the service is deployed on the local host:

$ sudo tcpdump -i lo0 -A -s 1024 -l 'dst host localhost and port 8080' | tee dump.log

I use sudo because tcpdump requires root privileges to run. In this example, the tcpdump listens to the loopback interface defined on my Mac as lo0 and pipes out the data to dump.log file. To see all available interfaces, run ifconfig or tcpdump with –D option.

The Web service I use in this example is deployed on an instance of Glassfish Open Source Application Server for J2EE 5 (https://glassfish.dev.java.net/). It has a couple of methods:


/**
* Coffee Shop service.
*
* @author mykola
*/
@WebService()
public class CoffeeShop {
@WebMethod
public String getName() {
return "CoffeeShop, Inc.";
}

@WebMethod
@WebResult(name="price")
public int placeOrder(
@WebParam(name="product")
String product) {
int price = -1;
if ("coffee".equalsIgnoreCase(product)) {
price = 2;
} else if ("cake".equalsIgnoreCase(product)) {
price = 5;
}
return price;
}
}


I created a client application and once I call getName() Web service method I’ve got these SOAP request and response in the dump.log file:


Request:



Response:


The tcpdump logs lots of data. For SOAP debugging, we are interested in the <S:Envelope> content and HTTP headers.

This is a quick and dirty way of getting raw SOAP on the wire. The advantage of this approach is that it is not intrusive, i.e. no special client or service configuration is required. It does not affect performance of the web service or the client. It logs every byte in the message, even control symbols, which could be a disadvantage in some cases. The tcpdump would be very hard to use for debugging SOAP over HTTPS. Also, this approach is hard to use in cases where automated SOAP validation is required. I use filters for that. This is a topic for a future post.

I hope this post was helpful. Please let me know if you have any questions or comments. Thank you for reading.


1 comment:

oligofren said...

Thanks for posting this! I used it as a basis for doing a lot of other stuff.

piping the output into the following sed expression will for instance print all soap headers.

sed -n '/POST\ \/some\/url,/<\/SOAP-ENV:Header>/ p'

Regards
Carl-Erik