wormhole-proxy 3.3.2__tar.gz → 3.3.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: wormhole-proxy
3
- Version: 3.3.2
3
+ Version: 3.3.4
4
4
  Summary: Asynchronous I/O HTTP and HTTPS Proxy on Python >= 3.11
5
5
  License: MIT
6
6
  Keywords: wormhole,asynchronous,web,proxy
@@ -1,7 +1,7 @@
1
1
  # Main project metadata (PEP 621 standard)
2
2
  [project]
3
3
  name = "wormhole-proxy"
4
- version = "3.3.2"
4
+ version = "3.3.4"
5
5
  description = "Asynchronous I/O HTTP and HTTPS Proxy on Python >= 3.11"
6
6
  readme = "README.md"
7
7
  authors = [
@@ -303,9 +303,13 @@ async def process_https_tunnel(
303
303
 
304
304
  finally:
305
305
  # Ensure server streams are closed if they were opened.
306
- if server_writer and not server_writer.is_closing():
306
+ if server_writer is not None and not server_writer.is_closing():
307
307
  server_writer.close()
308
- await server_writer.wait_closed()
308
+ wc = getattr(server_writer, "wait_closed", None)
309
+ if callable(wc):
310
+ result = wc()
311
+ if asyncio.iscoroutine(result):
312
+ await result
309
313
 
310
314
 
311
315
  async def _send_http_request(
@@ -432,7 +436,11 @@ async def process_http_request(
432
436
  )
433
437
  if server_writer and not server_writer.is_closing():
434
438
  server_writer.close()
435
- await server_writer.wait_closed()
439
+ wc = getattr(server_writer, "wait_closed", None)
440
+ if callable(wc):
441
+ result = wc()
442
+ if asyncio.iscoroutine(result):
443
+ await result
436
444
 
437
445
  # Attempt 2: Fallback to original HTTP/1.0
438
446
  original_headers = [
@@ -49,8 +49,16 @@ async def main_async(args) -> None:
49
49
  )
50
50
  )
51
51
 
52
+ # Initialize the resolver with the configured verbosity.
53
+ resolver.initialize(verbose=args.verbose)
54
+
52
55
  if args.allowlist:
53
- num_allowed = load_allowlist(args.allowlist, args.host)
56
+ num_allowed = load_allowlist(
57
+ args.allowlist,
58
+ args.host,
59
+ ident={"id": "000000", "client": args.host},
60
+ verbose=args.verbose,
61
+ )
54
62
  if num_allowed > 0:
55
63
  logger.info(
56
64
  flm(
@@ -61,7 +69,12 @@ async def main_async(args) -> None:
61
69
  )
62
70
 
63
71
  if args.ad_block_db:
64
- num_blocked = await load_ad_block_db(args.ad_block_db, args.host)
72
+ num_blocked = await load_ad_block_db(
73
+ args.ad_block_db,
74
+ args.host,
75
+ ident={"id": "000000", "client": args.host},
76
+ verbose=args.verbose,
77
+ )
65
78
  if num_blocked > 0:
66
79
  logger.info(
67
80
  flm(
@@ -73,11 +86,18 @@ async def main_async(args) -> None:
73
86
 
74
87
  shutdown_event = asyncio.Event()
75
88
 
89
+ def _shutdown_handler():
90
+ """Handles shutdown signals to gracefully stop the server."""
91
+ shutdown_event.set()
92
+
76
93
  # Set up signal handlers for graceful shutdown.
77
94
  loop = asyncio.get_running_loop()
78
- for sig in (signal.SIGINT, signal.SIGTERM):
79
- loop.add_signal_handler(sig, lambda: shutdown_event.set())
95
+ [
96
+ loop.add_signal_handler(sig, _shutdown_handler)
97
+ for sig in (signal.SIGINT, signal.SIGTERM)
98
+ ]
80
99
 
100
+ # Start the Wormhole server with the provided arguments.
81
101
  server = await start_wormhole_server(
82
102
  args.host,
83
103
  args.port,
@@ -86,6 +106,7 @@ async def main_async(args) -> None:
86
106
  args.allow_private,
87
107
  )
88
108
 
109
+ # Log the server startup completion, 000000 means internal server ID.
89
110
  logger.info(
90
111
  flm(
91
112
  "Server startup complete. Waiting for connections...",
@@ -246,7 +267,6 @@ def main() -> int:
246
267
  args.verbose,
247
268
  async_mode=is_server_mode,
248
269
  )
249
- resolver.configure(verbose=args.verbose)
250
270
 
251
271
  if args.update_ad_block_db:
252
272
  # For this standalone utility, configure a simple logger to show progress.
@@ -32,12 +32,12 @@ class Resolver:
32
32
  self.resolver: aiodns.DNSResolver | None = None
33
33
  self.hosts_cache: dict[str, str] = {}
34
34
  self.verbose: int = 0 # Verbosity level, configured separately
35
- self._load_hosts_file()
36
35
  Resolver._instance = self
37
36
 
38
- def configure(self, verbose: int) -> None:
39
- """Sets the verbosity level for logging."""
37
+ def initialize(self, verbose: int) -> None:
38
+ """Initializes the resolver with a verbosity level and loads the hosts file."""
40
39
  self.verbose = verbose
40
+ self._load_hosts_file()
41
41
 
42
42
  @staticmethod
43
43
  def get_instance() -> "Resolver":
@@ -64,7 +64,7 @@ class Resolver:
64
64
  def _load_hosts_file(self) -> None:
65
65
  """Parses the system's hosts file and populates the cache."""
66
66
  hosts_path = self._get_hosts_path()
67
- ident = {"id": "resolver", "client": "internal"}
67
+ ident = {"id": "000000", "client": "0.0.0.0"}
68
68
 
69
69
  if not hosts_path.exists():
70
70
  logger.warning(
@@ -144,7 +144,10 @@ class Resolver:
144
144
  for res in results:
145
145
  if isinstance(res, list):
146
146
  for record in res:
147
- resolved_ips.add(record.host)
147
+ if isinstance(record.host, bytes):
148
+ resolved_ips.add(record.host.decode())
149
+ else:
150
+ resolved_ips.add(record.host)
148
151
  elif isinstance(res, aiodns.error.DNSError):
149
152
  # Ignore common "not found" errors. Log other DNS errors for debugging.
150
153
  if res.args[0] not in (
@@ -1,4 +1,4 @@
1
- from .logger import logger
1
+ from .logger import logger, format_log_message as flm
2
2
  from functools import lru_cache
3
3
  import aiosqlite
4
4
  import ipaddress
@@ -7,6 +7,8 @@ import sys
7
7
 
8
8
  # A hardcoded default allowlist for most known safe domains.
9
9
  DEFAULT_ALLOWLIST: set[str] = {
10
+ "bit.ly", # Bitly for URL shortening
11
+ "azurewebsites.net", # Azure Web App
10
12
  "s3.amazonaws.com", # Amazon S3 for static assets"
11
13
  "fonts.googleapis.com", # Google Fonts
12
14
  "safebrowsing.googleapis.com", # Google Safe Browsing for security
@@ -84,7 +86,9 @@ def is_private_ip(ip_str: str) -> bool:
84
86
  return True
85
87
 
86
88
 
87
- async def load_ad_block_db(path: str, host: str) -> int:
89
+ async def load_ad_block_db(
90
+ path: str, host: str, ident: dict[str, str], verbose: int = 0
91
+ ) -> int:
88
92
  """
89
93
  Loads a list of domains to block from a SQLite database into a global set
90
94
  for fast in-memory access.
@@ -105,7 +109,11 @@ async def load_ad_block_db(path: str, host: str) -> int:
105
109
  AD_BLOCK_SET.add(row[0])
106
110
  except Exception as e:
107
111
  logger.error(
108
- f"[000000][{host}]: Could not load ad-block database from '{path}': {e}",
112
+ flm(
113
+ f"Could not load ad-block database from '{path}': {e}",
114
+ ident=ident,
115
+ verbose=verbose,
116
+ )
109
117
  )
110
118
 
111
119
  if AD_BLOCK_SET:
@@ -114,13 +122,19 @@ async def load_ad_block_db(path: str, host: str) -> int:
114
122
  content_size = sum(sys.getsizeof(s) for s in AD_BLOCK_SET)
115
123
  total_size_mb = (set_size + content_size) / (1024 * 1024)
116
124
  logger.debug(
117
- f"[000000][{host}]: Ad-block set memory usage: ~{total_size_mb:.2f} MB for {len(AD_BLOCK_SET)} domains"
125
+ flm(
126
+ f"Ad-block set memory usage: ~{total_size_mb:.2f} MB for {len(AD_BLOCK_SET)} domains",
127
+ ident=ident,
128
+ verbose=verbose,
129
+ )
118
130
  )
119
131
 
120
132
  return len(AD_BLOCK_SET)
121
133
 
122
134
 
123
- def load_allowlist(path: str, host: str) -> int:
135
+ def load_allowlist(
136
+ path: str, host: str, ident: dict[str, str], verbose: int = 0
137
+ ) -> int:
124
138
  """
125
139
  Loads domains from a user-provided file and adds them to the global allowlist set.
126
140
  """
@@ -130,7 +144,13 @@ def load_allowlist(path: str, host: str) -> int:
130
144
  if line.strip() and not line.startswith("#"):
131
145
  ALLOW_LIST_SET.add(line.strip().lower())
132
146
  except FileNotFoundError:
133
- logger.error(f"[000000][{host}]: Allowlist file not found at '{path}'")
147
+ logger.error(
148
+ flm(
149
+ f"Allowlist file not found at '{path}'",
150
+ ident=ident,
151
+ verbose=verbose,
152
+ )
153
+ )
134
154
  return len(ALLOW_LIST_SET)
135
155
 
136
156
 
File without changes
File without changes