Issue #27164: Allow decompressing raw Deflate streams with predefined zdict

Based on patch by Xiang Zhang.
This commit is contained in:
Martin Panter 2016-06-05 10:48:34 +00:00
parent 484c913ed9
commit 3f0ee83f14
3 changed files with 56 additions and 18 deletions

View File

@ -553,6 +553,15 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase):
self.assertEqual(dco.unconsumed_tail, b'') self.assertEqual(dco.unconsumed_tail, b'')
self.assertEqual(dco.unused_data, remainder) self.assertEqual(dco.unused_data, remainder)
# issue27164
def test_decompress_raw_with_dictionary(self):
zdict = b'abcdefghijklmnopqrstuvwxyz'
co = zlib.compressobj(wbits=-zlib.MAX_WBITS, zdict=zdict)
comp = co.compress(zdict) + co.flush()
dco = zlib.decompressobj(wbits=-zlib.MAX_WBITS, zdict=zdict)
uncomp = dco.decompress(comp) + dco.flush()
self.assertEqual(zdict, uncomp)
def test_flush_with_freed_input(self): def test_flush_with_freed_input(self):
# Issue #16411: decompressor accesses input to last decompress() call # Issue #16411: decompressor accesses input to last decompress() call
# in flush(), even if this object has been freed in the meanwhile. # in flush(), even if this object has been freed in the meanwhile.

View File

@ -131,6 +131,9 @@ Core and Builtins
Library Library
------- -------
- Issue #27164: In the zlib module, allow decompressing raw Deflate streams
with a predefined zdict. Based on patch by Xiang Zhang.
- Issue #24291: Fix wsgiref.simple_server.WSGIRequestHandler to completely - Issue #24291: Fix wsgiref.simple_server.WSGIRequestHandler to completely
write data to the client. Previously it could do partial writes and write data to the client. Previously it could do partial writes and
truncate data. Also, wsgiref.handler.ServerHandler can now handle stdout truncate data. Also, wsgiref.handler.ServerHandler can now handle stdout

View File

@ -22,6 +22,10 @@
#define LEAVE_ZLIB(obj) #define LEAVE_ZLIB(obj)
#endif #endif
#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1221
#define AT_LEAST_ZLIB_1_2_2_1
#endif
/* The following parameters are copied from zutil.h, version 0.95 */ /* The following parameters are copied from zutil.h, version 0.95 */
#define DEFLATED 8 #define DEFLATED 8
#if MAX_MEM_LEVEL >= 8 #if MAX_MEM_LEVEL >= 8
@ -474,6 +478,31 @@ zlib_compressobj_impl(PyModuleDef *module, int level, int method, int wbits,
return (PyObject*)self; return (PyObject*)self;
} }
static int
set_inflate_zdict(compobject *self)
{
Py_buffer zdict_buf;
int err;
if (PyObject_GetBuffer(self->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) {
return -1;
}
if ((size_t)zdict_buf.len > UINT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"zdict length does not fit in an unsigned int");
PyBuffer_Release(&zdict_buf);
return -1;
}
err = inflateSetDictionary(&(self->zst),
zdict_buf.buf, (unsigned int)zdict_buf.len);
PyBuffer_Release(&zdict_buf);
if (err != Z_OK) {
zlib_error(self->zst, err, "while setting zdict");
return -1;
}
return 0;
}
/*[clinic input] /*[clinic input]
zlib.decompressobj zlib.decompressobj
@ -515,6 +544,20 @@ zlib_decompressobj_impl(PyModuleDef *module, int wbits, PyObject *zdict)
switch(err) { switch(err) {
case (Z_OK): case (Z_OK):
self->is_initialised = 1; self->is_initialised = 1;
if (self->zdict != NULL && wbits < 0) {
#ifdef AT_LEAST_ZLIB_1_2_2_1
if (set_inflate_zdict(self) < 0) {
Py_DECREF(self);
return NULL;
}
#else
PyErr_Format(ZlibError,
"zlib version %s does not allow raw inflate with dictionary",
ZLIB_VERSION);
Py_DECREF(self);
return NULL;
#endif
}
return (PyObject*)self; return (PyObject*)self;
case(Z_STREAM_ERROR): case(Z_STREAM_ERROR):
Py_DECREF(self); Py_DECREF(self);
@ -741,29 +784,12 @@ zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data,
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (err == Z_NEED_DICT && self->zdict != NULL) { if (err == Z_NEED_DICT && self->zdict != NULL) {
Py_buffer zdict_buf; if (set_inflate_zdict(self) < 0) {
if (PyObject_GetBuffer(self->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) {
Py_DECREF(RetVal); Py_DECREF(RetVal);
RetVal = NULL; RetVal = NULL;
goto error; goto error;
} }
if ((size_t)zdict_buf.len > UINT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"zdict length does not fit in an unsigned int");
PyBuffer_Release(&zdict_buf);
Py_CLEAR(RetVal);
goto error;
}
err = inflateSetDictionary(&(self->zst),
zdict_buf.buf, (unsigned int)zdict_buf.len);
PyBuffer_Release(&zdict_buf);
if (err != Z_OK) {
zlib_error(self->zst, err, "while decompressing data");
Py_CLEAR(RetVal);
goto error;
}
/* Repeat the call to inflate. */ /* Repeat the call to inflate. */
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
err = inflate(&(self->zst), Z_SYNC_FLUSH); err = inflate(&(self->zst), Z_SYNC_FLUSH);