From 00afd141aec5c76cee6d8bab995ec59aa351757a Mon Sep 17 00:00:00 2001 From: Username Date: Sun, 15 Feb 2026 12:27:55 +0100 Subject: [PATCH] httpd: add /proxies/all endpoint for unlimited proxy list --- httpd.py | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/httpd.py b/httpd.py index 66f78a8..86787f2 100644 --- a/httpd.py +++ b/httpd.py @@ -914,6 +914,7 @@ class ProxyAPIHandler(BaseHTTPServer.BaseHTTPRequestHandler): '/api/stats/export': self.handle_stats_export, '/api/countries': self.handle_countries, '/proxies': self.handle_proxies, + '/proxies/all': self.handle_proxies_all, '/proxies/count': self.handle_count, '/health': self.handle_health, } @@ -930,6 +931,7 @@ class ProxyAPIHandler(BaseHTTPServer.BaseHTTPRequestHandler): '/api/stats': 'runtime statistics (JSON)', '/api/stats/export': 'export stats (params: format=json|csv)', '/proxies': 'list working proxies (params: limit, proto, country, asn)', + '/proxies/all': 'list ALL working proxies (params: proto, country, asn, format)', '/proxies/count': 'count working proxies', '/health': 'health check', } @@ -1107,6 +1109,49 @@ class ProxyAPIHandler(BaseHTTPServer.BaseHTTPRequestHandler): except Exception as e: self.send_json({'error': str(e)}, 500) + def handle_proxies_all(self): + params = {} + if '?' in self.path: + for pair in self.path.split('?')[1].split('&'): + if '=' in pair: + k, v = pair.split('=', 1) + params[k] = v + + proto = params.get('proto', '') + country = params.get('country', '') + asn = params.get('asn', '') + fmt = params.get('format', 'json') + + sql = 'SELECT ip, port, proto, country, asn, avg_latency FROM proxylist WHERE failed=0 AND proto IS NOT NULL' + args = [] + + if proto: + sql += ' AND proto=?' + args.append(proto) + if country: + sql += ' AND country=?' + args.append(country.upper()) + if asn: + sql += ' AND asn=?' + args.append(int(asn)) + + sql += ' ORDER BY avg_latency ASC, tested DESC' + + try: + db = mysqlite.mysqlite(self.database, str) + rows = db.execute(sql, args).fetchall() + + if fmt == 'plain': + self.send_text('\n'.join('%s://%s:%s' % (r[2] or 'http', r[0], r[1]) for r in rows)) + else: + proxies = [{ + 'ip': r[0], 'port': r[1], 'proto': r[2], + 'country': r[3], 'asn': r[4], 'latency': r[5] + } for r in rows] + self.send_json({'count': len(proxies), 'proxies': proxies}) + except Exception as e: + self.send_json({'error': str(e)}, 500) + def handle_count(self): try: db = mysqlite.mysqlite(self.database, str) @@ -1243,6 +1288,7 @@ class ProxyAPIServer(threading.Thread): '/api/register': 'register as worker (POST)', '/api/workers': 'list connected workers', '/proxies': 'list working proxies (params: limit, proto, country, asn)', + '/proxies/all': 'list ALL working proxies (params: proto, country, asn, format)', '/proxies/count': 'count working proxies', '/health': 'health check', } @@ -1421,6 +1467,35 @@ class ProxyAPIServer(threading.Thread): return json.dumps({'count': len(proxies), 'proxies': proxies}, indent=2), 'application/json', 200 except Exception as e: return json.dumps({'error': str(e)}), 'application/json', 500 + elif path == '/proxies/all': + try: + proto = query_params.get('proto', '') + country = query_params.get('country', '') + asn = query_params.get('asn', '') + fmt = query_params.get('format', 'json') + + sql = 'SELECT ip, port, proto, country, asn, avg_latency FROM proxylist WHERE failed=0 AND proto IS NOT NULL' + args = [] + if proto: + sql += ' AND proto=?' + args.append(proto) + if country: + sql += ' AND country=?' + args.append(country.upper()) + if asn: + sql += ' AND asn=?' + args.append(int(asn)) + sql += ' ORDER BY avg_latency ASC, tested DESC' + + db = mysqlite.mysqlite(self.database, str) + rows = db.execute(sql, args).fetchall() + + if fmt == 'plain': + return '\n'.join('%s://%s:%s' % (r[2] or 'http', r[0], r[1]) for r in rows), 'text/plain', 200 + proxies = [{'proxy': '%s:%s' % (r[0], r[1]), 'proto': r[2], 'country': r[3], 'asn': r[4], 'latency': r[5]} for r in rows] + return json.dumps({'count': len(proxies), 'proxies': proxies}, indent=2), 'application/json', 200 + except Exception as e: + return json.dumps({'error': str(e)}), 'application/json', 500 elif path == '/proxies/count': try: db = mysqlite.mysqlite(self.database, str)