Thursday, February 10, 2011

Understanding the SoapAction mystery

For a current project I was asked why a provided WS-I Basic Profile 1.1 compliant webservice wasn't using the SoapAction attribute.
Therefore, I will explain the usage of the SoapAction keyword here.


The SOAPAction header in SOAP 1.1 has given many developers and implementors fits about understanding its purpose. I suggest that this is because of the two very different ways in which SOAP can be used.


Below the statements of the specifications
The SOAP 1.1 specification says this about the HTTP SOAPAction header.
"The SOAPAction HTTP request header field can be used to indicate the intent of the SOAP HTTP request. The value is a URI identifying the intent. SOAP places no restrictions on the format or specificity of the URI or that it is resolvable. An HTTP client MUST use this header field when issuing a SOAP HTTP Request"


The WS-I Basic Profile says this about the HTTP SOAPAction header
Interoperability testing has demonstrated that requiring the SOAPAction HTTP header field-value to be quoted increases interoperability of implementations. Even though HTTP allows for header field-values to be unquoted, some implementations require that the value be quoted.
The SOAPAction header is purely a hint to processors. All vital information regarding the intent of a message is carried in the envelope.


The presence and content of the SOAPAction header field can be used by servers such as firewalls to appropriately filter SOAP request messages in HTTP. The header field value of empty string (”") means that the intent of the SOAP message is provided by the HTTP Request-URI. No value means that there is no indication of the intent of the message.


So if you’ve got a SOAP message like this one:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   <SOAP-ENV:Body>
      <m:GetLastTradePrice xmlns:m="Some-URI">
          <symbol>DIS</symbol>
      </m:GetLastTradePrice>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


Then you see that the intent of this message being sent is the meaning of “GetLastTradePrice”. 
Given this use of SOAP (with the method in the SOAP envelope), it should not be surprising at all that developers are confused, as it appears as though the value of SOAPAction is redundant.

As the SOAPAction is transport specific -an HTTP header field, you should try to avoid it's use when authoring WSDL files for your new services, especially if you plan to use other transports for the same service.
There are only a few usecases where you really need it: it's when you are using overloaded methods (if your language of choice permit it).
The Key to this problem is to understand the relationship between the WSDL and the wire format, and to realize that the name of the wsdl:operation is not necessary present on the wire.


We can imagine a soap envelope like the one below in which no explicit operation is defined.

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <env:Body>
    <ans1:eid xmlns:ans1="http://ws.fusion.com/">eid</ans1:eid>
  </env:Body>
</env:Envelope>

From the wire format above, once cannot which operation is called. In order to route such a message, you need extra information - it's the purpose of the SOAPAction header in the list displayed below.

User-Agent: Oracle HTTPClient Version 10h
SOAPAction: "urn:lookupEmail"
Accept-Encoding: gzip, x-gzip, compress, x-compress
Content-type: text/xml; charset=UTF-8
Content-length: 302

The main reason the SOAPAction is used by most Web Services framework is as a performance optimization. It provides a key to lookup the operation where the message should be routed at, without to have to process the SOAP payload (the soap:body).

To sum up:

  • use an empty value if you can.
  • use it when you are using overloaded methods; the QName of the top-level element of the soap:body can be used to uniquely identify the operation that should process the incoming message

Note that this tips is specific to SOAP 1.1 and will not apply moving forward, as the routing attribute will be factored in the addressing header.