diff --git a/httpd.py b/httpd.py new file mode 100644 index 0000000..baad8b2 --- /dev/null +++ b/httpd.py @@ -0,0 +1,178 @@ +#!/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')