mirror of https://github.com/FluuxIO/go-xmpp
Transports need to handle open/close stanzas
XMPP and WebSocket transports require different open and close stanzas. To handle this the responsibility handling those and creating the XML decoder is moved to the Transport.pull/123/head
parent
25fd476328
commit
92329b48e6
@ -0,0 +1,13 @@
|
||||
package stanza
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
// Open Packet
|
||||
// Reference: WebSocket connections must start with this element
|
||||
// https://tools.ietf.org/html/rfc7395#section-3.4
|
||||
type WebsocketOpen struct {
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-framing open"`
|
||||
From string `xml:"from,attr"`
|
||||
Id string `xml:"id,attr"`
|
||||
Version string `xml:"version,attr"`
|
||||
}
|
@ -1,167 +1,14 @@
|
||||
package stanza
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
// ============================================================================
|
||||
// StreamFeatures Packet
|
||||
// Reference: The active stream features are published on
|
||||
// https://xmpp.org/registrar/stream-features.html
|
||||
// Note: That page misses draft and experimental XEP (i.e CSI, etc)
|
||||
|
||||
type StreamFeatures struct {
|
||||
XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"`
|
||||
// Server capabilities hash
|
||||
Caps Caps
|
||||
// Stream features
|
||||
StartTLS tlsStartTLS
|
||||
Mechanisms saslMechanisms
|
||||
Bind Bind
|
||||
StreamManagement streamManagement
|
||||
// Obsolete
|
||||
Session StreamSession
|
||||
// ProcessOne Stream Features
|
||||
P1Push p1Push
|
||||
P1Rebind p1Rebind
|
||||
p1Ack p1Ack
|
||||
Any []xml.Name `xml:",any"`
|
||||
}
|
||||
|
||||
func (StreamFeatures) Name() string {
|
||||
return "stream:features"
|
||||
}
|
||||
|
||||
type streamFeatureDecoder struct{}
|
||||
|
||||
var streamFeatures streamFeatureDecoder
|
||||
|
||||
func (streamFeatureDecoder) decode(p *xml.Decoder, se xml.StartElement) (StreamFeatures, error) {
|
||||
var packet StreamFeatures
|
||||
err := p.DecodeElement(&packet, &se)
|
||||
return packet, err
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
// Reference: https://xmpp.org/extensions/xep-0115.html#stream
|
||||
// "A server MAY include its entity capabilities in a stream feature element so that connecting clients
|
||||
// and peer servers do not need to send service discovery requests each time they connect."
|
||||
// This is not a stream feature but a way to let client cache server disco info.
|
||||
type Caps struct {
|
||||
XMLName xml.Name `xml:"http://jabber.org/protocol/caps c"`
|
||||
Hash string `xml:"hash,attr"`
|
||||
Node string `xml:"node,attr"`
|
||||
Ver string `xml:"ver,attr"`
|
||||
Ext string `xml:"ext,attr,omitempty"`
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Supported Stream Features
|
||||
|
||||
// StartTLS feature
|
||||
// Reference: RFC 6120 - https://tools.ietf.org/html/rfc6120#section-5.4
|
||||
type tlsStartTLS struct {
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls starttls"`
|
||||
Required bool
|
||||
}
|
||||
|
||||
// UnmarshalXML implements custom parsing startTLS required flag
|
||||
func (stls *tlsStartTLS) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
stls.XMLName = start.Name
|
||||
|
||||
// Check subelements to extract required field as boolean
|
||||
for {
|
||||
t, err := d.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch tt := t.(type) {
|
||||
|
||||
case xml.StartElement:
|
||||
elt := new(Node)
|
||||
|
||||
err = d.DecodeElement(elt, &tt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if elt.XMLName.Local == "required" {
|
||||
stls.Required = true
|
||||
}
|
||||
|
||||
case xml.EndElement:
|
||||
if tt == start.End() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sf *StreamFeatures) DoesStartTLS() (feature tlsStartTLS, isSupported bool) {
|
||||
if sf.StartTLS.XMLName.Space+" "+sf.StartTLS.XMLName.Local == nsTLS+" starttls" {
|
||||
return sf.StartTLS, true
|
||||
}
|
||||
return feature, false
|
||||
}
|
||||
|
||||
// Mechanisms
|
||||
// Reference: RFC 6120 - https://tools.ietf.org/html/rfc6120#section-6.4.1
|
||||
type saslMechanisms struct {
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanisms"`
|
||||
Mechanism []string `xml:"mechanism"`
|
||||
}
|
||||
|
||||
// StreamManagement
|
||||
// Reference: XEP-0198 - https://xmpp.org/extensions/xep-0198.html#feature
|
||||
type streamManagement struct {
|
||||
XMLName xml.Name `xml:"urn:xmpp:sm:3 sm"`
|
||||
}
|
||||
|
||||
func (sf *StreamFeatures) DoesStreamManagement() (isSupported bool) {
|
||||
if sf.StreamManagement.XMLName.Space+" "+sf.StreamManagement.XMLName.Local == "urn:xmpp:sm:3 sm" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// P1 extensions
|
||||
// Reference: https://docs.ejabberd.im/developer/mobile/core-features/
|
||||
|
||||
// p1:push support
|
||||
type p1Push struct {
|
||||
XMLName xml.Name `xml:"p1:push push"`
|
||||
}
|
||||
|
||||
// p1:rebind suppor
|
||||
type p1Rebind struct {
|
||||
XMLName xml.Name `xml:"p1:rebind rebind"`
|
||||
}
|
||||
|
||||
// p1:ack support
|
||||
type p1Ack struct {
|
||||
XMLName xml.Name `xml:"p1:ack ack"`
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// StreamError Packet
|
||||
|
||||
type StreamError struct {
|
||||
XMLName xml.Name `xml:"http://etherx.jabber.org/streams error"`
|
||||
Error xml.Name `xml:",any"`
|
||||
Text string `xml:"urn:ietf:params:xml:ns:xmpp-streams text"`
|
||||
}
|
||||
|
||||
func (StreamError) Name() string {
|
||||
return "stream:error"
|
||||
}
|
||||
|
||||
type streamErrorDecoder struct{}
|
||||
|
||||
var streamError streamErrorDecoder
|
||||
|
||||
func (streamErrorDecoder) decode(p *xml.Decoder, se xml.StartElement) (StreamError, error) {
|
||||
var packet StreamError
|
||||
err := p.DecodeElement(&packet, &se)
|
||||
return packet, err
|
||||
import "encoding/xml"
|
||||
|
||||
// Start of stream
|
||||
// Reference: XMPP Core stream open
|
||||
// https://tools.ietf.org/html/rfc6120#section-4.2
|
||||
type Stream struct {
|
||||
XMLName xml.Name `xml:"http://etherx.jabber.org/streams stream"`
|
||||
From string `xml:"from,attr"`
|
||||
To string `xml:"to,attr"`
|
||||
Id string `xml:"id,attr"`
|
||||
Version string `xml:"version,attr"`
|
||||
}
|
||||
|
@ -0,0 +1,167 @@
|
||||
package stanza
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
// ============================================================================
|
||||
// StreamFeatures Packet
|
||||
// Reference: The active stream features are published on
|
||||
// https://xmpp.org/registrar/stream-features.html
|
||||
// Note: That page misses draft and experimental XEP (i.e CSI, etc)
|
||||
|
||||
type StreamFeatures struct {
|
||||
XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"`
|
||||
// Server capabilities hash
|
||||
Caps Caps
|
||||
// Stream features
|
||||
StartTLS tlsStartTLS
|
||||
Mechanisms saslMechanisms
|
||||
Bind Bind
|
||||
StreamManagement streamManagement
|
||||
// Obsolete
|
||||
Session StreamSession
|
||||
// ProcessOne Stream Features
|
||||
P1Push p1Push
|
||||
P1Rebind p1Rebind
|
||||
p1Ack p1Ack
|
||||
Any []xml.Name `xml:",any"`
|
||||
}
|
||||
|
||||
func (StreamFeatures) Name() string {
|
||||
return "stream:features"
|
||||
}
|
||||
|
||||
type streamFeatureDecoder struct{}
|
||||
|
||||
var streamFeatures streamFeatureDecoder
|
||||
|
||||
func (streamFeatureDecoder) decode(p *xml.Decoder, se xml.StartElement) (StreamFeatures, error) {
|
||||
var packet StreamFeatures
|
||||
err := p.DecodeElement(&packet, &se)
|
||||
return packet, err
|
||||
}
|
||||
|
||||
// Capabilities
|
||||
// Reference: https://xmpp.org/extensions/xep-0115.html#stream
|
||||
// "A server MAY include its entity capabilities in a stream feature element so that connecting clients
|
||||
// and peer servers do not need to send service discovery requests each time they connect."
|
||||
// This is not a stream feature but a way to let client cache server disco info.
|
||||
type Caps struct {
|
||||
XMLName xml.Name `xml:"http://jabber.org/protocol/caps c"`
|
||||
Hash string `xml:"hash,attr"`
|
||||
Node string `xml:"node,attr"`
|
||||
Ver string `xml:"ver,attr"`
|
||||
Ext string `xml:"ext,attr,omitempty"`
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Supported Stream Features
|
||||
|
||||
// StartTLS feature
|
||||
// Reference: RFC 6120 - https://tools.ietf.org/html/rfc6120#section-5.4
|
||||
type tlsStartTLS struct {
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls starttls"`
|
||||
Required bool
|
||||
}
|
||||
|
||||
// UnmarshalXML implements custom parsing startTLS required flag
|
||||
func (stls *tlsStartTLS) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||
stls.XMLName = start.Name
|
||||
|
||||
// Check subelements to extract required field as boolean
|
||||
for {
|
||||
t, err := d.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch tt := t.(type) {
|
||||
|
||||
case xml.StartElement:
|
||||
elt := new(Node)
|
||||
|
||||
err = d.DecodeElement(elt, &tt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if elt.XMLName.Local == "required" {
|
||||
stls.Required = true
|
||||
}
|
||||
|
||||
case xml.EndElement:
|
||||
if tt == start.End() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sf *StreamFeatures) DoesStartTLS() (feature tlsStartTLS, isSupported bool) {
|
||||
if sf.StartTLS.XMLName.Space+" "+sf.StartTLS.XMLName.Local == nsTLS+" starttls" {
|
||||
return sf.StartTLS, true
|
||||
}
|
||||
return feature, false
|
||||
}
|
||||
|
||||
// Mechanisms
|
||||
// Reference: RFC 6120 - https://tools.ietf.org/html/rfc6120#section-6.4.1
|
||||
type saslMechanisms struct {
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanisms"`
|
||||
Mechanism []string `xml:"mechanism"`
|
||||
}
|
||||
|
||||
// StreamManagement
|
||||
// Reference: XEP-0198 - https://xmpp.org/extensions/xep-0198.html#feature
|
||||
type streamManagement struct {
|
||||
XMLName xml.Name `xml:"urn:xmpp:sm:3 sm"`
|
||||
}
|
||||
|
||||
func (sf *StreamFeatures) DoesStreamManagement() (isSupported bool) {
|
||||
if sf.StreamManagement.XMLName.Space+" "+sf.StreamManagement.XMLName.Local == "urn:xmpp:sm:3 sm" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// P1 extensions
|
||||
// Reference: https://docs.ejabberd.im/developer/mobile/core-features/
|
||||
|
||||
// p1:push support
|
||||
type p1Push struct {
|
||||
XMLName xml.Name `xml:"p1:push push"`
|
||||
}
|
||||
|
||||
// p1:rebind suppor
|
||||
type p1Rebind struct {
|
||||
XMLName xml.Name `xml:"p1:rebind rebind"`
|
||||
}
|
||||
|
||||
// p1:ack support
|
||||
type p1Ack struct {
|
||||
XMLName xml.Name `xml:"p1:ack ack"`
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// StreamError Packet
|
||||
|
||||
type StreamError struct {
|
||||
XMLName xml.Name `xml:"http://etherx.jabber.org/streams error"`
|
||||
Error xml.Name `xml:",any"`
|
||||
Text string `xml:"urn:ietf:params:xml:ns:xmpp-streams text"`
|
||||
}
|
||||
|
||||
func (StreamError) Name() string {
|
||||
return "stream:error"
|
||||
}
|
||||
|
||||
type streamErrorDecoder struct{}
|
||||
|
||||
var streamError streamErrorDecoder
|
||||
|
||||
func (streamErrorDecoder) decode(p *xml.Decoder, se xml.StartElement) (StreamError, error) {
|
||||
var packet StreamError
|
||||
err := p.DecodeElement(&packet, &se)
|
||||
return packet, err
|
||||
}
|
Loading…
Reference in New Issue