~samwhited/xmpp

585adf75e574651d10322838b604d88d8fce5b14 — Sam Whited 11 months ago fa7bcf2
all: change stream feature Parse signature

This is a breaking change that makes the function signature of the Parse
function on StreamFeatures actually do what everyone is going to
immediately do with it anyways.

It also fixes the API to make it clear that we're passing a Decoder
which we had to do anyways because if we passed a wrapped TokenReader
and the user created a new decoder from that it wouldn't have had the
start element that we pass in popped from it and would error on reachign
its end element. This wasn't happening only because we were passing the
Decoder anyways and the NewTokenDecoder function would return the
original if the TokenReader was already a Decoder.

Signed-off-by: Sam Whited <sam@samwhited.com>
7 files changed, 13 insertions(+), 12 deletions(-)

M CHANGELOG.md
M bind.go
M compress/compression.go
M features.go
M ibr2/ibr2.go
M sasl.go
M starttls.go
M CHANGELOG.md => CHANGELOG.md +2 -0
@@ 10,6 10,8 @@ All notable changes to this project will be documented in this file.
  available for all stream errors
- stream: the `TokenReader` method signature has changed to make it match the
  `xmlstream.Marshaler` interface
- xmpp: the `StreamFeature` type's `Parse` function now takes an xml.Decoder
  instead of an `xml.TokenReader`
- xtime: change the `Time` type to fix unmarshaling



M bind.go => bind.go +2 -2
@@ 106,11 106,11 @@ func bind(server func(jid.JID, string) (jid.JID, error)) StreamFeature {
			err = e.EncodeToken(start.End())
			return req, err
		},
		Parse: func(ctx context.Context, r xml.TokenReader, start *xml.StartElement) (bool, interface{}, error) {
		Parse: func(ctx context.Context, d *xml.Decoder, start *xml.StartElement) (bool, interface{}, error) {
			parsed := struct {
				XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
			}{}
			return true, nil, xml.NewTokenDecoder(r).DecodeElement(&parsed, start)
			return true, nil, d.DecodeElement(&parsed, start)
		},
		Negotiate: func(ctx context.Context, session *Session, data interface{}) (mask SessionState, rw io.ReadWriter, err error) {
			r := session.TokenReader()

M compress/compression.go => compress/compression.go +2 -2
@@ 69,12 69,12 @@ func New(methods ...Method) xmpp.StreamFeature {

			return req, e.EncodeToken(start.End())
		},
		Parse: func(ctx context.Context, r xml.TokenReader, start *xml.StartElement) (bool, interface{}, error) {
		Parse: func(ctx context.Context, d *xml.Decoder, start *xml.StartElement) (bool, interface{}, error) {
			listed := struct {
				XMLName xml.Name `xml:"http://jabber.org/features/compress compression"`
				Methods []string `xml:"http://jabber.org/features/compress method"`
			}{}
			if err := xml.NewTokenDecoder(r).DecodeElement(&listed, start); err != nil {
			if err := d.DecodeElement(&listed, start); err != nil {
				return false, nil, err
			}


M features.go => features.go +1 -1
@@ 54,7 54,7 @@ type StreamFeature struct {
	// Returns whether or not the feature is required, and any data that will be
	// needed if the feature is selected for negotiation (eg. the list of
	// mechanisms if the feature was SASL authentication).
	Parse func(ctx context.Context, r xml.TokenReader, start *xml.StartElement) (req bool, data interface{}, err error)
	Parse func(ctx context.Context, d *xml.Decoder, start *xml.StartElement) (req bool, data interface{}, err error)

	// A function that will take over the session temporarily while negotiating
	// the feature. The "mask" SessionState represents the state bits that should

M ibr2/ibr2.go => ibr2/ibr2.go +2 -3
@@ 76,13 76,12 @@ func listFunc(challenges ...Challenge) func(context.Context, xmlstream.TokenWrit
	}
}

func parseFunc(challenges ...Challenge) func(context.Context, xml.TokenReader, *xml.StartElement) (req bool, supported interface{}, err error) {
	return func(ctx context.Context, r xml.TokenReader, start *xml.StartElement) (bool, interface{}, error) {
func parseFunc(challenges ...Challenge) func(context.Context, *xml.Decoder, *xml.StartElement) (req bool, supported interface{}, err error) {
	return func(ctx context.Context, d *xml.Decoder, start *xml.StartElement) (bool, interface{}, error) {
		// Parse the list of challenge types sent down by the server.
		parsed := struct {
			Challenges []string `xml:"urn:xmpp:register:0 challenge"`
		}{}
		d := xml.NewTokenDecoder(r)
		err := d.DecodeElement(&parsed, start)
		if err != nil {
			return false, false, err

M sasl.go => sasl.go +2 -2
@@ 63,12 63,12 @@ func SASL(identity, password string, mechanisms ...sasl.Mechanism) StreamFeature
			}
			return req, e.EncodeToken(start.End())
		},
		Parse: func(ctx context.Context, r xml.TokenReader, start *xml.StartElement) (bool, interface{}, error) {
		Parse: func(ctx context.Context, d *xml.Decoder, start *xml.StartElement) (bool, interface{}, error) {
			parsed := struct {
				XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanisms"`
				List    []string `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanism"`
			}{}
			err := xml.NewTokenDecoder(r).DecodeElement(&parsed, start)
			err := d.DecodeElement(&parsed, start)
			return true, parsed.List, err
		},
		Negotiate: func(ctx context.Context, session *Session, data interface{}) (mask SessionState, rw io.ReadWriter, err error) {

M starttls.go => starttls.go +2 -2
@@ 36,14 36,14 @@ func StartTLS(cfg *tls.Config) StreamFeature {
			}
			return true, e.EncodeToken(start.End())
		},
		Parse: func(ctx context.Context, r xml.TokenReader, start *xml.StartElement) (bool, interface{}, error) {
		Parse: func(ctx context.Context, d *xml.Decoder, start *xml.StartElement) (bool, interface{}, error) {
			parsed := struct {
				XMLName  xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls starttls"`
				Required struct {
					XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls required"`
				}
			}{}
			err := xml.NewTokenDecoder(r).DecodeElement(&parsed, start)
			err := d.DecodeElement(&parsed, start)
			return parsed.Required.XMLName.Local == "required" && parsed.Required.XMLName.Space == ns.StartTLS, nil, err
		},
		Negotiate: func(ctx context.Context, session *Session, data interface{}) (mask SessionState, rw io.ReadWriter, err error) {