feat: Simplify the JID parser

Fixes #13.
This commit is contained in:
PapaTutuWawa 2023-01-04 17:19:37 +01:00
parent 55d2ef9c25
commit 763c93857d
2 changed files with 52 additions and 77 deletions

View File

@ -6,67 +6,38 @@ class JID {
const JID(this.local, this.domain, this.resource); const JID(this.local, this.domain, this.resource);
factory JID.fromString(String jid) { factory JID.fromString(String jid) {
// 0: Parsing either the local or domain part // Algorithm taken from here: https://blog.samwhited.com/2021/02/xmpp-addresses/
// 1: Parsing the domain part var localPart = '';
// 2: Parsing the resource var domainPart = '';
var state = 0; var resourcePart = '';
var buffer = '';
var local_ = '';
var domain_ = '';
var resource_ = '';
for (var i = 0; i < jid.length; i++) {
final c = jid[i];
final eol = i == jid.length - 1;
switch (state) {
case 0: {
if (c == '@') {
local_ = buffer;
buffer = '';
state = 1;
} else if (c == '/') {
domain_ = buffer;
buffer = '';
state = 2;
} else if (eol) {
domain_ = buffer + c;
} else {
buffer += c;
}
}
break;
case 1: {
if (c == '/') {
domain_ = buffer;
buffer = '';
state = 2;
} else if (eol) {
domain_ = buffer;
if (c != ' ') { final slashParts = jid.split('/');
domain_ = domain_ + c; if (slashParts.length == 1) {
} resourcePart = '';
} else if (c != ' ') { } else {
buffer += c; resourcePart = slashParts.sublist(1).join('/');
}
}
break;
case 2: {
if (eol) {
resource_ = buffer;
if (c != ' ') { assert(resourcePart.isNotEmpty, 'Resource part cannot be there and empty');
resource_ = resource_ + c;
}
} else if (c != ''){
buffer += c;
}
}
}
} }
return JID(local_, domain_, resource_); final atParts = slashParts.first.split('@');
if (atParts.length == 1) {
localPart = '';
domainPart = atParts.first;
} else {
localPart = atParts.first;
domainPart = atParts.sublist(1).join('@');
assert(localPart.isNotEmpty, 'Local part cannot be there and empty');
}
return JID(
localPart,
domainPart.endsWith('.') ?
domainPart.substring(0, domainPart.length - 1) :
domainPart,
resourcePart,
);
} }
final String local; final String local;
final String domain; final String domain;

View File

@ -3,39 +3,43 @@ import 'package:test/test.dart';
void main() { void main() {
test('Parse a full JID', () { test('Parse a full JID', () {
final jid = JID.fromString('test@server/abc'); final jid = JID.fromString('test@server/abc');
expect(jid.local, 'test'); expect(jid.local, 'test');
expect(jid.domain, 'server'); expect(jid.domain, 'server');
expect(jid.resource, 'abc'); expect(jid.resource, 'abc');
expect(jid.toString(), 'test@server/abc'); expect(jid.toString(), 'test@server/abc');
}); });
test('Parse a bare JID', () { test('Parse a bare JID', () {
final jid = JID.fromString('test@server'); final jid = JID.fromString('test@server');
expect(jid.local, 'test'); expect(jid.local, 'test');
expect(jid.domain, 'server'); expect(jid.domain, 'server');
expect(jid.resource, ''); expect(jid.resource, '');
expect(jid.toString(), 'test@server'); expect(jid.toString(), 'test@server');
}); });
test('Parse a JID with no local part', () { test('Parse a JID with no local part', () {
final jid = JID.fromString('server/abc'); final jid = JID.fromString('server/abc');
expect(jid.local, ''); expect(jid.local, '');
expect(jid.domain, 'server'); expect(jid.domain, 'server');
expect(jid.resource, 'abc'); expect(jid.resource, 'abc');
expect(jid.toString(), 'server/abc'); expect(jid.toString(), 'server/abc');
}); });
test('Equality', () { test('Equality', () {
expect(JID.fromString('hallo@welt/abc') == JID('hallo', 'welt', 'abc'), true); expect(JID.fromString('hallo@welt/abc') == JID('hallo', 'welt', 'abc'), true);
expect(JID.fromString('hallo@welt') == JID('hallo', 'welt', 'a'), false); expect(JID.fromString('hallo@welt') == JID('hallo', 'welt', 'a'), false);
}); });
test('Whitespaces', () { test('Dot suffix at domain part', () {
expect(JID.fromString('hallo@welt ') == JID('hallo', 'welt', ''), true); expect(JID.fromString('hallo@welt.example.') == JID('hallo', 'welt.example', ''), true);
expect(JID.fromString('hallo@welt/abc ') == JID('hallo', 'welt', 'abc'), true); expect(JID.fromString('hallo@welt.example./test') == JID('hallo', 'welt.example', 'test'), true);
});
test('Parse resource with a slash', () {
expect(JID.fromString('hallo@welt.example./test/welt') == JID('hallo', 'welt.example', 'test/welt'), true);
}); });
} }