From: Michael Tremer Date: Sun, 9 Feb 2025 13:56:00 +0000 (+0000) Subject: registry: Send proper API error if something wasn't found X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6cbe9f80883bd82226cf61c2bc3803981cff2e02;p=pbs.git registry: Send proper API error if something wasn't found Signed-off-by: Michael Tremer --- diff --git a/src/web/registry.py b/src/web/registry.py index 0c7a7a29..3c270040 100644 --- a/src/web/registry.py +++ b/src/web/registry.py @@ -28,6 +28,32 @@ import tornado.web from . import base from ..decorators import run_in_thread +class NotFoundError(tornado.web.HTTPError): + def __init__(self): + super().__init__(status_code=404) + + +class BlobUnknownError(NotFoundError): + """ + Raised when we could not find the blob + """ + pass + + +class ManifestUnknownError(NotFoundError): + """ + Raised when we could not find the manifest + """ + pass + + +class NameUnknownError(NotFoundError): + """ + Raised when we could not find the distro + """ + pass + + class BaseHandler(base.BaseHandler): """ A base handler for any registry stuff @@ -64,7 +90,41 @@ class BaseHandler(base.BaseHandler): self.write(chunk) async def write_error(self, *args, **kwargs): - pass # Don't send any body + # Fetch the exception information + exc_info = kwargs.get("exc_info") + + # Send nothing if we don't know enough about this error + if not exc_info: + return + + # Unpack exception info + type, exception, traceback = exc_info + + # Match our own API errors + if isinstance(exception, BlobUnknownError): + self.finish({ + "errors" : [ + { "code" : "BLOB_UNKNOWN" }, + ], + }) + + elif isinstance(exception, ManifestUnknownError): + self.finish({ + "errors" : [ + { "code" : "MANIFEST_UNKNOWN" }, + ], + }) + + elif isinstance(exception, NameUnknownError): + self.finish({ + "errors" : [ + { "code" : "NAME_UNKNOWN" }, + ], + }) + + # Don't send anything for other errors + else: + pass class NotFoundHandler(BaseHandler): @@ -91,7 +151,7 @@ class ManifestLabelHandler(BaseHandler): # Fetch the distribution distro = await self.backend.distros.get_by_slug(distro_slug) if not distro: - raise tornado.web.HTTPError(404) + raise NameUnknownError # Fetch the release if label == "latest": @@ -101,7 +161,7 @@ class ManifestLabelHandler(BaseHandler): # Fail if we could not find a release if not release: - raise tornado.web.HTTPError(404) + raise ManifestUnknownError # Check if the client supports the index format if not self.client_accepts("application/vnd.oci.image.index.v1+json"): @@ -109,7 +169,7 @@ class ManifestLabelHandler(BaseHandler): # Fail if there are no OCI images if not release.oci_images: - raise tornado.web.HTTPError(404, "Release has no OCI images") + raise ManifestUnknownError manifests = [] @@ -141,12 +201,12 @@ class ManifestHandler(BaseHandler): # Fetch the distribution distro = await self.backend.distros.get_by_slug(distro_slug) if not distro: - raise tornado.web.HTTPError(404) + raise NameUnknownError # Fetch the blob blob = await self.get_blob(distro, digest) if not blob: - raise tornado.web.HTTPError(404) + raise BlobUnknownError # Set Content-Type self.set_header("Content-Type", "application/vnd.oci.image.manifest.v1+json") @@ -164,12 +224,12 @@ class BlobHandler(BaseHandler): # Fetch the distribution distro = await self.backend.distros.get_by_slug(distro_slug) if not distro: - raise tornado.web.HTTPError(404) + raise NameUnknownError # Fetch the blob blob = await self.get_blob(distro, digest) if not blob: - raise tornado.web.HTTPError(404) + raise BlobUnknownError # Set Content-Type self.set_header("Content-Type", "application/octet-stream")