From: Michael Tremer Date: Tue, 11 Feb 2025 15:43:29 +0000 (+0000) Subject: mirrors: Support HEAD requests in load balancer X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0cdc3c51666d96ae3b0205a98867042f98a5efce;p=pbs.git mirrors: Support HEAD requests in load balancer Signed-off-by: Michael Tremer --- diff --git a/src/buildservice/__init__.py b/src/buildservice/__init__.py index ee9a2a30..24bc179d 100644 --- a/src/buildservice/__init__.py +++ b/src/buildservice/__init__.py @@ -9,6 +9,7 @@ import logging import os import shutil import ssl +import stat import systemd.journal import tempfile import urllib.parse @@ -363,6 +364,26 @@ class Backend(object): return os.path.exists(path) + @run_in_thread + def stat(self, path, fmt=None): + """ + stat()s a file + """ + # Make the path absolute + if not path.startswith("/"): + path = self.path(path) + + # Stat the file + s = os.stat(path) + + # Check if the format matches + if fmt: + # Return nothing if the format does not match + if not stat.S_IFMT(s.st_mode) == fmt: + return + + return s + @run_in_thread def makedirs(self, path, **kwargs): """ diff --git a/src/web/mirrors.py b/src/web/mirrors.py index ff036414..b16c1d35 100644 --- a/src/web/mirrors.py +++ b/src/web/mirrors.py @@ -1,6 +1,8 @@ #!/usr/bin/python +import datetime import logging +import stat import tornado.web from . import base @@ -140,7 +142,7 @@ class DownloadsHandler(base.BaseHandler): @base.ratelimit(limit=100, minutes=60, key="downloads") async def get(self, path): # Check if the file exists - if not await self.backend.exists(path): + if not await self.backend.stat(path, stat.S_IFREG): raise tornado.web.HTTPError(404) # Fetch all mirrors for this client @@ -168,6 +170,20 @@ class DownloadsHandler(base.BaseHandler): self.redirect(url) + @base.ratelimit(limit=100, minutes=60, key="downloads") + async def head(self, path): + # Stat the file + s = await self.backend.stat(path, stat.S_IFREG) + + # Send 404 if the file does not exist + if not s: + raise tornado.web.HTTPError(404) + + # Send a couple of headers + self.set_header("Content-Type", "application/octet-stream") + self.set_header("Content-Length", s.st_size) + self.set_header("Last-Modified", datetime.datetime.fromtimestamp(s.st_mtime)) + async def write_error(self, *args, **kwargs): """ Don't send any body in error responses