-
.....
-
#define MAXLINE 150
-
.....
-
extern char **environ; /* defined by libc */
-
-
void handle_req(int fd);
-
int parse_uri(char *uri, char *filename, char *cgiargs);
-
void serve_static(int fd, char *filename, int filesize);
-
void get_filetype(char *filename, char *filetype);
-
void exec_cgi(int fd, char *method, int content_length, char *filename, char *cgiargs);
-
void error_msg(int fd, char *cause, char *errnum,
-
char *shortmsg, char *longmsg);
-
-
############## - ### 处理HTTP请求/响应
-
void handle_req(int fd)
-
{
-
char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
-
char filename[MAXLINE], cgiargs[MAXLINE];
-
###################
- ### 转换文件描述符到文件指针
- ### FILE *fdopen(int fd,const char *mode)
-
FILE *f = fdopen(fd, "r");
-
if (!f) {
-
perror("Unable to open input fd");
-
close(fd);
-
return;
-
}
#####################
### 设置文件缓冲区
### void setbuf(FILE *stream,char *buf)
### 参数 stream 为流文件指针,buf为政府串数组的指针
### 该函数没有返回值
### 函数中参数如果为NULL,0,则默认该文件的读为无缓冲操作,此时每一次操作都是对该文件的操作。
-
setbuf(f, 0);
#####################
### 获取 HTTP命令行
### char *fgets(char *str,int num,FILE *stream) 从流文件中读出一行数据
### 通过fgets函数读取第一行,或者如果第一行很长的话,只读取MAXLINE-1大小的字符串
-
if (!fgets(buf, MAXLINE, f)) {
-
perror("Error reading buffer");
-
fclose(f);
-
return;
-
}
#####################
### int sscanf(const char *str,const char *foramt[...]) 格式化字符串取值
### 按照 format 格式解析
###将buf按照 %s,%s,%s,解析到 metnho ,uri,version,三者之间用空格分隔
-
sscanf(buf, "%s %s %s", method, uri, version);
-
#ifdef DEBUG
-
printf("method: %s, uri: %s, version: %s \n", method, uri, version);
-
#endif
#####################
### 通过strcasecmp 来检查 method 是否为 GET 或者 POST
### 这是 miniwebserver 支持的两种方法,如果是其他的方法,我们通过 error_msg 函数给客户端一个简单的错误信息
### 告知 miniwebserver 还不支持这个方法
-
if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) {
-
error_msg(fd, method, "501", "Not Implemented",
-
"MiniWebServer does not support this method yet!");
-
return;
-
}
######################
### 继续读取问阿金指针f中的内容,按照HTTP协议规范,接下来是 0 行或者多行的请求报头
### 我们的miniwebserver 仅仅关心 “content-length:” 字符串之后所紧跟的数值,这是在使用 POST方法时的一个重要数值,后文酱油详细介绍
-
char buf_header[MAXLINE];
-
int content_length = 0;
-
while (fgets(buf_header, 150, f) && (strlen(buf_header) > 2)) {
-
if (strncasecmp(buf_header, "Content-length:", 15) == 0) {
-
content_length = atoi(buf_header + 15);
-
}
-
}
-
#ifdef DEBUG
-
printf("content length: %d \n", content_length);
-
#endif
-
- #############################
- ### 接受完HTTP请求之后,我们便来检查所要求的具体内容
- ### parse_uri 得到HTTP请求的具体uri,文件名filename,以及CGI参数cgiargs
- ### if中,检查filename是否存在,没有的调用 error_msg函数通知客户端浏览器
-
-
int is_cgi = parse_uri(uri, filename, cgiargs);
-
struct stat sbuf;
-
if (stat(filename, &sbuf) < 0) {
-
error_msg(fd, filename, "404", "Not found",
-
"Couldn't find this file");
-
return;
-
}
########################
### 分别对要求的静态网页和CGI程序进行处理,检查权限后分别转到相应的函数
-
if (is_cgi) { /* Serve CGI request */
-
if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) {
-
error_msg(fd, filename, "403", "Forbidden",
-
"You have no permission to run the CGI program");
-
return;
-
}
-
exec_cgi(fd, method, content_length, filename, cgiargs); #####
-
}
-
else { /* Serve static content */
-
if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode)) {
-
error_msg(fd, filename, "403", "Forbidden",
-
"You have no permission to read the file");
-
return;
-
}
-
serve_static(fd, filename, sbuf.st_size); #####
-
}
-
}
-