除了日记03所介绍的bufstr结构体,现在准备介绍的buffile结构体也是使用mempool内存池来存放服务器处理信息的。
buffile结构体主要是用于存放响应信息的主体部分文件内容(html、text、jpg等类型文件),并且记录文件的相关属性。
(1)buffile结构体的具体实现:
typedef struct {
//文件内容
memblock *fcontent;
//文件名字
bufstr *fname;
//文件类型(扩展名)
bufstr *ftype;
//文件属性信息
struct stat *fstat;
//是否url被改写,访问资源错误,返回error.html
int is_rewrite;
//文件大小(字节)
int fused;
//内存块数目
int fmbnum;
//总共内存空间大小(字节)
int size;
} buffile;
(2)下面是buffile结构体的初始化和释放操作:
buffile *buffile_init(mempool *mpool)
{
int mbsize;
buffile *temp;
mbsize = MBSIZE;
temp = calloc(1,sizeof(buffile));
temp->fcontent = mempool_take_mblocks(mpool,1);
temp->fstat = (struct stat *)calloc(1,sizeof(struct stat));
temp->fused = 0;
temp->fmbnum = 1;
temp->size = mbsize * temp->fmbnum;
return temp;
}
void buffile_free(mempool *mpool,buffile *bf)
{
mempool_put_mblocks(mpool,bf->fcontent);
if(bf->fname)
{
bufstr_free(mpool,bf->fname);
}
if(bf->ftype)
{
bufstr_free(mpool,bf->ftype);
}
free(bf->fstat);
free(bf);
}
当服务器解析http报文的起始行中url后,通过该url判断本地是否有该文件,若存在则构建该文件的buffile结构体,否则构建出错页面的buffile结构体。
(3)构建指定文件的buffile结构体操作具体实现:
/*
当指定的是文件时,在/www下存在,则返回相应文件,否则返回error.html文件
当指定的是目录时,若是/www下返回index.html文件,否则返回error.html文件
*/
buffile *buffile_create(mempool *mpool,char *docroot,bufstr *furl)
{
char url[100];
char url1[100];
char *temp =NULL;
char *buff =NULL;
int readn =0,mbsize;
buffile *ftemp =NULL;
FILE *fp=NULL;
mbsize = MBSIZE;
buff =(char*)calloc(mbsize,sizeof(char));
ftemp = buffile_init(mpool);
if(furl ==NULL)
{
free(buff);
buffile_free(mpool,ftemp);
return NULL;
}
strcpy(url,docroot);
temp = read_string_bufstr(furl);
strcat(url,temp);
if(lstat(url,ftemp->fstat) != -1)
{
if(S_ISREG(ftemp->fstat->st_mode))
{
fp = fopen(url,"r");
if(fp == NULL)
{
printf("bufstr_init:open file error!\n");
free(temp);
free(buff);
buffile_free(mpool,ftemp);
return NULL;
}
while((readn = fread(buff,1,mbsize,fp)) > 0)
{
buffile_append_string_len(mpool,ftemp,buff,readn);
}
ftemp->fname = bufstr_copy_filename(mpool,url);
ftemp->ftype = bufstr_copy_etrname(mpool,url);
ftemp->is_rewrite =0;
fclose(fp);
free(buff);
free(temp);
return ftemp;
}
//若是/www,则返回该目录下的index.html
if(S_ISDIR(ftemp->fstat->st_mode))
{
if(bufstr_compare_string(furl,"/"))
{
strcpy(url1,docroot);
strcat(url1,"/index.html");
printf("url:%s\n",url1);
fp = fopen(url1,"r");
if(fp == NULL)
{
printf("buffile_init:open file error!\n");
free(temp);
free(buff);
buffile_free(mpool,ftemp);
return NULL;
}
while((readn = fread(buff,1,mbsize,fp)) > 0)
{
buffile_append_string_len(mpool,ftemp,buff,readn);
}
ftemp->fname = bufstr_copy_filename(mpool,url1);
ftemp->ftype = bufstr_copy_etrname(mpool,url1);
ftemp->is_rewrite =0;
fclose(fp);
free(buff);
free(temp);
return ftemp;
}
//不是指定/www目录,则返回error.html文件
else
{
strcpy(url1,docroot);
strcat(url1,"/error_404.html");
fp = fopen(url1,"r");
if(fp == NULL)
{
printf("buffile_init:open file error!\n");
free(temp);
free(buff);
buffile_free(mpool,ftemp);
return NULL;
}
while((readn = fread(buff,1,mbsize,fp)) > 0)
{
buffile_append_string_len(mpool,ftemp,buff,readn);
}
ftemp->fname = bufstr_copy_filename(mpool,url1);
ftemp->ftype = bufstr_copy_etrname(mpool,url1);
ftemp->is_rewrite =1;
fclose(fp);
free(buff);
free(temp);
return ftemp;
}
}
}
//不存在资源,则返回error.html文件
strcpy(url1,docroot);
strcat(url1,"/error_404.html");
printf("url:%s\n",url1);
fp = fopen(url1,"r");
if(fp == NULL)
{
printf("buffile_init:open file error!\n");
free(temp);
free(buff);
buffile_free(mpool,ftemp);
return NULL;
}
while((readn = fread(buff,1,mbsize,fp)) > 0)
{
buffile_append_string_len(mpool,ftemp,buff,readn);
}
ftemp->fname = bufstr_copy_filename(mpool,url1);
ftemp->ftype = bufstr_copy_etrname(mpool,url1);
ftemp->is_rewrite =1;
fclose(fp);
free(buff);
free(temp);
return ftemp;
}
(4)而服务器最终是以bufstr结构体的形式来发送响应报文的,而当我们把起始行和首部构建好后,我们需要将buffile结构体的内容放入存放响应报文的bufstr的内容后面。
该操作的具体实现:
//将buffile结构体des的数据添加到bufstr结构体src的尾后,去掉src最后的'\0'
int bufstr_append_buffile(mempool *mpool,bufstr *des,buffile *src)
{
int slen,total,mbsize,smbnum,scnum,dmbnum,dcnum,n,count;
memblock * temp =NULL;
if(des==NULL||src==NULL||des->used == 0)
{
return 0;
}
mbsize = MBSIZE;
slen = src->fused;
temp = src->fcontent;
smbnum = des->used / mbsize;
scnum = des->used % mbsize;
count = mbsize-scnum+1;
for(;;)
{
total = des->size - des->used + 1;
if(total>=slen)
{
if(scnum > 0)
{
//'\0':&des-ptr[b->used / mbsize][(b->used % mbsize)-1]
if(count >= slen)
{
memcpy((&des->ptr[smbnum][scnum-1]),temp->memptr,slen);
}
else
{
memcpy((&des->ptr[smbnum][scnum-1]),temp->memptr,count);
dmbnum = (slen - count) / mbsize;
dcnum = (slen - count) % mbsize;
n=0;
while(n<dmbnum)
{
memcpy(des->ptr[smbnum+1+n],&temp->memptr[count],mbsize - count);
temp = temp->next;
memcpy(&des->ptr[smbnum+1+n][mbsize - count],temp->memptr,count);
n++;
}
if(dcnum>0)
{
if(scnum == 1 && count == mbsize)
{
temp = temp->next;
memcpy(des->ptr[smbnum+1+n],temp->memptr,dcnum);
}
else
{
memcpy(des->ptr[smbnum+1+n],&temp->memptr[count],dcnum);
}
}
}
}
else
{
//'\0':&des-ptr[(b->used / mbsize)-1][mbsize-1]
memcpy((&des->ptr[smbnum-1][mbsize- 1]),temp->memptr,1);
dmbnum = (slen - 1) / mbsize;
dcnum = (slen - 1) % mbsize;
n=0;
while(n<dmbnum)
{
memcpy(des->ptr[smbnum+n],&temp->memptr[1],mbsize-1);
temp = temp->next;
memcpy(&des->ptr[smbnum+n][mbsize-1],temp->memptr,1);
n++;
// exit(0);
}
if(dcnum>0)
{
memcpy(des->ptr[smbnum+n],&temp->memptr[1],dcnum);
}
}
des->used+=slen;
return 1;
}
else
{
bufstr_prepare_size(mpool,des,slen);
}
}
}