Skip to content

Commit ec5dff1

Browse files
committed
Merge pull request #105 from msgpack/max-xxx-size
Add max_<type>_len option to unpacker. (fixes #97).
2 parents c43fb48 + 2985f4d commit ec5dff1

File tree

6 files changed

+286
-53
lines changed

6 files changed

+286
-53
lines changed

.travis.yml

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ language: python
77
python:
88
- 2.7
99

10+
env:
11+
- TOXENV=py26-c,py27-c
12+
- TOXENV=py32-c,py33-c,py34-c
13+
- TOXENV=py26-pure,py27-pure
14+
- TOXENV=py32-pure,py33-pure,py34-pure
15+
- TOXENV=pypy-pure,pypy3-pure
16+
1017
install:
1118
- pip install wheel tox
1219
- ls -la wheelhouse

msgpack/_unpacker.pyx

+55-15
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ cdef extern from "unpack.h":
2828
PyObject* ext_hook
2929
char *encoding
3030
char *unicode_errors
31+
Py_ssize_t max_str_len
32+
Py_ssize_t max_bin_len
33+
Py_ssize_t max_array_len
34+
Py_ssize_t max_map_len
35+
Py_ssize_t max_ext_len
3136

3237
ctypedef struct unpack_context:
3338
msgpack_user user
@@ -46,10 +51,18 @@ cdef extern from "unpack.h":
4651
cdef inline init_ctx(unpack_context *ctx,
4752
object object_hook, object object_pairs_hook,
4853
object list_hook, object ext_hook,
49-
bint use_list, char* encoding, char* unicode_errors):
54+
bint use_list, char* encoding, char* unicode_errors,
55+
Py_ssize_t max_str_len, Py_ssize_t max_bin_len,
56+
Py_ssize_t max_array_len, Py_ssize_t max_map_len,
57+
Py_ssize_t max_ext_len):
5058
unpack_init(ctx)
5159
ctx.user.use_list = use_list
5260
ctx.user.object_hook = ctx.user.list_hook = <PyObject*>NULL
61+
ctx.user.max_str_len = max_str_len
62+
ctx.user.max_bin_len = max_bin_len
63+
ctx.user.max_array_len = max_array_len
64+
ctx.user.max_map_len = max_map_len
65+
ctx.user.max_ext_len = max_ext_len
5366

5467
if object_hook is not None and object_pairs_hook is not None:
5568
raise TypeError("object_pairs_hook and object_hook are mutually exclusive.")
@@ -85,7 +98,12 @@ def default_read_extended_type(typecode, data):
8598

8699
def unpackb(object packed, object object_hook=None, object list_hook=None,
87100
bint use_list=1, encoding=None, unicode_errors="strict",
88-
object_pairs_hook=None, ext_hook=ExtType):
101+
object_pairs_hook=None, ext_hook=ExtType,
102+
Py_ssize_t max_str_len=2147483647, # 2**32-1
103+
Py_ssize_t max_bin_len=2147483647,
104+
Py_ssize_t max_array_len=2147483647,
105+
Py_ssize_t max_map_len=2147483647,
106+
Py_ssize_t max_ext_len=2147483647):
89107
"""
90108
Unpack packed_bytes to object. Returns an unpacked object.
91109
@@ -115,7 +133,8 @@ def unpackb(object packed, object object_hook=None, object list_hook=None,
115133
cerr = PyBytes_AsString(unicode_errors)
116134

117135
init_ctx(&ctx, object_hook, object_pairs_hook, list_hook, ext_hook,
118-
use_list, cenc, cerr)
136+
use_list, cenc, cerr,
137+
max_str_len, max_bin_len, max_array_len, max_map_len, max_ext_len)
119138
ret = unpack_construct(&ctx, buf, buf_len, &off)
120139
if ret == 1:
121140
obj = unpack_data(&ctx)
@@ -144,8 +163,7 @@ def unpack(object stream, object object_hook=None, object list_hook=None,
144163

145164

146165
cdef class Unpacker(object):
147-
"""
148-
Streaming unpacker.
166+
"""Streaming unpacker.
149167
150168
arguments:
151169
@@ -183,6 +201,19 @@ cdef class Unpacker(object):
183201
Raises `BufferFull` exception when it is insufficient.
184202
You shoud set this parameter when unpacking data from untrasted source.
185203
204+
:param int max_str_len:
205+
Limits max length of str. (default: 2**31-1)
206+
207+
:param int max_bin_len:
208+
Limits max length of bin. (default: 2**31-1)
209+
210+
:param int max_array_len:
211+
Limits max length of array. (default: 2**31-1)
212+
213+
:param int max_map_len:
214+
Limits max length of map. (default: 2**31-1)
215+
216+
186217
example of streaming deserialize from file-like object::
187218
188219
unpacker = Unpacker(file_like)
@@ -220,8 +251,13 @@ cdef class Unpacker(object):
220251

221252
def __init__(self, file_like=None, Py_ssize_t read_size=0, bint use_list=1,
222253
object object_hook=None, object object_pairs_hook=None, object list_hook=None,
223-
str encoding=None, str unicode_errors='strict', int max_buffer_size=0,
224-
object ext_hook=ExtType):
254+
encoding=None, unicode_errors='strict', int max_buffer_size=0,
255+
object ext_hook=ExtType,
256+
Py_ssize_t max_str_len=2147483647, # 2**32-1
257+
Py_ssize_t max_bin_len=2147483647,
258+
Py_ssize_t max_array_len=2147483647,
259+
Py_ssize_t max_map_len=2147483647,
260+
Py_ssize_t max_ext_len=2147483647):
225261
cdef char *cenc=NULL,
226262
cdef char *cerr=NULL
227263

@@ -253,19 +289,25 @@ cdef class Unpacker(object):
253289
if encoding is not None:
254290
if isinstance(encoding, unicode):
255291
self.encoding = encoding.encode('ascii')
256-
else:
292+
elif isinstance(encoding, bytes):
257293
self.encoding = encoding
294+
else:
295+
raise TypeError("encoding should be bytes or unicode")
258296
cenc = PyBytes_AsString(self.encoding)
259297

260298
if unicode_errors is not None:
261299
if isinstance(unicode_errors, unicode):
262300
self.unicode_errors = unicode_errors.encode('ascii')
263-
else:
301+
elif isinstance(unicode_errors, bytes):
264302
self.unicode_errors = unicode_errors
303+
else:
304+
raise TypeError("unicode_errors should be bytes or unicode")
265305
cerr = PyBytes_AsString(self.unicode_errors)
266306

267307
init_ctx(&self.ctx, object_hook, object_pairs_hook, list_hook,
268-
ext_hook, use_list, cenc, cerr)
308+
ext_hook, use_list, cenc, cerr,
309+
max_str_len, max_bin_len, max_array_len,
310+
max_map_len, max_ext_len)
269311

270312
def feed(self, object next_bytes):
271313
"""Append `next_bytes` to internal buffer."""
@@ -365,7 +407,7 @@ cdef class Unpacker(object):
365407
raise ValueError("Unpack failed: error = %d" % (ret,))
366408

367409
def read_bytes(self, Py_ssize_t nbytes):
368-
"""read a specified number of raw bytes from the stream"""
410+
"""Read a specified number of raw bytes from the stream"""
369411
cdef size_t nread
370412
nread = min(self.buf_tail - self.buf_head, nbytes)
371413
ret = PyBytes_FromStringAndSize(self.buf + self.buf_head, nread)
@@ -375,8 +417,7 @@ cdef class Unpacker(object):
375417
return ret
376418

377419
def unpack(self, object write_bytes=None):
378-
"""
379-
unpack one object
420+
"""Unpack one object
380421
381422
If write_bytes is not None, it will be called with parts of the raw
382423
message as it is unpacked.
@@ -386,8 +427,7 @@ cdef class Unpacker(object):
386427
return self._unpack(unpack_construct, write_bytes)
387428

388429
def skip(self, object write_bytes=None):
389-
"""
390-
read and ignore one object, returning None
430+
"""Read and ignore one object, returning None
391431
392432
If write_bytes is not None, it will be called with parts of the raw
393433
message as it is unpacked.

0 commit comments

Comments
 (0)