使用http-parser解析http请求和响应数据

news2024/11/20 12:41:00

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;
      }
    
  • 打印结果
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1609771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【前端面试3+1】15 CSS如隐藏元素、css块级元素和行内元素有哪些?两者有什么区别?、JavaScript中“==”与“===”的区别、【丢失的数字】

一、CSS如何隐藏元素&#xff1f; 1、使用 display: none; 这种方法会隐藏元素&#xff0c;并且不占据页面空间。元素会被完全移除&#xff0c;无法通过任何方式显示出来。 .hidden-element {display: none; }2、使用 visibility: hidden; 这种方法会隐藏元素&#xff0c;但仍然…

线段树汇总

线段树是一种二叉搜索树&#xff0c;与区间树相似&#xff0c;它将一个区间划分成一些单元区间&#xff0c;每个单元区间对应线段树中的一个叶结点。 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数&#xff0c;时间复杂度为O(logN)。而未优化的空间复杂度为2N&a…

Office 2024安装教程(附免费安装包资源)

鼠标右击软件压缩包&#xff0c;选择“解压到Office 2024安装包”。 打开解压后的文件夹&#xff0c;鼠标右击“YAOCTRI_Installer”选择“以管理员身份运行”。 输入数字“1”自动开始安装。 软件正在安装&#xff0c;请耐心等待&#xff0c;谢谢。 安装完成&#xff0c;点击“…

浅析Redis④:字典dict实现

什么是dict&#xff1f; 在 Redis 中&#xff0c;dict 是指哈希表&#xff08;hash table&#xff09;的一种实现&#xff0c;用于存储键值对数据。dict 是 Redis 中非常常用的数据结构之一&#xff0c;用于实现 Redis 的键空间。 在 Redis 源码中&#xff0c;dict 是一个通用…

初学python记录:力扣39. 组合总和

题目&#xff1a; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidates 中的 同一个 数字可以 无限…

Electron 30.0.0 发布,升级 Node 和 V8 引擎

近日&#xff0c;Electron 30.0.0 正式发布&#xff01;你可以通过 npm install electronlatest 进行安装&#xff0c;或者从 Electron 的发布网站下载&#xff0c;继续阅读了解此版本的详细信息。 &#x1f525; 主要更新 Windows 上支持 ASAR 完整性融合。如果未正确配置&am…

【JAVA基础篇教学】第十一篇:Java中字符串操作详解

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第十篇&#xff1a;Java中字符串操作详解。 在 Java 编程中&#xff0c;字符串是一种常见的数据类型&#xff0c;通常用于存储文本信息。Java 提供了丰富的字符串操作方法&#xff0c;可以对字符串进行分割、截取、查找…

网络变压器在网络分析仪上能通过测试,装上设备后网速达不到呢?

Hqst华轩盛(石门盈盛)电子导读&#xff1a;今天和大家一起探讨网络变压器在网络分析仪上能通过测试&#xff0c;装上设备后网通设备网速达不到的可能原因及其处理方式 一、出现这种情况可能有以下原因&#xff1a; 1.1. 设备兼容性问题&#xff1a;设备其它元器件与 网络…

快速掌握缓存技术:学习多个缓存供应商(ehcache,redis,memcached,jetcache,j2cache)

缓存技术 缓存模拟缓存Spring缓存技术第三方缓存技术Ehcache缓存供应Redis缓存memcached缓存&#xff08;国内&#xff09; jetcache缓存供应商jetcache的基本使用设置外部服务设置本地服务 jetcache方法缓存j2cache 缓存 什么是缓存 缓存是一种介于数据永久存储介质与数据应用…

graphviz嵌入latex的方法

效果&#xff1a; graphviz graphviz是一个开源的工具包&#xff0c;用DOT语言编写可以自动转换成图形&#xff0c;因为写法非常简单&#xff0c;只用代码描述好连接关系&#xff0c;就能直接得到最终的图形&#xff0c;所以优势很大。 latex&#xff1a; 就不介绍了 graphvi…

单片机项目中太多全局变量有什么弊端?

最近有读者遇到了这样的问题&#xff1a; 入职接到前同事丢下的“烂摊子”&#xff0c;项目中很多全局变量 问我&#xff1a;全局变量太多有哪些弊端&#xff1f;该如何规避&#xff0c;以及如何管理全局变量等。 全局变量太多有哪些弊端&#xff1f; 真正做过项目的同学应该都…

备战2024年上海初中生古诗文大会:单选题真题示例和独家解析

上海市中小学生的初中生古诗文大会——即上海中学生古诗文大会&#xff08;初中组&#xff09;和小学生古诗文大会&#xff08;比赛&#xff09;除了题型略有不同外&#xff0c;最主要的是考察的内容深度和广度不同&#xff0c;初中的题目中对于文言文的考察大幅增加&#xff0…

SpringBoot相关知识点总结

1 SpringBoot的目的 简化开发&#xff0c;开箱即用。 2 Spring Boot Starter Spring Boot Starter 是 Spring Boot 中的一个重要概念&#xff0c;它是一种提供依赖项的方式&#xff0c;可以帮助开发人员快速集成各种第三方库和框架。Spring Boot Starter 的目的是简化 Sprin…

C语言数据结构之顺序表

目录 1.线性表2.顺序表2.1顺序表相关概念及结构2.2增删查改等接口的实现 3.数组相关例题 1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性&#xff08;数据类型相同&#xff09;的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff…

【RV1106的ISP使用记录之基础知识】硬件连接关系与设备树的构建

RV1106具备2个mipi csi2 dphy硬件&#xff0c;1个VICAP硬件和1个ISP硬件。其中&#xff1a; 1、mipi csi2 dphy 用于对数据流的解析&#xff0c;支持MIPC,LVDS,DVP三种接口&#xff1b; 2、VICAP用于数据流的捕获&#xff1b; 3、ISP用于对图像数据进行处理&#xff1b; 这三个…

【QTM中文教程】01:Quick Terrain Modeller介绍、下载与安装

文章目录 一、Quick Terrain Modeller简介二、Quick Terrain Modeller特点功能三、Quick Terrain Modeller下载安装1. 下载地址2. 安装教程一、Quick Terrain Modeller简介 Quick Terrain Modeler(QTM)是一种专业的地形建模软件,用于处理和分析地形数据。它提供了一系列功能…

【漏洞复现】泛微e-cology ProcessOverRequestByXml接口存在任意文件读取漏洞

漏洞描述 泛微e-cology依托全新的设计理念,全新的管理思想。 为中大型组织创建全新的高效协同办公环境。 智能语音办公,简化软件操作界面。 身份认证、电子签名、电子签章、数据存证让合同全程数字化。泛微e-cology ProcessOverRequestByXml接口存在任意文件读取漏洞 免责声…

【漏洞复现】宏景eHR showmediainfo SQL注入漏洞

0x01 产品简介 北京宏景世纪软件股份有限公司&#xff08;简称“宏景软件”&#xff09;专注于国有企事业单位人力与人才管理数智化&#xff08;数字化、智能化&#xff09;产品的研发和应用推广。 0x02 漏洞概述 宏景eHR /workbench/duty/showmediainfo接口存在SQL注入漏洞…

Jenkins用maven风格build报错解决过程记录

1、Jenkins2.453新建项目&#xff0c;构建风格选的maven 2、自由风格构建部署没有任何问题&#xff0c;但是maven风格build一直失败&#xff0c;报错如下图 3、解决方案&#xff1a;在系统管理–系统配置–Maven项目配置&#xff0c;删除全局MAVEN_OPT的路径信息&#xff0c;…

oracle 清空回收站

参考官方文档 select * from user_recyclebin; select * from dba_recyclebin; ---清除回收站中当前用户下的对象 purge recyclebin; ---清除回收站中所有的对象 purge dba_recyclebin; ---清除回收站中指定用户的表 PURGE TABLE owner.table_name; ---清除回收站中指…