coap-packet
Advanced tools
Comparing version 1.1.0 to 1.1.1
@@ -1,1 +0,1 @@ | ||
{"processes":{"430d400a-f407-4f89-9bfa-184cceee4790":{"parent":null,"children":[]}},"files":{"/Users/matteo/repositories/coap-packet/index.js":["430d400a-f407-4f89-9bfa-184cceee4790"]},"externalIds":{}} | ||
{"processes":{"ada348e7-c6f6-4685-8f6d-85b1206ff1ab":{"parent":null,"children":[]}},"files":{"/Users/matteo/repositories/coap-packet/index.js":["ada348e7-c6f6-4685-8f6d-85b1206ff1ab"]},"externalIds":{}} |
@@ -66,3 +66,3 @@ export type OptionName = | ||
export function generate(packet: Packet): Buffer; | ||
export function generate(packet: Packet, maxLength?: number): Buffer; | ||
export function parse(buffer: Buffer): ParsedPacket; |
153
index.js
@@ -31,3 +31,3 @@ | ||
module.exports.generate = function generate (packet) { | ||
module.exports.generate = function generate (packet, maxLength = 1280) { | ||
let pos = 0 | ||
@@ -38,7 +38,17 @@ | ||
const length = calculateLength(packet, options) | ||
const tokenLength = packet.token.length | ||
let tokenMask | ||
if (length > 1280) { | ||
throw new Error('Max packet size is 1280: current is ' + length) | ||
if (tokenLength < 13) { | ||
tokenMask = tokenLength | ||
} else if (tokenLength < 270) { | ||
tokenMask = 13 | ||
} else if (tokenLength < 65805) { | ||
tokenMask = 14 | ||
} | ||
if (length > maxLength) { | ||
throw new Error(`Max packet size is ${maxLength}: current is ${length}`) | ||
} | ||
const buffer = Buffer.alloc(length) | ||
@@ -50,3 +60,3 @@ | ||
byte |= confirmableAckResetMask(packet) | ||
byte |= packet.token.length | ||
byte |= tokenMask | ||
buffer.writeUInt8(byte, pos++) | ||
@@ -65,5 +75,13 @@ | ||
if (tokenLength > 268) { | ||
buffer.writeUInt16BE(tokenLength - 269, pos) | ||
pos += 2 | ||
} else if (tokenLength > 12) { | ||
buffer.writeUInt8(tokenLength - 13, pos) | ||
pos++ | ||
} | ||
// the token might be an empty buffer | ||
packet.token.copy(buffer, pos) | ||
pos += packet.token.length | ||
pos += tokenLength | ||
@@ -155,5 +173,11 @@ // write the options | ||
function parseToken (buffer) { | ||
const length = buffer.readUInt8(0) & 15 | ||
let length = buffer.readUInt8(0) & 15 | ||
if (length > 8) { | ||
if (length === 13) { | ||
length = buffer.readUInt8(index) + 13 | ||
index += 1 | ||
} else if (length === 14) { | ||
length = buffer.readUInt16BE(index) + 269 | ||
index += 2 | ||
} else if (length === 15) { | ||
throw new Error('Token length not allowed') | ||
@@ -169,46 +193,49 @@ } | ||
const numMap = { | ||
1: 'If-Match', | ||
3: 'Uri-Host', | ||
4: 'ETag', | ||
5: 'If-None-Match', | ||
6: 'Observe', | ||
7: 'Uri-Port', | ||
8: 'Location-Path', | ||
9: 'OSCORE', | ||
11: 'Uri-Path', | ||
12: 'Content-Format', | ||
14: 'Max-Age', | ||
15: 'Uri-Query', | ||
16: 'Hop-Limit', | ||
17: 'Accept', | ||
19: 'Q-Block1', | ||
20: 'Location-Query', | ||
23: 'Block2', | ||
27: 'Block1', | ||
28: 'Size2', | ||
31: 'Q-Block2', | ||
35: 'Proxy-Uri', | ||
39: 'Proxy-Scheme', | ||
60: 'Size1', | ||
258: 'No-Response', | ||
2049: 'OCF-Accept-Content-Format-Version', | ||
2053: 'OCF-Content-Format-Version' | ||
const OPTIONS_BY_NAME = { | ||
'If-Match': 1, | ||
'Uri-Host': 3, | ||
ETag: 4, | ||
'If-None-Match': 5, | ||
Observe: 6, | ||
'Uri-Port': 7, | ||
'Location-Path': 8, | ||
OSCORE: 9, | ||
'Uri-Path': 11, | ||
'Content-Format': 12, | ||
'Max-Age': 14, | ||
'Uri-Query': 15, | ||
'Hop-Limit': 16, | ||
Accept: 17, | ||
'Q-Block1': 19, | ||
'Location-Query': 20, | ||
Block2: 23, | ||
Block1: 27, | ||
Size2: 28, | ||
'Q-Block2': 31, | ||
'Proxy-Uri': 35, | ||
'Proxy-Scheme': 39, | ||
Size1: 60, | ||
'No-Response': 258, | ||
'OCF-Accept-Content-Format-Version': 2049, | ||
'OCF-Content-Format-Version': 2053 | ||
} | ||
const optionNumberToString = (function genOptionParser () { | ||
let code = Object.keys(numMap).reduce(function (acc, key) { | ||
acc += 'case ' + key + ':\n' | ||
acc += ' return \'' + numMap[key] + '\'\n' | ||
const OPTIONS_BY_NUMBER = new Array(2054) | ||
for (const key in OPTIONS_BY_NAME) { | ||
const number = OPTIONS_BY_NAME[key] | ||
OPTIONS_BY_NUMBER[number] = key | ||
} | ||
return acc | ||
}, 'switch(number) {\n') | ||
function optionNumberToString (number) { | ||
const string = OPTIONS_BY_NUMBER[number] | ||
if (string) return string | ||
return '' + number | ||
} | ||
code += 'default:\n' | ||
code += 'return \'\' + number' | ||
code += '}\n' | ||
function optionStringToNumber (string) { | ||
const number = OPTIONS_BY_NAME[string] | ||
if (number) return number | ||
return parseInt(string) | ||
} | ||
return new Function('number', code) /* eslint-disable-line no-new-func */ | ||
})() | ||
function parseOptions (buffer) { | ||
@@ -295,3 +322,3 @@ let number = 0 | ||
if (packet.token.length > 8) { | ||
if (packet.token.length > 65804) { | ||
throw new Error('Token too long') | ||
@@ -350,2 +377,10 @@ } | ||
if (packet.token.length > 12) { | ||
length += 1 | ||
} | ||
if (packet.token.length > 268) { | ||
length += 1 | ||
} | ||
if (packet.code !== '0.00' && packet.payload.toString() !== '') { | ||
@@ -362,22 +397,2 @@ length += 1 | ||
const optionStringToNumber = (function genOptionParser () { | ||
let code = Object.keys(numMap).reduce(function (acc, key) { | ||
acc += 'case \'' + numMap[key] + '\':\n' | ||
acc += ' return \'' + key + '\'\n' | ||
return acc | ||
}, 'switch(string) {\n') | ||
code += 'default:\n' | ||
code += 'return parseInt(string)' | ||
code += '}\n' | ||
return new Function('string', code) /* eslint-disable-line no-new-func */ | ||
})() | ||
const nameMap = Object.keys(numMap).reduce(function (acc, key) { | ||
acc[numMap[key]] = key | ||
return acc | ||
}, {}) | ||
function optionSorter (a, b) { | ||
@@ -387,4 +402,4 @@ a = a.name | ||
a = parseInt(nameMap[a] || a) | ||
b = parseInt(nameMap[b] || b) | ||
a = parseInt(OPTIONS_BY_NAME[a] || a) | ||
b = parseInt(OPTIONS_BY_NAME[b] || b) | ||
@@ -391,0 +406,0 @@ if (a < b) { |
{ | ||
"name": "coap-packet", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Generate and Parse CoAP packets", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -15,3 +15,3 @@ CoAP-Packet | ||
This library follows [RFC 7252](https://datatracker.ietf.org/doc/html/rfc7252) for generating and parsing of CoAP packets. | ||
This library follows [RFC 7252](https://datatracker.ietf.org/doc/html/rfc7252) and [RFC 8974](https://datatracker.ietf.org/doc/html/rfc8974) for generating and parsing of CoAP packets. | ||
It also supports the method and option codes specified by other specifications, such as [RFC 7641](https://datatracker.ietf.org/doc/html/rfc7641), [RFC 7959](https://datatracker.ietf.org/doc/html/rfc7959), and [RFC 8132](https://datatracker.ietf.org/doc/html/rfc8132). | ||
@@ -18,0 +18,0 @@ |
80
test.js
@@ -185,2 +185,63 @@ | ||
}) | ||
it('should not allow for a token length value of 15', function () { | ||
byte = 0 | ||
byte |= 1 << 6 // byte two bits are version | ||
byte |= 15 // the TKL length is invalid | ||
buffer.writeUInt8(byte, 0) | ||
expect(parse.bind(null, buffer)).to.throw('Token length not allowed') | ||
}) | ||
it('should parse a token with extended length of 13 bytes', function () { | ||
buffer = Buffer.alloc(20) | ||
byte = 0 | ||
byte |= 1 << 6 // byte two bits are version | ||
byte |= 1 << 4 // the message is non-confirmable | ||
byte |= 13 // the TKL length is specified in the byte before the token | ||
buffer.writeUInt8(byte, 0) | ||
buffer.writeUInt8(1, 1) // it is a post | ||
buffer.writeUInt16BE(42, 2) // the message ID | ||
buffer.writeUInt8(0, 4) // it has a token length of 13 bytes | ||
const token = Buffer.alloc(13) | ||
token.copy(buffer, 5, 0, 13) | ||
buffer.writeUInt8(255, 18) // the payload seperator | ||
buffer.writeUInt8(42, 19) // the payload | ||
packet = parse(buffer) | ||
expect(packet.code).to.eql('0.01') | ||
expect(packet.token).to.eql(token) | ||
expect(packet.payload).to.eql(Buffer.of(42)) | ||
}) | ||
it('should parse a token with extended length of 269 bytes', function () { | ||
buffer = Buffer.alloc(280) | ||
byte = 0 | ||
byte |= 1 << 6 // byte two bits are version | ||
byte |= 1 << 4 // the message is non-confirmable | ||
byte |= 14 // the TKL length is specified in the two bytes before the token | ||
buffer.writeUInt8(byte, 0) | ||
buffer.writeUInt8(1, 1) // it is a post | ||
buffer.writeUInt16BE(42, 2) // the message ID | ||
buffer.writeInt16BE(0, 3) // it has a token length of 269 bytes | ||
const token = Buffer.alloc(269) | ||
token.copy(buffer, 6, 0) | ||
buffer.writeUInt8(255, 278) // the payload seperator | ||
buffer.writeUInt8(42, 279) // the payload | ||
packet = parse(buffer) | ||
expect(packet.code).to.eql('0.01') | ||
expect(packet.token).to.eql(token) | ||
expect(packet.payload).to.eql(Buffer.of(42)) | ||
}) | ||
}) | ||
@@ -741,4 +802,4 @@ | ||
it('should have a maximum token length of 8', function () { | ||
token = Buffer.alloc(9) | ||
it('should have a maximum token length of 65804', function () { | ||
token = Buffer.alloc(65805) | ||
expect(generate.bind(null, { token: token })).to.throw('Token too long') | ||
@@ -1052,2 +1113,17 @@ }) | ||
it('should generate and parse a packet with token length 13', function () { | ||
const token = Buffer.alloc(13) | ||
expect(parse(generate({ token })).token).to.eql(token) | ||
}) | ||
it('should generate and parse a packet with token length 1000', function () { | ||
const token = Buffer.alloc(1000) | ||
expect(parse(generate({ token })).token).to.eql(token) | ||
}) | ||
it('should generate and parse a packet with token length 65804', function () { | ||
const token = Buffer.alloc(65804) | ||
expect(parse(generate({ token }, 65810)).token).to.eql(token) | ||
}) | ||
it('should process a packet with Uri-Path and Observe', function () { | ||
@@ -1054,0 +1130,0 @@ orig = { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
93330
1374