📄 helpfunc.c
字号:
/*****************************************************/
/**创建者:杨希 日期:2005/04/30 **/
/**文件名:globals.h 版本:1.0.4 **/
/**描 述:WEB服务器的帮助头文件的具体实现 **/
/**其 它:相比1.0.2主要改正了getparaments的一些BUG **/
/*****************************************************/
#include"globals.h"
#include"helpfunc.h"
static char* envp[5]; /* 环境变量 */
static char pathname[100]; /* CGI 程序路径名 */
static char cginame[20]; /* CGI 程序名 */
static char para[1024]; /* CGI 参数 */
static int GET_FLAG = 1; /* 请求类型标志,默认为POST */
/* 该函数的功能是从buf中读取CGI参数,并将之存入相应的变量 */
int getparaments(char* buf)
{
char c, *p, *p1;
if(GET_FLAG){
p = strchr(buf, '?');
/* 略过'?' */
p++;
p1 = strstr(p, "HTTP");
c = *p1;
*p1 = '\0';
strcpy(para, p);
*p1 = c;
}else{
p = strrchr(buf, '\n');
/* 略过'\n' */
p++;
strcpy(para, p);
}
return 0;
}
/* 该函数的功能是从buf中读取CGI程序名,并将之存入相应的变量 */
int getcginame(char* path, char* name)
{
char *p;
p = strstr(path, "cgi-bin");
p += sizeof("cgi-bin");
strcpy(name, p);
return 0;
}
/* 该函数的功能是从buf中读取CGI程序路径名,并将之存入相应的变量 */
int getpathname(char* buf, char* req, char* path)
{
char* p;
if(!strncmp(req, "GET", 3))
strcpy(path, buf + 4);
else if(!strcmp(req, "POST"))
strcpy(path, buf + 5);
else{
fprintf(stderr, "no GET nor POST\n");
exit(1);
}
if(GET_FLAG)
p = strstr(path, "?");
else
p = strstr(path, " HTTP");
if(!p){
fprintf(stderr, "the request grammer is false\n");
exit(1);
}
*p = '\0';
return 0;
}
/* 该函数的功能是从buf中读取内容类型并将之写入环境变量中 */
int getcontenttype(char* buf)
{
char* p;
char* con_type;
p = strstr(buf, "Content-Type:");
p += sizeof("Content-Type:");
con_type = (char *)malloc(sizeof(char)*50);
if(!con_type){
fprintf(stderr, "malloc error : getcontenttype\n");
exit(1);
}
strcpy(con_type, p);
*(con_type + 33) = '\0';
strcpy(envp[0], "CONTENT_TYPE=");
strcat(envp[0], con_type);
return 0;
}
/* 该函数的功能是从buf中读取CGI参数的长度并将之写入环境变量中 */
int getcontentlen(char* buf)
{
char* p;
char* con_len;
if(GET_FLAG){
/* 优先处理GET方法 */
sprintf(envp[2], "CONTENT_LENGTH=%d", strlen(para));
return;
}
p = strstr(buf, "Content-Length:");
p += sizeof("Content-Length:");
con_len = (char*)malloc(sizeof(char)*3);
if(!con_len){
fprintf(stderr, "malloc error : getcontentlen\n");
exit(1);
}
strcpy(con_len, p);
*(con_len + 2) = '\0';
strcpy(envp[2], "CONTENT_LENGTH=");
strcat(envp[2], con_len);
return 0;
}
/* 该函数的功能是从buf中分离出绝对路径名,然后将所需要的
文件读入ret_buf中, 返回0没有错, 否则返回-1*/
int read_file(char* buf, char* ret_buf)
{
int i, j = 0;
char *p1,*p2;
FILE* f;
/* p1指向文件名开头 */
p1 = strstr(buf, "/");
p1++;
/* 使p2 指向路径名尾 */
p2 = strstr(buf, " HTTP");
/* 此时p1中存的即为浏览器所请求的文件路径名 */
if(p2!= NULL) *p2 = '\0';
printf("$$$file:%s\n", p1);
if(!strcmp(p1, ""))
f = fopen(INDEX_PAGE, "r");
else
f = fopen(p1, "r");
if(!f){
fprintf(stderr, "Cannot open file %s !\n", p1);
fclose(f);
strcpy(ret_buf, ERROR_STR);
return -1;
}
#if 0
/* 加入对图片.GIF的支持 */
if(strstr(p1, ".gif") || strstr(p1, ".GIF")){
sprintf(ret_buf, "Content-type: image/gif\nServer: miniWebServer by dayangxi 1.0.4\nExpires: 0\n\n");
j = sizeof("Content-type: image/gif\n")
+ sizeof("Server: miniWebServer by dayangxi 1.0.4\n")
+ sizeof("Expires: 0\n") + 1;
#endif
/* 读文件数据到ret_bu */
i = fread(ret_buf+j, 1, RET_BUF_SIZE, f);
ret_buf[i]='\0';
if(i == 0){
fclose(f);
strcpy(ret_buf, ERROR_STR);
return -1;
}
printf("%d bytes read from file %s\n", i, p1);
fclose(f);
return 0;
}
/* 具体处理客户的请求 */
void handleRequest(int sock, struct sockaddr_in clientAddr)
{
int i;
char* recvBuffer;
int totalReceived;
int size;
int totalSent;
int bytesSent;
pid_t pid;
int fd1[2], fd2[2];
char request[5];
char ret_buf[RET_BUF_SIZE+1]; /* 当所请求的HTML文件不存在时返回该信息给浏览器 */
/* 服务器端接收缓冲区 */
recvBuffer = (char *)malloc(RECV_BUF_SIZE+1);
if(!recvBuffer){
fprintf(stderr, "malloc recvBuffer error!\n");
exit(1);
}
/* 为环境变量的分配空间并设置初始值 */
envp[0] = (char *)malloc(sizeof(char) * 50);
envp[1] = (char *)malloc(sizeof(char) * 30);
envp[2] = (char *)malloc(sizeof(char) * 30);
envp[3] = (char *)malloc(sizeof(char) * 1024);
if(!envp[0] || !envp[1] || !envp[2] || !envp[3]){
fprintf(stderr, "malloc envp error!\n");
exit(1);
}
strcpy(envp[0], "CONTENT_TYPE=application/x-www-form-urlencoded");
strcpy(envp[1], "REQUEST_METHOD=GET");
strcpy(envp[2], "CONTENT_LENGTH=");
strcpy(envp[3], "QUERY_STRING=");
envp[4] = NULL;
i = recv(sock, recvBuffer, RECV_BUF_SIZE, 0);
if(i < 0){
fprintf(stderr, "recv data error!\n");
exit(0);
}
recvBuffer[i]='\0';
printf("\n%s\n", recvBuffer);
/* 本服务器所有的cgi程序都放在一个cgi-bin文件夹中,因此通过判断接收缓
冲区中的字符时不是包含cgi-bin来判断是否为cgi请求 */
if(!strstr(recvBuffer, "cgi-bin")){
printf("$$this is not a CGI REQUEST!!\n");
/* 如果不是cgi请求,那么直接调用函数read_file(),返回所请求的文件 */
read_file(recvBuffer, ret_buf);
size = strlen(ret_buf);
totalSent = 0;
do{
bytesSent = send(sock, ret_buf+totalSent, strlen(ret_buf+totalSent), 0);
if(bytesSent < 0) break;
totalSent += bytesSent;
}while(totalSent < size);
close(sock);
}else{
char tempPara[1024];
request[4] = '\0';
strncpy(request,recvBuffer,4);
if(!strcmp(request, "POST")){
strcpy(envp[1], "REQUEST_METHOD=POST");
GET_FLAG = 0;
}
getparaments(recvBuffer);
getcontentlen(recvBuffer);
#if 0
getcontenttype(recvBuffer);
#endif
sprintf(envp[3], "QUERY_STRING=%s", para);
strcpy(tempPara, para);
getpathname(recvBuffer, request, pathname);
strcpy(para, tempPara);
getcginame(pathname, cginame);
/* 创建父子进程通信用的管道 */
if(pipe(fd1) < 0 || pipe(fd2) < 0){
fprintf(stderr, "creat pipe error!\n");
exit(1);
}
if((pid = fork()) < 0){
fprintf(stderr, "fork error!\n");
exit(1);
}else if(pid > 0){
/* 父进程中 */
close(fd1[0]); /* 关闭管道的读端以只写 */
close(fd2[1]); /* 关闭管道的写端以只读 */
if(!strcmp(request, "POST")){
/* 如果是POST方法,那么通过写管道fd1[1],
将参数由标准输入传给CGI程序 */
printf("CGI POST!\n");
write(fd1[1], para, strlen(para));
}else{
printf("CGI GET!\n");
}
/* 等待子进程结束 */
printf("$waiting for cgi's respond..........\n");
waitpid(pid, NULL, 0);
/* 从管道fd2[0]读取cgi 程序的返回结果 */
i = read(fd2[0], ret_buf, RET_BUF_SIZE);
if(i == 0){
fprintf(stderr, " read 0!\n");
exit(1);
}
ret_buf[i] = '\0';
/* 将取得的返回结果发送给浏览器 */
size = strlen(ret_buf);
totalSent = 0;
do{
bytesSent = send(sock, ret_buf+totalSent, strlen(ret_buf+totalSent), 0);
if(bytesSent == -1) break;
totalSent += bytesSent;
}while(totalSent < size);
close(sock);
}else{
char buf[100];
/* 子进程中执行CGI程序 */
close(fd1[1]); /* 关闭管道的写端以只读 */
close(fd2[0]); /* 关闭管道的读端以只写 */
if(fd1[0] != STDIN_FILENO){
/* 重定向子进程的标准输入到fd1[0] */
if(dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO){
fprintf(stderr, "dup2 error\n");
exit(1);
}
close(fd1[0]);
}
if(fd2[1] != STDOUT_FILENO){
/* 重定向子进程的标准输出到fd2[1] */
if(dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO){
fprintf(stderr, "dup2 error\n");
exit(1);
}
close(fd2[1]);
}
/* 取得当前的工作目录 */
getcwd(buf, sizeof(buf));
strcat(buf, pathname);
/* 装入cgi程序,传递环境变量,并运行 */
execle(buf, cginame, NULL, envp);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -