request结构体在antweb服务器中的作用是存放请求报文内容的,而其请求报文主要包含起始行的http版本号、url和请求方法,首部的host、connection、accept等等,还有主体内容(若请求方法是post)。
antweb服务器在分析请求报文进行响应处理时,需要从request结构体中获取每一部分的信息进行分析后得出响应报文,然后构建出response结构体来存放响应报文。
而antweb中的request结构体中存放的请求报文的首部并不是http所有的首部,我只是挑了一些首部进行存放,保证服务器基本能运行,若读者想增加更多的首部项只需要修改该结构体就可以了。
(1)request结构体:
typedef struct {
//请求报文
bufstr *request_content;
//请求报文的起始行
bufstr *request_line;
//请求报文的首部
bufstr *request_head;
//是否有请求主体
int have_body;
//请求报文的主体部分
bufstr *request_body;
//是否主体数据接收完整
int read_all;
//请求报文的方法
bufstr *line_method;
//请求报文起始行的url
bufstr *line_url;
//请求报文的http版本号
bufstr *line_version;
//请求报文的首部host项的值
bufstr *head_host;
//请求报文的首部Connection项的值
bufstr *head_connection;
//请求报文的首部Content-Length项(若有主体)的值
bufstr *head_content_length;
//请求报文的首部accept项的值
bufstr *head_accept;
} request;
在下面操作函数是对请求报文进行存放、分解、分析操作,而用bufstr结构体(日记03介绍)进行存放,因为request如上面所示,存放请求报文的各部分是用bufstr结构体。
(2)从某个连接套接字中获取请求报文
bufstr *request_read(mempool *mpool,int fd)
{
int n,mbsize,flag=0;
memblock *mblock = NULL;
char *swap = NULL;
bufstr *src = bufstr_init(mpool);
mbsize = MBSIZE;
mblock = mempool_take_mblocks(mpool,1);
swap = (char*)mblock->memptr;
while((n = recv(fd,swap,mbsize,MSG_DONTWAIT))>0)
{
flag = 1 ;
bufstr_append_string_len(mpool,src,swap,n);
}
if(!flag)
{
return NULL;
}
mempool_put_mblocks(mpool,mblock);
return src;
}
(3)从请求报文中获取起始行:
bufstr *request_read(mempool *mpool,int fd)
{
int n,mbsize,flag=0;
memblock *mblock = NULL;
char *swap = NULL;
bufstr *src = bufstr_init(mpool);
mbsize = MBSIZE;
mblock = mempool_take_mblocks(mpool,1);
swap = (char*)mblock->memptr;
while((n = recv(fd,swap,mbsize,MSG_DONTWAIT))>0)
{
flag = 1 ;
bufstr_append_string_len(mpool,src,swap,n);
}
if(!flag)
{
return NULL;
}
mempool_put_mblocks(mpool,mblock);
return src;
}
(4)从请求报文中获取首部(不是http全部首部,我只获取部分首部)并转换成小写字母:
bufstr *get_header_lower(mempool *mpool, bufstr *src)
{
char *start = NULL, *end = NULL,*http_message = NULL;
bufstr *header = NULL;
if(!src || !mpool)
{
return NULL;
}
if(!src->used)
{
return NULL;
}
http_message = read_string_bufstr(src);
start = strstr(http_message,"\n");
if(start == NULL || strlen(http_message) == start - http_message + 1)
{
return NULL;
}
start ++;
header = bufstr_init(mpool);
end = strstr(start,"\r\n\r\n");
if(end != NULL)
{
end += 2;
*end = '/0';
}
else
{
end = strstr(start,"\n\n");
if(end != NULL)
{
end += 1;
*end = '/0';
}
else
{
end = http_message + strlen(http_message);
}
}
string_to_lower(start);
bufstr_copy_string_len(mpool,header,start,end - start);
free(http_message);
return header;
}
(5)若请求方法是post或其他含有主体的请求报文,则从请求报文中获取主体:
bufstr *get_request_body(mempool *mpool,bufstr *src,int *content_length)
{
char *temp = NULL,*http_message = NULL;
bufstr *body = NULL;
if(!mpool || !src)
{
return NULL;
}
if(!src->used)
{
return NULL;
}
http_message = read_string_bufstr(src);
temp = strstr(http_message,"\r\n\r\n");
if(temp != NULL && strlen(http_message) > temp - http_message + 4)
{
temp += 4;
body = bufstr_init(mpool);
bufstr_copy_string_len(mpool,body,temp,http_message + strlen(http_message) - temp);
return body;
}
temp = strstr(http_message,"\n\n");
if(temp == NULL || strlen(http_message) == temp - http_message + 2)
{
return NULL;
}
temp += 2;
body = bufstr_init(mpool);
bufstr_copy_string_len(mpool,body,temp,http_message + strlen(http_message) - temp);
if(content_length != NULL)
{
*content_length = strlen(temp);
}
free(http_message);
return body;
}
下面是其他的操作函数,若读者需要了解某个函数时可以评论告诉我,我看见就更新内容:
//创建一个request结构体并通过函数返回
request *request_init();
//释放resquest结构体rq
void request_free(mempool *mpool,request *rq);
//读取连接的请求报文存入到src中
bufstr *request_read(mempool *mpool,int fd);
//获取http起始行,以bufstr指针返回
bufstr *get_start_line(mempool *mpool, bufstr *src);
//获取http首部(字母为小写),以bufstr指针返回
bufstr *get_header_lower(mempool *mpool, bufstr *src);
//获取http主体部分,以bufstr指针返回,其长度以content_length指针返回
bufstr *get_request_body(mempool *mpool,bufstr *src,int *content_length);
//获取请求起始行的方法
bufstr *get_start_line_method(mempool *mpool, bufstr *src);
//获取请求起始行的url
bufstr *get_start_line_url(mempool *mpool, bufstr *src);
//获取请求起始行url的原始路径
bufstr *get_raw_url(mempool *mpool, bufstr *url);
//获取请求起始行的版本号
bufstr *get_start_line_version(mempool *mpool, bufstr *src);
//获取指定首部字段(小写)的value值
bufstr *get_header_value(mempool *mpool, bufstr *head, char *key);