Files
ppf/httpd.py
Username 2212a9e00a httpd: add HTTP API server for proxy queries
- Endpoints: /proxies, /proxies/count, /health
- Query params: limit, proto, country, format (json/plain)
- Threaded server with CORS support
2025-12-20 22:28:10 +01:00

179 lines
5.3 KiB
Python

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""Simple HTTP API server for querying working proxies."""
import BaseHTTPServer
import json
import threading
import mysqlite
from misc import _log
class ProxyAPIHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""HTTP request handler for proxy API."""
# Shared database connection (set by server)
database = None
def log_message(self, format, *args):
"""Suppress default logging, use our own."""
pass
def send_json(self, data, status=200):
"""Send JSON response."""
body = json.dumps(data, indent=2)
self.send_response(status)
self.send_header('Content-Type', 'application/json')
self.send_header('Content-Length', len(body))
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
self.wfile.write(body)
def send_text(self, text, status=200):
"""Send plain text response."""
self.send_response(status)
self.send_header('Content-Type', 'text/plain')
self.send_header('Content-Length', len(text))
self.end_headers()
self.wfile.write(text)
def do_GET(self):
"""Handle GET requests."""
path = self.path.split('?')[0]
if path == '/':
self.handle_index()
elif path == '/proxies':
self.handle_proxies()
elif path == '/proxies/count':
self.handle_count()
elif path == '/health':
self.handle_health()
else:
self.send_json({'error': 'not found'}, 404)
def handle_index(self):
"""Show available endpoints."""
endpoints = {
'endpoints': {
'/proxies': 'list working proxies (params: limit, proto, country)',
'/proxies/count': 'count working proxies',
'/health': 'health check',
}
}
self.send_json(endpoints)
def handle_proxies(self):
"""List working proxies."""
# Parse query params
params = {}
if '?' in self.path:
query = self.path.split('?')[1]
for pair in query.split('&'):
if '=' in pair:
k, v = pair.split('=', 1)
params[k] = v
limit = min(int(params.get('limit', 100)), 1000)
proto = params.get('proto', '')
country = params.get('country', '')
format = params.get('format', 'json')
# Build query
sql = 'SELECT ip, port, proto, country FROM proxylist WHERE failed=0'
args = []
if proto:
sql += ' AND proto=?'
args.append(proto)
if country:
sql += ' AND country=?'
args.append(country.upper())
sql += ' ORDER BY tested DESC LIMIT ?'
args.append(limit)
try:
db = mysqlite.mysqlite(self.database, str)
rows = db.execute(sql, args).fetchall()
if format == 'plain':
# Plain text format: ip:port per line
lines = ['%s:%s' % (row[0], row[1]) for row in rows]
self.send_text('\n'.join(lines))
else:
# JSON format
proxies = []
for row in rows:
proxies.append({
'ip': row[0],
'port': row[1],
'proto': row[2],
'country': row[3]
})
self.send_json({'count': len(proxies), 'proxies': proxies})
except Exception as e:
self.send_json({'error': str(e)}, 500)
def handle_count(self):
"""Count working proxies."""
try:
db = mysqlite.mysqlite(self.database, str)
row = db.execute('SELECT COUNT(*) FROM proxylist WHERE failed=0').fetchone()
count = row[0] if row else 0
self.send_json({'count': count})
except Exception as e:
self.send_json({'error': str(e)}, 500)
def handle_health(self):
"""Health check endpoint."""
self.send_json({'status': 'ok'})
class ProxyAPIServer(threading.Thread):
"""Threaded HTTP API server."""
def __init__(self, host, port, database):
threading.Thread.__init__(self)
self.host = host
self.port = port
self.database = database
self.daemon = True
self.server = None
def run(self):
"""Start the HTTP server."""
ProxyAPIHandler.database = self.database
self.server = BaseHTTPServer.HTTPServer((self.host, self.port), ProxyAPIHandler)
_log('httpd listening on %s:%d' % (self.host, self.port), 'info')
self.server.serve_forever()
def stop(self):
"""Stop the HTTP server."""
if self.server:
self.server.shutdown()
if __name__ == '__main__':
# Test server
import sys
host = '127.0.0.1'
port = 8081
database = 'websites.sqlite'
if len(sys.argv) > 1:
database = sys.argv[1]
_log('starting test server on %s:%d (db: %s)' % (host, port, database), 'info')
server = ProxyAPIServer(host, port, database)
server.start()
try:
while True:
import time
time.sleep(1)
except KeyboardInterrupt:
server.stop()
_log('server stopped', 'info')