An IQ can only have a single payload

"An IQ stanza of type "get" or "set" MUST contain exactly one
 child element, which specifies the semantics of the particular
 request."
This commit is contained in:
Mickael Remond 2019-06-19 10:21:57 +02:00 committed by Mickaël Rémond
parent d455f29258
commit af0ae525b8
8 changed files with 23 additions and 29 deletions

View file

@ -198,7 +198,7 @@ func bind(t *testing.T, c net.Conn, decoder *xml.Decoder) {
} }
// TODO Check all elements // TODO Check all elements
switch iq.Payload[0].(type) { switch iq.Payload.(type) {
case *BindBind: case *BindBind:
result := `<iq id='%s' type='result'> result := `<iq id='%s' type='result'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>

View file

@ -78,18 +78,16 @@ func TestParsingDelegationIQ(t *testing.T) {
// Check that we have extracted the delegation info as IQPayload // Check that we have extracted the delegation info as IQPayload
var node string var node string
for _, ext := range iq.Payload { if iq.Payload != nil {
if delegation, ok := ext.(*Delegation); ok { if delegation, ok := iq.Payload.(*Delegation); ok {
packet := delegation.Forwarded.Stanza packet := delegation.Forwarded.Stanza
forwardedIQ, ok := packet.(IQ) forwardedIQ, ok := packet.(IQ)
if !ok { if !ok {
t.Errorf("Could not extract packet IQ") t.Errorf("Could not extract packet IQ")
return return
} }
payload := forwardedIQ.Payload if forwardedIQ.Payload != nil {
if len(payload) > 0 { if pubsub, ok := forwardedIQ.Payload.(*PubSub); ok {
pl := payload[0]
if pubsub, ok := pl.(*PubSub); ok {
node = pubsub.Publish.Node node = pubsub.Publish.Node
} }
} }

View file

@ -20,7 +20,7 @@ func TestControlSet(t *testing.T) {
t.Errorf("Unmarshal(%s) returned error", data) t.Errorf("Unmarshal(%s) returned error", data)
} }
if cs, ok := parsedIQ.Payload[0].(*ControlSet); !ok { if cs, ok := parsedIQ.Payload.(*ControlSet); !ok {
t.Errorf("Paylod is not an iot control set: %v", cs) t.Errorf("Paylod is not an iot control set: %v", cs)
} }
} }

14
iq.go
View file

@ -123,13 +123,13 @@ func (x Err) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
type IQ struct { // Info/Query type IQ struct { // Info/Query
XMLName xml.Name `xml:"iq"` XMLName xml.Name `xml:"iq"`
PacketAttrs PacketAttrs
// FIXME: We can only have one payload: // We can only have one payload on IQ:
// "An IQ stanza of type "get" or "set" MUST contain exactly one // "An IQ stanza of type "get" or "set" MUST contain exactly one
// child element, which specifies the semantics of the particular // child element, which specifies the semantics of the particular
// request." // request."
Payload []IQPayload `xml:",omitempty"` Payload IQPayload `xml:",omitempty"`
RawXML string `xml:",innerxml"` Error Err `xml:"error,omitempty"`
Error Err `xml:"error,omitempty"` RawXML string `xml:",innerxml"`
} }
func NewIQ(iqtype, from, to, id, lang string) IQ { func NewIQ(iqtype, from, to, id, lang string) IQ {
@ -145,10 +145,6 @@ func NewIQ(iqtype, from, to, id, lang string) IQ {
} }
} }
func (iq *IQ) AddPayload(payload IQPayload) {
iq.Payload = append(iq.Payload, payload)
}
func (iq IQ) MakeError(xerror Err) IQ { func (iq IQ) MakeError(xerror Err) IQ {
from := iq.From from := iq.From
to := iq.To to := iq.To
@ -217,7 +213,7 @@ func (iq *IQ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
if err != nil { if err != nil {
return err return err
} }
iq.Payload = append(iq.Payload, iqExt) iq.Payload = iqExt
} else { } else {
// TODO: Fix me. We do nothing of that element here. // TODO: Fix me. We do nothing of that element here.
// elt = new(Node) // elt = new(Node)

View file

@ -47,7 +47,7 @@ func TestGenerateIq(t *testing.T) {
{Var: xmpp.NSDiscoItems}, {Var: xmpp.NSDiscoItems},
}, },
} }
iq.AddPayload(&payload) iq.Payload = &payload
data, err := xml.Marshal(iq) data, err := xml.Marshal(iq)
if err != nil { if err != nil {
@ -97,7 +97,7 @@ func TestDiscoItems(t *testing.T) {
payload := xmpp.DiscoItems{ payload := xmpp.DiscoItems{
Node: "music", Node: "music",
} }
iq.AddPayload(&payload) iq.Payload = &payload
data, err := xml.Marshal(iq) data, err := xml.Marshal(iq)
if err != nil { if err != nil {
@ -123,7 +123,7 @@ func TestUnmarshalPayload(t *testing.T) {
t.Errorf("Unmarshal(%s) returned error", query) t.Errorf("Unmarshal(%s) returned error", query)
} }
if len(parsedIQ.Payload) != 1 { if parsedIQ.Payload == nil {
t.Errorf("Incorrect payload size: %d", len(parsedIQ.Payload)) t.Error("Missing payload")
} }
} }

View file

@ -157,10 +157,10 @@ func (m nsIQMatcher) Match(p Packet, match *RouteMatch) bool {
if !ok { if !ok {
return false return false
} }
if len(iq.Payload) < 1 { if iq.Payload == nil {
return false return false
} }
return matchInArray(m, iq.Payload[0].Namespace()) return matchInArray(m, iq.Payload.Namespace())
} }
// IQNamespaces adds an IQ matcher, expecting both an IQ and a // IQNamespaces adds an IQ matcher, expecting both an IQ and a

View file

@ -33,7 +33,7 @@ func TestNameMatcher(t *testing.T) {
// Check that an IQ packet is not matched // Check that an IQ packet is not matched
conn = NewSenderMock() conn = NewSenderMock()
iq := xmpp.NewIQ("get", "", "localhost", "1", "") iq := xmpp.NewIQ("get", "", "localhost", "1", "")
iq.Payload = append(iq.Payload, &xmpp.DiscoInfo{}) iq.Payload = &xmpp.DiscoInfo{}
router.Route(conn, iq) router.Route(conn, iq)
if conn.String() == successFlag { if conn.String() == successFlag {
t.Error("IQ should not have been matched and routed") t.Error("IQ should not have been matched and routed")
@ -52,11 +52,11 @@ func TestIQNSMatcher(t *testing.T) {
conn := NewSenderMock() conn := NewSenderMock()
iqDisco := xmpp.NewIQ("get", "", "localhost", "1", "") iqDisco := xmpp.NewIQ("get", "", "localhost", "1", "")
// TODO: Add a function to generate payload with proper namespace initialisation // TODO: Add a function to generate payload with proper namespace initialisation
iqDisco.Payload = append(iqDisco.Payload, &xmpp.DiscoInfo{ iqDisco.Payload = &xmpp.DiscoInfo{
XMLName: xml.Name{ XMLName: xml.Name{
Space: xmpp.NSDiscoInfo, Space: xmpp.NSDiscoInfo,
Local: "query", Local: "query",
}}) }}
router.Route(conn, iqDisco) router.Route(conn, iqDisco)
if conn.String() != successFlag { if conn.String() != successFlag {
t.Errorf("IQ should have been matched and routed: %v", iqDisco) t.Errorf("IQ should have been matched and routed: %v", iqDisco)
@ -66,11 +66,11 @@ func TestIQNSMatcher(t *testing.T) {
conn = NewSenderMock() conn = NewSenderMock()
iqVersion := xmpp.NewIQ("get", "", "localhost", "1", "") iqVersion := xmpp.NewIQ("get", "", "localhost", "1", "")
// TODO: Add a function to generate payload with proper namespace initialisation // TODO: Add a function to generate payload with proper namespace initialisation
iqVersion.Payload = append(iqVersion.Payload, &xmpp.DiscoInfo{ iqVersion.Payload = &xmpp.DiscoInfo{
XMLName: xml.Name{ XMLName: xml.Name{
Space: "jabber:iq:version", Space: "jabber:iq:version",
Local: "query", Local: "query",
}}) }}
router.Route(conn, iqVersion) router.Route(conn, iqVersion)
if conn.String() == successFlag { if conn.String() == successFlag {
t.Errorf("IQ should not have been matched and routed: %v", iqVersion) t.Errorf("IQ should not have been matched and routed: %v", iqVersion)

View file

@ -165,7 +165,7 @@ func (s *Session) bind(o Config) {
} }
// TODO Check all elements // TODO Check all elements
switch payload := iq.Payload[0].(type) { switch payload := iq.Payload.(type) {
case *BindBind: case *BindBind:
s.BindJid = payload.Jid // our local id (with possibly randomly generated resource s.BindJid = payload.Jid // our local id (with possibly randomly generated resource
default: default: