一个简单的wed服务器SHTTPD(4)————SHTTPD支持CGI的实现
//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的实现的更多相关文章
- 一个简单的wed服务器SHTTPD(3)————SHTTPD多客户端支持的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(9)————main函数文件,Makefile,头文件
主函数: #include "lcw_shttpd.h" //初始化时服务器的默认配置 extern struct conf_opts conf_para= { "/us ...
- 一个简单的wed服务器SHTTPD(1)————命令行和文件配置解析
开始学习<LInux网络编程>中的综合案例,虽然代码书上有,还是自己打一下加深理解和印象. 主要有两个函数,完成命令行的解析,另一个实现配置文件的解析,注释还是比较丰富的哦. //star ...
- 一个简单的wed服务器SHTTPD(6)———— SHTTPD错误处理的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(5)————服务器SHTTPD请求方法解析
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(7)———— SHTTPD内容类型的实现
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(8)———— URI分析
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 一个简单的wed服务器SHTTPD(2)———— 客户端请求分析
//start from the very beginning,and to create greatness //@author: Chuangwei Lin //@E-mail:979951191 ...
- 自己动手模拟开发一个简单的Web服务器
开篇:每当我们将开发好的ASP.NET网站部署到IIS服务器中,在浏览器正常浏览页面时,可曾想过Web服务器是怎么工作的,其原理是什么?“纸上得来终觉浅,绝知此事要躬行”,于是我们自己模拟一个简单的W ...
随机推荐
- Java第二十二天,异常
异常 程序在执行过程中,出现的非正常的情况,最终会导致JVM非正常停止. 注意: 在Java等面向对象编程语言当中,异常本身是一个类,产生异常的本质就是抛出一个异常对象.Java对异常采取中断处理方式 ...
- 8.4 StringBuilder的介绍及用法(String 和StringBuilder区别)
* StringBuilder:是一个可变的字符串.字符串缓冲区类.** String和StringBuilder的区别:* String的内容是固定的.(方法区的内容)* StringBuilder ...
- gcc/g++堆栈保护技术
最近学习内存分布,通过gdb调试发现一些问题,栈空间变量地址应该是从高往低分布的,但是调试发现地址虽然是从高往低分布,但是变量地址的顺序是乱的,请教同事他说可能是gcc/g++默认启用了堆栈保护, ...
- Python操作rabbitmq系列(四):根据类型订阅消息
在上一章中,所有的接收端获取的所有的消息.这一章,我们将讨论,一些消息,仍然发送给所有接收端.其中,某个接收端,只对其中某些消息感兴趣,它只想接收这一部分消息.如下图:C1,只对error感兴趣,C2 ...
- JS入门系列(1)-原型-函数原型
实例1: 首先定义一个Persion类或者说是函数 var p1 = Persion();:表示,作为普通函数调用 var p2 = new Persion();:表示,作为构造器调用 创建函数之后, ...
- 对象中属性 加锁 用:volatile 关键词修饰 而 不用 synchronized 加锁
一个对象中有一个状态 属性,现在业务需求 存在多线程来修改 和 拿去 这个状态 的值,这种情况如果加锁怎么加? 一种是 在 set 和get 这个状态的 方法那加 synchronized . 还有一 ...
- CNVD
漏洞编号 漏洞名称 漏洞积分 奖励时间 CNVD-2020-15798 中国平乐县委员会组织部网站管理系统登录存在弱口令漏洞 1.0 2020-03-09 09:58:46.0 CNVD-2020-1 ...
- ******Prometheus(二)***********
Prometheus的数据与安全模型: (1)Metric (度量)名字就是描述采集数据的名称——例如,website_visits_total 作为网站访问总数.名称可以包含ASCII字母.数字.下 ...
- stand up meeting 12/11/2015
part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云 完成单词释义热度排序:允许用户自主添加释义:完成了button位置的修正(finally)和弹窗的美化: 6 tr ...
- stand up meeting 11/30/2015
part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云 完善了UI的各项功能,弹窗的显示格式等方面的规范:解决logic部分调用该dll的问题:解决鼠标事件的捕捉中~ ...