ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

fluent-bit 内置 nghttp2 之 HPACK 解压器初始化:nghttp2_hd_inflate_new 全解析

fluent-bit 内置 nghttp2 之 HPACK 解压器初始化:nghttp2_hd_inflate_new 全解析 fluent-bit 内置 nghttp2 之 HPACK 解压器初始化nghttp2_hd_inflate_new 全解析【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit导读本文聚焦于 Fluent Bit 项目内置的 HTTP/2 实现库 nghttp2 中HPACK 头字段解压inflate入口函数nghttp2_hd_inflate_new。该函数负责为名称/值对name/value pairs的解压流程初始化一个nghttp2_hd_inflater解压器对象是服务端接收压缩请求头、客户端解析压缩响应头的第一道工序。读完本文你将掌握该函数的原型、初始化流程、失败语义、配套生命周期函数以及它在 nghttp2 解压状态机与 Fluent Bit HTTP/2 请求处理链路中的真实位置。函数速览初始化一个 HPACK 解压器nghttp2_hd_inflate_new的完整声明位于 lib/nghttp2-1.65.0/lib/includes/nghttp2/nghttp2.h对应的参考文档即 lib/nghttp2-1.65.0/doc/nghttp2_hd_inflate_new.rst使用它需要包含头文件#include nghttp2/nghttp2.h函数原型int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);参数inflater_ptr指向nghttp2_hd_inflater *指针的指针。成功时新分配并完成初始化的解压器对象被写入*inflater_ptr返回值成功返回0失败返回负错误码见下文错误码一节失败语义重要若函数失败*inflater_ptr保持原值不变left untouched。这意味着调用方在失败后不能读取*inflater_ptr也不需要对其执行释放操作只需直接返回错误即可。nghttp2_hd_inflater是一个不透明类型opaque struct其完整结构定义不暴露给应用层头文件中仅给出前置声明struct nghttp2_hd_inflater; typedef struct nghttp2_hd_inflater nghttp2_hd_inflater;见 lib/nghttp2-1.65.0/lib/includes/nghttp2/nghttp2.h。应用层只能通过本函数及配套的nghttp2_hd_inflate_hd3()、nghttp2_hd_inflate_end_headers()、nghttp2_hd_inflate_del()等公开 API 来操作它。底层实现new → new2 → init 的两级调用链从源码结构看nghttp2_hd_inflate_new的实现非常简洁它只是一个转发封装真实逻辑在nghttp2_hd_inflate_new2与nghttp2_hd_inflate_init中完成三者形成清晰的调用链int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr) { return nghttp2_hd_inflate_new2(inflater_ptr, NULL); } int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr, nghttp2_mem *mem) { int rv; nghttp2_hd_inflater *inflater; if (mem NULL) { mem nghttp2_mem_default(); } inflater nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_inflater)); if (inflater NULL) { return NGHTTP2_ERR_NOMEM; } rv nghttp2_hd_inflate_init(inflater, mem); if (rv ! 0) { nghttp2_mem_free(mem, inflater); return rv; } *inflater_ptr inflater; return 0; }以上实现位于 lib/nghttp2-1.65.0/lib/nghttp2_hd.c。几个关键设计点默认分配器nghttp2_hd_inflate_new2的mem参数为NULL时自动回退到nghttp2_mem_default()因此nghttp2_hd_inflate_new等价于使用默认内存分配器的new2先分配后初始化先用nghttp2_mem_malloc按sizeof(nghttp2_hd_inflater)分配内存再调用nghttp2_hd_inflate_init完成字段初始化失败回滚一旦nghttp2_hd_inflate_init返回非零例如内部hd_context_init失败立即nghttp2_mem_free释放已分配的内存并向上返回错误保证*inflater_ptr不被写入——这正是文档所承诺的left untouched语义的落地实现。初始化阶段设置了什么nghttp2_hd_inflate_initlib/nghttp2-1.65.0/lib/nghttp2_hd.c把新对象置于一个确定的初始状态通过hd_context_init初始化 HPACK 上下文含静态表、动态表、内存分配器settings_hd_table_bufsize_max设为默认值NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZEmin_hd_table_bufsize_max设为UINT32_MAX名称/值缓冲区namebuf、valuebuf置空opcode置为NGHTTP2_HD_OPCODE_NONE解压状态机state置为NGHTTP2_HD_STATE_INFLATE_START——即尚未开始解压任何一个头块的初始态Huffman 编码标志huffman_encoded、索引index、剩余待读字节数left等全部清零。对应的struct nghttp2_hd_inflater字段定义见 lib/nghttp2-1.65.0/lib/nghttp2_hd.h其中settings_hd_table_bufsize_max的注释明确说明它承载的是对端通过SETTINGS_HEADER_TABLE_SIZE传来的值而min_hd_table_bufsize_max则记录nghttp2_hd_inflate_change_table_size()设置过的最小表大小。返回的错误码文档明确本函数失败时只可能返回以下负错误码错误码枚举值见 nghttp2.h含义NGHTTP2_ERR_NOMEM-901内存不足。分配nghttp2_hd_inflater结构体或初始化内部缓冲区失败应用层通常配合nghttp2_strerror()将错误码转换为可读字符串用于日志。由于分配是在nghttp2_hd_inflate_new2中显式进行的NGHTTP2_ERR_NOMEM是最主要的失败路径理论上nghttp2_hd_inflate_init内部也可能因hd_context_init的分配失败而返回该错误码。配套生命周期 API初始化之后怎么用、怎么释放nghttp2_hd_inflate_new只是解压器生命周期的起点围绕它还有三个必须配套使用的函数均在 nghttp2.h 中声明nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr, nghttp2_mem *mem)nghttp2_hd_inflate_new的增强版允许传入自定义内存分配器memmem可为NULL等价于new。注意函数不接管mem的所有权调用方负责释放mem且库在函数返回后不再引用mem因此可以安全地及时释放。见 nghttp2.h。nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater)释放解压器占用的全部资源与new/new2配对使用。实现见 lib/nghttp2-1.65.0/lib/nghttp2_hd.c它先调用内部nghttp2_hd_inflate_free释放 name/value 的rcbuf引用与 HPACK 上下文再释放对象本身。nghttp2_hd_inflate_hd3(...)核心解压入口把压缩字节流逐块送入 inflater 并产出解压后的 name/value 对。nghttp2_hd_inflate_end_headers(...)通知 inflater 一个头块header block已结束把状态机复位回NGHTTP2_HD_STATE_INFLATE_START并释放内部暂存的 name/value 引用hd_inflate_keep_free见 lib/nghttp2-1.65.0/lib/nghttp2_hd.c。一个典型的完整生命周期如下nghttp2_hd_inflater *inflater NULL; int rv; /* 1. 初始化解压器失败时 inflater 保持 NULL可直接报错返回 */ rv nghttp2_hd_inflate_new(inflater); if (rv ! 0) { /* 处理 NGHTTP2_ERR_NOMEM 等错误 */ return rv; } /* 2. 循环调用 nghttp2_hd_inflate_hd3() 消费压缩字节流 每次产出带 NGHTTP2_HD_INFLATE_EMIT 标志的 name/value 对 */ /* 3. 头块结束复位解压器 */ nghttp2_hd_inflate_end_headers(inflater); /* 4. 释放解压器 */ nghttp2_hd_inflate_del(inflater);在 HPACK 解压流程中的位置nghttp2_hd_inflate_new是整个 HPACK 解压子系统的构造函数。nghttp2 的官方教程文档 lib/nghttp2-1.65.0/doc/sources/tutorial-hpack.rst 展示了它的典型用法先用本函数创建nghttp2_hd_inflater对象再循环调用nghttp2_hd_inflate_hd3()解压头字段最后用nghttp2_hd_inflate_del()清理。在 nghttp2 内部nghttp2_hd_inflate_hd3的解压状态机在初始化完成后进入NGHTTP2_HD_STATE_INFLATE_START逐字节解析 opcode、整型索引、字符串字面量支持 Huffman 解码并在完整解析出一个 name/value 对后设置NGHTTP2_HD_INFLATE_EMIT标志、通过hd_inflate_commit_newname/hd_inflate_commit_indname提交结果遇到in_final且状态不在起始态时返回NGHTTP2_ERR_HEADER_COMP见 lib/nghttp2-1.65.0/lib/nghttp2_hd.c。这一切都建立在nghttp2_hd_inflate_new正确初始化的基础上。仓库中的单元测试 lib/nghttp2-1.65.0/tests/nghttp2_hd_test.c 与命令行工具 lib/nghttp2-1.65.0/src/inflatehd.cc 都调用了nghttp2_hd_inflate_new来驱动解压流程可以作为理解本函数调用方式的直接参考。小结nghttp2_hd_inflate_new是 nghttp2 向应用层提供的 HPACK 解压器初始化入口具有以下要点成功时在*inflater_ptr中返回一个已初始化状态机处于NGHTTP2_HD_STATE_INFLATE_START、动态表配置为默认容量的nghttp2_hd_inflater对象失败时返回负错误码主要是NGHTTP2_ERR_NOMEM且保证*inflater_ptr不被修改底层实现为nghttp2_hd_inflate_new→nghttp2_hd_inflate_new2默认分配器→nghttp2_hd_inflate_init字段初始化的三级调用链需要与nghttp2_hd_inflate_hd3()、nghttp2_hd_inflate_end_headers()、nghttp2_hd_inflate_del()配对使用构成完整的解压器生命周期需要自定义内存分配器的场景可直接改用nghttp2_hd_inflate_new2并传入nghttp2_mem。【免费下载链接】fluent-bitFast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows项目地址: https://gitcode.com/GitHub_Trending/fl/fluent-bit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表