Get underlying error when conversion fails

When we get an early EOF from the converter process, we should
immediately get the exit code of that process, to find out the actual
underlying error. Currently, the exception we raise masks the underlying
error.

Raise a ConverterProcException, that in turns makes our error handling
code read the exit code of the spawned process, and converts it to a
helpful error message.

Fixes #714
This commit is contained in:
Alex Pyrgiotis 2024-02-19 15:06:31 +02:00
parent 6ee1d14c9a
commit 634523dac9
No known key found for this signature in database
GPG key ID: B6C15EBA0357C9AA
4 changed files with 8 additions and 18 deletions

View file

@ -8,21 +8,11 @@ MAX_PAGE_WIDTH = 10000
MAX_PAGE_HEIGHT = 10000 MAX_PAGE_HEIGHT = 10000
class InterruptedConversionException(Exception):
"""Data received was less than expected"""
def __init__(self) -> None:
super().__init__(
"Something interrupted the conversion and it could not be completed."
)
class ConverterProcException(Exception): class ConverterProcException(Exception):
"""Some exception occurred in the converter""" """Some exception occurred in the converter"""
def __init__(self, proc: subprocess.Popen) -> None: def __init__(self) -> None:
self.proc = proc super().__init__("The process spawned for the conversion has exited early")
super().__init__()
class ConversionException(Exception): class ConversionException(Exception):

View file

@ -27,7 +27,7 @@ def read_bytes(f: IO[bytes], size: int, exact: bool = True) -> bytes:
"""Read bytes from a file-like object.""" """Read bytes from a file-like object."""
buf = f.read(size) buf = f.read(size)
if exact and len(buf) != size: if exact and len(buf) != size:
raise errors.InterruptedConversionException() raise errors.ConverterProcException()
return buf return buf
@ -35,7 +35,7 @@ def read_int(f: IO[bytes]) -> int:
"""Read 2 bytes from a file-like object, and decode them as int.""" """Read 2 bytes from a file-like object, and decode them as int."""
untrusted_int = f.read(INT_BYTES) untrusted_int = f.read(INT_BYTES)
if len(untrusted_int) != INT_BYTES: if len(untrusted_int) != INT_BYTES:
raise errors.InterruptedConversionException() raise errors.ConverterProcException()
return int.from_bytes(untrusted_int, "big", signed=False) return int.from_bytes(untrusted_int, "big", signed=False)
@ -80,7 +80,7 @@ class IsolationProvider(ABC):
if document.archive_after_conversion: if document.archive_after_conversion:
document.archive() document.archive()
except errors.ConverterProcException as e: except errors.ConverterProcException as e:
exception = self.get_proc_exception(e.proc) exception = self.get_proc_exception(conversion_proc)
self.print_progress(document, True, str(exception), 0) self.print_progress(document, True, str(exception), 0)
document.mark_as_failed() document.mark_as_failed()
except errors.ConversionException as e: except errors.ConversionException as e:
@ -103,7 +103,7 @@ class IsolationProvider(ABC):
p.stdin.write(f.read()) p.stdin.write(f.read())
p.stdin.close() p.stdin.close()
except BrokenPipeError as e: except BrokenPipeError as e:
raise errors.ConverterProcException(p) raise errors.ConverterProcException()
assert p.stdout assert p.stdout
n_pages = read_int(p.stdout) n_pages = read_int(p.stdout)

View file

@ -48,7 +48,7 @@ class IsolationProviderTest:
monkeypatch.setattr( monkeypatch.setattr(
provider, "start_doc_to_pixels_proc", start_doc_to_pixels_proc provider, "start_doc_to_pixels_proc", start_doc_to_pixels_proc
) )
with pytest.raises(errors.InterruptedConversionException): with pytest.raises(errors.ConverterProcException):
provider.doc_to_pixels(doc, tmpdir) provider.doc_to_pixels(doc, tmpdir)
assert provider.get_proc_exception(proc) == errors.MaxPagesException # type: ignore [arg-type] assert provider.get_proc_exception(proc) == errors.MaxPagesException # type: ignore [arg-type]

View file

@ -58,7 +58,7 @@ class TestQubes(IsolationProviderTest):
provider, "start_doc_to_pixels_proc", start_doc_to_pixels_proc provider, "start_doc_to_pixels_proc", start_doc_to_pixels_proc
) )
with pytest.raises(errors.InterruptedConversionException) as e: with pytest.raises(errors.ConverterProcException) as e:
doc = Document(sample_doc) doc = Document(sample_doc)
provider.doc_to_pixels(doc, tmpdir) provider.doc_to_pixels(doc, tmpdir)
assert provider.get_proc_exception(proc) == errors.QubesQrexecFailed # type: ignore [arg-type] assert provider.get_proc_exception(proc) == errors.QubesQrexecFailed # type: ignore [arg-type]