Archive for December, 2006

SOAP Compliance

Monday, December 11th, 2006

One of the ideas behind web services is that parties communicate in a way defined by a service contract. This contract should be adhered by both the server and the client. The usage and compliance to interface contracts has been considered the Right Way of writing software for a Long Time, at least by the component and static-typing fans (link). Web Services define (yet another) platform independent way of defining contracts trough the means of WSDL and XML Schema. Almost all WSDL documents currently in existence define a SOAP-over-HTTP binding (the only one supported by the WS-I Basic profile), but it’s not always easy to guarantee the service will return an answer in this form. Due to intermediary components, this (quite important) aspect of the contract is easily broken.

Let’s start with an example. A WSDL document containing a Schema could define you can, should and must only send HTTP Post requests containing body contents formatted like:

<soap:Envelope
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <addRequest
        xmlns="http://ivor.bosloper.nl/ws/example/1.0" >
      <a>2</a>
      <b>3</b>
    </addRequest>
 </soap:Body>
</soap:Envelope>

in which case the server will return a message in the specific resultFormat:

<soap:Envelope
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <addResponse
        xmlns="http://ivor.bosloper.nl/ws/example/1.0">
      <result>5</result>5
    </addResponse>
 </soap:Body>
</soap:Envelope>

Additionally, the SOAP protocol defines the service is implicitly allowed to return a SOAP:Fault Message in case something goes wrong, just like an unchecked (and undeclared) Exception in Java. But for good or for worse, the WSDL definition (provided by link because like any WSDL document it’s scary verbose) promises the service will accept and return messages in the SOAP format.

I experienced that it’s not easy to guarantee correct SOAP responses in all cases. While testing a service set up to adhere it’s interface in all foreseen circumstances, I received an answer like:

HTTP/1.0 503 Service not available

<html><body>Service not available</body></html>

It puzzled me for a few seconds, because I could not think of a library or component in the service implementation that would generate the HTML error message. But then I realized there were (many) entities between the service client and the service implementation, each of which could be responsible for the error. I’ll enumerate the route from the client to the service implementation.

The 1. Service Client uses a generated 2. client-side proxy (a.k.a. stub) which executes the HTTP call. It arrives at one or more 3. Server-side proxies; things like a firewall, Secure Content Accelerator (dedicated SSL codec), load balancer or web cache, or -like in my case- all of them! Only then the message arrives at the front-end 4. Webserver (like Apache or IIS), which (if configured correctly) forwards the message to the 5. Container, where it passes trough one or more 6. Serlvet Filters to be handled by the generic 7. JAX-RPC Servlet which calls the 8. Service Implementation (a.k.a. Tie).

Sequence Diagram

If any error occurs in a component before the Service Implementation (MyTie_implementation), either on the way into the implementation or on it’s way back, the response message might not be one generated by the service implementation. Some of these parts can be configured to generate the right SOAP error (Fault). For instance, the Container can be configured to return SOAP Fault messages if an error occurs (use the errorPage directive). This is not always possible for every intermediary component because; 1) error handling can not be configured, 2) it’ s configured by another (unwilling) department, or 3) the component (e.g. a firewall) is shared by other (non SOAP) applications, and error messages can not be tailored for specific applications.

Here’s a list of strategies I’ve applied for some of these components:

  • User agent. Internet explorer has a habit of generating ’smart’ HTML error pages in case the size of the error page returned from the webserver is small. As web service results aren’t written for browsers, it’s not something wel have to consider here.
  • Server Proxy, Load Balancer, SSL machine, firewall. Are not realistic candidates to break a lot. You’re just unlucky if this or the component next in line bails out.
  • Webservers can be configured to deliver custom errorPages. Happens if the back-end server is not accepting connections or times out (high load).
  • Container and the components within it; define JSP error pages and throwable catch-all page in web.xml.

You will end up never knowing for sure if you’ve tackled every case, so I’d say: prepare your WS-Client implementations to handle HTML errors ;-) !