msgpack5 6.0.2 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,6 +18,52 @@ test('decode throws when object has forbidden __proto__ property', function (t)
18
18
  t.end()
19
19
  })
20
20
 
21
+ test('decode defaults protoAction with partial options', function (t) {
22
+ const payload = { hello: 'world' }
23
+ Object.defineProperty(payload, '__proto__', {
24
+ value: { polluted: true },
25
+ enumerable: true
26
+ })
27
+
28
+ const encoded = msgpack().encode(payload)
29
+ const options = [
30
+ {},
31
+ { forceFloat64: true },
32
+ { compatibilityMode: true },
33
+ { disableTimestampEncoding: true },
34
+ { preferMap: false },
35
+ { sortKeys: true },
36
+ { protoAction: undefined }
37
+ ]
38
+
39
+ options.forEach(function (opts) {
40
+ t.throws(function () {
41
+ msgpack(opts).decode(encoded)
42
+ }, /Object contains forbidden prototype property/)
43
+ })
44
+ t.equal({}.polluted, undefined, 'does not affect Object.prototype')
45
+ t.end()
46
+ })
47
+
48
+ test('does not mutate the caller options object', function (t) {
49
+ const options = { forceFloat64: true }
50
+ msgpack(options)
51
+
52
+ t.equal(options.protoAction, undefined)
53
+ t.end()
54
+ })
55
+
56
+ test('validates protoAction', function (t) {
57
+ const invalid = [null, false, '', 'typo']
58
+
59
+ invalid.forEach(function (protoAction) {
60
+ t.throws(function () {
61
+ msgpack({ protoAction })
62
+ }, /protoAction must be "error", "remove", or "ignore"/)
63
+ })
64
+ t.end()
65
+ })
66
+
21
67
  test('decode ignores forbidden __proto__ property if protoAction is "ignore"', function (t) {
22
68
  const encoder = msgpack({ protoAction: 'ignore' })
23
69
 
@@ -30,6 +76,9 @@ test('decode ignores forbidden __proto__ property if protoAction is "ignore"', f
30
76
  const decoded = encoder.decode(encoder.encode(payload))
31
77
 
32
78
  t.equal(decoded.polluted, true)
79
+ t.notEqual(Object.getPrototypeOf(decoded), Object.prototype)
80
+ t.notOk(Object.prototype.hasOwnProperty.call(decoded, 'polluted'))
81
+ t.equal({}.polluted, undefined, 'does not affect Object.prototype')
33
82
  t.end()
34
83
  })
35
84
 
@@ -45,5 +94,6 @@ test('decode removes forbidden __proto__ property if protoAction is "remove"', f
45
94
  const decoded = encoder.decode(encoder.encode(payload))
46
95
 
47
96
  t.equal(decoded.polluted, undefined)
97
+ t.equal(Object.getPrototypeOf(decoded), Object.prototype)
48
98
  t.end()
49
99
  })
@@ -0,0 +1,53 @@
1
+ 'use strict'
2
+
3
+ const Buffer = require('safe-buffer').Buffer
4
+ const test = require('tape').test
5
+ const msgpack = require('../')
6
+
7
+ const reservedByteError = '0xc1 is a reserved MessagePack byte'
8
+
9
+ test('reserved byte is invalid rather than incomplete', function (t) {
10
+ t.plan(3)
11
+
12
+ const pack = msgpack()
13
+ let error
14
+
15
+ try {
16
+ pack.decode(Buffer.from([0xc1]))
17
+ } catch (err) {
18
+ error = err
19
+ }
20
+
21
+ t.ok(error, 'must throw an error')
22
+ t.notOk(error instanceof pack.IncompleteBufferError, 'must not report incomplete input')
23
+ t.equal(error.message, reservedByteError, 'must identify the reserved byte')
24
+ })
25
+
26
+ test('stream decoder rejects reserved byte without retaining input', function (t) {
27
+ t.plan(5)
28
+
29
+ const decoder = msgpack().decoder()
30
+ let decoded = 0
31
+ let errors = 0
32
+
33
+ decoder.on('data', function () {
34
+ decoded++
35
+ })
36
+
37
+ decoder.on('error', function (err) {
38
+ errors++
39
+ t.equal(err.message, reservedByteError, 'must emit the decoding error')
40
+ })
41
+
42
+ decoder.on('close', function () {
43
+ t.equal(decoded, 0, 'must not emit decoded values')
44
+ t.equal(errors, 1, 'must emit one error')
45
+ t.equal(decoder._chunks.length, 0, 'must release buffered input')
46
+ t.ok(decoder.destroyed, 'must stop accepting input')
47
+ })
48
+
49
+ decoder.write(Buffer.concat([
50
+ Buffer.from([0xc1]),
51
+ Buffer.alloc(200 * 1024, 0x01)
52
+ ]))
53
+ })
package/test/streams.js CHANGED
@@ -183,6 +183,84 @@ test('concatenated buffers work', function (t) {
183
183
  encoder.end()
184
184
  })
185
185
 
186
+ test('map32 header split across chunks', function (t) {
187
+ t.plan(2)
188
+
189
+ const decoder = msgpack().decoder()
190
+
191
+ decoder.on('data', function (value) {
192
+ t.deepEqual(value, {}, 'must decode the map')
193
+ })
194
+
195
+ decoder.on('error', function (err) {
196
+ t.fail(err.message)
197
+ })
198
+
199
+ decoder.on('end', function () {
200
+ t.pass('must end normally')
201
+ })
202
+
203
+ const encoded = [0xdf, 0x00, 0x00, 0x00, 0x00]
204
+ encoded.forEach(function (byte) {
205
+ decoder.write(Buffer.from([byte]))
206
+ })
207
+ decoder.end()
208
+ })
209
+
210
+ test('many concatenated values do not overflow the stack', function (t) {
211
+ t.plan(2)
212
+
213
+ const total = 50000
214
+ const decoder = msgpack().decoder()
215
+ let decoded = 0
216
+
217
+ decoder.on('data', function () {
218
+ decoded++
219
+ })
220
+
221
+ decoder.write(Buffer.alloc(total, 0x01), function (err) {
222
+ t.error(err, 'must decode without an error')
223
+ t.equal(decoded, total, 'must decode every value')
224
+ })
225
+ })
226
+
227
+ test('incomplete containers resume without decoding elements again', function (t) {
228
+ t.plan(3)
229
+
230
+ const pack = msgpack()
231
+ const decoder = pack.decoder()
232
+ const values = []
233
+ let decodeCalls = 0
234
+ let maxBuffered = 0
235
+
236
+ function MyType (value) {
237
+ this.value = value
238
+ }
239
+
240
+ pack.register(0x42, MyType, function (obj) {
241
+ return Buffer.from([obj.value])
242
+ }, function (buf) {
243
+ decodeCalls++
244
+ return buf.readUInt8(0)
245
+ })
246
+
247
+ for (let i = 0; i < 100; i++) {
248
+ values.push(new MyType(i))
249
+ }
250
+
251
+ decoder.on('data', function (result) {
252
+ t.deepEqual(result, { values: values.map(function (value) { return value.value }) })
253
+ t.equal(decodeCalls, values.length, 'each completed element is decoded once')
254
+ })
255
+
256
+ const encoded = pack.encode({ values })
257
+ for (let i = 0; i < encoded.length; i++) {
258
+ decoder.write(encoded.slice(i, i + 1))
259
+ maxBuffered = Math.max(maxBuffered, decoder._chunks.length)
260
+ }
261
+ t.ok(maxBuffered <= 6, 'only the current incomplete value remains buffered')
262
+ decoder.end()
263
+ })
186
264
  test('nil processing works', function (t) {
187
265
  t.plan(3)
188
266