⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 helpfunc.c

📁 LINUX平台上小型WEB服务器的设计与实现,支持CGI接口.
💻 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 + -