1 简介

  • http-parser是一个用C编写的HTTP消息解析器,专为高性能HTTP应用程序设计。它能够解析HTTP/1.0和HTTP/1.1的消息,包括头部、主体和连续行。当解析到特定的HTTP元素(如请求行、头字段或消息体)时,会触发相应的回调函数,这使得它在处理大量并发请求时具有高效率,因为无需在每次解析时都遍历整个消息。

  • http-parser的主要特性包括:不依赖第三方库、处理持续流(keep-alive)、分块解码(decodes chunked encoding)、支持Upgrade以及防止缓冲区溢出攻击。每个TCP连接使用一个http_parser对象,使用http_parser_init函数初始化结构体并设置回调。

2 源码地址

  • http-parser
  • 使用时将 http_parser.h 和 http_parser.c 这两个文件集成到项目中即可使用。

3 相关API

3.1 初始化

  •   /*
      * @brief  用于初始化 http_parser 结构体,为后续的 HTTP 消息解析做好准备
      * @param  [IN]  parser  指向一个待初始化的 http_parser 结构体实例
      * @param  [IN]  type    枚举值,指定 parser 应该解析 HTTP 请求还是响应
      *                           HTTP_REQUEST - 解析请求
      *                           HTTP_RESPONSE - 解析响应
      *                           HTTP_BOTH - 两者都可以
      */
      void http_parser_init(http_parser *parser, enum http_parser_type type);
    

3.2 设置回调函数

  •   /*
      * @brief  设置默认的回调函数指针,这些回调函数会在解析HTTP消息的不同阶段被调用。
      * 	    通知用户程序有关HTTP请求或响应的详细信息。
      * @param  [IN]  settings  指向一个 http_parser_settings 结构体的指针
      * 						这个结构体包含了指向各种回调函数的指针,具体如下
      *                          	on_message_begin     - 开始解析时回调
      *                          	on_url               - 解析URL时回调
      *                          	on_status            - 解析响应状态描述信息时回调
      *                          	on_header_field      - 解析请求头key值时回调
      *                          	on_header_value      - 解析请求头value时回调
      *                          	on_headers_complete  - 开始解析请求头时回调
      *                          	on_body              - 解析请求或响应体时回调
      *                          	on_message_complete  - 解析完成时回调
      *                           
      */
      void http_parser_settings_init(http_parser_settings *settings);
    

3.3 解析数据

  •   /*
      * @brief  解析HTTP请求或响应的消息数据
      * @param  [IN]  parser      指向一个已初始化的 http_parser 结构体实例
      * 						  该结构体包含了 HTTP 消息的解析状态和其他相关信息,主要有以下参数
      *                              status_code - http响应状态码
      *                              method      - http请求方式。HTTP_GET,HTTP_POST
      * @param  [IN]  settings    指向一个 http_parser_settings 结构体,其中定义了一系列回调函数。
      * 						  当解析到 HTTP 消息的不同部分(比如请求行、头部、主体等)时,对应的回调函数会被调用。
      * @param  [IN]  data        待解析的HTTP数据
      * @param  [IN]  len         待解析的HTTP数据长度
      * @return  解析过程中成功处理了多少字节的数据,
      * 		如果小于len,可能是因为遇到了解析错误,或者是缓冲区中的数据不足以构成一个完整的 HTTP 消息片段。
      */
      size_t http_parser_execute(http_parser *parser, const http_parser_settings *settings, const char *data, size_t len);
    

4 使用示例

  • 测试代码
  •   #include <stdio.h>
      #include "http_parser.h"
      #include <string>
      #include <map>
      
      // 用于解析的全局变量
      std::map<std::string, std::string> mapReqHeadField;
      std::string strReqUrl;
      std::string strReqBody;
      std::string strReqFieldKey;
      
      std::map<std::string, std::string> mapRespHeadField;
      std::string strRespStatus;
      std::string strRespBody;
      std::string strRespFieldKey;
      
      // 用于解析http请求的回调函数
      int onReqMessageBegin(http_parser* pParser);
      int onReqHeaderComplete(http_parser* pParser);
      int onReqMessageComplete(http_parser* pParser);
      int onReqURL(http_parser* pParser, const char *at, size_t length);
      int onReqHeaderField(http_parser* pParser, const char *at, size_t length);
      int onReqHeaderValue(http_parser* pParser, const char *at, size_t length);
      int onReqBody(http_parser* pParser, const char *at, size_t length);
      
      // 用于解析http响应的回调函数
      int onRespMessageBegin(http_parser* pParser);
      int onRespHeaderComplete(http_parser* pParser);
      int onRespMessageComplete(http_parser* pParser);
      int onRespStatus(http_parser* pParser, const char *at, size_t length);
      int onRespHeaderField(http_parser* pParser, const char *at, size_t length);
      int onRespHeaderValue(http_parser* pParser, const char *at, size_t length);
      int onRespBody(http_parser* pParser, const char *at, size_t length);
      
      
      int main(int argc, char* argv[])
      {
          // 解析http请求
      
          // 待解析的请求报文
          std::string strHttpReq;
          strHttpReq += "POST /http-parser HTTP/1.1\r\n";
          strHttpReq += "Host: 127.0.0.1:10010\r\n";
          strHttpReq += "Accept: */*\r\n";
          strHttpReq += "Content-Type: application/json\r\n";
          strHttpReq += "Content-Length: 25\r\n";
          strHttpReq += "\r\n";
          strHttpReq += "{\"reqmsg\": \"Hello World\"}";
      
          http_parser httpReqParser;
          http_parser_settings httpReqSettings;
      
          // 初使化解析器
          http_parser_init(&httpReqParser, HTTP_REQUEST);
          // 设置回调函数
          http_parser_settings_init(&httpReqSettings);
          httpReqSettings.on_message_begin = onReqMessageBegin;
          httpReqSettings.on_headers_complete = onReqHeaderComplete;
          httpReqSettings.on_message_complete = onReqMessageComplete;
          httpReqSettings.on_url = onReqURL;
          httpReqSettings.on_header_field = onReqHeaderField;
          httpReqSettings.on_header_value = onReqHeaderValue;
          httpReqSettings.on_body = onReqBody;
      
          // 解析请求
          int reqSize = strHttpReq.size();
          int nParseSize = http_parser_execute(&httpReqParser, &httpReqSettings, strHttpReq.c_str(), reqSize);
          if(nParseSize < reqSize){
              printf("http_parser_execute http request failed.\n");
              return -1;
          }
      
          // 解析成功,打印解析结果
          if(httpReqParser.method == HTTP_GET){
              printf("method: Get\n");
          }else if(httpReqParser.method == HTTP_POST){
              printf("method: Post\n");
          }else if(httpReqParser.method == HTTP_HEAD){
              printf("method: Head\n");
          }else{
              printf("method: other\n");
          }
      
          printf("url: %s \n", strReqUrl.c_str());
          printf("req heads:\n");
          for (std::map<std::string, std::string>::iterator iter = mapReqHeadField.begin(); iter != mapReqHeadField.end(); ++iter){
              printf("\t %s : %s \n", iter->first.c_str(), iter->second.c_str());
          }
          printf("req body: %s \n", strReqBody.c_str());
      
          printf("==========================================\n");
      
          // 解析http响应
      
      
          // 待解析的响应报文
          std::string strHttpResponse;
          strHttpResponse += "HTTP/1.1 200 OK\r\n";
          strHttpResponse += "Server: nginx/1.18.0\r\n";
          strHttpResponse += "Accept: */*\r\n";
          strHttpResponse += "Connection: keep-alive\r\n";
          strHttpResponse += "\r\n";
          strHttpResponse += "{\"respmsg\": \"Welcome to http-parser\"}\r\n";
      
          http_parser httpRespParser;
          http_parser_settings httpRespSettings;
      
          // 初使化解析器
          http_parser_init(&httpRespParser, HTTP_RESPONSE);
          // 设置回调函数
          http_parser_settings_init(&httpRespSettings);
          httpRespSettings.on_message_begin = onRespMessageBegin;
          httpRespSettings.on_headers_complete = onRespHeaderComplete;
          httpRespSettings.on_message_complete = onRespMessageComplete;
          httpRespSettings.on_status = onRespStatus;
          httpRespSettings.on_header_field = onRespHeaderField;
          httpRespSettings.on_header_value = onRespHeaderValue;
          httpRespSettings.on_body = onRespBody;
      
          // 解析响应
          int responseSize = strHttpResponse.size();
          nParseSize = http_parser_execute(&httpRespParser, &httpRespSettings, strHttpResponse.c_str(), responseSize);
          if(nParseSize < responseSize){
              printf("http_parser_execute http response failed.\n");
              return -1;
          }
      
          // 解析成功,打印解析结果
          printf("code: %d\n", httpRespParser.status_code); 
          printf("status: %s \n", strRespStatus.c_str());
          printf("resp heads:\n");
          for (std::map<std::string, std::string>::iterator iter = mapRespHeadField.begin(); iter != mapRespHeadField.end(); ++iter){
              printf("\t %s : %s \n", iter->first.c_str(), iter->second.c_str());
          }
          printf("resp body: %s \n", strRespBody.c_str());
          return 0;
      }
      
      
      int onReqMessageBegin(http_parser* pParser)
      {
          // 开始解析报文
          printf("onReqMessageBegin call \n");
          return 0;
      }
      int onReqHeaderComplete(http_parser* pParser)
      {
          // 报文头解析完成
          // HTTP报文头是以两个 \r\n 结尾, 如果解析不到两个 \r\n, 说明http报文格式有问题或者报文不完整,这个回调不会被调用
          printf("onReqHeaderComplete call \n");
          return 0;
      }
      int onReqMessageComplete(http_parser* pParser)
      {
          // 全部解析完成
          printf("onReqMessageComplete call \n");
          return 0;
      }
      int onReqURL(http_parser* pParser, const char *at, size_t length)
      {
          // 解析URL
          strReqUrl.assign(at, length);
          return 0;
      }
      
      int onReqHeaderField(http_parser* pParser, const char *at, size_t length)
      {
          // 解析请求头key
          strReqFieldKey.assign(at, length);
          return 0;
      }
      int onReqHeaderValue(http_parser* pParser, const char *at, size_t length)
      {
          // 解析请求头value
          std::string strValue(at, length);
          mapReqHeadField.insert(std::make_pair(strReqFieldKey, strValue));
          return 0;
      }
      int onReqBody(http_parser* pParser, const char *at, size_t length)
      {
          // 解析请求或响应体
          strReqBody.append(at, length);
          return 0;
      }
      
      
      // ==================
      
      int onRespMessageBegin(http_parser* pParser)
      {
          // 开始解析报文
          printf("onRespMessageBegin call \n");
          return 0;
      }
      int onRespHeaderComplete(http_parser* pParser)
      {
          // 报文头解析完成
          // HTTP报文头是以两个 \r\n 结尾, 如果解析不到两个 \r\n, 说明http报文格式有问题或者报文不完整,这个回调不会被调用
          printf("onRespHeaderComplete call \n");
          return 0;
      }
      int onRespMessageComplete(http_parser* pParser)
      {
          // 全部解析完成
          printf("onRespMessageComplete call \n");
          return 0;
      }
      
      int onRespStatus(http_parser* pParser, const char *at, size_t length)
      {
          // 解析响应状态码
          strRespStatus.assign(at, length);
          return 0;
      }
      int onRespHeaderField(http_parser* pParser, const char *at, size_t length)
      {
          // 解析响应头key
          strRespFieldKey.assign(at, length);
          return 0;
      }
      int onRespHeaderValue(http_parser* pParser, const char *at, size_t length)
      {
          // 解析响应头value
          std::string strValue(at, length);
          mapRespHeadField.insert(std::make_pair(strRespFieldKey, strValue));
          return 0;
      }
      int onRespBody(http_parser* pParser, const char *at, size_t length)
      {
          // 解析请求或响应体
          strRespBody.append(at, length);
          return 0;
      }
    
  • 打印结果
    在这里插入图片描述
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐