Unraveling the Mystery of SOAPAction

by Mark Baker

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, and that SOAPAction exists primarily to support the use that few are making of SOAP, which IMO, is the more valuable of the uses.

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 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.

The ambiguity is principally over the word "intent". The definition of the related word "intention" seems fairly straightforward;

a determination to act in a certain way

So if you've got a SOAP message, like this one from the spec;

<m:GetLastTradePrice xmlns:m="Some-URI">

Then clearly the intent/intention of the 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.

However, there is another use of SOAP that can be made that demonstrates the value of SOAPAction. This use involves not putting the method name in the SOAP envelope, and instead using the method of the underlying application protocol (which is most commonly ignored by Web services). In the case of HTTP that means using the POST method.

HTTP POST means "accept as a subordinate", in the same way that adding a Java AWT component to a container does, as does the real world action of posting a letter into a mailbox. The end result - what state change occurs as a result of this operation - is unknown to the sender, except that upon receipt of a 2xx response code, they know that it was accepted. This is analogous to knowing that that a textfield was added to your container, but not knowing about how that operation changed the state of the container itself (such as its layout).

Now, using the AWT component/container example again, consider that there can be different types of containers, such as Panel, Box, Window, etc.. Sometimes, it's meaningful to the user of that container to know that's it's more than a generic container, and that it is indeed a Box. It's the same as the difference between these two code snippets;

comp = new TextField( "test" );
java.awt.Container c = Foo.bar();
c.add( comp );


comp = new TextField( "test" );
java.awt.Container c = Foo.bar();
((java.awt.Panel)c).add( comp );

The difference is one of expectations. "add()" has the same base meaning in both cases, but in the second case it has the extended meaning/intent of "add as a Panel". If the container is not a Panel, an exception is thrown so that the client knows this expectation cannot be met.

HTTP POST means basically the same thing as "add()" in that example, which provides a hint about how SOAPAction can be used; the value of the SOAPAction header should be a URI identifying the "extended intent", namely the type of the container that the sender of the SOAP/HTTP message expects to be dealing with. If the expectation cannot be met, a fault should be generated.

Note; in SOAP 1.2, the SOAPAction header has been replaced with the "action" attribute on the application/soap+xml media type. But it works almost exactly the same way as SOAPAction.

UPDATE; it turns out that the behaviour of SOAPAction isn't as I described with respect to the expected "type mismatch" fault. I consider this a bug in the specification of SOAPAction/action. Unfortunately, it's not one that can be easily patched because this is extended behaviour that existing SOAP agents/libraries don't know about and can't support.