#!/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')