about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNguyễn Gia Phong <cnx@loang.net>2025-05-26 17:45:48 +0900
committerNguyễn Gia Phong <cnx@loang.net>2025-05-26 17:45:48 +0900
commit56a032568443bdf85dd37df5f6716b3475626d6a (patch)
tree487de1b9bff07ede605d5321faa1f09706e3bd00 /src
parentb37d71bca632c1e29a3402fbaf69a14843eab8f2 (diff)
downloadscadere-56a032568443bdf85dd37df5f6716b3475626d6a.tar.gz
Fix handling of base URL
Diffstat (limited to 'src')
-rw-r--r--src/scadere/listen.py24
1 files changed, 14 insertions, 10 deletions
diff --git a/src/scadere/listen.py b/src/scadere/listen.py
index aa80c32..0777f4a 100644
--- a/src/scadere/listen.py
+++ b/src/scadere/listen.py
@@ -21,7 +21,7 @@ from functools import partial
 from urllib.parse import parse_qs, urljoin, urlsplit
 from xml.etree.ElementTree import (Element as xml_element,
                                    SubElement as xml_subelement,
-                                   indent, tostring as xml_to_string)
+                                   indent, tostring as str_from_xml)
 
 from . import __version__
 
@@ -84,13 +84,14 @@ async def handle(certs, base_url, reader, writer):
     """Handle HTTP request."""
     summaries = tuple(cert.rstrip().split(maxsplit=5)
                       for cert in certs.read_text().splitlines())
-    lookup = {f'/{path(hostname, port, issuer, serial)}':
+    lookup = {urlsplit(urljoin(base_url,
+                               path(hostname, port, issuer, serial))).path:
               (not_before, not_after, hostname, port, serial, issuer)
               for not_before, not_after, hostname, port, serial, issuer
               in summaries}
     request = await reader.readuntil(b'\r\n')
     url = request.removeprefix(b'GET ').rsplit(b' HTTP/', 1)[0]
-    url_parts = urlsplit(url.decode())
+    url_parts = urlsplit(urljoin(base_url, url.decode()))
     domains = tuple(parse_qs(url_parts.query).get('domain', ['']))
 
     if not request.startswith(b'GET '):
@@ -99,7 +100,9 @@ async def handle(certs, base_url, reader, writer):
         writer.close()
         await writer.wait_closed()
         return
-    elif url_parts.path == '/':  # Atom feed
+    elif url.startswith(b'//'):  # urljoin goes haywire
+        writer.write(b'HTTP/1.1 404 Not Found\r\n')
+    elif url_parts.path == urlsplit(base_url).path:  # Atom feed
         writer.write(b'HTTP/1.1 200 OK\r\n')
         writer.write(b'Content-Type: application/atom+xml\r\n')
         feed = xml(('feed', {'xmlns': 'http://www.w3.org/2005/Atom'},
@@ -112,9 +115,10 @@ async def handle(certs, base_url, reader, writer):
                       'version': __version__},
                      'Scadere'),
                     *(entry(base_url, cert)
-                      for cert in summaries if cert[2].endswith(domains))))
-        content = xml_to_string(feed, 'unicode', xml_declaration=True,
-                                default_namespace=None).encode()
+                      for cert in lookup.values()
+                      if cert[2].endswith(domains))))
+        content = str_from_xml(feed, 'unicode', xml_declaration=True,
+                               default_namespace=None).encode()
         writer.write(f'Content-Length: {len(content)}\r\n\r\n'.encode())
         writer.write(content)
     elif url_parts.path in lookup:  # accessible Atom entry's link/ID
@@ -134,8 +138,8 @@ async def handle(certs, base_url, reader, writer):
                      ('title', f'TLS certificate - {hostname}:{port}')),
                     ('body', *body(not_before, not_after,
                                    hostname, port, serial, issuer))))
-        content = xml_to_string(page, 'unicode', xml_declaration=True,
-                                default_namespace=None).encode()
+        content = str_from_xml(page, 'unicode', xml_declaration=True,
+                               default_namespace=None).encode()
         writer.write(f'Content-Length: {len(content)}\r\n\r\n'.encode())
         writer.write(content)
     else:
@@ -145,7 +149,7 @@ async def handle(certs, base_url, reader, writer):
     await writer.wait_closed()
 
 
-async def listen(certs, base_url, host, port):
+async def listen(certs, base_url, host, port):  # pragma: no cover
     """Serve HTTP server for TLS certificate expirations' Atom feed."""
     server = await start_server(partial(handle, certs, base_url), host, port)
     async with server: