llhttp是Node.js的HTTP1.1解析器,用来替代早期的http_parser,性能有了很大的提升,最近打算在No.js中引入llhttp来处理HTTP协议分析,本文简单介绍一下如何使用。llhttp项目是Node.js中的一个子项目,地址为:https://github.com/nodejs/llhttp。步骤如下:1、安装npx:npminpx-g2。执行ts生成c代码:npxts-nodebin/generate.ts,或者执行makegenerate3。此时在build目录下生成了llhttp.h和llhttp.c,再加上native下的c代码就是llhttp的全部代码,我们可以拷贝到自己的项目中使用,看下面的使用方法。llhttp使用了回调钩子的设计思想。在初始化解析器的时候,我们可以设置解析类型,是请求还是响应消息,然后设置解析状态的回调,比如解析URL时的回调,解析header时的回调。然后对传入消息执行llhttp_execute。以下是解析请求消息的示例。#include#include#include"llhttp.h"#defineMAX_LEN2048inton_message_begin(llhttp_t*parser){printf("parsestart\n");return0;}inton_url(llhttp_t*parser,constchar*at,size_tlength){charurl[MAX_LEN];strncpy(url,at,length);url[length]='\0';printf("on_url:%s\n",url);return0;}inton_header_field(llhttp_t*parser,constchar*at,size_tlength){charheader_field[MAX_LEN];strncpy(header_field,at,length);header_field[length]='\0';printf("headfield:%s\n",header_field);return0;}inton_header_value(llhttp_t*parser,constchar*at,size_tlength){charheader_value[MAX_LEN];strncpy(header_value,at,length);header_value[length]='\0';printf("headvalue:%s\n",header_value);return0;}inton_headers_complete(llhttp_t*parser){printf("on_headers_complete,major:%d,major:%d,keep-alive:%d,upgrade:%d\n",parser->http_major,parser->http_minor,llhttp_should_keep_alive(解析器),解析器->升级);返回0;}inton_body(llhttp_t*parser,constchar*at,size_tlength){charbody[MAX_LEN];strncpy(body,at,length);body[length]='\0';printf("on_body:%s\n",body);return0;}inton_message_complete(llhttp_t*parser){printf("on_message_complete\n");return0;}intmain(){llhttp_tparser;llhttp_settings_tsettings;llhttp_settings_init(&settings);llhttp_init(&parser,HTTP_REQUEST,&settings);设置。on_message_begin=on_message_begin;settings.on_url=on_url;settings.on_header_field=on_header_field;settings.on_header_value=on_header_value;settings.on_headers_complete=on_headers_complete;settings.on_body=on_body;settings.on_message_complete=on_message_complete;constchar*request="POST/index.htmlHTTP/1.1\r\nconnection:close\r\ncontent-length:1\r\n\r\n1\r\n\r\n";intrequest_len=strlen(request);enumllhttp_errnoerr=llhttp_execute(&parser,request,request_len);if(err!=HPE_OK){fprintf(stderr,"Parseerror:%s%s\n",llhttp_errno_name(err),parser.reason);}return0;}然后看解析response的例子#include#include#include"llhttp.h"#defineMAX_LEN2048inton_message_begin(llhttp_t*parser){printf("parsestart\n");return0;}inton_url(llhttp_t*parser,constchar*at,size_tlength){charurl[MAX_LEN];strncpy(url,at,length);url[length]='\0';printf("on_url:%s\n",url);return0;}inton_status(llhttp_t*parser,constchar*at,size_tlength){charstatus[MAX_LEN];strncpy(status,at,length);status[length]='\0';printf("on_status:%s\n",status);return0;}inton_header_field(llhttp_t*parser,constchar*at,size_tlength){charheader_field[MAX_LEN];strncpy(header_field,at,length);header_field[length]='\0';printf("headfield:%s\n",header_field);return0;}inton_header_value(llhttp_t*parser,constchar*at,size_tlength){charheader_value[MAX_LEN];strncpy(header_value,at,length);header_value[length]='\0';printf("headvalue:%s\n",header_value);return0;}inton_headers_complete(llhttp_t*parser){printf("on_headers_complete,major:%d,major:%d,keep-alive:%d,upgrade:%d\n",parser->http_major,parser->http_minor,llhttp_should_keep_alive(parser),parser->upgrade);return0;}inton_body(llhttp_t*parser,constchar*at,size_tlength){charbody[MAX_LEN];strncpy(body,at,length);body[length]='\0';printf("on_body:%s\n",body);return0;}inton_message_complete(llhttp_t*parser){printf("on_message_complete\n");return0;}intmain(){llhttp_tparser;llhttp_settings_tsettings;llhttp_settings_init(&settings);llhttp_init(&parser,HTTP_RESPONSE,&settings);settings.on_message_begin=on_message_begin;settings.on_url=on_url;settings.on_status=on_status;settings.on_header_field=on_header_field;settings.on_header_value=on_header_value;settings.on_headers_complete=on_headers_complete;settings.on_body=on_body;settings.on_message_complete=on_message_complete;constchar*reponse="HTTP/1.1200OK\r\n服务器:nginx\r\n内容长度:11\r\n\r\n你好:world\r\n\r\n";intreponse_len=strlen(reponse);enumllhttp_errnoerr=llhttp_execute(&parser,reponse,reponse_len);if(err!=HPE_OK){fprintf(stderr,"解析错误:%s%s\n",llhttp_errno_name(err),parser.reason);}return0;}llhttp目前支持以下钩子回调structllhttp_settings_s{/*Possiblereturnvalues0,-1,`HPE_PAUSED`*/llhttp_cbon_message_begin;/*Possiblereturnvalues0,-1,HPE_USER*/llhttp_data_cbon_url;llhttp_data_cbon_status;llhttp_data_cbon_header_field;llhttp_data_cbon_header_value;/*Possiblereturnvalues:*0-Proceednormally*1-Assumethatrequest/responsehasnobody,andproceedtoparsingthe*nextmessage*2-Assumeabsenceofbody(asabove)andmake`llhttp_execute()`return*`HPE_PAUSED_UPGRADE`*-1-Error*`HPE_PAUSED`*/llhttp_cbon_headers_complete;/*Possiblereturnvalues0,-1,HPE_USER*/llhttp_data_cbon_body;/*Possiblereturnvalues0,-1,`HPE_PAUSED`*/llhttp_cbon_message_complete;/*Whenon_chunk_headeriscalled,thecurrentchunklengthisstored*inparser->content_length.*Possiblereturnvalues0,-1,`HPE_PAUSED`*/llhttp_cbon_chunk_header;llhttp_cbon_chunk_complete;/*Information-onlycallbacks,returnvalueisignored*/llhttp_cbon_url_complete;llhttp_cbon_status_complete;llhttp_cbon_header_field_complete;llhttp_cbon_header_value_comple德;};我们也可以使用llhttp以静态库或动态库的形式执行makeall,在build目录下会生成静态库和动态库。我们将头文件llhttp.h和静态库或动态库复制到自己的项目中使用只需添加-lllhttp-L即可。编译时。总结:llhttp的使用比较简单明了。如果我们项目中需要分析HTTP协议,可以试试。使用demo可以参考https://github.com/theanarkh/llhttp-demo。