当httpd运行时,对文件具有可执行权限时,则认为该文件是cgi程序,调用函数 execute_cgi
/**********************************************************************/
/* Execute a CGI script. Will need to set environment variables as
* appropriate.
* Parameters: client socket descriptor
* path to the CGI script */
/**********************************************************************/
void execute_cgi(int client, const char *path,
const char *method, const char *query_string)
{
char buf[1024];
//------- 一个内存缓冲区,用于读取client_sock内容,后面又用户写入client_sock
int cgi_output[2];
//------- cgi的输出管道声明
int cgi_input[2];
//-------- cgi的输入管道声明
pid_t pid;
//-------- 执行cgi的子程序pid
int status;
//-------- 主进程等待cgi执行的状态
int i;
char c;
int numchars = 1;
int content_length = -1;
buf[0] = 'A'; buf[1] = '\0';
if (strcasecmp(method, "GET") == 0)
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
numchars = get_line(client, buf, sizeof(buf));
//---------- 如果是get方式忽略header和Body
else if (strcasecmp(method, "POST") == 0) /*POST*/
{
numchars = get_line(client, buf, sizeof(buf));
while ((numchars > 0) && strcmp("\n", buf))
{
buf[15] = '\0';
if (strcasecmp(buf, "Content-Length:") == 0)
content_length = atoi(&(buf[16]));
numchars = get_line(client, buf, sizeof(buf));
//------------POST方式,读取一些信息返回,这里本人不是太清楚,请自行研究下http的范围报文格式
}
if (content_length == -1) {
bad_request(client);
return;
}
//-------------- 读取不到,则为异常请求
}
else/*HEAD or other*/
{
}
if (pipe(cgi_output) < 0) {
cannot_execute(client);
return;
}
//-------- 得到输出管道
if (pipe(cgi_input) < 0) {
cannot_execute(client);
return;
}
//-------- 得到输入管道
if ( (pid = fork()) < 0 ) {
cannot_execute(client);
return;
}
//--------- 创建子进程
sprintf(buf, "HTTP/1.0 200 OK\r\n");
send(client, buf, strlen(buf), 0);
//---------- 响应内容
if (pid == 0) /* child: CGI script */
{
char meth_env[255];
char query_env[255];
char length_env[255];
dup2(cgi_output[1], STDOUT);
dup2(cgi_input[0], STDIN);
//---------- 将子进程的标准输入输出,加入管道
close(cgi_output[0]);
close(cgi_input[1]);
sprintf(meth_env, "REQUEST_METHOD=%s", method);
//----------- 给cgi的参数
putenv(meth_env);
if (strcasecmp(method, "GET") == 0) {
sprintf(query_env, "QUERY_STRING=%s", query_string);
putenv(query_env);
}
else { /* POST */
sprintf(length_env, "CONTENT_LENGTH=%d", content_length);
putenv(length_env);
}
//----------- 给cgi的参数
execl(path, NULL);
//---------- 执行
exit(0);
} else { /* parent */
close(cgi_output[1]);
close(cgi_input[0]);
if (strcasecmp(method, "POST") == 0)
for (i = 0; i < content_length; i++) {
recv(client, &c, 1, 0);
write(cgi_input[1], &c, 1);
}
//------------如果是post方式,将Http请求的body内容写入cgi_input,供cgi程序使用
while (read(cgi_output[0], &c, 1) > 0)
send(client, &c, 1, 0);
//---------读取cgi程序响应,写入client_sock
close(cgi_output[0]);
close(cgi_input[1]);
waitpid(pid, &status, 0);
}
}
另外还有
void cannot_execute(int);
void not_found(int);
void bad_request(int);
都是返回服务器的错误,本菜鸟都觉得简单,本系列结束。