# -*- coding: utf-8 -*- import socket import threading import time import sys # Configuration TARGET_HOST = "zentao.sunyard.com.cn" TARGET_PORT = 9788 B_HOST = "localhost" B_PORT = 8080 # Global lock for socket write operations socket_write_lock = threading.Lock() def get_thread_id(): """Get thread identifier for logging""" return threading.current_thread().getName() def log_info(source, message): """Log info message with thread ID""" thread_id = get_thread_id() log_line = "[%s] [INFO] [%s] [Thread:%s] %s" % ( time.strftime("%Y-%m-%d %H:%M:%S"), source, thread_id, message ) print(log_line) sys.stdout.flush() def log_error(source, message): """Log error message with thread ID""" thread_id = get_thread_id() log_line = "[%s] [ERROR] [%s] [Thread:%s] %s" % ( time.strftime("%Y-%m-%d %H:%M:%S"), source, thread_id, message ) print(log_line) sys.stdout.flush() def extract_request_id(request_data): """Extract X-Proxy-Request-ID from request headers""" if "\r\n\r\n" in request_data: headers_end = request_data.find("\r\n\r\n") headers = request_data[:headers_end] for line in headers.split("\r\n"): if line.lower().startswith("x-proxy-request-id:"): return line.split(":", 1)[1].strip() return None def modify_request_headers(request_data): """Modify request headers: replace Origin, Referer, Host; remove Connection headers""" lines = request_data.split("\r\n") new_lines = [] method = "" path = "" if lines: first_line = lines[0] parts = first_line.split() if len(parts) >= 2: method = parts[0] path = parts[1] for line in lines: line_str = line if line_str.startswith("Origin:"): new_lines.append("Origin: http://%s:%d" % (TARGET_HOST, TARGET_PORT)) elif line_str.startswith("Referer:"): new_lines.append("Referer: http://%s:%d/" % (TARGET_HOST, TARGET_PORT)) elif line_str.startswith("Host:"): new_lines.append("Host: %s:%d" % (TARGET_HOST, TARGET_PORT)) elif line_str.lower().startswith("connection:"): continue elif line_str.lower().startswith("keep-alive:"): continue elif line_str.lower().startswith("proxy-connection:"): continue elif line_str.lower().startswith("x-forwarded-for:"): continue elif line_str.lower().startswith("x-proxy-request-id:"): continue else: new_lines.append(line_str) modified_data = "\r\n".join(new_lines) if path.startswith("/"): new_path = "http://%s:%d%s" % (TARGET_HOST, TARGET_PORT, path) if method and modified_data: modified_data = modified_data.replace(path, new_path, 1) return modified_data, method, path def handle_request(request_data): """Handle a single request from device B - completely independent thread""" if isinstance(request_data, bytes): request_data_str = request_data.decode('utf-8') else: request_data_str = request_data request_id = extract_request_id(request_data_str) modified_data, method, path = modify_request_headers(request_data_str) body_size = 0 if "\r\n\r\n" in modified_data: body_size = len(modified_data) - modified_data.find("\r\n\r\n") - 4 log_info("System", "Request: %s %s - Body: %d bytes - ID: %s" % (method, path, body_size, request_id)) target_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) target_sock.settimeout(30) try: target_sock.connect((TARGET_HOST, TARGET_PORT)) log_info("System", "Connected to target: %s:%d" % (TARGET_HOST, TARGET_PORT)) if isinstance(modified_data, str): modified_data = modified_data.encode('utf-8') target_sock.sendall(modified_data) response = b"" while True: chunk = target_sock.recv(8192) if not chunk: break response += chunk if b"\r\n\r\n" in response: headers_end = response.find(b"\r\n\r\n") headers = response[:headers_end].decode('utf-8') content_length = 0 for line in headers.split("\r\n"): if line.lower().startswith("content-length:"): content_length = int(line.split(":", 1)[1].strip()) break body_start = headers_end + 4 if len(response) - body_start >= content_length: break if request_id: if b"\r\n\r\n" in response: headers_end = response.find(b"\r\n\r\n") headers = response[:headers_end] body = response[headers_end:] response = headers + ("\r\nX-Proxy-Request-ID: " + request_id).encode('utf-8') + body status_code = "500" if b"\r\n\r\n" in response: headers_end = response.find(b"\r\n\r\n") headers = response[:headers_end].decode('utf-8') for line in headers.split("\r\n"): if line.startswith("HTTP/"): status_code = line.split()[1] break log_info("System", "Response: %s %s - Status: %s - ID: %s" % (method, path, status_code, request_id)) return response except socket.error as e: if e.errno == 111 or e.errno == 10061: log_error("System", "Cannot connect to target: %s:%d" % (TARGET_HOST, TARGET_PORT)) error_response = ("HTTP/1.1 502 Bad Gateway\r\nX-Proxy-Request-ID: " + (request_id if request_id else "") + "\r\nContent-Type: text/plain\r\n\r\nCannot connect to target: %s:%d\r\n" % (TARGET_HOST, TARGET_PORT)).encode('utf-8') return error_response else: log_error("System", "Socket error: %s" % str(e)) error_response = ("HTTP/1.1 502 Bad Gateway\r\nX-Proxy-Request-ID: " + (request_id if request_id else "") + "\r\nContent-Type: text/plain\r\n\r\nSocket error\r\n").encode('utf-8') return error_response except socket.timeout: log_error("System", "Target connection timeout") error_response = ("HTTP/1.1 504 Gateway Timeout\r\nX-Proxy-Request-ID: " + (request_id if request_id else "") + "\r\nContent-Type: text/plain\r\n\r\nConnection timeout\r\n").encode('utf-8') return error_response except Exception as e: log_error("System", "Error handling request: %s" % str(e)) error_response = ("HTTP/1.1 500 Internal Server Error\r\nX-Proxy-Request-ID: " + (request_id if request_id else "") + "\r\nContent-Type: text/plain\r\n\r\nInternal error\r\n").encode('utf-8') return error_response finally: target_sock.close() def process_request(b_socket, request_data): """Process a request in separate thread and send response back""" response = handle_request(request_data) with socket_write_lock: try: b_socket.sendall(response) except Exception as e: log_error("System", "Failed to send response: %s" % str(e)) def listen_for_requests(sock): """Listen for requests from device B""" sock.settimeout(300) while True: try: data = b"" while True: chunk = sock.recv(8192) if not chunk: log_info("System", "Connection closed by device B") return data += chunk if b"\r\n\r\n" in data: headers_end = data.find(b"\r\n\r\n") headers = data[:headers_end].decode('utf-8') content_length = 0 for line in headers.split("\r\n"): if line.lower().startswith("content-length:"): content_length = int(line.split(":", 1)[1].strip()) break body_start = headers_end + 4 if len(data) - body_start >= content_length: break t = threading.Thread(target=process_request, args=(sock, data), name="ReqHandler-%d" % threading.activeCount()) t.daemon = True t.start() except socket.timeout: log_info("System", "Connection idle timeout, continuing to wait") continue except Exception as e: log_error("System", "Connection error: %s" % str(e)) return def connect_to_b_device(b_host, b_port): """Connect to device B and handle requests""" while True: try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) log_info("System", "Connecting to device B: %s:%d" % (b_host, b_port)) sock.connect((b_host, b_port)) log_info("System", "Connected to device B, waiting for PROXY_CONNECTED") response = sock.recv(1024) log_info("System", "Received from B: %r" % response) if not response or b"PROXY_CONNECTED" not in response: log_error("System", "Failed to receive connection confirmation") sock.close() time.sleep(3) continue log_info("System", "Sending READY to device B") sock.sendall(b"READY\r\n") log_info("System", "Successfully connected to device B: %s:%d" % (b_host, b_port)) listen_for_requests(sock) except socket.error as e: if e.errno == 111 or e.errno == 10061: log_info("System", "Device B not ready (%s:%d), retrying in 3 seconds..." % (b_host, b_port)) else: log_error("System", "Connection error: %s" % str(e)) time.sleep(3) except Exception as e: log_error("System", "Unexpected error: %s" % str(e)) time.sleep(3) def main(): print("=" * 60) print(" Proxy Client (Run on Computer A)") print("=" * 60) print("Target website:", TARGET_HOST, ":", TARGET_PORT) print("Device B address:", B_HOST, ":", B_PORT) print("=" * 60) sys.stdout.flush() try: connect_to_b_device(B_HOST, B_PORT) except KeyboardInterrupt: print("\nShutting down...") sys.exit(0) if __name__ == "__main__": main()