Skip to content

Commit

Permalink
fix: compatibility mode for bin format family (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
cigui authored Jul 15, 2022
1 parent d5c9146 commit c118cd3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ options:

- `forceFloat64`, a boolean to that forces all floats to be encoded as 64-bits floats. Defaults to false.
- `sortKeys`, a boolean to force a determinate keys order
- `compatibilityMode`, a boolean that enables "compatibility mode" which doesn't use str 8 format. Defaults to false.
- `compatibilityMode`, a boolean that enables "compatibility mode" which doesn't use bin format family and str 8 format. Defaults to false.
- `disableTimestampEncoding`, a boolean that when set disables the encoding of Dates into the [timestamp extension type](https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type). Defaults to false.
- `preferMap`, a boolean that forces all maps to be decoded to `Map`s rather than plain objects. This ensures that `decode(encode(new Map())) instanceof Map` and that iteration order is preserved. Defaults to false.
- `protoAction`, a string which can be `error|ignore|remove` that determines what happens when decoding a plain object with a `__proto__` property which would cause prototype poisoning. `error` (default) throws an error, `remove` removes the property, `ignore` (not recommended) allows the property, thereby causing prototype poisoning on the decoded object.
Expand Down
23 changes: 22 additions & 1 deletion lib/encoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ module.exports = function buildEncode (encodingTypes, options) {
}
// weird hack to support Buffer
// and Buffer-like objects
return bl([getBufferHeader(obj.length), obj])
const _getBufferHeader = options.compatibilityMode ? getCompatibleBufferHeader : getBufferHeader
return bl([_getBufferHeader(obj.length), obj])
}
if (Array.isArray(obj)) return encodeArray(obj, encode)
if (typeof obj === 'object') return encodeExt(obj, encodingTypes) || encodeObject(obj, options, encode)
Expand Down Expand Up @@ -225,6 +226,26 @@ function getBufferHeader (length) {
return header
}

function getCompatibleBufferHeader (length) {
let header
if (length <= 0x1f) {
// fix raw header: 101XXXXX
header = Buffer.allocUnsafe(1)
header[0] = 0xa0 | length
} else if (length <= 0xffff) {
// raw 16 header: 0xda, XXXXXXXX, XXXXXXXX
header = Buffer.allocUnsafe(3)
header[0] = 0xda
header.writeUInt16BE(length, 1)
} else {
// raw 32 header: 0xdb, XXXXXXXX, XXXXXXXX, XXXXXXXX, XXXXXXXX
header = Buffer.allocUnsafe(5)
header[0] = 0xdb
header.writeUInt32BE(length, 1)
}
return header
}

function encodeNumber (obj, options) {
let buf
if (isFloat(obj)) return encodeFloat(obj, options.forceFloat64)
Expand Down
33 changes: 33 additions & 0 deletions test/compatibility-mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
const test = require('tape').test
const msgpack = require('../')

function buildBuffer (size) {
const buf = Buffer.allocUnsafe(size)
buf.fill('a')

return buf
}

test('encode/compatibility mode', function (t) {
const compatEncoder = msgpack({
compatibilityMode: true
Expand Down Expand Up @@ -37,4 +44,30 @@ test('encode/compatibility mode', function (t) {
t.deepEqual(buf1, buf2, 'must be equal for two byte strings')
t.end()
})

const fixRawBuffer = buildBuffer(1)
const raw16Buffer = buildBuffer(Math.pow(2, 16) - 1)
const raw32Buffer = buildBuffer(Math.pow(2, 16) + 1)

t.test('compat. encoding a Buffer of length ' + fixRawBuffer.length, function (t) {
// fix raw header: 0xa0 | 1 = 0xa1
const buf = compatEncoder.encode(fixRawBuffer)
t.equal(buf[0], 0xa1, 'must have the proper header (fix raw)')
t.equal(buf.toString('utf8', 1, Buffer.byteLength(fixRawBuffer) + 1), fixRawBuffer.toString('utf8'), 'must decode correctly')
t.end()
})

t.test('compat. encoding a Buffer of length ' + raw16Buffer.length, function (t) {
const buf = compatEncoder.encode(raw16Buffer)
t.equal(buf[0], 0xda, 'must have the proper header (raw 16)')
t.equal(buf.toString('utf8', 3, Buffer.byteLength(raw16Buffer) + 3), raw16Buffer.toString('utf8'), 'must decode correctly')
t.end()
})

t.test('compat. encoding a Buffer of length ' + raw32Buffer.length, function (t) {
const buf = compatEncoder.encode(raw32Buffer)
t.equal(buf[0], 0xdb, 'must have the proper header (raw 32)')
t.equal(buf.toString('utf8', 5, Buffer.byteLength(raw32Buffer) + 5), raw32Buffer.toString('utf8'), 'must decode correctly')
t.end()
})
})

0 comments on commit c118cd3

Please sign in to comment.