summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ttun/__main__.py18
-rw-r--r--ttun/client.py138
2 files changed, 91 insertions, 65 deletions
diff --git a/ttun/__main__.py b/ttun/__main__.py
index cee662a..cbf8e16 100644
--- a/ttun/__main__.py
+++ b/ttun/__main__.py
@@ -27,12 +27,26 @@ def main():
27 default=None, 27 default=None,
28 help="The subdomain of the ttun tunnel", 28 help="The subdomain of the ttun tunnel",
29 ) 29 )
30 parser.add_argument(
31 "-t",
32 "--to",
33 default="127.0.0.1",
34 help="The host to proxy the request to",
35 )
36 parser.add_argument(
37 "--https",
38 help="Use this if the proxied server uses https",
39 action="store_true",
40 default=False,
41 )
30 args = parser.parse_args() 42 args = parser.parse_args()
31 43
32 client = Client( 44 client = Client(
33 port=args.port, 45 port=args.port,
34 subdomain=args.subdomain, 46 subdomain=args.subdomain,
35 server=args.server, 47 server=args.server,
48 to=args.to,
49 https=args.https,
36 ) 50 )
37 51
38 try: 52 try:
@@ -45,14 +59,14 @@ def main():
45 59
46 def print_info(server: Server): 60 def print_info(server: Server):
47 print("Tunnel created:") 61 print("Tunnel created:")
48 print(f'{client.config["url"]} -> http://localhost:{args.port}') 62 print(f'{client.config["url"]} -> {client.proxy_origin}')
49 print("") 63 print("")
50 print(f"Inspect requests:") 64 print(f"Inspect requests:")
51 print(f"http://localhost:{server.port}") 65 print(f"http://localhost:{server.port}")
52 66
53 server = Server( 67 server = Server(
54 config=client.config, 68 config=client.config,
55 on_resend=client.proxyRequest, 69 on_resend=client.proxy_request,
56 on_started=print_info, 70 on_started=print_info,
57 ) 71 )
58 72
diff --git a/ttun/client.py b/ttun/client.py
index 6d05da7..9e597ab 100644
--- a/ttun/client.py
+++ b/ttun/client.py
@@ -25,14 +25,22 @@ from ttun.types import ResponseData
25 25
26 26
27class Client: 27class Client:
28 def __init__(self, port: int, server: str, subdomain: str = None): 28 def __init__(
29 self.port = port 29 self,
30 port: int,
31 server: str,
32 subdomain: str = None,
33 to: str = "127.0.0.1",
34 https: bool = False,
35 ):
30 self.server = server 36 self.server = server
31 self.subdomain = subdomain 37 self.subdomain = subdomain
32 38
33 self.config: Optional[Config] = None 39 self.config: Optional[Config] = None
34 self.connection: WebSocketClientProtocol = None 40 self.connection: WebSocketClientProtocol = None
35 41
42 self.proxy_origin = f'{"https" if https else "http"}://{to}:{port}'
43
36 async def send(self, data: dict): 44 async def send(self, data: dict):
37 await self.connection.send(json.dumps(data)) 45 await self.connection.send(json.dumps(data))
38 46
@@ -65,73 +73,77 @@ class Client:
65 return self.connection 73 return self.connection
66 74
67 async def handle_messages(self): 75 async def handle_messages(self):
68 while True: 76 async with ClientSession(
69 try: 77 base_url=self.proxy_origin, cookie_jar=DummyCookieJar()
70 request: RequestData = await self.receive() 78 ) as session:
71 await self.proxy_request( 79 while True:
72 request=request, on_response=lambda response: self.send(response) 80 try:
73 ) 81 request: RequestData = await self.receive()
74 82 await self.proxy_request(
75 except ConnectionClosed: 83 session=session,
76 break 84 request=request,
85 on_response=lambda response: self.send(response),
86 )
87 except ConnectionClosed:
88 break
77 89
78 async def proxy_request( 90 async def proxy_request(
79 self, 91 self,
92 session: ClientSession,
80 request: RequestData, 93 request: RequestData,
81 on_response: Callable[[ResponseData], Awaitable] = None, 94 on_response: Callable[[ResponseData], Awaitable] = None,
82 ): 95 ):
83 async with ClientSession(cookie_jar=DummyCookieJar()) as session: 96 request_id = uuid4()
84 request_id = uuid4() 97 await PubSub.publish(
85 await PubSub.publish( 98 {
86 { 99 "type": "request",
87 "type": "request", 100 "payload": {
88 "payload": { 101 "id": request_id.hex,
89 "id": request_id.hex, 102 "timestamp": datetime.now().isoformat(),
90 "timestamp": datetime.now().isoformat(), 103 **request,
91 **request, 104 },
92 }, 105 }
93 } 106 )
107
108 start = perf_counter()
109 try:
110 response = await session.request(
111 method=request["method"],
112 url=request["path"],
113 headers=request["headers"],
114 data=b64decode(request["body"].encode()),
115 allow_redirects=False,
94 ) 116 )
117 end = perf_counter()
118
119 response_data = ResponseData(
120 status=response.status,
121 headers=[
122 (key, value)
123 for key, value in response.headers.items()
124 if key.lower() not in ["transfer-encoding", "content-encoding"]
125 ],
126 body=b64encode(await response.read()).decode(),
127 )
128 except ClientError as e:
129 end = perf_counter()
95 130
96 start = perf_counter() 131 response_data = ResponseData(
97 try: 132 status=(504 if isinstance(e, ClientConnectionError) else 502),
98 response = await session.request( 133 headers=[("content-type", "text/plain")],
99 method=request["method"], 134 body=b64encode(str(e).encode()).decode(),
100 url=f'http://localhost:{self.port}{request["path"]}',
101 headers=request["headers"],
102 data=b64decode(request["body"].encode()),
103 allow_redirects=False,
104 )
105 end = perf_counter()
106
107 response_data = ResponseData(
108 status=response.status,
109 headers=[
110 (key, value)
111 for key, value in response.headers.items()
112 if key.lower() not in ["transfer-encoding", "content-encoding"]
113 ],
114 body=b64encode(await response.read()).decode(),
115 )
116 except ClientError as e:
117 end = perf_counter()
118
119 response_data = ResponseData(
120 status=(504 if isinstance(e, ClientConnectionError) else 502),
121 headers=[("content-type", "text/plain")],
122 body=b64encode(str(e).encode()).decode(),
123 )
124
125 if on_response is not None:
126 await on_response(response_data)
127
128 await PubSub.publish(
129 {
130 "type": "response",
131 "payload": {
132 "id": request_id.hex,
133 "timing": end - start,
134 **response_data,
135 },
136 }
137 ) 135 )
136
137 if on_response is not None:
138 await on_response(response_data)
139
140 await PubSub.publish(
141 {
142 "type": "response",
143 "payload": {
144 "id": request_id.hex,
145 "timing": end - start,
146 **response_data,
147 },
148 }
149 )