99import time
1010from dataclasses import dataclass , field
1111from typing import Any , Dict , Optional , Set
12+ from urllib .parse import urlparse , urlunparse
1213
1314import aiohttp
1415import msgpack # type: ignore[import-untyped]
@@ -609,7 +610,12 @@ async def _handle_proxy_connection(
609610
610611 if not tunnel :
611612 self .logger .error (f"No tunnel found for URL: { url } " )
613+ self .logger .error (f"Available tunnels: { list (self .tunnels .keys ())} " )
614+ for tid , t in self .tunnels .items ():
615+ self .logger .error (f" Tunnel { tid } : tunnel_id={ t .tunnel_id } , url={ t .url } " )
612616 break
617+ else :
618+ self .logger .info (f"Found tunnel for URL { url } : tunnel_id={ tunnel .tunnel_id } , tunnel.url={ tunnel .url } " )
613619
614620 # Connect to local service
615621 local_reader , local_writer = await asyncio .open_connection (
@@ -630,6 +636,8 @@ async def _handle_proxy_connection(
630636 query = http_req .get ("query" , "" )
631637 headers = http_req .get ("headers" , {})
632638 body = http_req .get ("body" , b"" )
639+
640+ self .logger .info (f"Incoming request: { method } { path } { '?' + query if query else '' } " )
633641
634642 # Build request line
635643 if query :
@@ -727,6 +735,58 @@ async def _handle_proxy_connection(
727735
728736 break
729737
738+ # Log response details for debugging
739+ self .logger .debug (f"Response status: { status_code } " )
740+ self .logger .debug (f"Response headers: { response_headers } " )
741+
742+ # Handle redirects (301, 302, 303, 307, 308)
743+ if status_code in [301 , 302 , 303 , 307 , 308 ]:
744+ self .logger .info (f"Processing redirect with status { status_code } " )
745+
746+ # Check for Location header (case-insensitive)
747+ location_key = None
748+ location_value = None
749+ for key , value in response_headers .items ():
750+ if key .lower () == "location" :
751+ location_key = key
752+ location_value = value
753+ break
754+
755+ if location_value and tunnel :
756+ self .logger .info (f"Original Location header: { location_value } " )
757+
758+ # Parse the location URL
759+ if location_value .startswith ("/" ):
760+ # Relative URL - prepend tunnel URL
761+ # Remove trailing slash from tunnel URL if present
762+ base_url = tunnel .url .rstrip ("/" )
763+ new_location = f"{ base_url } { location_value } "
764+ response_headers [location_key ] = new_location
765+ self .logger .info (f"Rewritten relative redirect to: { new_location } " )
766+ elif location_value .startswith ("http://localhost" ) or location_value .startswith ("http://127.0.0.1" ) or location_value .startswith ("https://localhost" ) or location_value .startswith ("https://127.0.0.1" ):
767+ # Absolute URL pointing to localhost (with or without port)
768+ # Extract the path and query
769+ try :
770+ parsed = urlparse (location_value )
771+ # Reconstruct with tunnel URL
772+ tunnel_parsed = urlparse (tunnel .url )
773+ new_location = urlunparse ((
774+ tunnel_parsed .scheme ,
775+ tunnel_parsed .netloc ,
776+ parsed .path ,
777+ parsed .params ,
778+ parsed .query ,
779+ parsed .fragment
780+ ))
781+ response_headers [location_key ] = new_location
782+ self .logger .info (f"Rewritten absolute localhost redirect to: { new_location } " )
783+ except Exception as e :
784+ self .logger .error (f"Error parsing redirect URL: { e } " )
785+ else :
786+ self .logger .info (f"Not rewriting external redirect: { location_value } " )
787+ else :
788+ self .logger .warning (f"Redirect response but no Location header found. Headers: { response_headers } " )
789+
730790 # Send response back
731791 response_meta = {
732792 "status" : status_code ,
0 commit comments