I'm using a SOAP server that apparently base64-encodes replies
automatically when they contain non-ASCII characters.
It might return something like this:
<SOAP-ENV:Envelope
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<namesp1:listProjectsResponse xmlns:namesp1="...uri...">
<s-gensym3
xsi:type="SOAP-ENC:base64">dGhpcyBpcyBiYXNlIDY0IGVuY29kZWQgZGF0YQ==</s-gensym3>
</namesp1:listProjectsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Does TclSOAP have the ability to automatically base64-decode replies
when necessary? (and how about automatically encoding requests?).
The result I get in the above example is
"dGhpcyBpcyBiYXNlIDY0IGVuY29kZWQgZGF0YQ==". It thus seems like SOAP
recognizes the <s-gensym3> tag and eats it, however without decoding the
string.
Thanks,
Christian
TclSOAP only deals with passing the parameters. It expects you to know
what to do with the results - in this case that means it's your job to
decode the base64. At some future date a WSDL package could make this
more automated - but I don't have any immediate plans to deal with
that.
What you can do is utilise the hook procedures, in this case -postProc
is probably the most useful. ie:
proc mycode::decode {methodName result} {
return [base64::decode $result]
}
SOAP::configure yourMethod -postProc mycode::decode
The above will achieve what you are after - yourMethod would
now automatically return the decoded result.
--
Pat Thoyts http://www.zsplat.freeserve.co.uk/resume.html
To reply, rot13 the return address or read the X-Address header.
PGP fingerprint 2C 6E 98 07 2C 59 C8 97 10 CE 11 E6 04 E0 B9 DD
Cameron Laird <Cam...@Lairds.com>
Business: http://www.Phaseit.net
Personal: http://starbase.neosoft.com/~claird/home.html
> ...
> TclSOAP only deals with passing the parameters. It expects you to know
> what to do with the results - in this case that means it's your job to
> decode the base64. At some future date a WSDL package could make this
> more automated - but I don't have any immediate plans to deal with
> that.
In the case of
<SOAP-ENV:Envelope
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<namesp1:listProjectsResponse xmlns:namesp1="...uri...">
<s-gensym3
xsi:type="SOAP-ENC:base64">dGhpcyBpcyBiYXNlIDY0IGVuY29kZWQgZGF0YQ==</s-gensym3>
</namesp1:listProjectsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
it should then return
<s-gensym3
xsi:type="SOAP-ENC:base64">dGhpcyBpcyBiYXNlIDY0IGVuY29kZWQgZGF0YQ==</s-gensym3>
because this is the contents of
<listProjectsResponse>...</listProjectsResponse>, right?
But it doesn't, it returns only
dGhpcyBpcyBiYXNlIDY0IGVuY29kZWQgZGF0YQ==
and that means that I have no clue as to whether it is an encoded string or
not. Of course I can always look at 'SOAP::dump -reply myMethod' and check
whether there is a <s-gensym3 ...base64> somewhere, but that's pretty
cumbersome.
> What you can do is utilise the hook procedures, in this case -postProc
> is probably the most useful. ie:
>
> proc mycode::decode {methodName result} {
> return [base64::decode $result]
> }
> SOAP::configure yourMethod -postProc mycode::decode
>
> The above will achieve what you are after - yourMethod would
> now automatically return the decoded result.
This only works when the replies are _always_ encoded, which is not the case.
They are only encoded by the server when they contain non-ASCII characters.
As it turns out, I always expect replies to be valid XML strings. What I can
do is just try to XML-parse the reply, and if this doesn't work, I can decode
it and try to parse it again. Not pretty, but it works in my case.
Best regards,
Christian
Nope. The whole point is not to pass out the XML. This is supposed to
be RPC so if your server method returns ints you get ints regardless
of the intermediate transport.
Where is this endpoint? It's the first one I've come across which
changes what its doing depending upon the input. Looks like we need
yet another switch. I take it this is generated by Perl's SOAP::Lite?
> because this is the contents of
> <listProjectsResponse>...</listProjectsResponse>, right?
>
> But it doesn't, it returns only
>
> dGhpcyBpcyBiYXNlIDY0IGVuY29kZWQgZGF0YQ==
>
That's right. What you have above is a method returning one named
result. In fact what you are getting is [list blather] but of course
Tcl reduces that to the above. If there were two results you'd see the
list.
> and that means that I have no clue as to whether it is an encoded string or
> not. Of course I can always look at 'SOAP::dump -reply myMethod' and check
> whether there is a <s-gensym3 ...base64> somewhere, but that's pretty
> cumbersome.
>
> > What you can do is utilise the hook procedures, in this case -postProc
> > is probably the most useful. ie:
> >
> > proc mycode::decode {methodName result} {
> > return [base64::decode $result]
> > }
> > SOAP::configure yourMethod -postProc mycode::decode
> >
> > The above will achieve what you are after - yourMethod would
> > now automatically return the decoded result.
>
> This only works when the replies are _always_ encoded, which is not the case.
> They are only encoded by the server when they contain non-ASCII characters.
>
Ah the joys of hooks. We also have a -replyProc for those who would
like to manipulate the XML before the tooklit parses it and a
-parseProc for those who want a different parser (de-serialiser in
Perl speak :) ).
I do expect the SOAP method to always return the same type of result.
Looks like I was wrong. If this is a standard mechanism (and I suspect
it is) then it'll need to be fitted into the default parser which in
this case is SOAP::parse_soap_response which goes to
SOAP::Utils::decomposeSoap which retrieves the value for the element.
I guess in here we can put
if {$child_elements == {}} {
set result [getElementValue $domElement]
+ set encoding [getElementAttribute $domElement "xsi:type"]
+ switch -exact -- $encoding {
+ SOAP-ENC:base64 { set result [base64::decode $result] }
+ }
} else {
Before I stick that into the package I'll check the specs to see if
this is normal or expected though. Also that chunk will have to be
expanded to deal with those who like to write 'soap-enc:base64' or
even 'e:base64' etc. find_namespaceURI can help with the expansion of
namespace names into URIs.
>
> As it turns out, I always expect replies to be valid XML strings. What I can
> do is just try to XML-parse the reply, and if this doesn't work, I can decode
> it and try to parse it again. Not pretty, but it works in my case.
Tcl is nothing if not flexible :)
Pat Thoyts.
> ...
> Where is this endpoint? It's the first one I've come across which
> changes what its doing depending upon the input. Looks like we need
> yet another switch. I take it this is generated by Perl's SOAP::Lite?
Yes, it's Perl's SOAP::Lite.
> ...
> I do expect the SOAP method to always return the same type of result.
> Looks like I was wrong. If this is a standard mechanism (and I suspect
> it is) then it'll need to be fitted into the default parser which in
> this case is SOAP::parse_soap_response which goes to
> SOAP::Utils::decomposeSoap which retrieves the value for the element.
> I guess in here we can put
>
> if {$child_elements == {}} {
> set result [getElementValue $domElement]
> + set encoding [getElementAttribute $domElement "xsi:type"]
> + switch -exact -- $encoding {
> + SOAP-ENC:base64 { set result [base64::decode $result] }
> + }
> } else {
>
> Before I stick that into the package I'll check the specs to see if
> this is normal or expected though...
Great!
Thanks,
Christian