Releases: Hical61/Hical
Releases · Hical61/Hical
v2.6.5
Added
- Expect: 100-continue 支持(#8):Router 新增
exists()路由预检方法,HttpSessionImpl 解析Expect头;路由不存在返回 404,body 大小超限返回 413,均通过时发送100 Continue让客户端传输 body。配套集成测试
Changed
setBodyAPI 变更(#9):setBody(body)单参版本不再自动覆写Content-Type,得用双参setBody(body, contentType)手动传。框架内部所有内置错误响应(notFound/badRequest/serverError/rangeNotSatisfiable)和调用点都改成显式传参了OpenApiDocument::generateString()线程安全:改成按值返回,之前invalidate()跨线程调的时候跟generateString()并发读会有 data race/docs页面缓存:加了Cache-Control: public, max-age=3600recommendedMaxConnections上限放开:从 65535 提到 100 万
Performance
- 空闲长连接内存砍半:搞了个
ReadBufferPool(thread_local 无锁池,BufferHandleRAII 接管借还),空闲时不占 readBuf,来了请求借一块、写完了还回去。空闲连接从 17.44 KB 降到 ~8 KB。顺带把GenericConnection::inputBuffer_改成optional<PmrBuffer>懒分配,readLoop 第一次进来才创建,每个空闲连接再省 ~2 KB。按百万长连接算总共省了大概 9.5 GB HeaderMap::toLower()编译期 256 查表:constexpr array替代挨个tolower(),头部大小写归一化热路径加速Router::urlDecode()编译期 hex 查表:256 条constexpr查表替代运行时分支判断,URL 解码加速HttpSessionImplConnection 头预扫描:解析 header 时顺手把Connection值抓出来,省了后面单独 O(n) 扫一遍
Fixed
- burst 建连时连接数限制失效:原来逻辑是先 load 判断再 fetch_add,但
handleSession走coSpawn异步投递,高速建连时计数跟不上,限流失效。改成 accept 处先 fetch_add 占位,超限就 fetch_sub 退回来 close socket,AcceptGuardRAII 保底不回漏;maxConnections_改成atomic让多 acceptor 并发没问题 - WS 升级路径堆损坏:一串三个生命周期 bug——PoolSlots 线程退出时裸指针没释放(LeakSanitizer 能抓到)、IOCP 两阶段析构后 readBuf 还到已销毁的 tlsPool、socket move 后 idleEntry 还挂在 IdleScanner 链表上。修法:move socket 前把 readBuf 和 Guard 都先 release 掉,handleWebSocket 签名改成接 string 参数,从根上断了对 readBuf 的引用
- MinGW thread_local 析构时序炸堆:CI 上 msys2-gcc 测试跑完了退进程时爆 0xC0000374 或 SEGFAULT。原因是 PoolSlots 的析构在 DLL TLS 回调里跑,那时候 CRT 堆已经没了。修法:
#ifndef __MINGW32__跳过 MinGW 下的 TLS 清理,进程退出 OS 自己收 - AsyncFileSink 析构 data race:bgThread_ 成员声明在 flushRequests_ 前面,C++ 反向析构时 flushRequests_ 先被销毁,后台线程还在写它,TSan(Clang-20)抓到。把 bgThread_ 移到 flushRequests_ 后面,保证先 join 线程再销毁队列
Full Changelog: v2.6.4...v2.6.5
v2.6.4
Added
IdleScanner集中式空闲连接扫描(IdleScanner.h/cpp):per-io_context 单定时器 + 侵入式双链表替代 per-connectionsteady_timer协程。Entry嵌入协程栈(零堆分配),atomic<int64_t> lastActiveMs无锁时间戳,GuardRAII 管理注册/注销生命周期。扫描间隔max(1s, timeout/4),shutdown()幂等取消 timer 切断与timer_service的依赖StringPool线程本地字符串对象池(StringPool.h):5 级大小类(256/512/1K/2K/4K,各 32 槽),acquire(size)返回池化shared_ptr<string>,自定义 deleter 归还池中。send()热路径池化避免 per-send malloc/free
Performance
- IdleScanner 替代 per-connection timer:每连接独立
steady_timer协程改为每 io_context 一个IdleScanner集中扫描,消除每连接的 timer 协程帧分配和epoll_ctl调用 - EventLoopPool 最少连接分发:
nextLoop()从 round-robin 改为挑选connectionCount_最小的 loop,负载均衡更优 - GenericConnection writeLoop drain 上限:
kMaxDrainBatch = 256限制单轮 drain 节点数,防止突发队列饥饿 io_context 其他任务 - DbConnectionPool acquire 快速淘汰:
acquire()在持锁期间isAlive()预检,死连接收集后在锁外析构,避免无效 ping - idleCheckLoop 精确唤醒:
min_element找到最早过期的空闲连接,timer 精确到期唤醒,idleCheckInterval作为最大等待兜底,减少无效扫描 - 响应前缀模板化:连接级
responsePrefix[128]预构建Server/Connection/Date通用头部 wire bytes(~90B),keep-alive 请求memcpy替代 3 次HeaderMap::insert+ 序列化循环
Fixed
- IdleScanner UAF:
idleScanners_声明顺序调整到baseLoop_/ioPool_之前(scanner 比 io_context 后析构),timer_改optional<steady_timer>+shutdown()在~HttpServer()中提前 cancel+reset timer,双向切断 scanner ↔ io_context 环形依赖 - Windows IOCP 关服 SegFault:根因为
io_context::stop()后 IOCP queue 中 abort completions 未 dispatch,~io_context()强杀协程帧导致崩溃。最终方案:移除io_context::stop()调用,改为 cancel 所有 pending op +releaseWork()释放 work_guard,协程自然退出后run()返回,queue 为空无两阶段销毁问题。同时修复stop()跨线程直接操作 timer/socket 的 UB(改为post到对应线程)、WS 升级后连接未注册到 scanner、gcLooptimer 提升为成员变量gcTimer_确保可 cancel、IdleScanner新增closeAll()关闭残留 socket
Full Changelog: v2.6.3...v2.6.4
v2.6.3
Added
- HTTP 206 Range 请求:
StaticFiles支持单范围Range/If-RangeETag 条件请求,parseByteRange()解析器,HttpResponse新增FileBody(path/offset/length)延迟异步分块发送,200 响应自动添加Accept-Ranges: bytes MimallocResource:可选 mimalloc 作为 PMR 最底层 upstream 分配器(HICAL_WITH_MIMALLOCCMake 选项,Conan/vcpkg 同步)
Changed
- 统一命名风格:
m_前缀全部迁移为尾下划线,static constexpr常量改用k前缀,枚举值补h前缀
Performance
- GenericConnection MPSC 无锁写队列:写队列从
mutex+deque升级为 Vyukov Intrusive MPSC Queue(wait-free O(1) push,摊销 O(1) pop),移除isInLoopThread分支和lock_guard,writeLoop批量 drain +seq_cst反饥饿 re-check - TcpServer 连接表 per-loop 分片:全局
mutex+unordered_set改为 per-loopLoopShard,idle 扫描/增删全程无锁 - requestPool 无锁扩容:
createRequestPool()upstream 从globalPool改为threadLocalPool,扩容零锁竞争 - Worker 线程 CPU 亲和性绑核(Linux):
EventLoopPool::start()使用pthread_setaffinity_np将 worker 线程绑定到对应 CPU 核心,减少线程迁移导致的 TLB flush 和跨核 IPI - coSpawn recycling_allocator:所有
coSpawn()重载改用boost::asio::bind_allocator(recycling_allocator<void>(), ...)包装 completion handler,thread_local缓存避免高并发下重复 malloc/free - Idle timeout 条件初始化:
HttpSessionImpl会话协程中socketAlive/lastActiveMs仅在idleTimeout_ > 0时分配,benchmark 场景设setIdleTimeout(0)后每连接省 3 次make_shared+ 1 个 timer 协程 - SocketGuard 条件 shutdown:析构时仅在
cleanExit(正常 keep-alive 结束)才执行shutdown(),避免对已断开连接的无效系统调用 - HTTP 响应前缀模板化:连接级预构建
Server/Connection/Date三个通用头部的 wire bytes(~90B),keep-alive 请求直接memcpy替代 3 次HeaderMap::insert+ 逐字段序列化循环;Date值每秒最多一次 29B 覆写。新增NativeResponse::serializeHeadTo(buf, prefix, prefixLen)带前缀重载 - TcpCorkGuard 文件响应合并小包:
writeFileResponse路径新增 RAIITcpCorkGuard(LinuxTCP_CORK/ macOSTCP_NOPUSH/ Windows no-op),将头部(~200B)与首个 64KB 文件 chunk 合并为一个 TCP 段发送,消除 TCP_NODELAY 下的小包问题 - Docker 压测环境升级:启用 mimalloc 分配器(
HICAL_WITH_MIMALLOC=ON)、RPS/RFS 网络亲和配置(bench-entrypoint.sh)、容器内存提升至 1GB + fd 上限 65536
Full Changelog: v2.6.2...v2.6.3
v2.6.2
Added
- WsHub 广播管理器(
WsHub.h/cpp):连接注册/移除、房间分组、广播(shared_mutex+weak_ptr,跨线程coSpawn安全写入) - WebSocket Binary 消息:
sendBinary()/receiveMessage()支持 Text/Binary 类型区分 - WebSocket 写串行化:
acquireWrite()/releaseWrite()防止 Ping 与消息并发async_write - WebSocket 自定义关闭码:
closeAsync(code, reason)+ 连接上下文setContext()/getContext<T>() - WebSocket 心跳:
WsOptions增加心跳间隔配置,集成 Ping 协程 - WebSocket 子协议协商:
negotiateSubprotocol()服务端优先匹配 +Sec-WebSocket-Protocol响应头 - WebSocket 参数路由:
findWsRoute()返回WsRouteMatch支持{param}路径参数
Changed
- WebSocket 代码消重 + 零分配优化:
receive()/receiveMessage()合并为receiveInternal(),消除 ~150 行重复;WsHubbroadcast 合并为broadcastImpl,接口统一改string_view;透明哈希应用于allowedOrigins/rooms;握手 key 拼接改栈上char[64];sendTo()单目标用string move替代shared_ptr控制块分配 - vcpkg ports 完善:picohttpparser 声明为正式依赖(对应 vcpkg#51743),新增
ports/picohttpparser/overlay port,移除 bundled 构建
Performance
- GenericConnection WriteEntry 去虚函数化:内联
shared_ptr<string>消除三层间接(shared_ptr→control block→WriteNode→虚函数),字段按访问频率重排 +alignas(64)隔离lastActiveTimeMs_ - MemoryPool TrackedResource:四个 atomic 计数器各自
alignas(64)消除 false sharing,新增HICAL_ENABLE_MEMORY_TRACKING条件编译(关闭时零开销) - Middleware MiddlewareTimingStats:热计数器
alignas(64)+ 冷数据移至末尾
Fixed
- AsioEventLoop::stop() 数据竞争:
quit_.exchange(true)一次性门卫,确保workGuard_.reset()/stop()只执行一次 - TSan 检出的 3 处数据竞争:
threadId_改std::atomic;AsioTimer::cancel()post 到 executor 线程执行;TcpServer::stop()acceptor 关闭 post 到baseLoop_线程 HICAL_ENABLE_MEMORY_TRACKINGCMake 选项缺失:补充option(默认 ON)+ PUBLIC compile definition,修复 4 个依赖 stats 的测试断言失败WsDeflate.cpp缺少#include <cstdint>(PR #7)
New Contributors
Full Changelog: v2.6.0...v2.6.2
v2.6.1
Added
- HTTP Date 头缓存:
thread_local每秒更新一次,响应自动插入 RFC 7231Date头
Changed
hical_core强制静态库:移除WINDOWS_EXPORT_ALL_SYMBOLS,add_library显式 STATIC- picohttpparser 条件集成:新增
HICAL_USE_SYSTEM_PICOHTTPPARSER开关,include 从 PUBLIC 改为 PRIVATE - tests/CMakeLists.txt 重构:提取
hical_add_test()函数消除重复样板 - bench_main.cpp 精简为 TFB 专用:仅
/json+/plaintext - Conan/vcpkg 构建完善:Conan 新增
with_openapi选项和宏透传,vcpkg port 新增 picohttpparser 系统依赖
Bug Fixes
- fix: idleTimerLoop 悬空引用 (steady_timer& → shared_ptr<steady_timer>)
- fix: idleTimerLoop cancel 后 yield 确保协程帧退出
- fix: 回退 co_await post() yield,与 stopAllLoops 竞态导致 double-free
- fix: HttpServer 成员析构顺序 (activeConnections_/draining_ 移到 baseLoop_ 之前)
Performance
- perf: HTTP pipelining 优化:parse-before-read 快速路径 + 延迟 memmove
Build & Ports
- chore: 添加 HICAL_USE_SYSTEM_PICOHTTPPARSER CMake 选项
- chore: 新增 picohttpparser vcpkg port (对应 microsoft/vcpkg#51743)
- chore: v2.6.1 构建系统整理与 Date 头缓存
- chore: 分离 TFB 与框架对比 benchmark 入口
Full Changelog: v2.6.0...v2.6.1
v2.6.0
Breaking Changes
- 移除 Boost.Beast 依赖:HTTP 解析/序列化和 WebSocket 全部替换为自研实现,
native()返回自研NativeRequest/NativeResponse(原 Beast 类型) - 新增 zlib 依赖:WebSocket permessage-deflate 压缩需要 zlib
Added
- 原生 HTTP 栈:集成 picohttpparser 替代 Beast HTTP parser(CPU 占比 10% → 0.08%),零拷贝
NativeRequest(string_view引用连接级readBuf,栈上RequestHeaders零堆分配),自研NativeResponse序列化(FixedBuffer<512>栈缓冲 + scatter-gather I/O) - 自研 WebSocket 栈(RFC 6455 完整实现):手写帧解析/构造(
WsFrame.h)、握手协议(WsHandshake.h)、permessage-deflate 压缩(WsDeflate.h/cpp,pimpl 封装 zlib),WebSocketSession完全重写为 raw socket 实现,支持消息分片重组 + 控制帧穿插 HeaderMap头部容器:vector<pair>实现,大小写不敏感查找,延迟 reserve(默认构造零堆分配)- SO_REUSEPORT 多 acceptor:每个 worker loop 独立 acceptor,accept 与 I/O 同线程零跨线程调度(Windows 自动回退单 acceptor)
- 连接级 atomic 时间戳超时:替代 per-request timer,keep-alive 连接
epoll_ctl调用降至 0 - Chunked Transfer-Encoding 支持(RFC 7230)
- 错误码统一映射(
Error.h/cpp):36 个ErrorCode+NetworkError结构,隔离上层对 Asio 错误码的直接依赖 coSpawn()扩展:任意 executor 重载 +logOnException替代detached(未捕获异常输出到 stderr)- Docker 压测基础设施:bench-server / bench-wrk Dockerfile + docker-compose 编排
Changed
- QPS 从 27K 提升至 159K(+489%),与 Cinatra/Drogon 持平
HttpServer多 acceptor 架构:acceptLoop参数化支持并发运行,gracefulStop()改为串行化关闭所有 acceptor- 热路径微优化:header 按长度+首字符快速过滤、响应头
insert()O(1) 替代set()O(N)、attributes_延迟构造、FixedBuffer从 4096 降至 512、200 OK 状态行预计算 - RouteGroup 同步中间件链优化:纯同步场景零协程帧开销(10 层同步中间件仅比无中间件低 2.1%)
Fixed
- readBuf 残留数据丢弃:TCP 粘包场景下 keep-alive 请求解析错误,
bufUsed移到循环外修复
Security
- WebSocket 协议校验强化:客户端掩码强制检查、RSV 位限制、控制帧大小限制(≤125B)、zip bomb 防护
- HTTP 头部/Body 大小限制:头部超限返回 431,Body 超限返回 413
Full Changelog: v2.5.2...v2.6.0
v2.5.2
Changed
- Router 同步快速路径:
- 新增
Router::dispatchSync()方法,同步注册的 handler 直接调用返回结果,跳过协程帧分配(~40-130ns/req) - 新增
RouteEntry结构体(asyncHandler+ 可选syncHandler)替代裸RouteHandler存储 - 新增
Router::resolveRoute()内部方法,统一 URL 解码、路径深度校验、静态/参数路由查找、405 检测,dispatch()和dispatchSync()共用,消除 ~40 行重复代码和 404/405 场景的 double-lookup dispatch()也优先检查syncHandler,有值时co_return syncHandler(req)跳过co_await asyncHandler(req)- 同步 handler 注册只存
syncHandler,不再创建 asyncHandler wrapper,消除std::function拷贝 HttpSessionImpl.cpp无中间件路径先尝试dispatchSync(),有值直接返回(零协程帧),nullopt时 fallback 到co_await dispatch()
- 新增
- GenericConnection 编译防火墙:
- 模板方法实现从
GenericConnection.h(~780 行)提取到GenericConnection.hci,头文件仅保留声明 +extern template声明 - 显式实例化集中在
GenericConnection.cpp(tcp::socket+ssl::stream<tcp::socket>) .hci文件有#ifndef HICAL_BUILDING_GENERIC_CONNECTION防误包含守卫
- 模板方法实现从
- HttpServer 编译防火墙:
handleSession()+handleWebSocket()从HttpServer.cpp移至HttpSessionImpl.cpp,隔离 Beast HTTP parser/serializer 和 WebSocket 重模板代码- 修改 HttpServer 配置逻辑不再触发 Beast 模板重编译
- MetaJson 错误抛出优化:
throw std::runtime_error(...)从模板代码提取为MetaJsonError.h/cpp中的[[noreturn]]非模板函数(throwTypeMismatch/throwMissingField/throwParseError)- 减少每个用户类型
HICAL_JSON实例化的代码体积,改善 icache 利用率
Fixed
SyncAfterHandler安全约束:禁止修改 body(仅允许setHeader/setCookie),因Content-Length已由prepare_payload()固定,修改 body 会导致 HTTP Content-Length 不一致
Full Changelog: v2.5.1...v2.5.2
v2.5.1
Added
- SyncMiddleware 快速路径(零协程帧中间件):
- 新增
SyncBeforeHandler/SyncAfterHandler/SyncMiddlewareResult类型(Middleware.h) - 新增
MiddlewareEntry统一存储结构(Async/Sync 标签联合) MiddlewarePipeline新增 3 个同步use()重载,RouteGroup新增 2 个buildOptimizedChain()算法:连续 Sync 条目合并为单个协程帧,N 层同步中间件仅 1 次协程帧堆分配
- 新增
MemoryPool::threadLocalPool()公共方法,暴露 thread-local 无锁池资源指针
Changed
- HttpServer 多 io_context 架构:
ioContext_替换为AsioEventLoop baseLoop_+EventLoopPool ioPool_(1 Thread : 1 io_context)acceptLoop()去除make_strand,round-robin 分发到 worker loop(单线程天然串行)- accept 后立即设置
TCP_NODELAY减少 Nagle 延迟 stop()/gracefulStop()改为停止所有 loop(baseLoop + ioPool)
handleSession()请求级 PMR 池改为栈上monotonic_buffer_resource+ thread-local 无锁池作 upstream,消除make_unique堆分配和同步锁竞争MiddlewarePipeline::build()/buildFor()非 profiling 路径改用buildOptimizedChain(entries_)MiddlewarePipeline::size()改为返回entries_.size()(支持纯 Sync 中间件计数)- 新增
HttpServer::recommendedMaxConnections(availableMemoryMB)静态方法:按 25KB/连接 估算并预留 30% 内存,上限 65535,供使用者根据机器内存自行设置maxConnections(默认值仍为 10000) PoolConfig::requestPoolInitialSize默认值从 8192 降至 4096handleSession()主路径去除冗余prepare_payload()调用(已由setBody()/setJsonBody()内部完成)- RouteGroup 中间件预构建优化:
RouteGroup同步分支接入buildOptimizedChain(),组级 Sync 中间件同样享受零协程帧合并
Full Changelog: v2.5.0...v2.5.1
v2.5.0
Added
- 日志系统(6 级日志,零开销设计):
Log.h/cpp—Logger单例 + 6 级LogLevel(Trace/Debug/Info/Warn/Error/Fatal),std::format风格 API(HICAL_LOG_INFO("port={}", 8080))、流式 API(HICAL_LOG_INFO_STREAM << val)、条件宏(HICAL_LOG_INFO_IF)、结构化字段 API(HICAL_LOG_INFO_F),NDEBUG 下 TRACE 编译期消除,thread_local时间戳/线程 ID 缓存,可配置 flush 级别,Fatal 自动 abortLogRecord.h— 结构化日志条目(level/timestamp/threadId/file/line/message +boost::json::objectfields + traceId)LogFormatter.h/cpp— 格式化器接口 +TextFormatter(thread_local时间戳缓存)+JsonFormatter(JSON Lines,UTC 时间戳)LogSink.h/cpp— 可插拔输出后端接口 +StderrSink(fprintf)+FileSink(同步 fwrite + LogFile 轮转)+OStreamSink(线程安全 ostream 包装)LogFile.h/cpp— 日志文件轮转引擎(按大小轮转默认 100MB、最大文件数限制、时间戳序列命名、严格文件名匹配清理)AsyncFileSink.h/cpp— 异步双缓冲文件 Sink(std::jthread+stop_token后台线程、4MB 前后缓冲交换、背压保护丢弃 + 计数、1 秒超时刷盘、优雅关闭含最终缓冲排空)FixedBuffer.h— 栈上固定缓冲区模板(默认 4KB),std::to_chars整数/浮点格式化,溢出自动 fallback 到堆LogChannel.h/cpp— 命名日志通道(独立 level/formatter/sinks),LogChannelRegistry(shared_mutex读多写少),HICAL_LOG_TO通道路由宏LogMiddleware.h/cpp— 洋葱模型日志中间件(OpenSSL RAND_bytes 128 位 trace-id 自动生成,结构化访问日志到命名通道)LogAdmin.h/cpp— 动态日志级别管理端点(GET /admin/log-level查询 +PUT /admin/log-level运行时调整)- 9 个测试文件(97 个用例):test_log / test_log_ndebug / test_fixed_buffer / test_log_file / test_async_file_sink / test_log_formatter / test_log_channel / test_log_middleware / test_log_admin
- OpenAPI 3.0 自动生成模块(
HICAL_WITH_OPENAPI=ON,默认开启,零新依赖):OpenApiSchema.h— 从HICAL_JSON宏自动生成 JSON Schema(基本类型/vector/嵌套结构体/$ref),HICAL_SCHEMA_NAME注册类型名,collectSchemas<T>()递归收集OpenApiRegistry.h/cpp— 路由元数据注册表(HICAL_API()综合标注宏 +builder::*辅助函数、HICAL_ROUTES_WITH_API()增强版路由收集、registerRoutesWithOpenApi()同时注册路由和元数据)OpenApiDocument.h/cpp— 文档组装(惰性生成 + 缓存、自动路径参数提取、同路径不同 method 合并为同一 Path Item)OpenApiEndpoint.h—serveOpenApi()一键注册/openapi.json+/docs(Swagger UI CDN),boost::json::serialize()安全转义防 JS 注入- 1 个测试文件(35 个用例):test_openapi
- 1 个示例:examples/openapi_server.cpp
Full Changelog: v2.4.0...v2.5.0
v2.4.0
Added
- CORS 中间件:
Cors.h—makeCorsMiddleware(CorsOptions{...}),支持 Origin 通配符/精确匹配、Preflight OPTIONS 自动响应、Vary: Origin缓存提示、凭证模式下禁止通配符安全校验、可配置 maxAge
- 路由组(Route Group):
RouteGroup.h/cpp—router.group("/api/v1")前缀分组,支持组级中间件继承、多层嵌套、镜像 Router API(get/post/put/del/route)
- HTTP 核心增强:
HttpRequest新增查询参数解析 API(queryParam()/queryParams())和表单参数解析 API(formParam()/formParams())HttpResponse新增redirect()便捷方法HttpServer新增全局错误处理器setErrorHandler(),优雅关闭shutdown()支持- 7 个测试文件:test_query_params / test_form_params / test_redirect / test_cors / test_route_group / test_error_handler / test_graceful_shutdown
Full Changelog: v2.3.0...v2.4.0