Commit cf599f6f authored by Zackery Spytz's avatar Zackery Spytz Committed by Serhiy Storchaka

bpo-6584: Add a BadGzipFile exception to the gzip module. (GH-13022)

Co-Authored-By: default avatarFilip Gruszczyński <gruszczy@gmail.com>
Co-Authored-By: default avatarMichele Orrù <maker@tumbolandia.net>
parent d28772ab
...@@ -59,6 +59,14 @@ The module defines the following items: ...@@ -59,6 +59,14 @@ The module defines the following items:
.. versionchanged:: 3.6 .. versionchanged:: 3.6
Accepts a :term:`path-like object`. Accepts a :term:`path-like object`.
.. exception:: BadGzipFile
An exception raised for invalid gzip files. It inherits :exc:`OSError`.
:exc:`EOFError` and :exc:`zlib.error` can also be raised for invalid gzip
files.
.. versionadded:: 3.8
.. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None) .. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None)
Constructor for the :class:`GzipFile` class, which simulates most of the Constructor for the :class:`GzipFile` class, which simulates most of the
......
...@@ -304,6 +304,11 @@ gzip ...@@ -304,6 +304,11 @@ gzip
Added the *mtime* parameter to :func:`gzip.compress` for reproducible output. Added the *mtime* parameter to :func:`gzip.compress` for reproducible output.
(Contributed by Guo Ci Teo in :issue:`34898`.) (Contributed by Guo Ci Teo in :issue:`34898`.)
A :exc:`~gzip.BadGzipFile` exception is now raised instead of :exc:`OSError`
for certain types of invalid or corrupt gzip files.
(Contributed by Filip Gruszczyński, Michele Orrù, and Zackery Spytz in
:issue:`6584`.)
idlelib and IDLE idlelib and IDLE
---------------- ----------------
......
...@@ -11,7 +11,7 @@ import builtins ...@@ -11,7 +11,7 @@ import builtins
import io import io
import _compression import _compression
__all__ = ["GzipFile", "open", "compress", "decompress"] __all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"]
FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16 FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
...@@ -112,6 +112,11 @@ class _PaddedFile: ...@@ -112,6 +112,11 @@ class _PaddedFile:
def seekable(self): def seekable(self):
return True # Allows fast-forwarding even in unseekable streams return True # Allows fast-forwarding even in unseekable streams
class BadGzipFile(OSError):
"""Exception raised in some cases for invalid gzip files."""
class GzipFile(_compression.BaseStream): class GzipFile(_compression.BaseStream):
"""The GzipFile class simulates most of the methods of a file object with """The GzipFile class simulates most of the methods of a file object with
the exception of the truncate() method. the exception of the truncate() method.
...@@ -413,12 +418,12 @@ class _GzipReader(_compression.DecompressReader): ...@@ -413,12 +418,12 @@ class _GzipReader(_compression.DecompressReader):
return False return False
if magic != b'\037\213': if magic != b'\037\213':
raise OSError('Not a gzipped file (%r)' % magic) raise BadGzipFile('Not a gzipped file (%r)' % magic)
(method, flag, (method, flag,
self._last_mtime) = struct.unpack("<BBIxx", self._read_exact(8)) self._last_mtime) = struct.unpack("<BBIxx", self._read_exact(8))
if method != 8: if method != 8:
raise OSError('Unknown compression method') raise BadGzipFile('Unknown compression method')
if flag & FEXTRA: if flag & FEXTRA:
# Read & discard the extra field, if present # Read & discard the extra field, if present
...@@ -502,10 +507,10 @@ class _GzipReader(_compression.DecompressReader): ...@@ -502,10 +507,10 @@ class _GzipReader(_compression.DecompressReader):
# stored is the true file size mod 2**32. # stored is the true file size mod 2**32.
crc32, isize = struct.unpack("<II", self._read_exact(8)) crc32, isize = struct.unpack("<II", self._read_exact(8))
if crc32 != self._crc: if crc32 != self._crc:
raise OSError("CRC check failed %s != %s" % (hex(crc32), raise BadGzipFile("CRC check failed %s != %s" % (hex(crc32),
hex(self._crc))) hex(self._crc)))
elif isize != (self._stream_size & 0xffffffff): elif isize != (self._stream_size & 0xffffffff):
raise OSError("Incorrect length of data produced") raise BadGzipFile("Incorrect length of data produced")
# Gzip files can be padded with zeroes and still have archives. # Gzip files can be padded with zeroes and still have archives.
# Consume all zero bytes and set the file position to the first # Consume all zero bytes and set the file position to the first
......
...@@ -391,6 +391,15 @@ class TestGzip(BaseTest): ...@@ -391,6 +391,15 @@ class TestGzip(BaseTest):
d = f.read() d = f.read()
self.assertEqual(d, data1 * 50, "Incorrect data in file") self.assertEqual(d, data1 * 50, "Incorrect data in file")
def test_gzip_BadGzipFile_exception(self):
self.assertTrue(issubclass(gzip.BadGzipFile, OSError))
def test_bad_gzip_file(self):
with open(self.filename, 'wb') as file:
file.write(data1 * 50)
with gzip.GzipFile(self.filename, 'r') as file:
self.assertRaises(gzip.BadGzipFile, file.readlines)
def test_non_seekable_file(self): def test_non_seekable_file(self):
uncompressed = data1 * 50 uncompressed = data1 * 50
buf = UnseekableIO() buf = UnseekableIO()
......
Add a :exc:`~gzip.BadGzipFile` exception to the :mod:`gzip` module.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment