高性能Linux服务器--解析HTTP请求报文

解析HTTP报文

HTTP报文格式

在这里插入图片描述
在这里插入图片描述

一些状态描述符

HTTP请求方法,此项目只支持GET


    enum METHOD {GET = 0, POST, HEAD, PUT, DELETE, TRACE, OPTIONS, CONNECT};
/*
    解析客户端请求时,主状态机的状态
    CHECK_STATE_REQUESTLINE:当前正在分析请求行
    CHECK_STATE_HEADER:当前正在分析头部字段
    CHECK_STATE_CONTENT:当前正在解析请求体
*/
    enum CHECK_STATE { CHECK_STATE_REQUESTLINE = 0, CHECK_STATE_HEADER, CHECK_STATE_CONTENT };
/*
    服务器处理HTTP请求的可能结果,报文解析的结果
    NO_REQUEST          :   请求不完整,需要继续读取客户数据
    GET_REQUEST         :   表示获得了一个完成的客户请求
    BAD_REQUEST         :   表示客户请求语法错误
    NO_RESOURCE         :   表示服务器没有资源
    FORBIDDEN_REQUEST   :   表示客户对资源没有足够的访问权限
    FILE_REQUEST        :   文件请求,获取文件成功
    INTERNAL_ERROR      :   表示服务器内部错误
    CLOSED_CONNECTION   :   表示客户端已经关闭连接了
*/
    enum HTTP_CODE { NO_REQUEST, GET_REQUEST, BAD_REQUEST, NO_RESOURCE, FORBIDDEN_REQUEST, FILE_REQUEST, INTERNAL_ERROR, CLOSED_CONNECTION };
// 从状态机的三种可能状态,即行的读取状态,分别表示
// 1.读取到一个完整的行 2.行出错 3.行数据尚且不完整
    enum LINE_STATUS { LINE_OK = 0, LINE_BAD, LINE_OPEN

状态机

在CHECK_STATE_REQUESTLINE、CHECK_STATE_HEADER和CHECK_STATE_CONTENT三中状态切换,一次去处理HTTP报文的请求行,请求头和请求体

//主状态机,解析请求
HTTP_CODE http_conn::process_read(){
    LINE_STATUS line_status = LINE_OK;
    HTTP_CODE ret = NO_REQUEST;
    char* text = 0;
    while (((m_check_state == CHECK_STATE_CONTENT) && (line_status == LINE_OK))
            || ((line_status = parse_line()) == LINE_OK)) {
        //获取一行数据
        text = get_line();
        m_start_line = m_checked_idx;
        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_STATE_CONTENT:{
            ret = parse_content(text);
            if(ret == BAD_REQUEST){
                return BAD_REQUEST;
            }else if(ret == GET_REQUEST){

解析HTTP请求报文的相关函数

解析请求行

通过解析请求行获取请求方法,目标URL,以及HTTP版本号


//解析HTTP请求行,获得请求方法,目标URL,以及HTTP版本号
HTTP_CODE http_conn::parse_request_line(char * text){
    // GET /index.html HTTP/1.1
    m_url = strpbrk(text, " \t");
    if(!m_url){
        return BAD_REQUEST;
    }
    *m_url = '\0';
    m_url++;

    char* method = text;
    if(strcasecmp(method, "GET") == 0){
        m_method = GET;
    }else{
        return BAD_REQUEST;
    }

    m_version = strpbrk(m_url, " \t");
    if(!m_version){
        return BAD_REQUEST;
    }
    *m_version = '\0';
    m_version++;
    if(strcasecmp(m_version, "HTTP/1.1") != 0){
        return BAD_REQUEST;
    }

    if(strcasecmp(m_url,"http://", 7) == 0){
        m_url += 7;
        m_url = strchr(m_url, '/');
    }

    if(!m_url || m_url[0] != '/'){
        return BAD_REQUEST;
    }

    m_check_state = CHECK_STATE_HEADER; //简称状态变成检查头
    return NO_REQUEST;
}

解析请求头


//解析HTTP请求的一个头部信息
HTTP_CODE http_conn::parse_headers(char * text){
    //遇到空行表示请求头解析完毕,检查是否有请求体
    //如有还需转换到CHECK_STATE_CONTENT状态
    if(text[0] == '\0'){
        if(m_content_length != 0) {
            m_check_state = CHECK_STATE_CONTENT;
            return NO_REQUEST;
        }
        //否则说明我们已经得到了一个完整的HTTP请求
        return GET_REQUEST;
    }else if(strcasecmp(text, "Host:", 5) == 0) {
        text += 5;
        text += strspn(text, " \t");//strspn()检查text开头有多少个连续的字符是str2里的,返回数量
        m_host = text;

    }else if(strcasecmp(text, "Connection:", 11) == 0){
        text += 11;
        text += strspn(text, " \t");//strspn()检查text开头有多少个连续的字符是str2里的,返回数量
        if(strcasecmp(text, "keep-alive") == 0) {
            m_linger = true;
        }

    }else if(strcasecmp(text, "Connect-Length:", 15) == 0){
        text += 15;
        text += strspn(text, " \t");//strspn()检查text开头有多少个连续的字符是str2里的,返回数量
        m_content_length = atol(text);
    }else{
        printf("oop! unkonw header %s\n", text);
    }
    return NO_REQUEST;
}

解析请求体


//解析HTTP请求的请求体
//我们没有真正解析HTTP请求的消息体
HTTP_CODE http_conn::parse_content(char * text){
    if(m_read_idx >= (m_content_length + m_checked_idx)) {
        text[m_content_length] = '\0';
        return GET_REQUEST;
    }
    return NO_REQUEST;

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux下使用C语言实现HTTP服务器解析POST请求的过程可以分为以下几个步骤: 1. 接收客户端发送的HTTP请求:使用socket函数创建服务器套接字,并使用bind函数将套接字与服务器IP地址和端口号绑定,使用listen函数监听客户端的连接请求,使用accept函数接受客户端连接请求并返回一个新的套接字用于与客户端通信。 2. 解析HTTP请求报文:读取客户端发送的HTTP请求报文,根据请求报文的方法字段判断该请求是GET还是POST请求,如果是POST请求,需要解析请求头中的Content-Length字段获取HTTP请求体的长度。 3. 接收HTTP请求体:使用read函数读取HTTP请求体,需要循环读取直到读取到Content-Length指定的长度为止。 4. 解析HTTP请求体:根据Content-Type字段判断HTTP请求体的类型,如果是application/x-www-form-urlencoded类型,则需要解析请求体中的键值对;如果是multipart/form-data类型,则需要解析请求体中的文件数据。 5. 处理HTTP请求:根据请求的路径和参数等信息,调用相应的处理函数进行处理,并生成HTTP响应报文。 6. 发送HTTP响应:使用write函数将HTTP响应报文发送给客户端,关闭套接字,结束本次HTTP请求处理过程。 需要注意的是,解析POST请求时需要注意处理请求体的长度和类型,以及对不同类型的请求体进行正确的解析。此外,还需要防范POST请求中的恶意攻击,如SQL注入、跨站脚本攻击等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值