使用状态机完成对HTTP请求的读取和分析
主状态机作用(parse_content()):读取请求行与头部行数据
状态:请求行、头部行
从状态机作用(parse_line):读取每一行数据
状态:读取成功、失败、需要继续读取
parse_request():读取请求行,并将主状态机状态更改为头部行
parse_header():读取头部行
主状态机初始状态为请求行,
循环调用parse_line,若为成功状态继续(失败退出返回失败原因)
并且判断主状态机状态
请求->parse_request()->继续循环(失败退出返回失败原因)
头部->parse_header()->成功返回好的请求结果(失败退出返回失败原因)
//http请求的读取和分析
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<fcntl.h>
#define BUFFER_SIZE 4096
//主状态机可能的状态
enum CHECK_STATE
{
CHECK_STATE_REQUESTION = 0,//正在分析当前请求行
CHECK_STATE_HEADER//正在分析头部字段
};
//从状态机可能的状态
enum LINE_STATUS
{
LINE_OK = 0,//读取到一个完整的行
LINE_BAD,//行出错
LINE_OPEN//行数据尚且不完整
};
//服务器处理http请求的结果
enum HTTP_CODE
{
NO_REQUEST,//请求不完整需要继续读取
GET_REQUEST,//得到了一个完整的请求
BAD_REQUEST,//请求有语法错误
FORBIDDEN_REQUEST,//没有足够的权限
INTERNAL_ERROR,//服务器内部错误
CLOSED_CONNECTION//客户端连接已关闭
};
static const char* szret[] =
{
"i get a corret result\n",
"Sonmething wrong\n"
};
//从状态机,用于解析出一行内容
LINE_STATES parse_line(char * buffer, int & checked_index, int & read_index)
{
char temp;
for( ; checked_index < read_index; ++checked_index)
{
//获得当前分析的字
temp = buffer[checked_index];
//如果当前的字节是\r,即回车符,则说明可能读取到一个完整的行
if(temp == '\r')
{
//如果\r字符碰巧是目前buffer中的最后一个已经被读入的客户数据,那么这次分析没有读取到一个完整的行,需要继续读取数据
if(check_index + 1 == read_index)
return LINE_OPEN;
//表示读到了一个完整的行
if(temp == '\n')
{
buffer[check_index++] == '\0';
buffer[check_index++] == '\0';
return LINE_OK;
}
//以上都不是,就是存在语法错误
return LINE_BAD;
}
//当前字符为\n也有可能是到了一行的情况
else if(temp == '\n')
{
//因为\r\n一起用,还得判断