|
Some basics...
SOAP Header blocks are used to extend an application with additional features.
They are a means to "layer" additional functionality over the core message.
Things like authentication mechanisms or transaction control come to mind right
away. A few things are worth noting about Header blocks:
-
They MUST be namespace qualified. As a practical matter, it makes sense to
define a separate namespace for each "application" you might define, and
qualify the Header block tag names accordingly.
-
Header blocks may possess an 'actor' (SOAP 1.1) or 'role' (SOAP 1.2) attribute.
The value of this attribute is a URI, and is used to "target" the Header block.
A SOAP message may pass through intermediary nodes on its way to the ultimate
destination, and the 'actor' or 'role' attribute may be used to control which
intermediary processes the Header block. This assumes that each intermediary
"knows" which roles it identified with, so that it recognizes the Header blocks
it needs to process. In the case of the White Mesa SOAP Server, one or more
roles are specified for a service as one of its configuration settings. If no
'actor' or 'role' attribute is present, it is assumed that the Header block is
targeted at the ultimate destination of the message (the 'default role'). In
addition, the SOAP specs define a special actor URI:
-
http://schemas.xmlsoap.org/soap/actor/next
(SOAP 1.1)
-
http://www.w3.org/2003/05/soap-envelope/role/next (SOAP 1.2)
which targets a Header block at whichever processor receives it. All SOAP
processing nodes must support the special role "next", making it useful for
targeting an inserted Header block at the next processor in a message path.
SOAP 1.2 Header blocks may be targeted at these additional special roles:
-
http://www.w3.org/2003/05/soap-envelope/role/none
-
http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver
The use of role "none" indicates that the block has no target, and exists only
to convey data needed for the processing of other Header blocks. The use of Role
"ultimateReceiver" indicates that a Header block is
targeted at the ultimate SOAP receiver in a message path. The White Mesa SOAP
Server recognizes all of the above special roles and processes the Header
blocks accordingly.
-
Header blocks may possess a 'mustUnderstand' attribute. If this attribute is
present, with a value of "1" (or optionally "true" for SOAP 1.2), then the
Header block MUST be understood and processed the receiver. If not, a SOAP
"MustUnderstand" Fault message will be returned to the sender. The White Mesa
SOAP Server ensures that all Header blocks are "understood" before processing
begins, as described below.
-
Processing of Header blocks which are targeted at the receiver but which are
not marked as "mustUnderstand" is not mandatory, such Header blocks may be
ignored. If so, and the receiver is acting as a SOAP intermediary, these
unprocessed blocks are removed from the message before it is forwarded to the
next node in the message path.
-
SOAP 1.2 Header blocks may possess a 'relay' attribute. If this attribute is
present with a value of "true" or "1", and the block is targeted at a receiver
acting as a SOAP intermediary, and:
-
The block is targeted at the receiver.
-
The receiver is acting as a SOAP intermediary.
-
The receiver does not "understand" and process the block.
then the receiver MUST forward the block on to the next node in the message
path. The idea is that setting relay="true" forces SOAP processors to propagate
a Header block along the message path that would otherwise be lost using the
default processing rules. Naturally, the SOAP 1.2 spec states that this
attribute has no effect if "mustUnderstand" is also set on the Header block.
The White Mesa SOAP Server takes care of forwarding SOAP 1.2 Header blocks
marked with relay="true" automatically.
-
Header blocks may appear as a "literal" XML instance, or be "encoded". The
instance XML of an encoded Header block is the result of applying encoding
(serialization) rules to a data graph. The "SOAP-ENV:encodingStyle" attribute
is used to indicate if encoding is in force on an element contained within the
SOAP message envelope, and if the value:
-
http://schemas.xmlsoap.org/soap/encoding/
(SOAP 1.1)
-
http://www.w3.org/2003/05/soap-encoding(SOAP 1.2)
is in scope for a Header block, the relevant SOAP Encoding rules are in force.
If an encodingStyle declaration is in scope with values:
-
an empty URI ("")
(SOAP 1.1 and 1.2)
-
http://www.w3.org/2003/05/soap-envelope/encoding/none (SOAP 1.2)
is in scope for a Header block, then it is presumed that the XML instance is
not encoded.
The use of the "SOAP-ENV:encodingStyle" attribute by a sender is optional. If a
header block is received which has no encodingStyle declaration, the White Mesa
SOAP Server will attempt to look up the Header blocks definition in the WSDL
document for the service. If the Header block is declared as "encoded" within
the WSDL document, then it is treated as such. If it is declared as "literal",
or no definition for that Header block is found in the WSDL document, then it
is treated as "literal".
So how does it work?
The White Mesa SOAP server requires that Header processing be done by COM
components that implement an IDispatch interface with two special methods:
-
HRESULT OnProcessHeader([in] VARIANT SOAPMsgInterface, [out, retval]
VARIANT_BOOL *pResult);
>
-
HRESULT OnTestMUHeaderBlock([in] BSTR bstrNamespace, [in] BSTR bstrLocalName,
[out, retval] VARIANT_BOOL *pResult);
For each service, any Header processors to be used are specified in the
configuration data. This information is maintained using the Control Panel
application. In the case of the Header processors, it is supplied as a space
delimited list of the ProgIDs. When a SOAP message is received, each of the
Header processors will be instantiated by the White Mesa SOAP Server. It is
important to realize that the Header processing described below occurs twice
on a node for each SOAP message.
For a node acting as the "ultimate receiver" in a message path:
-
When the message is first received, prior to Body processing
-
After Body processing is complete, prior to sending the response message. This
is the point at which Header blocks may be inserted into the response message.
For a node acting as an SOAP processing intermediary in a message path:
-
When the message is first received, prior to forwarding it to the next node in
the message path. At this point Header blocks may be inserted into the message
to be sent on to the next node.
-
After the response has arrived from the next node in the message path, prior to
sending the response message back to the previous node in the path. This is the
point at which Header blocks may be inserted into the response message.
Header block processing proceeds in three steps:
See the source code for the SOAP Digest Authentication Server (wmsoapauth2.cpp)
for a good example of processing SOAP Encoded Header blocks. An example of
processing of "literal" Header blocks is found in the source code for the
WS-Routing implementation (wmwsrouter2obj.cpp ),
which uses the XML parser supplied as part of the White Mesa SOAP server
package.
As outlined above the SOAP processing model allows for consumption,
processing, and insertion of Header blocks as the message travels from sender
to destination, that is, in what corresponds to the 'request' or outgoing phase
of processing in this case. Since the transport is HTTP, the return message
from destination to sender happens to pass back through any intermediary nodes,
and the SOAP processor will call each Header processor a second time, again
providing access to the message contents. This is done to give the Header
processors the opportunity to generate any side effects desired (e.g. logging),
or consume or insert response message Header blocks.
Headers blocks and WSDL
WSDL 1.1 provides a means to declare Header blocks as "message parts". This is
very convenient and involves placing the soap:header extension element
as a child of the associated input or output element for a
particular operation in the SOAP protocol binding. Each soap:header
element contains a message attribute which identifies a wsdl:message
element by qualified name. Also present is a part attribute, which
identifies the wsdl:part within that message which defines the makeup of
the Header block element. Details such as the Header block element's name and
type are learned by referencing the message part declaration. The namespace
attribute of the soap:header element specifies the namespace with which
the Header block element name is qualified. The use attribute declares
whether the Header block will be a "literal" XML instance or be "encoded". If
encoded, the value of the encodingStyle attribute is a URI identifying
the encoding used. soap:header elements may contain soap:headerfault
elements, which declare any Header block elements that would be returned in the
response message in the event that processing of the Header block by the
recipient results in a fault. These have the same syntax as the soap:header
elements. Here is an example snippet:
<message name="Soapsvcmgr_Headers_Request">
<part name="AuthCS" type="xsd2:AuthCS_Struct"/>
</message>
<message name="Soapsvcmgr_Headers_Response">
<part name="AuthSC" type="xsd2:AuthSC_Struct"/>
</message>
<message name="Soapsvcmgr_Fault_Response">
<part name="AuthSCF" type="xsd2:AuthSC_Fault_Struct"/>
</message>
<binding name="WMSOAPSvrMgr_SOAPBinding"
type="tns:WMSOAPSvrMgr_portType"> <soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="GetServerStats">
<soap:operation
soapAction="http://www.whitemesa.com/soapsvcmgr/GetServerStats"/>
<input>
<soap:body use="encoded"
namespace="http://www.whitemesa.com/soapsvcmgr/"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
<soap:header
message="tns:Soapsvcmgr_Headers_Request" part="AuthCS" use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://whitemesa.com/WMSOAPSvr/soapsvcmgr/headers.xsd">
<soap:headerfault
message="tns:Soapsvcmgr_Fault_Response" part="AuthSCF" use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://whitemesa.com/WMSOAPSvr/soapsvcmgr/headers.xsd"/>
</soap:header>
</input>
<output>
<soap:body use="encoded"
namespace="http://www.whitemesa.com/soapsvcmgr/"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
<soap:header
message="tns:Soapsvcmgr_Headers_Response" part="AuthSC" use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://whitemesa.com/WMSOAPSvr/soapsvcmgr/headers.xsd"/>
</output>
</operation>
</binding>
In this example, Header block elements with names "AuthCS", "AuthSC", and
"AuthSCF" are declared, all in namespace
"http://www.whitemesa.com/soapsvcmgr/". Their types are given by the type
attributes in the corresponding wsdl:message part elements. These point
to types found in a schema we will assume is present in the types element
of the WSDL document. In this way the necessary type information is available
to serialize/deserialize the Header blocks at runtime. Also, these Header
blocks use SOAP 1.1 Section 5 encoding, as indicated by the value of the use
attribute ("encoded"), and the value of the encodingStyle attribute
("http://schemas.xmlsoap.org/soap/encoding/"). Note that the input message
soap:header elements contain soap:headerfault elements, declaring
the Header blocks that will be received in any fault message returned to the
sender by the recipient if processing of the Header specified by the soap:header
element fails.
|