FastCGI協議分析

工程師WWW發表於2016-11-07

不知道什麼時候,就開始有了讓HomeServer支援PHP的念頭。於是分析起了FastCGI協議。FastCGI用於WebServer與WebApplication之間的通訊,例如Apache與PHP程式。

FastCGI協議資料包是8位元組對齊的,由包頭(Header)和包體(Body)組成。例如要請求一個index.php的頁面,WebServer首先向WebApp傳送一個Request資料包。包頭有個請求ID用於並行工作時,區別不同的請求。

包頭
[版本:1][型別:1][請求ID:2][資料長度:2][填充位元組數:1][保留:1]

包體
[角色:2][引數:1][保留:5]

接著,再傳送一個Params資料包,用於傳遞執行頁面所需要的引數和環境變數。

包頭
[版本:1][型別:1][請求ID:2][資料長度:2][填充位元組數:1][保留:1]

包體
[名稱長度:1或4][值長度:1或4][名稱:變長][值:變長] …

其中,名稱和值的長度佔用的位元組數是可變,取決於第一個位元組(高位)的最高位是否為1,為1則長度是4個位元組,否則為1個位元組。即如果長度不超過128位元組,就用一個位元組來儲存長度足夠了。

引數傳送後還要傳送一個沒有包體,只有包頭的空的Params資料包,用來表示引數傳送結束。

如果請求頁面時POST方式,還會傳送表單資料。這就要用到Stdin資料包了。

包頭
[版本:1][型別:1][請求ID:2][資料長度:2][填充位元組數:1][保留:1]

包體
[資料內容:長度在包頭中設定,8位元組對齊]

有時候POST的資料大於或等於64KB,就不能使用一個Stdin資料包傳送完畢了,需要使用多次Stdin資料包來完成所有資料的傳輸。與Params資料包一樣,結尾要傳送一個沒有包體,只有包頭的空的Stdin資料包,用來表示引數傳送結束。

至此,WebServer要提供給WebApplication的資料已經傳送完畢。接著就接收來自WebApplication的資料了。

資料接收包Stdout與Stdin是差不多的,這裡不再描述。不過接收到的資料由HTTP頭和網頁資料兩部分組成,WebServer要對其做一定的處理後才能傳送到瀏覽器。同Stdin資料包一樣,WebServer會接收到一個來自WebApplication的Stdout的空資料包,表示接收的Stdout資料已經完畢。

最後,WebApplication會傳送一個包含狀態的EndRequest資料包,至此,一次頁面請求處理完畢。

下面給出一些相關結構參考。

通用包頭:

typedef struct {
    unsigned char version;
    unsigned char type;
    unsigned char requestIdB1;
    unsigned char requestIdB0;
    unsigned char contentLengthB1;
    unsigned char contentLengthB0;
    unsigned char paddingLength;
    unsigned char reserved;
}FCGI_Header;

typedef struct {
    unsigned char roleB1;
    unsigned char roleB0;
    unsigned char flags;
    unsigned char reserved[5];
} FCGI_BeginRequestBody;

typedef struct {
    FCGI_Header header;
    FCGI_BeginRequestBody body;
} FCGI_BeginRequestRecord;

typedef struct {
    unsigned char appStatusB3;
    unsigned char appStatusB2;
    unsigned char appStatusB1;
    unsigned char appStatusB0;
    unsigned char protocolStatus;
    unsigned char reserved[3];
} FCGI_EndRequestBody;

每次請求頁面時,傳遞給PHP程式的引數:

SCRIPT_FILENAME,

QUERY_STRING,

REQUEST_METHOD,

CONTENT_TYPE,

CONTENT_LENGTH,

SCRIPT_NAME,

REQUEST_URI,

DOCUMENT_URI,

DOCUMENT_ROOT,

SERVER_PROTOCOL,

GATEWAY_INTERFACE,

SERVER_SOFTWARE,

REMOTE_ADDR,

REMOTE_PORT,

SERVER_ADDR,

SERVER_PORT,

SERVER_NAME,

REDIRECT_STATUS,

HTTP_ACCEPT,

HTTP_ACCEPT_LANGUAGE,

HTTP_ACCEPT_ENCODING,

HTTP_USER_AGENT,

HTTP_HOST,

HTTP_CONNECTION,

HTTP_CONTENT_TYPE,

HTTP_CONTENT_LENGTH,

HTTP_CACHE_CONTROL,

HTTP_COOKIE,

HTTP_FCGI_PARAMS_MAX

好像很多,但是很多空值的,可以省去,不傳送之,即可。

參考文獻:

FastCGI Specification

感謝狙擊手同志提供相關幫助。

相關文章