您的代码存在一些问题。
Issue #1
最后一个字节FCGI_Record
被命名padding
。它表示在该有效负载之后应跳过多少字节。您将其设置为 0,因此那里并不重要,但是从服务器读取时,您必须跳过这么多字节:
let mut pad = vec![0; responseHeader[7] as usize];
socket.read_exact (&mut pad).unwrap();
这解释了如果您尝试执行读取循环,您将得到垃圾而不是FCGI_END_REQUEST
frame.
Issue #2
The params部分需要标头,但您正在发送原始数据。
您必须计算序列化参数的完整长度并在此之前发送标头:
let params_len: u16 = (param_name.len() + param_value.len() + lengths.len()) as u16;
let paramsRequest = vec![
FCGI_VERSION_1, FCGI_PARAMS,
(requestId >> 8) as u8, (requestId & 0xFF) as u8,
(params_len >> 8) as u8, (params_len & 0xFF) as u8,
0, 0,
];
socket.write_all (¶msRequest).unwrap();
Issue #3
我没有在任何地方找到所需的最小参数php-fpm
, but 浏览源代码,你至少需要添加REQUEST_METHOD
:
let param1_name = "SCRIPT_FILENAME".as_bytes();
let param1_value = "/var/www/html/index.php".as_bytes();
let lengths1 = [ param1_name.len() as u8, param1_value.len() as u8 ];
let params1_len: u16 = (param1_name.len() + param1_value.len() + lengths1.len()) as u16;
let param2_name = b"REQUEST_METHOD";
let param2_value = b"GET";
let lengths2 = [ param2_name.len() as u8, param2_value.len() as u8 ];
let params2_len: u16 = (param2_name.len() + param2_value.len() + lengths2.len()) as u16;
let params_len = params1_len + params2_len;
let paramsRequest = vec![
FCGI_VERSION_1, FCGI_PARAMS,
(requestId >> 8) as u8, (requestId & 0xFF) as u8,
(params_len >> 8) as u8, (params_len & 0xFF) as u8,
0, 0,
];
socket.write_all (¶msRequest).unwrap();
socket.write_all (&lengths1).unwrap();
socket.write_all (param1_name).unwrap();
socket.write_all (param1_value).unwrap();
socket.write_all (&lengths2).unwrap();
socket.write_all (param2_name).unwrap();
socket.write_all (param2_value).unwrap();
在这一点上,我认为您应该考虑为这些东西编写正确的类型和序列化原语,而不是原始字节数组......
通过这些更改,我们已经获得了完整的输出:
Ok("X-Powered-By: PHP/8.1.11\r\nContent-type: text/html; charset=UTF-8\r\n\r\nFirst file")
Issue #4
您应该循环读取响应代码,连接任何FCGI_STDOUT
数据,记录或忽略其他消息,可能记录FCGI_STDERR
消息,直到您收到FCGI_END_REQUEST
.
在这个特定的示例中,输出非常短,以至于它适合一条消息,但是如果不执行循环,您就看不到FCGI_END_REQUEST
.
之后FCGI_END_REQUEST
,取决于您是否使用过FCGI_KEEP_CONN
您可以关闭套接字或保持其打开状态以发送新请求。