Skip to content

Commit ed90a1c

Browse files
committed
wip
1 parent c64cff1 commit ed90a1c

File tree

3 files changed

+101
-1
lines changed

3 files changed

+101
-1
lines changed

retunnel/client/high_performance_model.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import time
1010
from dataclasses import dataclass, field
1111
from typing import Any, Dict, Optional, Set
12+
from urllib.parse import urlparse, urlunparse
1213

1314
import aiohttp
1415
import 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,

test_redirect.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/usr/bin/env python3
2+
"""Test script for redirect handling"""
3+
4+
from flask import Flask, redirect, url_for
5+
import sys
6+
7+
app = Flask(__name__)
8+
9+
@app.route('/')
10+
def index():
11+
return '<h1>Home Page</h1><a href="/backend/">Go to backend</a>'
12+
13+
@app.route('/backend/')
14+
def backend_slash():
15+
# This should trigger a redirect
16+
return redirect('/backend/dashboard')
17+
18+
@app.route('/backend/dashboard')
19+
def dashboard():
20+
return '<h1>Backend Dashboard</h1><p>If you see this, redirects are working!</p>'
21+
22+
@app.route('/absolute')
23+
def absolute_redirect():
24+
# Test absolute localhost redirect
25+
return redirect('http://localhost:5000/backend/dashboard')
26+
27+
@app.route('/external')
28+
def external_redirect():
29+
# Test external redirect (should not be rewritten)
30+
return redirect('https://www.google.com')
31+
32+
if __name__ == '__main__':
33+
port = int(sys.argv[1]) if len(sys.argv) > 1 else 5000
34+
print(f"Starting test server on port {port}")
35+
print("Test URLs:")
36+
print(f" http://localhost:{port}/ - Home page")
37+
print(f" http://localhost:{port}/backend/ - Should redirect to /backend/dashboard")
38+
print(f" http://localhost:{port}/absolute - Should redirect to absolute localhost URL")
39+
print(f" http://localhost:{port}/external - Should redirect to external URL")
40+
app.run(port=port, debug=True)

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)