From e210c4855cbd7d3f18e03cec50eccbdaca0f3393 Mon Sep 17 00:00:00 2001 From: xolom <1269774+xolom@users.noreply.github.com> Date: Tue, 26 May 2026 21:45:27 +0200 Subject: [PATCH] fix: include client addresses in webui request logs --- server.py | 19 +++++++++++++-- tests/test_issue2775_log_request.py | 36 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/server.py b/server.py index 678e6422..8d82f4ce 100644 --- a/server.py +++ b/server.py @@ -274,13 +274,28 @@ class Handler(BaseHTTPRequestHandler): """Structured JSON logs for each request.""" import json as _json duration_ms = round((time.time() - getattr(self, '_req_t0', time.time())) * 1000, 1) - record = _json.dumps({ + remote = '-' + try: + if getattr(self, 'client_address', None): + remote = str(self.client_address[0]) + except Exception: + remote = '-' + forwarded_for = None + try: + forwarded_for = (self.headers.get('X-Forwarded-For') or '').split(',')[0].strip() or None + except Exception: + forwarded_for = None + record_data = { 'ts': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()), + 'remote': remote, 'method': getattr(self, 'command', None) or '-', 'path': getattr(self, 'path', None) or '-', 'status': int(code) if str(code).isdigit() else code, 'ms': duration_ms, - }) + } + if forwarded_for: + record_data['forwarded_for'] = forwarded_for + record = _json.dumps(record_data) print(f'[webui] {record}', flush=True) def do_GET(self) -> None: diff --git a/tests/test_issue2775_log_request.py b/tests/test_issue2775_log_request.py index 3beebb73..687c1830 100644 --- a/tests/test_issue2775_log_request.py +++ b/tests/test_issue2775_log_request.py @@ -16,3 +16,39 @@ def test_log_request_handles_malformed_request_without_path(capsys): assert record["method"] == "-" assert record["path"] == "-" assert record["status"] == 400 + assert record["remote"] == "-" + + +def test_log_request_includes_remote_address(capsys): + handler = Handler.__new__(Handler) + handler.command = "POST" + handler.path = "/api/auth/login" + handler.client_address = ("192.0.2.10", 54321) + handler.headers = {} + + Handler.log_request(handler, "401") + + line = capsys.readouterr().out.strip() + record = json.loads(line.removeprefix("[webui] ")) + assert record["remote"] == "192.0.2.10" + assert "forwarded_for" not in record + + +def test_log_request_includes_first_forwarded_for_address(capsys): + class Headers: + def get(self, key): + assert key == "X-Forwarded-For" + return "203.0.113.7, 198.51.100.9" + + handler = Handler.__new__(Handler) + handler.command = "POST" + handler.path = "/api/auth/login" + handler.client_address = ("192.0.2.10", 54321) + handler.headers = Headers() + + Handler.log_request(handler, "401") + + line = capsys.readouterr().out.strip() + record = json.loads(line.removeprefix("[webui] ")) + assert record["remote"] == "192.0.2.10" + assert record["forwarded_for"] == "203.0.113.7"