FastCGI protocol analysis and implementation of FastCGI in PHP

Source: Internet
Author: User
Tags strtok
Before discussing FastCGI, we have to say that the traditional CGI works, and should probably understand the CGI 1.1 protocol

Analysis of traditional CGI working principle

After the client accesses a URL address, submits the data through get/post/put and other means, and makes a request to the WEB server via the HTTP protocol, the server-side HTTP Daemon (daemon) passes the information described in the HTTP request through the standard input stdin and environment variables (environment variable) is passed to the CGI program specified by the home page and starts the application for processing (including processing of the database), the processing results are returned to the HTTP Daemon daemon through the standard output stdout, and then by the HTTP Daemon process through H The TTP protocol is returned to the client.

The above paragraph may be more abstract, as illustrated below by a GET request.

Web Server Code

#include
 
  #include
  
   #include
   
    #include
    
     #include
     
      #include #include
      
       #include
       
         #define Serv_port 9003char* Str_join (char *str1, char *str2); char* html_response (Char *res, char *buf); int main (void) {int LFD, CFD; struct sockaddr_in serv_addr,clin_addr; socklen_t Clin_len; Char buf[1024],web_result[1024] ; int Len; FILE *cin; if (LFD = socket (af_inet,sock_stream,0)) = =-1) {perror ("Create socket Failed"); exit (1);} memset (&serv_addr, 0, size Of (SERV_ADDR)); serv_addr.sin_family = af_inet; SERV_ADDR.SIN_ADDR.S_ADDR = htonl (Inaddr_any); Serv_addr.sin_port = htons (Serv_port); if (Bind (LFD, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) = =-1) {perror ("bind error"); exit (1);} if (Listen (LFD , (+) = =-1) {perror ("Listen error"); exit (1);} signal (sigcld,sig_ign); while (1) {Clin_len = sizeof (CLIN_ADDR), if (cfd = Accept (LFD, (struct sockaddr *) &clin_addr, &clin_len)) = =-1) {perror ("receive error \ n"); continue;} cin = Fdopen (CFD, "R"); Setbuf (CIN, (char *) 0); Fgets (buf,1024,cin); Read the first line of printf ("\n%s", buf); ============================ CGI environment variable setting demo = ===========================//For example "get/user.cgi?id=1 http/1.1"; Char *delim = ""; Char *p; Char *method, *filename, *query_string; Char *query_string_pre = "query_string="; method = Strtok (Buf,delim); GET p = strtok (Null,delim); /user.cgi?id=1 filename = strtok (P, "?"); /user.cgi if (strcmp (filename, "/favicon.ico") = = 0) {continue;} query_string = Strtok (NULL, "?"); Id=1 putenv (Str_join (query_string_pre,query_string)); ============================ CGI environment variable setting demo ============================ int pid = fork (); if (PID > 0) {close (CFD);} else if (PID = = 0) {close (LFD); FILE *stream = Popen (Str_join (".", filename), "R"); Fread (Buf,sizeof (char), sizeof (BUF), stream); Html_response (WEB_RESULT,BUF); Write (cfd,web_result,sizeof (Web_result)); Pclose (stream); Close (CFD); Exit (0); } else {perror ("fork Error"); exit (1);}} Close (LFD); return 0;} char* Str_join (Char *str1, char *str2) {char *result = malloc (strlen (str1) +strlen (str2) +1), if (result = = NULL) exit (1); strcpy (result, sTR1); strcat (result, str2); return result;} char* Html_response (Char *res, char *buf) {char *html_response_template = "http/1.1-ok\r\ncontent-type:text/html\r\ Ncontent-length:%d\r\nserver:mengkang\r\n\r\n%s "; sprintf (Res,html_response_template,strlen (BUF), buf); return res;}
       
      
     
    
   
  
 

CGI Program (USER.C)

#include 
 
  
   
  #include 
  
   
    
   //Query the user's information by obtaining an ID of int main (void) {//============================ Simulation database = ===========================typedef struct {int  Id;char *username;int age  ;} user;user users[] = {{},{1, " Mengkang.zhou ", 18}};//============================ analog database ============================char *query_string;int ID; Query_string = getenv ("query_string"), if (query_string = = NULL) {printf ("No input Data"),} else if (sscanf (query_string, "id=%d ", &id)! = 1) {printf (" No input ID ");} else{printf ("User information query
   
    
Study Number:%d
Name:%s
Age:%d ", id,users[id].username,users[id].age);} return 0;}

Compile the above CGI program into GCC user.c-o user.cgi, which is placed in the sibling directory of the Web program above.

Analysis of working principle of FastCGI

Relative to the cgi/1.1 specification, the WEB server in the local fork a child process to execute a CGI program, populate the CGI predefined environment variables, put into the system environment variables, the HTTP body content through the standard input to the child process, after processing through the standard output returned to Web server. The core of the FastCGI is to outlaw the traditional fork-and-execute approach, reducing the overhead of each launch (as explained in PHP) and processing requests in a permanent manner.

The difference between the FastCGI and the traditional CGI mode is that the Web server does not directly execute the CGI program, but instead interacts with the FastCGI responder (FastCGI process Manager) through the socket, and the Web server needs to encapsulate the CGI interface data in accordance with the FASTCG I Send the FastCGI responder program to the protocol package. It is because the FastCGI process Manager is socket-based, and therefore distributed, that the Web server and the CGI responder server are deployed separately.

FastCGI protocol Message Flow

Some examples are listed in the official introduction document Http://www.fastcgi.com/devkit/doc/fcgi-spec.html#SB

Let's start with a more straightforward process, as shown in

For example, the following example

{fcgi_begin_request,   1, {fcgi_responder, 0}}{fcgi_params,          1, ' \013\002server_port80\013\016server_ ADDR199.170.183.42 ... "}{fcgi_stdin,           1," quantity=100&item=3047936 "}{fcgi_stdout,       1," content-type:text/html\r\n\r\n\n ... "}{fcgi_end_request,     1, {0, Fcgi_request_complete}}

FastCGI definition of each phase of the request in PHP

typedef enum _FCGI_REQUEST_TYPE {fcgi_begin_request=  1,/* [in]                              */fcgi_abort_request=  2,/* [in]  (not Supported)             */fcgi_end_request=  3,/* [out]                             */fcgi_params=  4,/* [in]  environment variables       */fcgi_stdin=  5,/* [in]  post data                   */fcgi_stdout=  6,/* [out] response                    */fcgi_stderr=  7,/* [out] errors                      */fcgi_data=  8,/* [in]  filter DATA (not supported) */fcgi_get_values=  9,/* [in]< c20/>*/fcgi_get_values_result=  */* [out]                             */} Fcgi_request_type;

Definition of FastCGI header in PHP

typedef struct _FCGI_HEADER {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;

Field interpretation

Version identifies fastcgi protocol versions.

Type identifies the fastcgi record type, which is the general function that records execution.

RequestID identifies the fastcgi request to which the record belongs.

ContentLength the number of bytes of the Contentdata component recorded.

Protocol description for XxB1 and xxB0 above: when two adjacent structural components are named in addition to the suffix "B1" and "B0", it means that both components can be considered as a single number valued as B1<<8 + B0. The name of the single number is the name of the component minus the suffix. This Convention sums up the processing of a number represented by more than two bytes.

For example, the maximum value represented by RequestID and ContentLength in the protocol header is 65535.

#include 
 
  
   
  #include 
  
   
    
   #include 
   
    
     
    int main () {   unsigned char requestIdB1 = UCHAR _max;   unsigned char requestIdB0 = Uchar_max;   printf ("%d\n", (requestIdB1 << 8) + requestIdB0); 65535
   
     }
  
   
 
  

Definition of fcgi_begin_request in PHP

typedef struct _FCGI_BEGIN_REQUEST {unsigned char roleb1;unsigned char roleb0;unsigned char flags;unsigned char reserved[ 5];} Fcgi_begin_request;

The Web server sends a Fcgi_begin_request record to start a request.

Field interpretation

Role represents the roles that the Web server expects the app to play. There are three roles defined in PHP.

typedef enum _FCGI_ROLE {fcgi_responder= 1,fcgi_authorizer= 2,fcgi_filter= 3} fcgi_role;

The flags component contains a bit that controls the line shutdown: Flags & Fcgi_keep_conn: If 0, the application closes the line after responding to this request. If not 0, the application does not close the line after responding to this request, and the Web server remains responsive to the line.

Definition of fcgi_end_request in PHP

typedef struct _FCGI_END_REQUEST {    unsigned char appStatusB3;    unsigned char appStatusB2;    unsigned char appStatusB1;    unsigned char appStatusB0;    unsigned char protocolstatus;    unsigned char reserved[3];} Fcgi_end_request;

The Appstatus component is the status code at the application level.

The Protocolstatus component is a status code at the protocol level; The value of Protocolstatus may be:

Fcgi_request_complete: The normal end of the request.

Fcgi_cant_mpx_conn: Reject new request. This occurs when the Web server sends concurrent requests to the application through a line, which is designed to process one request at a time per line.

Fcgi_overloaded: Reject new request. This occurs when the app runs out of certain resources, such as a database connection.

Fcgi_unknown_role: Reject new request. This occurs when the Web server specifies a role that the application does not recognize.

Protocolstatus is defined in PHP as follows

typedef enum _FCGI_PROTOCOL_STATUS {fcgi_request_complete= 0,fcgi_cant_mpx_conn= 1,fcgi_overloaded= 2,FCGI_UNKNOWN_ Role= 3} dcgi_protocol_status;

It is important to note that the values of each element of Dcgi_protocol_status and fcgi_role are defined in the FastCGI protocol, not PHP-customized.

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.