void execute_cgi(int client, const char *path,
const char *method, const char *query_string)
{
char buf[1024];
int cgi_output[2];
int cgi_input[2];
pid_t pid;
int status;
int i;
char c;
int numchars = 1;
int content_length = -1;
buf[0] = 'A';
buf[1] = '\0';
//保证进入
if (strcasecmp(method, "GET") == 0)//如果是get,则直接丢弃?
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
numchars = get_line(client, buf, sizeof(buf));
else /* 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]));//找到content-length长度
numchars = get_line(client, buf, sizeof(buf));
}
if (content_length == -1)//如果为-1,错误请求
{
bad_request(client);//返回400
return;
}
}
//开始写
sprintf(buf, "HTTP/1.0 200 OK\r\n");
send(client, buf, strlen(buf), 0);
//#include<unistd.h>
//int pipe(int filedes[2]);
//返回值:成功,返回0,否则返回-1。参数数组包含pipe使用的两个文件的描述符。fd[0]:读管道,fd[1]:写管道。
//必须在fork()中调用pipe(),否则子进程不会继承文件描述符。
//两个进程不共享祖先进程,就不能使用pipe。但是可以使用命名管道。
if (pipe(cgi_output) < 0)
{
cannot_execute(client);//错误代码500
return;
}
if (pipe(cgi_input) < 0)
{
cannot_execute(client);
return;
}
//成功建立管道
if ((pid = fork()) < 0)
{//子进程建立失败
cannot_execute(client);
return;
}
//进入子进程
if (pid == 0) /* child: CGI script */
{
char meth_env[255];//设置request_method 的环境变量
char query_env[255];//GET 的话设置 query_string 的环境变量
char length_env[255];//POST 的话设置 content_length 的环境变量
//标准输入文件的文件描述符:0
//标准输出文件的文件描述符:1
//标准错误输出的文件描述符:2
//dup2创建一个newfd,newfd指向oldfd的位置
dup2(cgi_output[1], 1);//这就是将标准输出重定向到output管道的写入端,也就是输出内容将会输出到output写入
dup2(cgi_input[0], 0);//将标准输入重定向到input读取端,也就是将从input[0]读内容到input缓冲
close(cgi_output[0]);//关闭output管道的的读取端
close(cgi_input[1]);//关闭input管道的写入端
sprintf(meth_env, "REQUEST_METHOD=%s", method);//把method保存到环境变量中
//函数说明:int putenv(const char * string)用来改变或增加环境变量的内容.
//如果该环境变量原先存在, 则变量内容会依参数string 改变, 否则此参数内容会成为新的环境变量.
//返回值:执行成功则返回0, 有错误发生则返回-1.
putenv(meth_env);
if (strcasecmp(method, "GET") == 0)//如果是get
{
sprintf(query_env, "QUERY_STRING=%s", query_string);//存储query_string到query_env
putenv(query_env);
}
else
{ /* POST */
sprintf(length_env, "CONTENT_LENGTH=%d", content_length);//存储tontent_length到length_env
putenv(length_env);
}
// 表头文件#include<unistd.h>
// int execl(const char * path,const char * arg,....);
// 函数说明: execl()用来执行参数path字符串所代表的文件路径,接下来的参数代表执行该文件时传递过去的argv(0)、argv[1]……,最后一个参数必须用空指针(NULL)作结束。
// 返回值: 如果执行成功则函数不会返回,执行失败则直接返回-1
execl(path, path, NULL);//执行path出的脚本
exit(0);//退出
}
else
{ /* parent */
close(cgi_output[1]);//关闭output的写入
close(cgi_input[0]);//关闭input的读取
if (strcasecmp(method, "POST") == 0)//如果是post
for (i = 0; i < content_length; i++)
{
recv(client, &c, 1, 0);//一个字节一个字节读取
write(cgi_input[1], &c, 1);//写入到input的写入
}
//从input写入后,进入子进程,子进程调用excel执行
//依次发送到客户端
while (read(cgi_output[0], &c, 1) > 0)
send(client, &c, 1, 0);
close(cgi_output[0]);//ouput的读
close(cgi_input[1]);//关闭input的写
waitpid(pid, &status, 0);//等待子进程中止
//定义函数:pid_t waitpid(pid_t pid, int * status, int options);
//函数说明:wait()会暂时停止目前进程的执行, 直到有信号来到或子进程结束.
//waitpid不会阻塞
//如果不在意结束状态值, 则参数status 可以设成NULL. 参数pid 为欲等待的子进程识别码, 其他数值意义如下:
//1、pid<-1 等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值
//2、pid=-1 等待任何子进程, 相当于wait().
//3、pid=0 等待进程组识别码与目前进程相同的任何子进程.
//4、pid>0 等待任何子进程识别码为pid 的子进程.
}
}
简单http学习:5 excute_cgi调用
最新推荐文章于 2022-02-20 12:49:48 发布