从之前讲述的really_start_request函数我们知道当设置的cgi_pattern不为空且文件具有其他用户可执行的权限且cgi_pattern与文件的扩展名称匹配时将调用CGI过程。
CGI过程根据用户的请求方式和请求参数调用存在于cgi_pattern文件目录中的可执行程序返回用户数据的过程。
程序流程
(1)判断已经使用的CGI的程序数量是否超过了设置的最大数量,如果是退出函数,反之继续执行。
(2)设置当前使用的CGI的程序数量加一。
(3)设置连接的文件描述符为阻塞模式。
(4)创建子进程,如果创建失败退出函数;如果创建成功子进程关闭服务器的文件描述符,调用cgi_child函数;父进程设置子进程超时处理函数,设置状态码等参数然后退出。
(5)设置连接的文件描述符的F_SETFD值为0。
(6)如果连接的文件描述符为标准输入输出或者是标准错误赋值连接的文件描述符为3。
(7)设置环境变量
(8)设置参数变量
(9)对于方式是POST方式,创建管道,创建失败返回500错误退出函数,创建成功将会创建子进程,创建子进程失败返回500错误退出函数,创建成功读取未读取完的数据写到管道的写数据端口,如果读管道的文件描述符不是标准输入复制为标准输入。对于不是POST方式设置连接的文件描述符的值为标准输入。
(10)复制连接的文件描述符到标准输入和标准错误
(10)设置子程序运行的优先级
(11)设置子程序的名称。
(12)调用子程序。
流程图
源程序
/**cgi程序处理*/
static int cgi( httpd_conn* hc )
{
int r;
ClientData client_data;
/**判断是否是有效的CGI程序*/
if ( hc->hs->cgi_limit != 0 && hc->hs->cgi_count >= hc->hs->cgi_limit )
{
httpd_send_err(hc, 503, httpd_err503title, "", httpd_err503form,hc->encodedurl );
return -1;
}
++hc->hs->cgi_count;
/**设置为非阻塞模式*/
httpd_clear_ndelay( hc->conn_fd );
/**创建子进程*/
r = fork( );
if ( r < 0 )
{
syslog( LOG_ERR, "fork - %m" );
httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl );
return -1;
}
/**子进程处理函数*/
if ( r == 0 )
{
/* Child process. */
sub_process = 1;
httpd