HTTP解析器llhttp的使用指南
導讀 | llhttp 是 Node.js 的 HTTP 1.1 解析器,用於替代早期的http_parser,效能上有了非常大的提升,最近打算在 No.js 裡引入 llhttp 來處理 HTTP 協議的解析,本文簡單介紹一下如何使用。 |
llhttp 是 Node.js 的 HTTP 1.1 解析器,用於替代早期的http_parser,效能上有了非常大的提升,最近打算在 No.js 裡引入 llhttp 來處理 HTTP 協議的解析,本文簡單介紹一下如何使用。
llhttp 專案是 Node.js 中的子專案,地址在:
。
使用步驟如下:
1. 安裝 npx:npm i npx -g
2. 執行 ts 生成 c 程式碼:npx ts-node bin/generate.ts,或者執行 make generate
3. 這時候build 目錄下生成了 llhttp.h 和 llhttp.c,再加上 native 下的 c 程式碼,就是 llhttp 的全部程式碼,我們可以把他複製到自己的專案中使用
下面看看如何使用。llhttp 使用回撥鉤子的設計思想,初始化解析器的時候,我們可以設定解析型別,是請求或響應報文,然後設定解析狀態的回撥,比如解析道 URL 時回撥,解析到 header 時回撥。接著傳入報文執行 llhttp_execute 就可以,下面是解析請求報文的例子。
#include #include #include "llhttp.h" #define MAX_LEN 2048 int on_message_begin(llhttp_t* parser){ printf("parse start\n"); return 0; } int on_url(llhttp_t* parser, const char* at, size_t length){ char url[MAX_LEN]; strncpy(url, at, length); url[length] = '\0'; printf("on_url: %s\n", url); return 0; } int on_header_field(llhttp_t* parser, const char* at, size_t length){ char header_field[MAX_LEN]; strncpy(header_field, at, length); header_field[length] = '\0'; printf("head field: %s\n", header_field); return 0; } int on_header_value(llhttp_t* parser, const char* at, size_t length){ char header_value[MAX_LEN]; strncpy(header_value, at, length); header_value[length] = '\0'; printf("head value: %s\n", header_value); return 0; } int on_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); return 0; } int on_body(llhttp_t* parser, const char* at, size_t length){ char body[MAX_LEN]; strncpy(body, at, length); body[length] = '\0'; printf("on_body: %s\n", body); return 0; } int on_message_complete(llhttp_t* parser){ printf("on_message_complete\n"); return 0; } int main(){ llhttp_t parser; llhttp_settings_t settings; llhttp_settings_init(&settings); llhttp_init(&parser, HTTP_REQUEST, &settings); 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; const char* request = "POST /index.html HTTP/1.1\r\nconnection:close\r\ncontent-length: 1\r\n\r\n1\r\n\r\n"; int request_len = strlen(request); enum llhttp_errno err = llhttp_execute(&parser, request, request_len); if (err != HPE_OK) { fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), parser.reason); } return 0; }
接著看解析響應的例子。
#include #include #include "llhttp.h" #define MAX_LEN 2048 int on_message_begin(llhttp_t* parser){ printf("parse start\n"); return 0; } int on_url(llhttp_t* parser, const char* at, size_t length){ char url[MAX_LEN]; strncpy(url, at, length); url[length] = '\0'; printf("on_url: %s\n", url); return 0; } int on_status(llhttp_t* parser, const char* at, size_t length){ char status[MAX_LEN]; strncpy(status, at, length); status[length] = '\0'; printf("on_status: %s\n", status); return 0; } int on_header_field(llhttp_t* parser, const char* at, size_t length){ char header_field[MAX_LEN]; strncpy(header_field, at, length); header_field[length] = '\0'; printf("head field: %s\n", header_field); return 0; } int on_header_value(llhttp_t* parser, const char* at, size_t length){ char header_value[MAX_LEN]; strncpy(header_value, at, length); header_value[length] = '\0'; printf("head value: %s\n", header_value); return 0; } int on_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); return 0; } int on_body(llhttp_t* parser, const char* at, size_t length){ char body[MAX_LEN]; strncpy(body, at, length); body[length] = '\0'; printf("on_body: %s\n", body); return 0; } int on_message_complete(llhttp_t* parser){ printf("on_message_complete\n"); return 0; } int main(){ llhttp_t parser; llhttp_settings_t settings; 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; const char* reponse = "HTTP/1.1 200 OK\r\nServer: nginx\r\ncontent-length: 11\r\n\r\nhello:world\r\n\r\n"; int reponse_len = strlen(reponse); enum llhttp_errno err = llhttp_execute(&parser, reponse, reponse_len); if (err != HPE_OK) { fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), parser.reason); } return 0; }
llhttp 目前支援以下鉤子回撥。
struct llhttp_settings_s { /* Possible return values 0, -1, `HPE_PAUSED` */ llhttp_cb on_message_begin; /* Possible return values 0, -1, HPE_USER */ llhttp_data_cb on_url; llhttp_data_cb on_status; llhttp_data_cb on_header_field; llhttp_data_cb on_header_value; /* Possible return values: * 0 - Proceed normally * 1 - Assume that request/response has no body, and proceed to parsing the * next message * 2 - Assume absence of body (as above) and make `llhttp_execute()` return * `HPE_PAUSED_UPGRADE` * -1 - Error * `HPE_PAUSED` */ llhttp_cb on_headers_complete; /* Possible return values 0, -1, HPE_USER */ llhttp_data_cb on_body; /* Possible return values 0, -1, `HPE_PAUSED` */ llhttp_cb on_message_complete; /* When on_chunk_header is called, the current chunk length is stored * in parser->content_length. * Possible return values 0, -1, `HPE_PAUSED` */ llhttp_cb on_chunk_header; llhttp_cb on_chunk_complete; /* Information-only callbacks, return value is ignored */ llhttp_cb on_url_complete; llhttp_cb on_status_complete; llhttp_cb on_header_field_complete; llhttp_cb on_header_value_complete;};
我們也可以以靜態庫或動態庫的方式使用 llhttp。執行 make all 就會在 build 目錄下生成靜態和動態庫,我們把標頭檔案 llhttp.h 和 靜態庫或動態庫複製到自己專案裡使用就可以,編譯的時候加上 -lllhttp -L.。
總結:llhttp 的使用上還算比較簡單清晰,如果我們專案裡需要解析 HTTP 協議的話可以試試,使用 demo 可以參考 。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2837744/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- EMQX_AUTH_HTTP 認證外掛使用指南MQHTTP
- .OBJ解析器的實現OBJ
- 解析-解析器
- JavaPoet的使用指南Java
- Graphviz的使用指南
- 解析-HTML 解析器HTML
- 二維碼解析器
- XML DOM 解析器概述XML
- SQL解析器詳解SQL
- Maven使用指南的筆記Maven筆記
- Android中WebView的使用指南:AndroidWebView
- 手寫javascript json解析器JavaScriptJSON
- 配置多檢視解析器
- 手寫一個解析器
- HTTP、HTTP1.1、HTTP/2的區別HTTP
- ESLint 使用指南EsLint
- SOAR 使用指南
- Rundeck使用指南
- gulp 使用指南
- FontAwesome使用指南
- ConstraintLayout使用指南AI
- git使用指南Git
- MacTeX 使用指南Mac
- SQLT 使用指南SQL
- Lombok使用指南Lombok
- CompletableFuture 使用指南
- Vim使用指南
- nmap使用指南
- GPG 使用指南
- Atom使用指南
- JMH 使用指南
- gulp使用指南
- OpenSUSE 使用指南
- jira 使用指南
- 最全面的Navigation的使用指南Navigation
- jbock:無反射的Java命令列引數解析器反射Java命令列
- c# 怎樣能寫個sql的解析器C#SQL
- Vue.js 模板解析器原理Vue.js