python代碼
import socket
import struct
import threading# FastCGI 頭格式(8 字節)
FCGI_HEADER_FORMAT = "!BBHHBx"
FCGI_VERSION = 1
FCGI_TYPE_BEGIN_REQUEST = 1
FCGI_TYPE_PARAMS = 4
FCGI_TYPE_STDIN = 5
FCGI_TYPE_STDOUT = 6
FCGI_TYPE_END_REQUEST = 3
FCGI_RESPONDER = 1def parse_fcgi_header(data):"""解析 FastCGI 頭"""version, type_, request_id, content_length, padding_length = struct.unpack(FCGI_HEADER_FORMAT, data)return version, type_, request_id, content_length, padding_lengthdef read_fcgi_record(client_socket):"""讀取并解析 FastCGI 記錄"""header = client_socket.recv(8) # 讀取 8 字節頭部if not header:return None, None, None, None, Noneversion, type_, request_id, content_length, padding_length = parse_fcgi_header(header)content = client_socket.recv(content_length) if content_length > 0 else b""client_socket.recv(padding_length) # 讀取并丟棄填充數據return type_, request_id, content, content_length, padding_lengthdef parse_fcgi_params(data):"""解析 FastCGI PARAMS(key-value 形式)"""params = {}i = 0while i < len(data):name_length = data[i]value_length = data[i + 1]i += 2# 處理長度值大于 127 的情況if name_length >= 128:name_length = ((name_length & 0x7F) << 24) | (data[i] << 16) | (data[i+1] << 8) | data[i+2]i += 3if value_length >= 128:value_length = ((value_length & 0x7F) << 24) | (data[i] << 16) | (data[i+1] << 8) | data[i+2]i += 3name = data[i : i + name_length].decode("utf-8", errors="ignore")value = data[i + name_length : i + name_length + value_length].decode("utf-8", errors="ignore")params[name] = valuei += name_length + value_lengthreturn paramsdef handle_request(client_socket):"""處理 FastCGI 請求"""try:# 讀取 BEGIN_REQUEST 記錄type_, request_id, content, _, _ = read_fcgi_record(client_socket)if type_ != FCGI_TYPE_BEGIN_REQUEST:client_socket.close()return# 讀取所有 PARAMS(FastCGI 請求參數)params_data = b""while True:type_, _, content, content_length, _ = read_fcgi_record(client_socket)if type_ != FCGI_TYPE_PARAMS or content_length == 0:break # 讀取完成params_data += content# **使用修正的解析函數**param_dict = parse_fcgi_params(params_data)print("Received FCGI Params:", param_dict)# 讀取 STDIN(HTTP 請求體)stdin_data = b""while True:type_, _, content, content_length, _ = read_fcgi_record(client_socket)if type_ != FCGI_TYPE_STDIN or content_length == 0:breakstdin_data += content# 生成 HTTP 響應response_body = b"Hello, FastCGI over TCP! (Threaded)"response_headers = b"Content-Type: text/plain\r\nContent-Length: %d\r\n\r\n" % len(response_body)stdout_data = response_headers + response_body# 發送 FastCGI 響應stdout_header = struct.pack(FCGI_HEADER_FORMAT, FCGI_VERSION, FCGI_TYPE_STDOUT, request_id, len(stdout_data), 0)end_header = struct.pack(FCGI_HEADER_FORMAT, FCGI_VERSION, FCGI_TYPE_END_REQUEST, request_id, 0, 0)client_socket.sendall(stdout_header + stdout_data) # 發送正文client_socket.sendall(end_header) # 發送結束標志except Exception as e:print(f"Error handling request: {e}")finally:client_socket.close()def start_fcgi_server(host="0.0.0.0", port=9000):"""啟動 FastCGI 多線程 TCP 服務器"""server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)server_socket.bind((host, port))server_socket.listen(5)print(f"FastCGI Server listening on {host}:{port}")while True:client_socket, _ = server_socket.accept()thread = threading.Thread(target=handle_request, args=(client_socket,))thread.start() # 啟動新線程處理請求if __name__ == "__main__":start_fcgi_server()
nginx添加配置
location /hello {include fastcgi_params;fastcgi_pass 127.0.0.1:9000;# 傳遞 FastCGI 相關參數fastcgi_param REQUEST_METHOD $request_method;fastcgi_param SCRIPT_FILENAME /dummy;fastcgi_param QUERY_STRING $query_string;fastcgi_param CONTENT_TYPE $content_type;fastcgi_param CONTENT_LENGTH $content_length;fastcgi_param PATH_INFO $fastcgi_script_name;
}
訪問結果