Home > Back-end >  How to write FCGI_PARAMS using unix sockets
How to write FCGI_PARAMS using unix sockets

Time:10-14

I ask for your help to understand part of the specification of the FastCGI protocol.

Currently this is the code I have:

#![allow(non_snake_case)]
#![allow(unused_must_use)]
use std::os::unix::net::{UnixStream};
use std::io::{Read, Write};

fn main() {
    pub const FCGI_VERSION_1: u8    = 1;
    pub const FCGI_BEGIN_REQUEST:u8 = 1;
    
    pub const FCGI_RESPONDER: u16  = 1;
    
    pub const FCGI_PARAMS: &str = "FCGI_PARAMS";


    let socket_path = "/run/php-fpm/php-fpm.sock";

    let mut socket = match UnixStream::connect(socket_path) {
        Ok(sock) => sock,
        Err(e) => {
            println!("Couldn't connect: {e:?}");
            return
        }
    };

    let requestId: u16 = 1;

    let role: u16 = FCGI_RESPONDER;

    let beginRequest = vec![
       // FCGI_Header
       FCGI_VERSION_1, FCGI_BEGIN_REQUEST, 
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       0x00, 0x08, // This is the size of `FCGI_BeginRequestBody`
       0, 0,
       // FCGI_BeginRequestBody
       (role >> 8) as u8, (role & 0xFF) as u8,
       0, // Flags
       0, 0, 0, 0, 0, // Reserved
    ];

    socket.write_all(&beginRequest).unwrap();

    let data = vec![
        (100) as u8, // this value is just an example
    ];

    let contentLength = data.len();

    assert!(contentLength <= usize::MAX);
    let requestHeader = vec![
       FCGI_VERSION_1, FCGI_BEGIN_REQUEST, 
       (requestId >> 8) as u8, (requestId & 0xFF) as u8,
       (contentLength >> 8) as u8, (contentLength & 0xFF) as u8,
       0, 0,
    ];

    socket.write_all(&requestHeader).unwrap();

}

I have this code thanks to the answer of my last question related to this topic, so, with that example code (which works perfectly for me) I would like to ask you my question.

How can I write the FCGI_PARAMS?

I mean, if I understand correctly, the documentation says:

FCGI_PARAMS is a stream record type used in sending name-value pairs from the Web server to the application

This means that the FCGI_PARAMS are Name-Value Pairs. And the part of the documentation that describes the Name-Value Pairs says:

FastCGI transmits a name-value pair as the length of the name, followed by the length of the value, followed by the name, followed by the value

Then this way I think that it would be (represented in code):

let param = vec![
  "SCRIPT_FILENAME".len(),
  "index.php".len(),
  "SCRIPT_FILENAME",
  "index.php",
]; // it is just an example, but i think it represents what i am talking about

But if I add this code, and then I write it to the socket with the following line:

socket.write_all(&param);

And then when reading the socket, the socket does not return anything. What am I doing wrong? How should I send the data? I hope you can help me with this, I want to clarify that I am quite new to FastCGI and unix sockets so I am very sorry if any line of my displayed code is poorly exemplified.

CodePudding user response:

Rust doesn't support heterogeneous vectors, so your let param =… shouldn't compile. The way to send the params is to use multiple writes:

let param_name = "SCRIPT_FILENAME".as_bytes(); // could also be written `b"SCRIPT_FILENAME"`
let param_value = "index.php".as_bytes();
let lengths = [ param_name.len() as u8, param_value.len() as u8 ];
socket.write_all (&lengths).unwrap();
socket.write_all (param_name).unwrap();
socket.write_all (param_value).unwrap();
  • Related