使用http-parser解析http请求和响应数据
http-parser是一个用C编写的HTTP消息解析器,专为高性能HTTP应用程序设计。它能够解析HTTP/1.0和HTTP/1.1的消息,包括头部、主体和连续行。当解析到特定的HTTP元素(如请求行、头字段或消息体)时,会触发相应的回调函数,这使得它在处理大量并发请求时具有高效率,因为无需在每次解析时都遍历整个消息。
·
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; }
- 打印结果
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献30条内容
所有评论(0)