~samwhited/xmpp

dd80b0dd11601b2498887da604ec3838f656d6a6 — Sam Whited 9 months ago 5d57749
component: unmarshal stream errors

Instead of returning a generic error that looks like it might have been
sent over the stream, causing confusion, actually unmarshal the error.

Signed-off-by: Sam Whited <sam@samwhited.com>
2 files changed, 43 insertions(+), 16 deletions(-)

M component/component.go
M component/component_test.go
M component/component.go => component/component.go +6 -2
@@ 123,10 123,14 @@ func Negotiator(addr jid.JID, secret []byte, recv bool) xmpp.Negotiator {
			return mask, nil, nil, errors.New("component: expected acknowledgement or error start token from server")
		}

		// TODO: Actually unmarshal the stream error.
		switch start.Name.Local {
		case "error":
			return mask, nil, nil, stream.NotAuthorized
			e := stream.Error{}
			err := d.DecodeElement(&e, &start)
			if err != nil {
				return mask, nil, nil, err
			}
			return mask, nil, nil, e
		case "handshake":
			if id == "" {
				return mask, nil, nil, errors.New("component: expected server stream to contain stream ID")

M component/component_test.go => component/component_test.go +37 -14
@@ 8,15 8,14 @@ import (
	"bytes"
	"context"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"reflect"
	"strings"
	"testing"

	"mellium.im/xmpp/component"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/stream"
)

const header = `<?xml version="1.0" encoding="UTF-8"?>`


@@ 34,9 33,13 @@ type componentClientTest struct {

var componentClientTests = [...]componentClientTest{
	0: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net'>`,
		err:    some{}, // missing ID attr
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net'></stream:stream>`,
		err:    errors.New("component: expected acknowledgement or error start token from server"),
	},
	//0: {
	//	server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net'></stream:stream>`,
	//	err:    errors.New("component: expected server stream to contain stream ID"),
	//},
	1: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'>`,
		err:    &xml.SyntaxError{Line: 1, Msg: "unexpected EOF"},


@@ 44,42 47,55 @@ var componentClientTests = [...]componentClientTest{
	2: {
		server: xml.Header + `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'>`,
		err:    some{}, // don't allow whitespace
		err:    errors.New("component: received unexpected token from server"),
	},
	3: {
		server: header + header + `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'>`,
		err:    some{}, // allow only a single XML header
		err:    errors.New("component: received unexpected proc inst from server"),
	},
	4: {
		server: `<stream xmlns='jabber:component:accept' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'>`,
		err:    some{}, // must start with stream:stream
		err:    errors.New("component: expected stream:stream from server"),
	},
	5: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'>test`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    some{}, // expect ack or error
		err:    errors.New("component: expected acknowledgement or error start token from server"),
	},
	6: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><error></error>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    stream.NotAuthorized, // expect not authorized if error reported
		err:    errors.New(""),
	},
	7: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><wrong/>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    some{}, // expect ack or error
		err:    errors.New("component: unknown start element: {{jabber:component:accept wrong} []}"),
	},
	8: {
		server: header + `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    nil,
	},
	9: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    nil,
	},
	10: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id='1234'><error><not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-streams"/></error>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>32532c0f7dbf1253c095b18b18e36d38d94c1256</handshake>`,
		err:    errors.New("not-authorized"),
	},
	11: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id=''><error><not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-streams"/></error>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'><handshake>e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4</handshake>`,
		err:    errors.New("not-authorized"),
	},
	12: {
		server: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' from='example.net' id=''><handshake></handshake>`,
		client: `<stream:stream xmlns='jabber:component:accept' xmlns:stream='http://etherx.jabber.org/streams' to='example.net'>`,
		err:    errors.New("component: expected server stream to contain stream ID"),
	},
}



@@ 100,12 116,19 @@ func TestComponent(t *testing.T) {
				Reader: in,
				Writer: out,
			}, false)
			if _, ok := tc.err.(some); (ok && err == nil) || (!ok && !reflect.DeepEqual(err, tc.err)) {
			var errStr, tcErrStr string
			if err != nil {
				errStr = err.Error()
			}
			if tc.err != nil {
				tcErrStr = tc.err.Error()
			}
			if errStr != tcErrStr {
				t.Fatalf("unexpected error: want=%v, got=%v", tc.err, err)
			}

			if o := out.String(); len(o) < len(tc.client) || o[:len(tc.client)] != tc.client {
				t.Errorf("unexpected output:\nwant=%s\n got=%s", tc.client, o)
				t.Errorf("unexpected output:\nwant=%v,\n got=%v", tc.client, o)
			}
		})
	}