How to Determine the SOAP Version of a Message
By Eran Chinthaka
- 9 Nov, 2008
|<Tool>||Debugging Web services|
Table of Contents
- Using SOAP Namespace
- Using Transport Binding Information
- Using SOAP Fault Information
- Other Ways of Differentiating the Two SOAP Versions
The tools available today hide the complexities of Web services invocations. Most of the users will not see a SOAP message or a WSDL description and only work with their preferred programming language. Users will see Web service invocation just as another method invocation within the same address space. But sometimes there are situations where one needs to understand what exactly is going on the wire. May it be for debugging purposes or be for some other reason, it is always a good idea to understand what is on the wire. We will talk about understanding different SOAP versions, in this article.
As you might probably know, there are two versions of SOAP specifications available and widely used today. Namely they are SOAP v1.1 and SOAP v1.2 specifications. There are a lot of differences between the widely adopted SOAP 1.1 and SOAP 1.2 specifications, but not all differences can be seen in the SOAP message itself. As mentioned, identifying the proper SOAP version, by looking at the SOAP message, might be useful for different purposes. Let's look at some of the features that can be easily used to differentiate between the SOAP versions.
Every XML message contains namespaces to properly qualify the entities within it. In SOAP 1.1 and SOAP 1.2 specifications, each had defined its own unique namespaces to define the entities belonging to those specifications.
SOAP 1.1 : http://schemas.xmlsoap.org/soap/envelope/
SOAP 1.2 : http://www.w3.org/2003/05/soap-envelope
This is the easiest and sometimes the only method some people use. You can look at the SOAP namespace of a SOAP message and easily determine its version.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Header> ......... </soapenv:Header> <soapenv:Body> .... </soapenv:Body> </soapenv:Envelope>
SOAP 1.1 message
You might argue that this is the only method you need to know to differentiate two different SOAP versions. This might not be the case all the time. For example, there can be a situation where you will need to know the SOAP version even before reading the SOAP message itself. Even though the previous statement seems unusual, this is how it is when we have two different object models or two different builders for the two SOAP versions. In such situations, as a developer, you cannot afford to touch the SOAP message to find out the version. Perhaps you can cheat by temporarily recording the first few events or entities, but that might not be the best solution.
In the next section, we will use transport binding rules, if available, to differentiate between the two different versions.
Each SOAP specification defines transport binding rules to be used when using different transports. These rules will define the semantics of the message, when it is transported through that transport medium. For example, HTTP binding rules will define which HTTP header it should have and its contents or restrictions, if any. Some of the rules defined in these binding specifications will help you to differentiate among the different SOAP versions. Since HTTP is used more often, we will only discuss HTTP binding here. If you need information on other transports, please refer to the respective transport binding specifications.
As the name depicts, the 'Content-Type' HTTP header will define the contents of the HTTP message. SOAP 1.1 HTTP binding mandates the presence of a defined content-type. Also, the specification mandates the presence of a new HTTP header, called the 'SOAPAction' header. This is normally used to indicate the intent of the SOAP message. Practically this header value gives a hint about the operation to be invoked with the given SOAP message.
POST /MyService HTTP/1.1 Content-Type: text/xml; charset="utf-8" Content-Length: xxx SOAPAction: "urn:uuid:myaction" <SOAP-ENV:Envelope...
A typical HTTP header of a SOAP 1.1 message
The content type of the message can be text/xml, but there can be other content types in the message. There should be a SOAPAction header in any SOAP 1.1 message. This SOAPAction header can be empty, but it has to be there.
With SOAP 1.2 the identification becomes tricky. As with the SOAP 1.1 specification, the content type can be application/soap+xml, but users can define their own appropriate content types depending on the content. Also the specification does not define any SOAPAction header to be included within HTTP headers. You may include the SOAPAction information into the Content-type header itself. This is not mandatory.
POST /MyService HTTP/1.1 Host: myexample.org Content-Type: application/soap+xml; charset="utf-8" Content-Length: xxx <SOAP-ENV:Envelope...
A typical HTTP header of a SOAP 1.2 message
You must have already understood that the strategy of using HTTP headers to identify SOAP versions is tricky. A simple rule you can use is to check the presence of a SOAPAction header. If it is present, then it can be a SOAP 1.1 message, and if not, it is a SOAP 1.2 message. The tricky thing here is that, even if the SOAPAction header is not defined in SOAP 1.2 HTTP binding, no one is restricted from sending that header. Someone might send the SOAPAction header irrespective of the SOAP version being used. Also, if your SOAP message receiver is processing other kinds of messages, like REST messages, you need more complicated rules to identify SOAP 1.2 messages.
What if someone gives you a fragment of the SOAP message? If they give you only the contents of the SOAP Body of a successful SOAP request or SOAP response, it is harder to differentiate between the SOAP versions. You have to somehow use one of the above two methods to get the version information. If they give you the content of a SOAP fault message, it is easier.
The structure of a SOAP fault message between the two versions are different. SOAP 1.2 has a better model of encapsulating SOAP faults and that model can even capture all the information of a SOAP 1.1 message. Look at the following examples of the fault messages from the two different versions.
<env:Envelope ...> <env:Body> <env:Fault> <faultcode>env:Server</faultcode> <faultstring>Processing error</faultstring> <detail> <e:myFaultDetails xmlns:e="http://myexample.org/faults" > <e:message>Invalid credit card details</e:message> <e:errorcode>999</e:errorcode> </e:myFaultDetails> </detail> </env:Fault> </env:Body> </env:Envelope>
A Sample SOAP 1.1 Fault
<env:Envelope ...> <env:Body> <env:Fault> <env:Code> <env:Value>env:Sender</env:Value> <env:Subcode> <env:Value>mycode:SomeError</env:Value> </env:Subcode> </env:Code> <env:Reason> <env:Text xml:lang="en-US">Processing error</env:Text> </env:Reason> <env:Detail> <e:myFaultDetails xmlns:e="http://myexample.org/faults" > <e:message>Invalid credit card details</e:message> <e:errorcode>999</e:errorcode> </e:myFaultDetails> </env:Detail> </env:Fault> </env:Body> </env:Envelope>
A sample SOAP 1.2 fault
As you can see, there are a couple of differences between these two messages. Some of these differences are easier to remember.
- Obviously the names of the fault elements are different in the two specifications.
- SOAP 1.1 fault elements are not namespace qualified, where as all SOAP 1.2 elements are namespace qualified.
- SOAP 1.1 uses lower case letters to name the fault elements.
- SOAP 1.2 Code element (which maps to the faultcode element in SOAP 1.1), can have sub codes within it that describe the SOAP fault hierarchy.
In addition to the above main differences, there are other minor differences you will see in these two versions. Once again it is important to note that the differences mentioned in this article are limited to the differences you would see in the SOAP message itself. There are more differences in these two specifications which you might encounter if you search on the web.
- Both SOAP specifications define a way to target certain headers to certain intermediaries. In SOAP 1.1 this is done using the actor attribute, and in SOAP 1.2 this is done using the role attribute.
... <env:Header> <p:MyHeader xmlns:p="http://example.com" env:role="http://example.com/Log"> ... </p:MyHeader> ... </env:Header> ...
SOAP 1.2 Header block with role attribute
In this article, we discussed how to identify SOAP versions by looking at the SOAP message itself. We introduced methods like using namespace, transport bindings and fault information to identify the SOAP versions. This knowledge can quite useful, especially when you are debugging Web services.
Eran Chinthaka, WS PMC Member/Member-Apache Software Foundation, eran(dot)chinthaka(Y)gmail.com, where [email protected]