Commit c2ccca0e authored by Vitaly Lipatov's avatar Vitaly Lipatov

route-web-api: add thread lock for concurrent list operations

Protect read-modify-write cycles in handle_add/remove/move and consistent reads in /api/list with _list_lock to prevent data loss when multiple users modify lists simultaneously. Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent b87a3775
......@@ -54,6 +54,7 @@ CHECK_GATEWAYS = [
CHECK_TIMEOUT = 10
_check_lock = threading.Lock()
_list_lock = threading.Lock()
def _check_one(name, proxy, url, ipver="-4"):
......@@ -1041,6 +1042,7 @@ class RouteHandler(http.server.BaseHTTPRequestHandler):
self.send_json(OPENAPI_SPEC)
elif path == "/api/list":
with _list_lock:
data = {}
for mode, fpath in LIST_FILES.items():
data[mode] = read_list(fpath)
......@@ -1118,6 +1120,7 @@ class RouteHandler(http.server.BaseHTTPRequestHandler):
self.send_error_json(400, "Invalid domain or IP")
return
with _list_lock:
# Check if already in the same list
entries = read_list(LIST_FILES[mode])
if domain in entries:
......@@ -1142,6 +1145,7 @@ class RouteHandler(http.server.BaseHTTPRequestHandler):
entries.append(domain)
write_list(LIST_FILES[mode], entries)
if moved_from:
self.log_message("MOVE %s: %s -> %s", domain, moved_from, mode)
else:
......@@ -1159,6 +1163,7 @@ class RouteHandler(http.server.BaseHTTPRequestHandler):
self.send_error_json(400, "Invalid domain or IP")
return
with _list_lock:
entries = read_list(LIST_FILES[mode])
if domain not in entries:
self.send_error_json(404, "Not found in %s list" % mode)
......@@ -1166,6 +1171,7 @@ class RouteHandler(http.server.BaseHTTPRequestHandler):
entries.remove(domain)
write_list(LIST_FILES[mode], entries)
self.log_message("REMOVE %s from %s", domain, mode)
self.send_json({"ok": True, "domain": domain, "mode": mode})
......@@ -1181,6 +1187,7 @@ class RouteHandler(http.server.BaseHTTPRequestHandler):
self.send_error_json(400, "Invalid domain or IP")
return
with _list_lock:
src_entries = read_list(LIST_FILES[src])
if domain not in src_entries:
self.send_error_json(404, "Not found in %s list" % src)
......@@ -1195,6 +1202,7 @@ class RouteHandler(http.server.BaseHTTPRequestHandler):
dst_entries.append(domain)
write_list(LIST_FILES[src], src_entries)
write_list(LIST_FILES[dst], dst_entries)
self.log_message("MOVE %s: %s -> %s", domain, src, dst)
self.send_json({"ok": True, "domain": domain, "from": src, "to": dst})
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment