]> git.ipfire.org Git - pbs.git/commitdiff
registry: Send proper API error if something wasn't found
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 9 Feb 2025 13:56:00 +0000 (13:56 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 9 Feb 2025 13:56:00 +0000 (13:56 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/web/registry.py

index 0c7a7a296ad5f1df17a9398399310be7f919ea50..3c2700408c85ad495b809f3a2365ef6999e0ec24 100644 (file)
@@ -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")