//start from the very beginning,and to create greatness
//@author: Chuangwei Lin
//@E-mail:979951191@qq.com
//@brief: SHTTPD支持CGI的实现
#include "lcw_shttpd.h"
/******************************************************
函数名: GenerateDirFile(struct worker_ctl *wctl)
参数:
功能:生成目录下的文件列表
*******************************************************/
int GenerateDirFile(struct worker_ctl *wctl)
{
struct conn_request *req = &wctl->conn.con_req;
struct conn_response *res = &wctl->conn.con_res;
char *command = strstr(req->uri, CGISTR) + strlen(CGISTR);
char *arg[ARGNUM];
int num = 0;
char *rpath = wctl->conn.con_req.rpath;
stat *fs = &wctl->conn.con_res.fsate;
//打开目录
DIR *dir = opendir(rpath);
if(dir == NULL)
{
//错误
res->status = 500;
retval = -1;
goto EXITgenerateIndex;
}
//建立临时文件保存目录列表
File *tmpfile;
char tmpbuff[2048];
int filesize = 0;
char *uri = wctl->conn.con_req.uri;
//以wb+形式创建一个临时二进制文件
tmpfile = tmpfile();
//标题部分
sprintf(tmpbuff,
"%s%s%s",
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<HTML><HEAD><TITLE>",
uri,
"</TITLE></HEAD>\n" );
fprintf(tmpfile, "%s", tmpbuff);
filesize += strlen(tmpbuff);
//标识部分
sprintf(tmpbuff,
"%s %s %s",
"<BODY><H1>Index of:",
uri,
" </H1> <HR><P><I>Date: </I> <I>Size: </I></P><HR>");
fprintf(tmpfile, "%s", tmpbuff);
filesize += strlen(tmpbuff);
//读取目录中的文件列表
struct dirent *de;
#define PATHLENGTH 2048
char path[PATHLENGTH];
char tmpath[PATHLENGTH];
char linkname[PATHLENGTH];
struct stat fs;//stat 结构定义于:/usr/include/sys/stat.h 文件中
strcpy(path, rpath);
if(rpath[strlen(rpath)]!='/')
{
rpath[strlen(rpath)]='/';
}
while ((de = readdir(dir)) != NULL)//读取一个文件
{
menset(tmpath, 0, sizeof(tmpath));
menset(linkname, 0, sizeof(linkname));
if(strcmp(de->d_name, "."))//不是当前目录
{
if(strcmp(de->d_name, ".."))//不是父目录
{
strcpy(linkname,de->d_name);//将目录名称作为链接名称
}
else//是父目录
{
strcpy(linkname, "Parent Directory");//将父目录作为链接名称
} sprintf(tmpath, "%s%s",path, de->d_name);//构建当前文件的全路径
stat(tmpath, &fs);//获得文件信息
if(S_ISDIR(fs.st_mode))//是一个目录
{
//打印目录的连接为目录名称
sprintf(tmpbuff, "<A HREF=\"%s/\">%s/</A><BR>\n", de->d_name,tmpath);
}
else//正常文件
{
char size_str[32];
off_t size_int;
size_int = fs.st_size;//文件大小
if (size_int < 1024)//不到1K
sprintf(size_str, "%d bytes", (int) size_int);
else if (size_int < 1024*1024)//不到1M
sprintf(size_str, "%1.2f Kbytes", (float) size_int / 1024);
else//其他
sprintf(size_str, "%1.2f Mbytes", (float) size_int / (1024*1024));
//输出文件大小
sprintf(tmpbuff, "<A HREF=\"%s\">%s</A> (%s)<BR>\n", de->d_name, linkname, size_int);
}
//将形成的字符串写入临时文件
fprintf(tmpfile, "%s", tmpbuff);
filesize += strlen(tmpbuff);
}
}
//生成临时的文件信息,主要是文件大小
fs.st_ctime = time(NULL);
fs.st_mtime = time(NULL);
fs.st_size = filesize;
fseek(tmpfile, (long) 0, SEEK_SET);//移动文件指针到头部
EXITgenerateIndex:
return 0;
} #define CGISTR "/cgi-bin/"//CGI目录的字符串
#define ARGNUM 16 //CGI程序变量的最大个数
#define READIN 0 //读出管道
#define WRITEOUT 1 //写入管道
/******************************************************
函数名:cgiHandler(struct worker_ctl *wctl)
参数:
功能:
*******************************************************/
int cgiHandler(struct worker_ctl *wctl)
{
struct conn_request *req = &wctl->conn.con_req;
struct conn_response *res = &wctl->conn.con_res;
//strstr(str1,str2);str1:被查找目标 str2:要查找对象 
char *command = strstr(req->uri, CGISTR) + strlen(CGISTR);//获得匹配字符串/cgi-bin/
char *arg[ARGNUM];
int num = 0;
char *rpath = wctl->conn.con_req.rpath;
stat *fs = &wctl->conn.con_res.fsate;
int retval = -1;
char *pos = command;//查找CGI的命令
for(;*pos != '?' && *pos !='\0';pos++);//找到命令尾
{
*pos = '\0';
}
sprintf(rpath, "%s%s",conf_para.CGIRoot,command);//构建全路径
//查找CGI的参数
pos++;
for(;*pos != '\0' && num < ARGNUM;)
{ //CGI的参数为紧跟CGI命令后的?的字符串,多个变量之间用+连接起来,所以可以根据加号的个数确定参数的个数
arg[num] = pos;//参数头
for(;*pos != '+' && *pos!='\0';pos++);
if(*pos == '+')
{
*pos = '\0';//参数尾
pos++;
num++;
}
}
arg[num] = NULL;
//命令的属性
if(stat(rpath,fs)<0)
{
//错误
res->status = 403;
retval = -1;
goto EXITcgiHandler;
}
else if((fs->st_mode & S_IFDIR) == S_IFDIR)
{
//是一个目录,列出目录下的文件
GenerateDirFile(wctl);
retval = 0;
goto EXITcgiHandler;
}
else if((fs->st_mode & S_IXUSR) != S_IXUSR)
{
//所指文件不能执行
res->status = 403;
retval = -1;
goto EXITcgiHandler;
}
//创建进程间通信的管道
int pipe_in[2];
int pipe_out[2]; if(pipe(pipe_in) < 0)//创建管道
{
res->status = 500;
retval = -1;
goto EXITcgiHandler;
}
if(pipe(pipe_out) < 0)
{
res->status = 500;
retval = -1;
goto EXITcgiHandler;
}
//进程分叉
int pid = 0;
pid = fork();
if(pid < 0)//错误
{
res->status = 500;
retval = -1;
goto EXITcgiHandler;
}
else if(pid > 0)//父进程
{
close(pipe_out[WRITEOUT]);//关闭写端
close(pipe_in[READIN]);//关闭读端
//主进程从CGI的标准输出读取数据 ,并将数据发送到网络资源请求的客户端
int size = 0;//这里初始化为0,怎么进入while循环?改为下面的情况
int end = 0;
//读取CGI进程数据
size = read(pipe_out[READIN], res->res.ptr, sizeof(wctl->conn.dres));
while(size > 0 && !end)
{
if(size > 0)
{//将数据发送给客户端
send(wctl->conn.cs, res->res.ptr, strlen(res->res.ptr));
}
else
{
end = 1;
}
size = read(pipe_out[READIN], res->res.ptr, sizeof(wctl->conn.dres));
}
wait(&end);//等待其子进程全部结束
close(pipe_out[READIN]);//关闭管道
close(pipe_in[WRITEOUT]);
retval = 0;
}
else//子进程
{
char cmdarg[2048];
char onearg[2048];
char *pos = NULL;
int i = 0;
//形成执行命令
memset(onearg, 0, 2048];
for(i = 0;i<num;i++)
sprintf(cmdarg,"%s %s", onearg, arg[i]);
//将写入的管道绑定到标注输出
close(pipe_out[READIN]); //关闭无用的读管道
dup2(pipe_out[WRITEOUT], 1); //将写管道绑定到标准输出
close(pipe_out[WRITEOUT]); //关闭写管道 close(pipe_in[WRITEOUT]); // 关闭无用的写管道
dup2(pipe_in[READIN], 0); // 将读管道绑定到标准输入
close(pipe_in[READIN]); // 关闭写管道
//execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,
//找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、
//argv[1]……,最后一个参数必须用空指针(NULL)作结束
execlp(rpath, arg);//执行命令,命令的输出需要为标准输出
}
EXITcgiHandler:
return retval;
}

一个简单的wed服务器SHTTPD(4)————SHTTPD支持CGI的实现的更多相关文章

  1. 一个简单的wed服务器SHTTPD(3)————SHTTPD多客户端支持的实现

    //start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...

  2. 一个简单的wed服务器SHTTPD(9)————main函数文件,Makefile,头文件

    主函数: #include "lcw_shttpd.h" //初始化时服务器的默认配置 extern struct conf_opts conf_para= { "/us ...

  3. 一个简单的wed服务器SHTTPD(1)————命令行和文件配置解析

    开始学习<LInux网络编程>中的综合案例,虽然代码书上有,还是自己打一下加深理解和印象. 主要有两个函数,完成命令行的解析,另一个实现配置文件的解析,注释还是比较丰富的哦. //star ...

  4. 一个简单的wed服务器SHTTPD(6)———— SHTTPD错误处理的实现

    //start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...

  5. 一个简单的wed服务器SHTTPD(5)————服务器SHTTPD请求方法解析

    //start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...

  6. 一个简单的wed服务器SHTTPD(7)———— SHTTPD内容类型的实现

    //start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...

  7. 一个简单的wed服务器SHTTPD(8)———— URI分析

    //start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...

  8. 一个简单的wed服务器SHTTPD(2)———— 客户端请求分析

    //start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...

  9. 自己动手模拟开发一个简单的Web服务器

    开篇:每当我们将开发好的ASP.NET网站部署到IIS服务器中,在浏览器正常浏览页面时,可曾想过Web服务器是怎么工作的,其原理是什么?“纸上得来终觉浅,绝知此事要躬行”,于是我们自己模拟一个简单的W ...

随机推荐

  1. Git mergetool 插件

    首先你喜欢使用git命令行操作,可以上网下载Kdiff3安装到你的电脑,然后按下面的操作就可以使用这个工具了. 1. 安装Kdiff3 软件.(最好使用默认路径) 2. 添加kdiff3到git me ...

  2. 35 编码 ASCII Unicode UTF-8 ,字符串的编码、io流的编码

    * 编码表: * 信息在计算机上是用二进制表示的,这种表示法让人理解就很困难.为保证人类和设备,设备和计算机之间能进行正确的信息交换,人们编制的统一的信息交换代码,这就是ASCII码表 *ASCII ...

  3. python3(四十)datetime timestamp str

    """时间处理 """ __author__on__ = 'shaozhiqi 2019/9/25' # !/usr/bin/env pyt ...

  4. 登陆ECP后,无法正常现实OU

    当我们在ECP创建邮箱账户或者会议室的时候,发现无法预览所有OU信息 这是因为,默认情况下,Exchange只能识别到500个OU,如果要解决这个问题就需要我们到后端服务器修改配置文件 文件路径:C: ...

  5. vue 本地调试跨域---带cookies(axios)

    cookise跨域第二期之便捷优雅的本地调试(axios) 1.打开config/index.js,在proxyTable中添写如下代码: proxyTable: { '/agent': { //使用 ...

  6. ios 中使用 animation-play-state: paused 属性失效的问题

    前言 因为要做一个播放器的播放图片旋转动画,像这样子 当音乐播放就转动,停止就暂停. 开始于是很自然地想到了使用Css3的 animation 动画属性CSS3 animation(动画) 属性 an ...

  7. 【three.js 第一课】创建场景,显示几何体

    <!DOCTYPE html> <html> <head> <title>demo1</title> </head> <s ...

  8. Dae-Da-Lus小组idea集锦

    Dae-Da-Lus小组成员经过认真的思考,每一位同学都提出了自己对于Team Project的想法,暂时Mark在这里,以备查阅~ 曹士杰: 作为一个计算机专业的学生,我想我们应该是幸运的.计算机科 ...

  9. S7通信协议之你不知道的事儿

    在电气学习的路上,西门子PLC应该是我的启蒙PLC,从早期的S7-300/400 PLC搭建Profibus-DP网络开始接触,到后来的S7-200Smart PLC,再到现在的S7-1200/150 ...

  10. Shell脚本日志关键字监控+告警

    最近小张的爬虫程序越来越多,可当爬虫程序报错,不能及时的发现,从而造成某些重要信息不能及时获取的问题,更有甚者,遭到领导的批评.于是就在想有没有一种方法,当爬取信息报错的时候,可以通过邮件或者短信的方 ...