wisp-python 0.4.2__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wisp_python-0.4.2 → wisp_python-0.5.0}/PKG-INFO +5 -2
- {wisp_python-0.4.2 → wisp_python-0.5.0}/README.md +4 -1
- {wisp_python-0.4.2 → wisp_python-0.5.0}/pyproject.toml +1 -1
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp/__init__.py +1 -2
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp/server/__main__.py +10 -1
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp/server/connection.py +16 -6
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp/server/http.py +13 -6
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp_python.egg-info/PKG-INFO +5 -2
- {wisp_python-0.4.2 → wisp_python-0.5.0}/LICENSE +0 -0
- {wisp_python-0.4.2 → wisp_python-0.5.0}/setup.cfg +0 -0
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp/server/__init__.py +0 -0
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp/server/net.py +0 -0
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp/server/ratelimit.py +0 -0
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp_python.egg-info/SOURCES.txt +0 -0
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp_python.egg-info/dependency_links.txt +0 -0
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp_python.egg-info/requires.txt +0 -0
- {wisp_python-0.4.2 → wisp_python-0.5.0}/src/wisp_python.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: wisp-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: An implementation of a Wisp proxy server in Python
|
|
5
5
|
Author: ading2210
|
|
6
6
|
Project-URL: Homepage, https://github.com/MercuryWorkshop/wisp-server-python
|
|
@@ -38,8 +38,9 @@ pip3 install wisp-python
|
|
|
38
38
|
To start the server, run `python3 -m wisp.server`. The program accepts the following arguments:
|
|
39
39
|
```
|
|
40
40
|
usage: wisp-server-python [-h] [--host HOST] [--port PORT] [--static STATIC] [--limits] [--bandwidth BANDWIDTH] [--connections CONNECTIONS] [--window WINDOW] [--allow-loopback] [--allow-private]
|
|
41
|
+
[--log-level LOG_LEVEL]
|
|
41
42
|
|
|
42
|
-
A Wisp server implementation, written in Python (v0.
|
|
43
|
+
A Wisp server implementation, written in Python (v0.5.0)
|
|
43
44
|
|
|
44
45
|
options:
|
|
45
46
|
-h, --help show this help message and exit
|
|
@@ -54,6 +55,8 @@ options:
|
|
|
54
55
|
--window WINDOW Fixed window length for rate limits, in seconds.
|
|
55
56
|
--allow-loopback Allow connections to loopback IP addresses.
|
|
56
57
|
--allow-private Allow connections to private IP addresses.
|
|
58
|
+
--log-level LOG_LEVEL
|
|
59
|
+
The log level (either debug, info, warning, error, or critical).
|
|
57
60
|
```
|
|
58
61
|
|
|
59
62
|
## Roadmap:
|
|
@@ -21,8 +21,9 @@ pip3 install wisp-python
|
|
|
21
21
|
To start the server, run `python3 -m wisp.server`. The program accepts the following arguments:
|
|
22
22
|
```
|
|
23
23
|
usage: wisp-server-python [-h] [--host HOST] [--port PORT] [--static STATIC] [--limits] [--bandwidth BANDWIDTH] [--connections CONNECTIONS] [--window WINDOW] [--allow-loopback] [--allow-private]
|
|
24
|
+
[--log-level LOG_LEVEL]
|
|
24
25
|
|
|
25
|
-
A Wisp server implementation, written in Python (v0.
|
|
26
|
+
A Wisp server implementation, written in Python (v0.5.0)
|
|
26
27
|
|
|
27
28
|
options:
|
|
28
29
|
-h, --help show this help message and exit
|
|
@@ -37,6 +38,8 @@ options:
|
|
|
37
38
|
--window WINDOW Fixed window length for rate limits, in seconds.
|
|
38
39
|
--allow-loopback Allow connections to loopback IP addresses.
|
|
39
40
|
--allow-private Allow connections to private IP addresses.
|
|
41
|
+
--log-level LOG_LEVEL
|
|
42
|
+
The log level (either debug, info, warning, error, or critical).
|
|
40
43
|
```
|
|
41
44
|
|
|
42
45
|
## Roadmap:
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
import asyncio
|
|
3
|
+
import logging
|
|
4
|
+
|
|
3
5
|
try:
|
|
4
6
|
import uvloop
|
|
5
7
|
use_uvloop = True
|
|
@@ -24,10 +26,17 @@ if __name__ == "__main__":
|
|
|
24
26
|
parser.add_argument("--window", default=60, help="Fixed window length for rate limits, in seconds.")
|
|
25
27
|
parser.add_argument("--allow-loopback", action="store_true",help="Allow connections to loopback IP addresses.")
|
|
26
28
|
parser.add_argument("--allow-private", action="store_true", help="Allow connections to private IP addresses.")
|
|
29
|
+
parser.add_argument("--log-level", default="info", help="The log level (either debug, info, warning, error, or critical).")
|
|
27
30
|
args = parser.parse_args()
|
|
28
31
|
|
|
32
|
+
logging.basicConfig(
|
|
33
|
+
format="[%(asctime)s] %(levelname)-8s %(message)s",
|
|
34
|
+
level=getattr(logging, args.log_level.upper()),
|
|
35
|
+
datefmt="%Y/%m/%d - %H:%M:%S"
|
|
36
|
+
)
|
|
37
|
+
|
|
29
38
|
if use_uvloop:
|
|
30
39
|
uvloop.run(wisp.server.http.main(args))
|
|
31
40
|
else:
|
|
32
|
-
|
|
41
|
+
logging.error("Importing uvloop failed. Falling back to asyncio, which is slower.")
|
|
33
42
|
asyncio.run(wisp.server.http.main(args))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import struct
|
|
3
3
|
import os
|
|
4
|
+
import logging
|
|
4
5
|
|
|
5
6
|
from websockets.exceptions import ConnectionClosed
|
|
6
7
|
|
|
@@ -32,7 +33,7 @@ class WSProxyConnection:
|
|
|
32
33
|
self.conn = net.TCPConnection(self.tcp_host, self.tcp_port)
|
|
33
34
|
await self.conn.connect()
|
|
34
35
|
except Exception as e:
|
|
35
|
-
|
|
36
|
+
logging.info(f"Creating a WSProxy stream to {self.tcp_host}:{self.tcp_port} failed: {e}")
|
|
36
37
|
await self.ws.close()
|
|
37
38
|
|
|
38
39
|
async def handle_ws(self):
|
|
@@ -59,11 +60,12 @@ class WSProxyConnection:
|
|
|
59
60
|
await self.ws.close()
|
|
60
61
|
|
|
61
62
|
class WispConnection:
|
|
62
|
-
def __init__(self, ws, path, client_ip):
|
|
63
|
+
def __init__(self, ws, path, client_ip, id=None):
|
|
63
64
|
self.ws = ws
|
|
64
65
|
self.path = path
|
|
65
66
|
self.active_streams = {}
|
|
66
67
|
self.client_ip = client_ip
|
|
68
|
+
self.id = id
|
|
67
69
|
|
|
68
70
|
#send the initial CONTINUE packet
|
|
69
71
|
async def setup(self):
|
|
@@ -74,6 +76,7 @@ class WispConnection:
|
|
|
74
76
|
async def new_stream(self, stream_id, payload):
|
|
75
77
|
stream_type, destination_port = struct.unpack(connect_format, payload[:3])
|
|
76
78
|
hostname = payload[3:].decode()
|
|
79
|
+
logging.debug(f"({self.id}) Creating a new stream to {hostname}:{destination_port}")
|
|
77
80
|
|
|
78
81
|
#rate limited
|
|
79
82
|
stream_count = ratelimit.get_client_attr(self.client_ip, "streams")
|
|
@@ -94,7 +97,7 @@ class WispConnection:
|
|
|
94
97
|
await connection.connect()
|
|
95
98
|
|
|
96
99
|
except Exception as e:
|
|
97
|
-
|
|
100
|
+
logging.warn(f"({self.id}) Creating a new stream to {hostname}:{destination_port} failed: {e}")
|
|
98
101
|
await self.send_close_packet(stream_id, 0x42)
|
|
99
102
|
self.close_stream(stream_id)
|
|
100
103
|
return
|
|
@@ -112,7 +115,7 @@ class WispConnection:
|
|
|
112
115
|
await target_func(*args, **kwargs)
|
|
113
116
|
except asyncio.CancelledError as e:
|
|
114
117
|
raise e
|
|
115
|
-
|
|
118
|
+
|
|
116
119
|
async def stream_ws_to_tcp(self, stream_id):
|
|
117
120
|
#this infinite loop should get killed by the task.cancel call later on
|
|
118
121
|
while True:
|
|
@@ -137,7 +140,7 @@ class WispConnection:
|
|
|
137
140
|
try:
|
|
138
141
|
data = await stream["conn"].recv()
|
|
139
142
|
except Exception as e:
|
|
140
|
-
|
|
143
|
+
logging.warn(f"({self.id}) Receiving data from stream failed: {e}")
|
|
141
144
|
await self.send_close_packet(stream_id, 0x03)
|
|
142
145
|
self.close_stream(stream_id)
|
|
143
146
|
return
|
|
@@ -163,7 +166,8 @@ class WispConnection:
|
|
|
163
166
|
if not stream_id in self.active_streams:
|
|
164
167
|
return #stream already closed
|
|
165
168
|
stream = self.active_streams[stream_id]
|
|
166
|
-
stream["conn"]
|
|
169
|
+
if stream["conn"]:
|
|
170
|
+
stream["conn"].close()
|
|
167
171
|
|
|
168
172
|
#kill the running tasks associated with this stream
|
|
169
173
|
if not stream["connect_task"].done():
|
|
@@ -181,6 +185,12 @@ class WispConnection:
|
|
|
181
185
|
data = await self.ws.recv()
|
|
182
186
|
except ConnectionClosed:
|
|
183
187
|
break
|
|
188
|
+
except Exception as e:
|
|
189
|
+
logging.warn(f"({self.id}) Receiving data from websocket failed: {e}")
|
|
190
|
+
break
|
|
191
|
+
|
|
192
|
+
if not isinstance(data, bytes):
|
|
193
|
+
continue #ignore non binary frames
|
|
184
194
|
|
|
185
195
|
#implement bandwidth limits
|
|
186
196
|
await ratelimit.limit_client_bandwidth(self.client_ip, len(data), "ws")
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import pathlib
|
|
3
3
|
import mimetypes
|
|
4
|
+
import logging
|
|
5
|
+
import random
|
|
4
6
|
|
|
5
7
|
from websockets.server import serve
|
|
6
8
|
|
|
@@ -14,11 +16,12 @@ async def connection_handler(websocket, path):
|
|
|
14
16
|
if client_ip == "127.0.0.1" and "X-Real-IP" in websocket.request_headers:
|
|
15
17
|
client_ip = websocket.request_headers["X-Real-IP"]
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
conn_id = "".join(random.choices("1234567890abcdef", k=8))
|
|
20
|
+
logging.info(f"({conn_id}) incoming connection on {path} from {client_ip}")
|
|
18
21
|
ratelimit.inc_client_attr(client_ip, "streams")
|
|
19
22
|
|
|
20
23
|
if path.endswith("/"):
|
|
21
|
-
wisp_conn = connection.WispConnection(websocket, path, client_ip)
|
|
24
|
+
wisp_conn = connection.WispConnection(websocket, path, client_ip, conn_id)
|
|
22
25
|
await wisp_conn.setup()
|
|
23
26
|
ws_handler = asyncio.create_task(wisp_conn.handle_ws())
|
|
24
27
|
await asyncio.gather(ws_handler)
|
|
@@ -57,18 +60,18 @@ async def static_handler(path, request_headers):
|
|
|
57
60
|
|
|
58
61
|
async def main(args):
|
|
59
62
|
global static_path
|
|
60
|
-
|
|
63
|
+
logging.info(f"running wisp-server-python v{wisp.version}")
|
|
61
64
|
|
|
62
65
|
if args.static:
|
|
63
66
|
static_path = pathlib.Path(args.static).resolve()
|
|
64
67
|
request_handler = static_handler
|
|
65
68
|
mimetypes.init()
|
|
66
|
-
|
|
69
|
+
logging.info(f"serving static files from {static_path}")
|
|
67
70
|
else:
|
|
68
71
|
request_handler = None
|
|
69
72
|
|
|
70
73
|
if args.limits:
|
|
71
|
-
|
|
74
|
+
logging.info("enabled rate limits")
|
|
72
75
|
ratelimit.enabled = True
|
|
73
76
|
ratelimit.connections_limit = int(args.connections)
|
|
74
77
|
ratelimit.bandwidth_limit = float(args.bandwidth)
|
|
@@ -78,6 +81,10 @@ async def main(args):
|
|
|
78
81
|
net.block_private = not args.allow_private
|
|
79
82
|
|
|
80
83
|
limit_task = asyncio.create_task(ratelimit.reset_limits_timer())
|
|
81
|
-
|
|
84
|
+
logging.info(f"listening on {args.host}:{args.port}")
|
|
85
|
+
|
|
86
|
+
ws_logger = logging.getLogger("websockets")
|
|
87
|
+
ws_logger.setLevel(logging.WARN)
|
|
88
|
+
|
|
82
89
|
async with serve(connection_handler, args.host, int(args.port), process_request=request_handler, compression=None):
|
|
83
90
|
await asyncio.Future()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: wisp-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: An implementation of a Wisp proxy server in Python
|
|
5
5
|
Author: ading2210
|
|
6
6
|
Project-URL: Homepage, https://github.com/MercuryWorkshop/wisp-server-python
|
|
@@ -38,8 +38,9 @@ pip3 install wisp-python
|
|
|
38
38
|
To start the server, run `python3 -m wisp.server`. The program accepts the following arguments:
|
|
39
39
|
```
|
|
40
40
|
usage: wisp-server-python [-h] [--host HOST] [--port PORT] [--static STATIC] [--limits] [--bandwidth BANDWIDTH] [--connections CONNECTIONS] [--window WINDOW] [--allow-loopback] [--allow-private]
|
|
41
|
+
[--log-level LOG_LEVEL]
|
|
41
42
|
|
|
42
|
-
A Wisp server implementation, written in Python (v0.
|
|
43
|
+
A Wisp server implementation, written in Python (v0.5.0)
|
|
43
44
|
|
|
44
45
|
options:
|
|
45
46
|
-h, --help show this help message and exit
|
|
@@ -54,6 +55,8 @@ options:
|
|
|
54
55
|
--window WINDOW Fixed window length for rate limits, in seconds.
|
|
55
56
|
--allow-loopback Allow connections to loopback IP addresses.
|
|
56
57
|
--allow-private Allow connections to private IP addresses.
|
|
58
|
+
--log-level LOG_LEVEL
|
|
59
|
+
The log level (either debug, info, warning, error, or critical).
|
|
57
60
|
```
|
|
58
61
|
|
|
59
62
|
## Roadmap:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|