Skip to content

Commit cf599f6

Browse files
ZackerySpytzgruszczymmaker
authored andcommitted
bpo-6584: Add a BadGzipFile exception to the gzip module. (GH-13022)
Co-Authored-By: Filip Gruszczyński <gruszczy@gmail.com> Co-Authored-By: Michele Orrù <maker@tumbolandia.net>
1 parent d28772a commit cf599f6

File tree

5 files changed

+34
-6
lines changed

5 files changed

+34
-6
lines changed

Doc/library/gzip.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ The module defines the following items:
5959
.. versionchanged:: 3.6
6060
Accepts a :term:`path-like object`.
6161

62+
.. exception:: BadGzipFile
63+
64+
An exception raised for invalid gzip files. It inherits :exc:`OSError`.
65+
:exc:`EOFError` and :exc:`zlib.error` can also be raised for invalid gzip
66+
files.
67+
68+
.. versionadded:: 3.8
69+
6270
.. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None)
6371

6472
Constructor for the :class:`GzipFile` class, which simulates most of the

Doc/whatsnew/3.8.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ gzip
304304
Added the *mtime* parameter to :func:`gzip.compress` for reproducible output.
305305
(Contributed by Guo Ci Teo in :issue:`34898`.)
306306

307+
A :exc:`~gzip.BadGzipFile` exception is now raised instead of :exc:`OSError`
308+
for certain types of invalid or corrupt gzip files.
309+
(Contributed by Filip Gruszczyński, Michele Orrù, and Zackery Spytz in
310+
:issue:`6584`.)
311+
307312

308313
idlelib and IDLE
309314
----------------

Lib/gzip.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import io
1212
import _compression
1313

14-
__all__ = ["GzipFile", "open", "compress", "decompress"]
14+
__all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"]
1515

1616
FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
1717

@@ -112,6 +112,11 @@ def seek(self, off):
112112
def seekable(self):
113113
return True # Allows fast-forwarding even in unseekable streams
114114

115+
116+
class BadGzipFile(OSError):
117+
"""Exception raised in some cases for invalid gzip files."""
118+
119+
115120
class GzipFile(_compression.BaseStream):
116121
"""The GzipFile class simulates most of the methods of a file object with
117122
the exception of the truncate() method.
@@ -413,12 +418,12 @@ def _read_gzip_header(self):
413418
return False
414419

415420
if magic != b'\037\213':
416-
raise OSError('Not a gzipped file (%r)' % magic)
421+
raise BadGzipFile('Not a gzipped file (%r)' % magic)
417422

418423
(method, flag,
419424
self._last_mtime) = struct.unpack("<BBIxx", self._read_exact(8))
420425
if method != 8:
421-
raise OSError('Unknown compression method')
426+
raise BadGzipFile('Unknown compression method')
422427

423428
if flag & FEXTRA:
424429
# Read & discard the extra field, if present
@@ -502,10 +507,10 @@ def _read_eof(self):
502507
# stored is the true file size mod 2**32.
503508
crc32, isize = struct.unpack("<II", self._read_exact(8))
504509
if crc32 != self._crc:
505-
raise OSError("CRC check failed %s != %s" % (hex(crc32),
506-
hex(self._crc)))
510+
raise BadGzipFile("CRC check failed %s != %s" % (hex(crc32),
511+
hex(self._crc)))
507512
elif isize != (self._stream_size & 0xffffffff):
508-
raise OSError("Incorrect length of data produced")
513+
raise BadGzipFile("Incorrect length of data produced")
509514

510515
# Gzip files can be padded with zeroes and still have archives.
511516
# Consume all zero bytes and set the file position to the first

Lib/test/test_gzip.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,15 @@ def test_zero_padded_file(self):
391391
d = f.read()
392392
self.assertEqual(d, data1 * 50, "Incorrect data in file")
393393

394+
def test_gzip_BadGzipFile_exception(self):
395+
self.assertTrue(issubclass(gzip.BadGzipFile, OSError))
396+
397+
def test_bad_gzip_file(self):
398+
with open(self.filename, 'wb') as file:
399+
file.write(data1 * 50)
400+
with gzip.GzipFile(self.filename, 'r') as file:
401+
self.assertRaises(gzip.BadGzipFile, file.readlines)
402+
394403
def test_non_seekable_file(self):
395404
uncompressed = data1 * 50
396405
buf = UnseekableIO()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add a :exc:`~gzip.BadGzipFile` exception to the :mod:`gzip` module.

0 commit comments

Comments
 (0)