重头
void accept_request(int client)
{
char buf[1024];
int numchars;
char method[255];
char url[255];
char path[512];
size_t i, j;
struct stat st;
/*
int stat(
const char *filename //文件或者文件夹的路径
, struct stat *buf //获取的信息保存在内存中
); 也就是通过提供文件描述符获取文件属性
stat结构体的元素
struct stat {
mode_t st_mode; //文件对应的模式,文件,目录等
ino_t st_ino; //inode节点号
dev_t st_dev; //设备号码
dev_t st_rdev; //特殊设备号码
nlink_t st_nlink; //文件的连接数
uid_t st_uid; //文件所有者
gid_t st_gid; //文件所有者对应的组
off_t st_size; //普通文件,对应的文件字节数
time_t st_atime; //文件最后被访问的时间
time_t st_mtime; //文件内容最后被修改的时间
time_t st_ctime; //文件状态改变时间
blksize_t st_blksize; //文件内容对应的块大小
blkcnt_t st_blocks; //伟建内容对应的块数量
};
*/
int cgi = 0; /* becomes true if server decides this is a CGI
* program */
char *query_string = NULL;
numchars = get_line(client, buf, sizeof(buf));
//读取一行http请求到buf中
i = 0;
j = 0;
//复制buf到method中,但是不能超过method大小255个
while (!ISspace(buf[j]) && (i < sizeof(method) - 1))
{
method[i] = buf[j];
i++;
j++;
}
method[i] = '\0';//给method增加一个结尾
//strcasecmp函数忽略大小写的比较字符串函数。
//若参数s1和s2字符串相等则返回0。s1大于s2则返回大于0 的值,s1 小于s2 则返回小于0的值
//此函数只在Linux中提供,相当于windows平台的 stricmp。
//如果既不是get也不是post,服务器无法处理
if (strcasecmp(method, "GET") && strcasecmp(method, "POST"))
{
unimplemented(client);
return;
}
//如果是post,激活cgi
if (strcasecmp(method, "POST") == 0)
cgi = 1;
//不管get还是post,都要进行读取url地址
i = 0;//处理空字符
while (ISspace(buf[j]) && (j < sizeof(buf)))
j++;
while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf)))
{
url[i] = buf[j];
i++;
j++;
}
url[i] = '\0';
//如果是get可能需要把url划分为两段
//get请求可能带有?表示查询参数
if (strcasecmp(method, "GET") == 0)
{
query_string = url;
while ((*query_string != '?') && (*query_string != '\0'))
query_string++;
if (*query_string == '?')
{//如果有?说明需要激活cgi
cgi = 1;//需要执行cgi,解析参数,设置标志位为1
*query_string = '\0';//这里变成url结尾
query_string++;//query_string作为剩下的起点
}
}
sprintf(path, "htdocs%s", url);//把url添加到htdocs后赋给path
if (path[strlen(path) - 1] == '/')//如果是以/结尾,需要把index.html添加到后面
//以/结尾,说明path只是一个目录,此时需要设置为首页index.html
strcat(path, "index.html");//strcat连接两个字符串
if (stat(path, &st) == -1)//执行成功则返回0,失败返回-1
{//如果不存在,那么读取剩下的请求行内容丢弃
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
numchars = get_line(client, buf, sizeof(buf));
not_found(client);//调用错误代码404
}
else
{
/*掩码
#define _S_IFMT 0xF000
#define _S_IFDIR 0x4000
#define _S_IFCHR 0x2000
#define _S_IFIFO 0x1000
#define _S_IFREG 0x8000
#define _S_IREAD 0x0100
#define _S_IWRITE 0x0080
#define _S_IEXEC 0x0040
*/
if ((st.st_mode & S_IFMT) == S_IFDIR)//mode_t st_mode;表示文件对应的模式,文件,目录等,做与运算能得到结果
strcat(path, "/index.html");//如果是目录,显示index.html这里和前面是否重复?
if ((st.st_mode & S_IXUSR) ||
(st.st_mode & S_IXGRP) ||
(st.st_mode & S_IXOTH))//IXUSR X可执行,R读,W写,USR用户,GRP用户组,OTH其他用户
cgi = 1;
if (!cgi)//如果不是cgi,直接返回
serve_file(client, path);
else
execute_cgi(client, path, method, query_string);//是的话,执行cgi
}
close(client);
}