Incorrect namespace handling
w65536 opened this issue · 5 comments
I am afraid the change introduced with #218 breaks a few things. I have not had the time to properly analyze this. But this is what I see so far.
Before, this is what my request and response looked like:
<operationX xmlns="http://www.example.com/service/v1">
<request xmlns="http://www.example.com/service/v1" id="1234">
</request>
</operationX>
<operationXResponse xmlns="http://www.example.com/service/v1">
<response xmlns="http://www.example.com/service/v1" id="1234">
<success>true</success>
</response>
</operationXResponse>
Now this is what the request looks like:
<operationX xmlns="http://www.example.com/service/v1">
<request xmlns="http://www.example.com/service/v1" xmlns:v1="http://www.example.com/service/v1" v1:id="1234">
</request>
</operationX>
Trying to marshal the response for printing panics. I speculate this is because the service does not respond in the format that is now expected by the generated Go code:
panic: reflect: call of reflect.Value.CanInterface on zero Value
Hi @w65536. Do you have a capture of the raw response the server sends back, and the service's WSDL?
If the service you're taking to expects an un-namespaced id
attribute, #218 will definitely cause problems. This is uncommon, in my experience, but certainly not impossible.
Unfortunately, Go's XML support is so broken that I don't know if the right thing can be done in both cases.
So I was able to capture the raw SOAP request/response before and after the change. It is all simplified and sanitized to just expose the problem.
Before #218:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<operationX xmlns="http://www.example.com/service/v1">
<request xmlns="http://www.example.com/service/v1" id="1234">
<userId>8888</userId>
<orderNr>9876</orderNr>
</request>
</operationX>
</soap:Body>
</soap:Envelope>
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<v1:operationXResponse xmlns:v1="http://www.example.com/service/v1">
<v1:response id="1234">
<v1:success>true</v1:success>
</v1:response>
</v1:operationXResponse>
</soapenv:Body>
</soapenv:Envelope>
After #218:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<operationX xmlns="http://www.example.com/service/v1">
<request xmlns="http://www.example.com/service/v1" xmlns:v1="http://www.example.com/service/v1" v1:id="1234">
<userId>8888</userId>
<orderNr>9876</orderNr>
</request>
</operationX>
</soap:Body>
</soap:Envelope>
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<v1:operationXResponse xmlns:v1="http://www.example.com/service/v1">
<v1:response>
<v1:success>true</v1:success>
</v1:response>
</v1:operationXResponse>
</soapenv:Body>
</soapenv:Envelope>
This is the diff of above traces:
--- soap-simplified-before-218-sanitized.log 2021-12-08 17:10:39.000000000 +0100
+++ soap-simplified-after-218-sanitized.log 2021-12-08 17:10:39.000000000 +0100
@@ -1,7 +1,7 @@
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<operationX xmlns="http://www.example.com/service/v1">
- <request xmlns="http://www.example.com/service/v1" id="1234">
+ <request xmlns="http://www.example.com/service/v1" xmlns:v1="http://www.example.com/service/v1" v1:id="1234">
<userId>8888</userId>
<orderNr>9876</orderNr>
</request>
@@ -14,7 +14,7 @@
<soapenv:Header/>
<soapenv:Body>
<v1:operationXResponse xmlns:v1="http://www.example.com/service/v1">
- <v1:response id="1234">
+ <v1:response>
<v1:success>true</v1:success>
</v1:response>
</v1:operationXResponse>
You can see that the server no longer responds with the id
attribute in the response, presumably because it did not understand the attribute in the request.
After seeing this, I realize that already before the change from #218 do I get a panic if I do not send the attribute in the request at all. I am seeing the following panic in all cases where the server responds without the id
attribute when trying to call xml.MarshalIndent
on the received response:
panic: reflect: call of reflect.Value.CanInterface on zero Value
goroutine 1 [running]:
reflect.Value.CanInterface(...)
/usr/local/go/src/reflect/value.go:1005
encoding/xml.(*printer).marshalAttr(0xc00018a120, 0xc0000d3950, 0x0, 0x0, 0x767700, 0xd, 0x0, 0x0, 0x0, 0x7d1040, ...)
/usr/local/go/src/encoding/xml/marshal.go:554 +0x1465
encoding/xml.(*printer).marshalValue(0xc00018a120, 0x73ffe0, 0xc0001783b0, 0x196, 0xc0000648a0, 0x0, 0xc0001783b0, 0x196)
/usr/local/go/src/encoding/xml/marshal.go:520 +0x60f
encoding/xml.(*printer).marshalStruct(0xc00018a120, 0xc0000b6120, 0x78cb80, 0xc000178390, 0x199, 0x16, 0x200000003)
/usr/local/go/src/encoding/xml/marshal.go:952 +0x2a6
encoding/xml.(*printer).marshalValue(0xc00018a120, 0x7400a0, 0xc000178390, 0x16, 0x0, 0x0, 0x88, 0x780180)
/usr/local/go/src/encoding/xml/marshal.go:530 +0x75d
encoding/xml.(*Encoder).Encode(0xc00018a120, 0x7400a0, 0xc000178390, 0xc0001c7000, 0x31)
/usr/local/go/src/encoding/xml/marshal.go:162 +0xbb
encoding/xml.MarshalIndent(0x7400a0, 0xc000178390, 0x0, 0x0, 0x7dcec3, 0x2, 0x0, 0x0, 0xed, 0x0, ...)
/usr/local/go/src/encoding/xml/marshal.go:129 +0x159
So the problem here is twofold:
- The
id
attribute is somehow broken in the request. As a consequence the server responds without theid
attribute. xml.MarshalIndent
panics when theid
attribute is not present in the response. It may not be present due to problem 1 or because it was deliberately left out in the request.
Bottom line:
- problem 1 is due to #218 and prevents me from getting this scenario to work.
- problem 2: what I am wondering (and I did not yet try to understand this): it this a problem of the code generated by gowsdl or is this due to a broken implementation of
xml.MarshalIndent
?
Here is the simplified and sanitized WSDL for reference:
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.example.com/service/ws/V001"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsg="http://www.example.com/service/v1"
xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/"
name="ServiceV001"
targetNamespace="http://www.example.com/service/ws/V001">
<wsdl:types>
<xsd:schema xmlns="http://www.example.com/service/v1"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsg="http://www.example.com/service/v1"
targetNamespace="http://www.example.com/service/v1"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:element name="operationX">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="request" type="wsg:operationXRequestType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="operationXResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="response" type="wsg:operationXAckType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="operationXRequestType">
<xsd:complexContent>
<xsd:extension base="requestType">
<xsd:sequence>
<xsd:choice>
<xsd:element ref="orderNr"/>
</xsd:choice>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="operationXAckType">
<xsd:complexContent>
<xsd:extension base="ackType">
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="requestType" abstract="true">
<xsd:complexContent>
<xsd:extension base="messageType">
<xsd:sequence>
<xsd:element ref="userId"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ackType" abstract="true">
<xsd:complexContent>
<xsd:extension base="messageType">
<xsd:sequence>
<xsd:element ref="success"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="messageType" abstract="true">
<xsd:attribute name="id" type="idType" use="optional"/> <!-- HERE IS THE ATTRIBUTE -->
</xsd:complexType>
<xsd:element name="success" type="xsd:boolean">
</xsd:element>
<xsd:element name="userId">
<xsd:simpleType>
<xsd:restriction base="xsd:int">
<xsd:totalDigits value="6"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="orderNr" type="orderNrType">
</xsd:element>
<xsd:simpleType name="orderNrType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[1-9]\d{25}"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="idType">
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="operationXRequest">
<wsdl:part name="parameters" element="wsg:operationX"/>
</wsdl:message>
<wsdl:message name="operationXResponse">
<wsdl:part name="parameters" element="wsg:operationXResponse"/>
</wsdl:message>
<wsdl:portType name="Wsg">
<wsdl:operation name="operationX">
<wsdl:input message="tns:operationXRequest"/>
<wsdl:output message="tns:operationXResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="WsgSoapBinding" type="tns:Wsg">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="operationX">
<soap:operation soapAction="https://www.example.com/wsg-outbound/services/ServiceV001/operationX"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="WsgService">
<wsdl:port name="ServiceV001" binding="tns:WsgSoapBinding">
<soap:address location="https://www.example.com/wsg-outbound/services/ServiceV001"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Thanks for the response. The issue here is this part of the XSD:
<xsd:schema … attributeFormDefault="unqualified">
Which indicates that attributes shouldn't be qualified with the targetNamespace
prefix. The previous version of gowsdl only sent unqualified attributes (which broke my usecase), and the current one only sends qualified ones (which broke yours).
Since these are defaults, I assume they can also change per xsd:attrubute
, which is another thing that ought to get handled.
The fix is to add a conditional around these two lines in types_tmpl.go
, based on the attributeFormDefault
in the schema definition, and whatever specifies that at the xsd:attribute
level.
This is a thing I could look at implementing, but don't have much bandwidth to take on at the moment. I see you've opened some PRs already, so maybe this is sufficient guidance for you to fix it.
Thanks for your insights. I get what you are saying and it is helpful indeed. I guess I might be able to fix this, but I also need to check my time management. I will try to look into it, if I can find some time.
Do you have any insights whatsoever on problem 2: xml.MarshalIndent
panics when the id
attribute is not present in the response. It may not be present due to problem 1 or because it was deliberately left out in the request. What I am wondering: is this a problem of the code generated by gowsdl or is this due to a broken implementation of xml.MarshalIndent
?
Do you have any insights whatsoever on problem 2:
xml.MarshalIndent
panics when theid
attribute is not present in the response. It may not be present due to problem 1 or because it was deliberately left out in the request. What I am wondering: is this a problem of the code generated by gowsdl or is this due to a broken implementation ofxml.MarshalIndent
?
I'm not sure. The stacktrace you shared is entirely inside of encoding/xml
, which suggests to me that it's a bug in Go itself. You might try filing a bug with them and seeing what they have to say.