📄 mini_httpd.c
字号:
state = HDR;
}
break;
/* 后两个case是用来处理消息头的,将得到的消息名和值分别存入request结构的nv数组中 */
case HDR:
/* 此case是用来得到头名字的 */
if (*p == ':')
{
v.ptr = p + 1;
state = HDRVAL;
}
else if (*p == '\n')
{
/* 单独一个回车换行代表所有消息头结束 */
reqptr->totlen = p - buffer + 1;
/* 若请求方法是POST,则将跟在请求头后面的实体体存入request结构的argstr中 */
p++;
if(vcasecmp(&tmpv, &reqptr->method) == 1)
{
reqptr->argstr.ptr = p;
reqptr->argstr.len = buffer+buflen-p;
}
return reqptr;
}
else if (h.len == 0 && *p == ' ')
{
/* 过滤前置空格 */
h.ptr = p + 1;
}
else
{
h.len++;
}
break;
case HDRVAL:
/* 此case是用来得到头名字所对应的值 */
if (*p == '\n')
{
if (v.len && p[-1] == '\r')
{
v.len--;
}
/* Save header */
hdr = &reqptr->header[reqptr->numOfHeader++];
if (reqptr->numOfHeader < MAXHEADER)
{
hdr->name = h;
hdr->value = v;
/* 调用cb回调函数,设置conn的相应的成员变量 */
if (cb)
{
cb(hdr, reqptr);
}
}
h.ptr = p + 1;
v.ptr = NULL;
h.len = v.len = 0;
state = HDR;
}
else if (v.len == 0 && *p == ' ')
{
/* 过滤前置空格 */
v.ptr = p + 1;
}
else
{
v.len++;
}
break;
}
}
return NULL;
}
/*
* parseURL():分析request结构中的url,将其分为uri和argstr(参数)两部分,
* 并解析argstr中的内容,将参数分别存入arg[]数组中.
*/
int
parseURL(struct request *reqp)
{
char *p;
char *q;
char *r;
char *end;
/* 将url以‘?’为界分割开 */
p = strchr(reqp->url.ptr, '?');
/* 无参数并且argstr为空 */
if(p == NULL && reqp->argstr.len == 0)
{
reqp->numOfArg = 0;
reqp->uri = reqp->url;
}
/* 有参数 */
else
{
/* 有‘?’,说明请求方法是GET,参数序列在url中给出 */
if(p != NULL)
{
end = (char*)(reqp->url.ptr+reqp->url.len);
reqp->uri.ptr = reqp->url.ptr;
reqp->uri.len = p - (char *)(reqp->url.ptr);
reqp->argstr.ptr = p+1;
reqp->argstr.len = end-p-1;
p++;
}
/* 没有‘?’,但argstr不为空,说明请求方法是POST,参数序列已经由parseRequest()函数存入argstr中 */
else if(p == NULL)
{
reqp->uri = reqp->url;
p = (char *)reqp->argstr.ptr;
end = p+reqp->argstr.len;
}
/* 解析参数序列,将参数分别存入argVal和argName数组中 */
for(q = strchr(p, '='); q != NULL && p<end && q<end; p=r+1, q = strchr(r, '='))
{
if(reqp->numOfArg < MAXARG)
{
reqp->arg[reqp->numOfArg].name.ptr = p;
reqp->arg[reqp->numOfArg].name.len = q-p;
q++;
reqp->arg[reqp->numOfArg].value.ptr = q;
r = strchr(q, '&');
if(r == NULL)
{
reqp->arg[reqp->numOfArg++].value.len = end-q;
return 0;
}
else
{
reqp->arg[reqp->numOfArg++].value.len = r-q;
}
}
else
{
showError("parseURL : numOfArg out of MAXARG");
return -1;
}
}
}
}
/*
* cgi处理
*/
int
dealCgi(struct request *reqp, int fdclient)
{
char *p, /* 临时存储环境变量的内容 */
qs[BUFSIZ], /* url中的?后面的参数列表 */
gi[BUFSIZ], /* cgi版本号 */
sn[BUFSIZ], /* 被请求的脚本文件名 */
path[BUFSIZ], /* 环境变量PATH的内容 */
ct[BUFSIZ], /* 存储CONTENT_TYPE */
rm[BUFSIZ], /* 请求方法(GET、HEAD、POST等) */
pl[BUFSIZ], /* perl库 */
user[BUFSIZ], /* 存储REMOTE_USER */
cookie[BUFSIZ], /* 存储HTTP_COOKIE */
cl[BUFSIZ], /* 存储CONTENT_LENGTH */
*env[20]; /* 用来存储环境变量,以便向execve()函数传送参数 */
char *argv[MAXARG]; /* 用来存储url中的cgi参数,以便向execve()函数传送参数 */
int i; /* 循环变量 */
/* 设置环境变量 */
env[0] = gi;
(void) snprintf(gi, sizeof(gi), "GATEWAY_INTERFACE=CGI/1.1");
env[1] = sn;
(void) snprintf(sn, sizeof(sn), "SCRIPT_NAME=%.*s", reqp->uri.len, (char *)reqp->uri.ptr);
env[2] = path;
/* getenv():用来取出以参数为名字的环境变量内容 */
if ((p = getenv("PATH")) == NULL)
{
p = "/bin:/sbin:/usr/bin:/usr/sbin";
}
(void) snprintf(path, sizeof(path), "PATH=%s", p);
env[3] = qs;
(void) snprintf(qs, sizeof(qs), "QUERY_STRING=%.*s", reqp->argstr.len, (char *)reqp->argstr.ptr);
env[4] = ct;
(void) snprintf(ct, sizeof(ct), "CONTENT_TYPE=%s", "text/html");
env[5] = rm;
(void) snprintf(rm, sizeof(rm), "REQUEST_METHOD=%.*s", reqp->method.len, (char *)reqp->method.ptr);
env[6] = pl;
if ((p = getenv("PERLLIB")) == NULL)
{
p = "/perl";
}
(void) snprintf(pl, sizeof(pl), "PERLLIB=%s", p);
env[7] = user;
(void) snprintf(user, sizeof(user), "REMOTE_USER=%s", "Mr. Bin");
env[8] = cookie;
(void) snprintf(cookie, sizeof(cookie), "HTTP_COOKIE=%.*s", reqp->cookie.len, (char *)reqp->cookie.ptr);
env[9] = cl;
(void) snprintf(cl, sizeof(cl), "CONTENT_LENGTH=%d", vtoint(&reqp->clength));
env[10] = ct;
(void) snprintf(ct, sizeof(ct), "CONTENT_TYPE=%.*s", reqp->ctype.len, (char *)reqp->ctype.ptr);
env[11] = NULL;
/* 设置参数 */
argv[0] = (char *)malloc(sizeof(char)*(reqp->uri.len+1));
strcpy(argv[0],docroot);
sprintf(argv[0]+strlen(docroot), "%.*s", reqp->uri.len, reqp->uri.ptr);
for(i = 1; i <= reqp->numOfArg; i++)
{
argv[i] = (char *)malloc(sizeof(char)*(reqp->arg[i-1].value.len+1));
sprintf(argv[i], "%.*s", reqp->arg[i-1].value.len, reqp->arg[i-1].value.ptr);
}
/* 发送响应头 */
sendheaders(reqp, fdclient);
/*
* execve(const char *filename, char *const argv[],char *const envp[]):
* 用来执行参数filename字符串所代表的文件路径,第二个参数系利用数组指
* 针来传递给执行文件,最后一个参数则为传递给执行文件的新环境变量数组.
* 如果执行成功则函数不会返回,执行失败则直接返回-1.
*/
if(execve(argv[0], argv, env) == -1)
{
showError("dealCgi : execve");
return -1;
}
}
/*
* redirect():将子进程的标准输入重定向为pipe1的读出端,标准输出端重定向
* 为pipe2的输入端,父进程不需要pipe1的读出端和pipe2的写入端.
*/
int
redirect(int *pipe1, int *pipe2, int flag)
{
/* 子进程的调用 */
if(flag == 0)
{
/* 子进程不需要pipe1的写入端和pipe2的读出端 */
close(pipe1[1]);
close(pipe2[0]);
/* 将子进程的标准输入重定向为pipe1的读出端,标准输出端重定向为pipe2的输入端 */
if(dup2(pipe1[0], 0) == -1 || dup2(pipe2[1], 1) == -1)
{
showError("redirect : son : dup2");
return -1;
}
close(pipe1[0]);
close(pipe2[1]);
}
/* 父进程的调用 */
else
{
/* 父进程不需要pipe1的读出端和pipe2的写入端 */
close(pipe1[0]);
close(pipe2[1]);
/* 将父进程的标准输入重定向为pipe2的读出端 */
if(dup2(pipe2[0], 0) == -1)
{
showError("redirect : father : dup2");
printf("%s\n",strerror(errno)); return -1;
}
close(pipe2[0]);
}
return 0;
}
/*
* reply():对cgi程序发来的结果进行处理(待扩展),之后发送给客户端
*/
intreply(int fdclient)
{
char replystr[BUFSIZ];
int i = 0;
while((replystr[i++] = fgetc(stdin)) != EOF)
{
if(i >= BUFSIZE)
{
showError("reply : replystr out of BUFSIZE");
return -1;
}
}
i--;
replystr[i] = '0';
if(send(fdclient, replystr, i, 0) == -1)
{
showError("reply : send");
return -1;
}
return 0;
}
/*
* htoi():将url编码汉字的%后的十六位数转换成int型的
*/
int
htoi(char *data)
{
char *digits="0123456789ABCDEF";
if(islower(data[0]))
{
data[0] = toupper(data[0]);
}
if(islower(data[1]))
{
data[1] = toupper(data[1]);
}
return 16*(strchr(digits,data[0])-strchr(digits,'0')) + (strchr(digits,data[1])-strchr(digits,'0'));
}
/*
* filter():过滤url编码的汉字,解码
*/
int
filter(char *str)
{
int ischinese = 0;
int i;
int j;
int n = strlen(str);
char *tmp;
char *p;
int result;
tmp = (char*)malloc(n+1);
strcpy(tmp,str);
if(strchr(tmp,'%')!=NULL)
{
ischinese = 1;
}
for(i = 0,j = 0; i < n; i++)
{
if(*(str+i) != '%')
{
*(tmp+j) = *(str+i);
j++;
}
}
*(tmp+j)=0;
if(ischinese)
{
printf("缂栫爜锛?s\n",tmp);
p = strchr(tmp,'=');
p++;
strncpy(str,tmp,p-tmp);
printf("*****%d******\n",strlen(p));
for(i = 0,j = p-tmp; i < strlen(p); i+=2)
{
result = htoi(p+i);
printf("杞
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -