一个简单的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 ...
随机推荐
- alg-最长公共子串
class Solution { public: const std::vector<std::string> LongestCommonSubstring(const std::stri ...
- Win8.1/Win10在某些程序输入中文变成问号的解决方法
之前我是使用Win8.1,在某些软件上输入中文,却显示问号,换输入法也没用,当时也没用太在意,后来升级到Win10还是一样.同样的软件在其它Win8.1/Win10电脑却可以正常显示中文. 解决方法如 ...
- 设计模式系列之迭代器模式(Iterator Pattern)——遍历聚合对象中的元素
模式概述 模式定义 模式结构图 模式伪代码 模式改进 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修 ...
- 关于gpu版本的tensorflow+anaconda+jupyter的一些安装问题(持续更新)
关于anaconda安装,虽然清华镜像站资源很丰富,但是不知道是网络还是运气的问题,用这个路径安装的时候总是出现文件丢失.具体表现可能是anaconda prompt 找不到,conda命令无效等问题 ...
- 猜数字和飞机大战(Python零基础入门)
前言 最近有很多零基础初学者问我,有没有适合零基础学习案例,毕竟零基础入门的知识点是非常的枯燥乏味的,如果没有实现效果展示出来,感觉学习起来特别的累,今天就给大家介绍两个零基础入门的基础案例:猜数字游 ...
- 移动硬盘临时文件太多怎么办,python黑科技帮你解决
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 星安果 PS:如果想了解更多关于python的应用,可以私信我,或者 ...
- L4文本预处理
文本预处理 timemachine.txt数据下载地址 链接:https://pan.baidu.com/s/1RO2OLyTRQZ90HJUW7V7BCQ 提取码:bjox NLTK数据集下载 链接 ...
- D - Free Candies UVA - 10118
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...
- C# 基础知识系列- 13 常见类库介绍(一)
0. 前言 每篇一个前言,介绍一下这一篇的内容.之前的内容都是针对某些知识点进行的介绍,这篇内容介绍一下实际开发中常用的一些类和命名空间.这一篇是个连续剧,大概有个三四集.嗯,就是这样. 1. Sys ...
- 微信小程序标签常见知识点归纳整理
1. <image src='/images/logo.png' mode='widthFix'></image> mode 属性表示图片随着指定的宽度自动拉伸以显示原图的正确 ...