diff --git a/sources/python/main.py b/sources/python/main.py index d4fff3e..a9504fe 100644 --- a/sources/python/main.py +++ b/sources/python/main.py @@ -103,7 +103,10 @@ server {{ location / {{ proxy_pass http://{upstream}; - # Headers pass through from ingress controller — no overwrite + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; }} }} """) diff --git a/sources/python/tap-proxy.py b/sources/python/tap-proxy.py index 16948c8..daf305c 100644 --- a/sources/python/tap-proxy.py +++ b/sources/python/tap-proxy.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """Tap Proxy — logs HTTP headers. Usage: python3 tap-proxy.py """ -import http.server, urllib.request, sys +import http.server, urllib.request, sys, socket from datetime import datetime PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8081 @@ -8,6 +8,18 @@ BACKEND = sys.argv[2] if len(sys.argv) > 2 else "127.0.0.1:80" LOG = (sys.argv[3] if len(sys.argv) > 3 else "/tmp") + "/tap-" + datetime.now().strftime("%Y%m%d-%H%M%S") + ".log" BACKEND_URL = "http://" + BACKEND +# Don't follow redirects — preserve Set-Cookie +class NoRedirect(urllib.request.HTTPRedirectHandler): + def http_error_302(self, req, fp, code, msg, headers): + fp.status, fp.reason = code, msg + return fp + http_error_301 = http_error_302 + http_error_303 = http_error_302 + http_error_307 = http_error_302 + http_error_308 = http_error_302 + +_opener = urllib.request.build_opener(NoRedirect) + class Tap(http.server.BaseHTTPRequestHandler): def do_GET(self): self._tap('GET') def do_POST(self): self._tap('POST') @@ -21,15 +33,34 @@ class Tap(http.server.BaseHTTPRequestHandler): for k, v in sorted(self.headers.items()): msg += " " + k + ": " + v + "\n" - body = self.rfile.read(int(self.headers.get('Content-Length', 0))) if 'Content-Length' in self.headers else None + # Handle chunked transfer-encoding + body = None + cl = self.headers.get('Content-Length') + te = self.headers.get('Transfer-Encoding', '').lower() + if cl: + body = self.rfile.read(int(cl)) + elif 'chunked' in te: + body = b'' + while True: + line = self.rfile.readline().strip() + if not line: continue + size = int(line, 16) + if size == 0: break + body += self.rfile.read(size) + self.rfile.readline() + while True: + line = self.rfile.readline().strip() + if not line: break + req = urllib.request.Request(BACKEND_URL + self.path, data=body, method=method) + # Pass through all headers including Host for k, v in self.headers.items(): - if k.lower() not in ('host', 'connection'): + if k.lower() not in ('connection',): req.add_header(k, v) try: - resp = urllib.request.urlopen(req, timeout=30) - msg += "\nRESPONSE: " + str(resp.status) + "\n" + resp = _opener.open(req, timeout=30) + msg += "\nRESPONSE: " + str(resp.status) + " " + str(resp.reason) + "\n" for k, v in resp.getheaders(): msg += " " + k + ": " + v + "\n" self.send_response(resp.status)