diff --git a/lib/services/get-event-information.js b/lib/services/get-event-information.js index 09afbb4c..dbfbd2bf 100644 --- a/lib/services/get-event-information.js +++ b/lib/services/get-event-information.js @@ -7,14 +7,23 @@ module.exports.encode = (buffer, lastReceivedObjectId) => { baAsn1.encodeContextObjectId(buffer, 0, lastReceivedObjectId.type, lastReceivedObjectId.instance); }; -module.exports.decode = (buffer, offset) => { +module.exports.decode = (buffer, offset, apduLen) => { let len = 0; const value = {}; - const result = baAsn1.decodeTagNumberAndValue(buffer, offset + len); - len += result.len; - const decodedValue = baAsn1.decodeObjectId(buffer, offset + len); - len += decodedValue.len; - value.lastReceivedObjectId = {type: decodedValue.objectType, instance: decodedValue.instance}; + value.lastReceivedObjectId = null; + // The 'lastReceivedObjectIdentifier' is optional (ASHRAE 135, 13.12.1.1). A + // client asking for the first batch of events omits it, which results in a + // service request without any payload. + const hasObjectId = (apduLen === undefined || apduLen > 0) && + offset < buffer.length && + baAsn1.decodeIsContextTag(buffer, offset, 0); + if (hasObjectId) { + const result = baAsn1.decodeTagNumberAndValue(buffer, offset + len); + len += result.len; + const decodedValue = baAsn1.decodeObjectId(buffer, offset + len); + len += decodedValue.len; + value.lastReceivedObjectId = {type: decodedValue.objectType, instance: decodedValue.instance}; + } value.len = len; return value; }; diff --git a/test/unit/service-get-event-information.spec.js b/test/unit/service-get-event-information.spec.js index 25db0372..45bffd26 100644 --- a/test/unit/service-get-event-information.spec.js +++ b/test/unit/service-get-event-information.spec.js @@ -14,6 +14,24 @@ describe('bacstack - Services layer GetEventInformation unit', () => { lastReceivedObjectId: {type: 8, instance: 15} }); }); + + it('should successfully decode a request without the optional object identifier', () => { + const buffer = utils.getBuffer(); + const result = baServices.getEventInformation.decode(buffer.buffer, 0, 0); + delete result.len; + expect(result).toEqual({ + lastReceivedObjectId: null + }); + }); + + it('should not read beyond the end of a request without payload', () => { + const buffer = Buffer.from([]); + const result = baServices.getEventInformation.decode(buffer, 0, 0); + delete result.len; + expect(result).toEqual({ + lastReceivedObjectId: null + }); + }); }); describe('GetEventInformationAcknowledge', () => {