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