webserver之处理HTTP请求

前言

此博客记录对于TinyWebServer项目的学习,并根据自己的理解做出些许更改。
原项目地址:https://github.com/qinguoyi/TinyWebServer

测试效果

先放一波效果图
在这里插入图片描述

HTTP请求

HTTP GET请求行内容。
在这里插入图片描述

第一行为请求行,分为三个部分:请求方法、请求地址URL和HTTP协议版本,它们之间用空格分割。
后面都是头部字段。
在所有头部字段之后,HTTP请求必须包含一个空行,以标识头部字段的结束。请求行和每个头部字段都必须以结束(回车符和换行符)﹔而空行则必须只包含一-个,不能有其他字符,甚至是空白字符。
这是解析HTTP请求的关键。
而post请求与get请求相比多了消息体,如下图所示,在处理时与get不同,需要将其中的内容提取出来。
在这里插入图片描述

解析HTTP请求

使用两个状态机实现,主状态机在内部调用从状态机,从状态机实现按行读取HTTP请求,如下图所示
在这里插入图片描述

主状态机调用从状态机读取到完整的一行请求后,按照HTTP请求的结构判断该行属于请求行还是头部字段,然后进行分别解析,直到遇到一个空行,表明得到了一个正确的http请求。

	//主状态机状态,检查请求报文中元素
    enum CHECK_STATE
    {
        CHECK_STATE_REQUESTLINE = 0,
        CHECK_STATE_HEADER,
        CHECK_STATE_CONTENT
    };
	//HTTP状态码
    enum HTTP_CODE
    {
        NO_REQUEST,
        GET_REQUEST,
        BAD_REQUEST,
        NO_RESOURCE,
        FORBIDDEN_REQUEST,
        FILE_REQUEST,
        INTERNAL_ERROR,
        CLOSED_CONNECTION
    };
	//从状态机的状态,文本解析是否成功
    enum LINE_STATUS
    {
        LINE_OK = 0,
        LINE_BAD,
        LINE_OPEN
    };
//从m_read_buf读取,并处理请求报文
    HTTP_CODE process_read();
	//向m_write_buf写入响应报文数据
    bool process_write(HTTP_CODE ret);
	//主状态机解析报文中的请求行数据
    HTTP_CODE parse_request_line(char *text);
	//主状态机解析报文中的请求头数据
    HTTP_CODE parse_headers(char *text);
	//主状态机解析报文中的请求内容
    HTTP_CODE parse_content(char *text);
	//m_start_line是已经解析的字符
	//get_line用于将指针向后偏移,指向未处理的字符
    char *get_line() { return m_read_buf + m_start_line; };
	//从状态机读取一行
    LINE_STATUS parse_line();
//存储读取的请求报文数据
    char m_read_buf[READ_BUFFER_SIZE];
	//缓冲区中m_read_buf中数据的最后一个字节的下一个位置
    int m_read_idx;
	//m_read_buf读取的位置m_checked_idx
    int m_checked_idx;
	//m_read_buf中已经解析的字符个数
    int m_start_line;
	//主状态机的状态
	CHECK_STATE m_check_state;

主状态机逻辑

//有限状态机处理请求报文
http_conn::HTTP_CODE http_conn::process_read()
{
    LINE_STATUS line_status = LINE_OK;
    HTTP_CODE ret = NO_REQUEST;
    char *text = 0;
    //parse_line()更新m_checked_idx,从而更新text
    while ((m_check_state == CHECK_STATE_CONTENT && line_status == LINE_OK) || ((line_status = parse_line()) == LINE_OK))
    {
        //text指向m_read_buf的未处理数据的开始
        text = get_line();
        //m_checked_idx表示当前已处理的位置,这里更新m_start_line为下一个的开始
        m_start_line = m_checked_idx;
        LOG_INFO("%s", text);
        switch (m_check_state)
        {
            //请求行
        case CHECK_STATE_REQUESTLINE:
        {
            ret = parse_request_line(text);
            if (ret == BAD_REQUEST)
                return BAD_REQUEST;
            break;
        }
        //头部字段
        case CHECK_STATE_HEADER:
        {
            ret = parse_headers(text);
            if (ret == BAD_REQUEST)
                return BAD_REQUEST;
            else if (ret == GET_REQUEST)
            {
                //得到一个完整的请求就进入处理请求的程序
                return do_request();
            }
            break;
        }
        case CHECK_S
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值