Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
`1.1.x` → `v1.2.0`、`1.2.x` → `v1.3.0`、`1.3.x` → `v1.4.0`、`1.4.1`–`1.4.4` → `v1.5.0`、
`1.5.1`–`1.5.3` → `v1.6.0`;`1.6.1`–`1.6.4` 是它之后的补丁版,不折叠、直接发布;
`1.6.5`–`1.6.61` → `v1.7.0`;`1.7.1`–`1.7.3` 是 `v1.7.0` 之后的开发档线,折进
`v1.7.4`;`1.7.5`–`1.7.6` 折进 `v1.8.0`;`1.8.1`、`1.8.2`、`1.8.3`、`1.8.4`、`1.8.5`、`1.8.6` 是它之后的补丁版,
`v1.7.4`;`1.7.5`–`1.7.6` 折进 `v1.8.0`;`1.8.1`、`1.8.2`、`1.8.3`、`1.8.4`、`1.8.5`、`1.8.6`、`1.8.7`、`1.8.8` 是它之后的补丁版,
不折叠、直接发布。想按时间线读,翻到最后的「逐个版本」。

当前源码树是 **1.8.6**(发布版) —— 即 `src/uvcpp/uvcpp_version.h` 里 `UVCPP_VERSION_STRING`
报告的那个串。已打过的 tag:`v1.0.0`、`v1.1.0`、`v1.2.0`、`v1.3.0`、`v1.4.0`、`v1.5.0`、`v1.6.0`、`v1.6.1`、`v1.6.2`、`v1.6.3`、`v1.6.4`、`v1.7.0`、`v1.7.4`、`v1.8.0`、`v1.8.1`、`v1.8.2`、`v1.8.3`、`v1.8.4`、`v1.8.5`、`v1.8.6`。
当前源码树是 **1.8.8**(发布版) —— 即 `src/uvcpp/uvcpp_version.h` 里 `UVCPP_VERSION_STRING`
报告的那个串。已打过的 tag:`v1.0.0`、`v1.1.0`、`v1.2.0`、`v1.3.0`、`v1.4.0`、`v1.5.0`、`v1.6.0`、`v1.6.1`、`v1.6.2`、`v1.6.3`、`v1.6.4`、`v1.7.0`、`v1.7.4`、`v1.8.0`、`v1.8.1`、`v1.8.2`、`v1.8.3`、`v1.8.4`、`v1.8.5`、`v1.8.6`、`v1.8.7`、`v1.8.8`。
其中若干条来自本仓第一位外部贡献者 [@sercebr](https://github.com/sercebr) 报的 issue。

## 目录
Expand Down Expand Up @@ -471,6 +471,9 @@

### HTTP/3(web 层)

- **extended CONNECT 流的发送队列上限**(`1.8.7`):`write_stream_data()` 的
待发队列限制在 4 MiB,接收端不读(QUIC 窗口打满、nghttp3 停止消费)时整笔
拒绝并返回 `UV_ENOBUFS`,不再无界增长到 OOM。
- **`uvcpp_h3_ws_server` 便捷封装**(`1.8.6`,#58):把 "QUIC 连接 →
`uvcpp_h3_connection` → `on_connect_request` → `uvcpp_h3_ws_connection::accept`"
这段每条应用都要手拼一遍的生命周期收进库里 —— 每条连接一个 h3 连接、按流号
Expand Down Expand Up @@ -1340,6 +1343,9 @@ ODBC** 四个后端,结果行按表取(列名或列号)。**默认关**(

### HTTP 与 WebSocket 语义

- **`connect_wait()` 超时后迟到的连接回调不再写死栈帧**(`1.8.7`):回调状态
改到堆上(`shared_ptr`)。连接超时返回后客户端析构会泵循环,先前那一笔迟到
回调写进已退栈的局部变量,表现为 `SIGSEGV in ~uvcpp_http_client`。
- **v120 上的 WebSocket:帧掩码的两处编译缺口**(`1.8.4`)。`uvcpp_ws_frame` 的
`mask_key[4] = {0}` 是数组成员上的默认初始化器(v120 报 C2536),改成构造函数清零;
掩码 PRNG 的 `static thread_local std::mt19937_64`(类类型,v120 的
Expand Down Expand Up @@ -1573,6 +1579,12 @@ ODBC** 四个后端,结果行按表取(列名或列号)。**默认关**(

### TLS 与网络

- **客户端析构不再漏掉 `uvcpp_ssl`**(`1.8.8`):`~uvcpp_tcp_client()` 的
"循环还在跑"分支原先只把 `tls_ssl_` 置空、不释放,每接一条 TLS 连接就漏
一个 `uvcpp_ssl` 及其 OpenSSL 状态(实测 ~57 KiB/连接;20 条连接 valgrind
报 1,172,840 字节)。现在按句柄状态释放:句柄已摘 ⇒ 当场删;句柄活着 ⇒
交给 `uv_close` 的完成回调(那时调用栈已解开);关闭槽已被占 ⇒ 与包装对象
同一条已知的罕见泄漏路径并告警。
- **域名解析改用 `AF_UNSPEC`,多地址逐个尝试**(`1.8.2`,#44):异步/同步两条路径
都按 `getaddrinfo` 顺序尝试,全部失败返回最后一次的真实错误;SNI 与证书校验仍用
目标域名。SOCKS5 代理连接与 `connect_wait()` 一并受益。
Expand Down Expand Up @@ -4006,6 +4018,33 @@ ODBC** 四个后端,结果行按表取(列名或列号)。**默认关**(
这一节按发版时间倒序,只列**已发布**的 tag。开发档线已折叠进对应的稳定版
(折叠表见开头),所以这里读到的每一版都是一个真实的 tag。

### v1.8.8 (2026-10-27)

`v1.8.7` 之后的补丁:**TLS 客户端析构的内存泄漏**。

**修复**:

- `~uvcpp_tcp_client()` 在"事件循环还在跑"那条分支上只把 `tls_ssl_` 置空、没有
释放 `enable_tls()` 分配的 `uvcpp_ssl`。服务端每接受一条 TLS 连接就漏一份
(valgrind:20 条连接 1,172,840 字节 definitely lost;实测 500 条短连接
RSS +26 MB,常驻服务在空闲时仍以 12–14 MB/min 增长)。现在按句柄状态释放:
句柄已摘 ⇒ 当场删;句柄活着 ⇒ 交给 `uv_close` 的完成回调;关闭槽已被占
⇒ 与包装对象同一条已知罕见的泄漏路径并告警(`tests/functional` 既有
TLS 用例覆盖所有权时序,本版未新增用例)。

### v1.8.7 (2026-10-26)

`v1.8.6` 的补丁:目录/服务端不可达时不再崩溃,并给 HTTP/3 扩展 CONNECT 流
加上发送队列上限。

**修复**:

- `uvcpp_http_client::connect_wait()` 的连接回调状态改到堆上。连接超时返回后,
析构客户端会泵事件循环;迟到的回调不再写入已失效的栈帧(此前表现为
`SIGSEGV in ~uvcpp_http_client`)。
- `uvcpp_h3_session::write_stream_data()` 的待发队列限制为 4 MiB,接收端不读时
返回 `UV_ENOBUFS`,避免 h3 中继把进程拖到 OOM。

### v1.8.6 (2026-10-26)

`v1.8.5` 之后的一版:**浏览器那条 h2 WebSocket 通了**(RFC 8441 extended
Expand Down
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img src="./uvcpp.svg" alt="libuvcpp logo" width="160" height="160">
</p>

[![version](https://img.shields.io/badge/version-1.8.6-blue.svg)](./RELEASE.md)
[![version](https://img.shields.io/badge/version-1.8.8-blue.svg)](./RELEASE.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
[![CI · Linux · Ubuntu](https://github.com/Antruly/libuvcpp/actions/workflows/ci-linux-ubuntu.yml/badge.svg)](https://github.com/Antruly/libuvcpp/actions/workflows/ci-linux-ubuntu.yml)
[![CI · Windows · MSVC](https://github.com/Antruly/libuvcpp/actions/workflows/ci-windows-msvc.yml/badge.svg)](https://github.com/Antruly/libuvcpp/actions/workflows/ci-windows-msvc.yml)
Expand All @@ -14,25 +14,25 @@
🔧 Modern C++11 wrapper for [libuv](https://github.com/libuv/libuv) — event-driven I/O with
object-oriented APIs, dual-mode async/sync support, HTTP/1.1, WebSocket (RFC 6455), and SSL/TLS.

- **Version**: `1.8.6` — **Author**: `zhuweiye` — **License**: `MIT`
- **Version**: `1.8.8` — **Author**: `zhuweiye` — **License**: `MIT`
- **Languages**: [English](./README.md) · [中文](./README.zh.md)

## Download

<!-- downloads:start -->
The newest release is **v1.8.6**. Six prebuilt packages, each one self-contained — the
The newest release is **v1.8.8**. Six prebuilt packages, each one self-contained — the
Release and Debug builds of the library, all the public headers, `uvcpp.pc` and the CMake
package files, and no extra DLLs or `.so` files to ship alongside. Which modules a given
package enables is recorded per version in [CHANGELOG.md](./CHANGELOG.md).

| Platform | Toolchain | Package |
|---|---|---|
| Windows x64 | MSVC 2022 | [libuvcpp-1.8.6-msvc-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-msvc-x64.zip) · 24.0 MB |
| Windows arm64 | MSVC 2022 | [libuvcpp-1.8.6-msvc-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-msvc-arm64.zip) · 24.9 MB |
| Windows x64 | MinGW-w64 (GCC) | [libuvcpp-1.8.6-mingw-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-mingw-x64.zip) · 29.8 MB |
| Windows arm64 | MinGW-w64 (clang + libc++) | [libuvcpp-1.8.6-mingw-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-mingw-arm64.zip) · 22.7 MB |
| Linux x64 | GCC | [libuvcpp-1.8.6-linux-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-linux-x64.zip) · 27.3 MB |
| Linux arm64 | GCC | [libuvcpp-1.8.6-linux-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-linux-arm64.zip) · 27.5 MB |
| Windows x64 | MSVC 2022 | [libuvcpp-1.8.7-msvc-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-msvc-x64.zip) · 24.0 MB |
| Windows arm64 | MSVC 2022 | [libuvcpp-1.8.7-msvc-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-msvc-arm64.zip) · 24.9 MB |
| Windows x64 | MinGW-w64 (GCC) | [libuvcpp-1.8.7-mingw-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-mingw-x64.zip) · 29.8 MB |
| Windows arm64 | MinGW-w64 (clang + libc++) | [libuvcpp-1.8.7-mingw-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-mingw-arm64.zip) · 22.7 MB |
| Linux x64 | GCC | [libuvcpp-1.8.7-linux-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-linux-x64.zip) · 27.3 MB |
| Linux arm64 | GCC | [libuvcpp-1.8.7-linux-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-linux-arm64.zip) · 27.5 MB |

Every earlier release is on the **[Releases page](https://github.com/Antruly/libuvcpp/releases)**.
What a package contains, and why it is laid out that way:
Expand Down
18 changes: 9 additions & 9 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img src="./uvcpp.svg" alt="libuvcpp logo" width="160" height="160">
</p>

[![版本](https://img.shields.io/badge/version-1.8.6-blue.svg)](./RELEASE.md)
[![版本](https://img.shields.io/badge/version-1.8.8-blue.svg)](./RELEASE.md)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
[![CI · Linux · Ubuntu](https://github.com/Antruly/libuvcpp/actions/workflows/ci-linux-ubuntu.yml/badge.svg)](https://github.com/Antruly/libuvcpp/actions/workflows/ci-linux-ubuntu.yml)
[![CI · Windows · MSVC](https://github.com/Antruly/libuvcpp/actions/workflows/ci-windows-msvc.yml/badge.svg)](https://github.com/Antruly/libuvcpp/actions/workflows/ci-windows-msvc.yml)
Expand All @@ -14,24 +14,24 @@
🔧 基于 [libuv](https://github.com/libuv/libuv) 的现代 C++11 封装库 — 面向对象的异步 I/O,
支持双模式(异步回调/同步等待)、HTTP/1.1、WebSocket(RFC 6455)和 SSL/TLS。

- **版本**:`1.8.6` — **作者**:`zhuweiye` — **许可证**:`MIT`
- **版本**:`1.8.8` — **作者**:`zhuweiye` — **许可证**:`MIT`
- **语言**:[English](./README.md) · [中文](./README.zh.md)

## 下载

<!-- downloads:start -->
最新版本是 **v1.8.6**。六个预编译包,每一个都自包含 —— 带 Release 与 Debug 两档库、
最新版本是 **v1.8.8**。六个预编译包,每一个都自包含 —— 带 Release 与 Debug 两档库、
全部公开头文件、`uvcpp.pc` 与 CMake 包配置,旁边不需要再放任何 DLL 或 `.so`。
某一版的包里到底开了哪些模块,按版本记在 [CHANGELOG.md](./CHANGELOG.md) 里。

| 平台 | 工具链 | 包 |
|---|---|---|
| Windows x64 | MSVC 2022 | [libuvcpp-1.8.6-msvc-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-msvc-x64.zip) · 24.0 MB |
| Windows arm64 | MSVC 2022 | [libuvcpp-1.8.6-msvc-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-msvc-arm64.zip) · 24.9 MB |
| Windows x64 | MinGW-w64(GCC) | [libuvcpp-1.8.6-mingw-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-mingw-x64.zip) · 29.8 MB |
| Windows arm64 | MinGW-w64(clang + libc++) | [libuvcpp-1.8.6-mingw-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-mingw-arm64.zip) · 22.7 MB |
| Linux x64 | GCC | [libuvcpp-1.8.6-linux-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-linux-x64.zip) · 27.3 MB |
| Linux arm64 | GCC | [libuvcpp-1.8.6-linux-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.6/libuvcpp-1.8.6-linux-arm64.zip) · 27.5 MB |
| Windows x64 | MSVC 2022 | [libuvcpp-1.8.7-msvc-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-msvc-x64.zip) · 24.0 MB |
| Windows arm64 | MSVC 2022 | [libuvcpp-1.8.7-msvc-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-msvc-arm64.zip) · 24.9 MB |
| Windows x64 | MinGW-w64(GCC) | [libuvcpp-1.8.7-mingw-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-mingw-x64.zip) · 29.8 MB |
| Windows arm64 | MinGW-w64(clang + libc++) | [libuvcpp-1.8.7-mingw-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-mingw-arm64.zip) · 22.7 MB |
| Linux x64 | GCC | [libuvcpp-1.8.7-linux-x64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-linux-x64.zip) · 27.3 MB |
| Linux arm64 | GCC | [libuvcpp-1.8.7-linux-arm64.zip](https://github.com/Antruly/libuvcpp/releases/download/v1.8.7/libuvcpp-1.8.7-linux-arm64.zip) · 27.5 MB |

更早的版本都在 **[Releases 页](https://github.com/Antruly/libuvcpp/releases)**。
包里装了什么、为什么是这个形状:[doc/release-process.md](doc/release-process.md)。
Expand Down
18 changes: 18 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,24 @@

**libuvcpp** 是一个基于 libuv 的现代 C++ 封装库,提供简洁的面向对象接口来使用 libuv 的异步 I/O 功能。

## v1.8.8 重点 (Highlights)

`v1.8.7` 的补丁:**TLS 客户端析构泄漏 `uvcpp_ssl`**。

- 服务端每接受一条 TLS 连接,`~uvcpp_tcp_client()` 都会漏掉一份 `uvcpp_ssl` 及其
OpenSSL 状态(实测 ~57 KiB/连接)。改动后按句柄状态释放:句柄已摘就地删、
句柄活着交给 `uv_close` 的完成回调,只有"关闭槽已被占"这条已知罕见的路径
继续告警并留下。
- 其余行为与 1.8.7 一致;六个平台包与调试档不变。

## v1.8.7 重点 (Highlights)

`v1.8.6` 的补丁:目录/服务端不可达时不再崩溃,并给 HTTP/3 扩展 CONNECT 流加上发送队列上限。

- **不可达服务器的析构崩溃**:`uvcpp_http_client::connect_wait()` 的连接回调状态改到堆上。连接超时返回后,析构客户端会泵事件循环;迟到的回调不再写入已失效的栈帧(此前表现为 `SIGSEGV in ~uvcpp_http_client`)。
- **HTTP/3 发送队列上限**:`write_stream_data()` 的待发队列限制为 4 MiB,接收端不读时返回 `UV_ENOBUFS`,避免 h3 中继把进程拖到 OOM。
- 其余行为与 1.8.6 一致;六个平台包与调试档不变。

## v1.8.6 重点 (Highlights)

`v1.8.5` 之后的一版:**WebSocket 不再只有 HTTP/1.1 那一档**(#58)。
Expand Down
12 changes: 6 additions & 6 deletions doc/http2-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ done)` → 最后一块 `end_stream = true`。三处要点:
**低层没有请求侧的合并入口** —— `uvcpp_h2_connection` 上的四个 `send_*` 全是响应侧的。
客户端提交完请求**必须自己调 `flush()`**。这一点在
`tests/functional/web_ssl_h2_server_func.cpp:461-461` 有一段专门的告诫,
库内正解在 `src/web/uvcpp_http_client.cpp:1840-1840`:
库内正解在 `src/web/uvcpp_http_client.cpp:1849-1849`:

```cpp
// doc-snippet: fragment — 从库内调用点摘的三句,前后文不在本页
Expand Down Expand Up @@ -314,10 +314,10 @@ void doc_h2_client_submit(uvcpp::uvcpp_h2_connection* conn) {
```

`uvcpp_http_client` 那条线是同一套顺序:`set_http2_enabled(true)`
(`src/web/uvcpp_http_client.cpp:1744-1744`)→ `connect()` 里 `enable_tls` 加 ALPN 名单
(`src/web/uvcpp_http_client.cpp:1753-1753`)→ `connect()` 里 `enable_tls` 加 ALPN 名单
(`src/web/uvcpp_http_client.cpp:292-292` / `src/web/uvcpp_http_client.cpp:308-308`,`h2` 在前、`http/1.1` 兜底)→ connect 成功回调里读
`tls_alpn_selected()`(`src/web/uvcpp_http_client.cpp:327-327`)→ `start_h2()`(`src/web/uvcpp_http_client.cpp:331-331` → `src/web/uvcpp_http_client.cpp:1772-1772`)→ 装回调(`src/web/uvcpp_http_client.cpp:1774-1774`)
→ `h2_->start(sc, cc)`(`src/web/uvcpp_http_client.cpp:1815-1815`)→ `send()` 分流到 `send_h2`(`src/web/uvcpp_http_client.cpp:480-480`)。
`tls_alpn_selected()`(`src/web/uvcpp_http_client.cpp:327-327`)→ `start_h2()`(`src/web/uvcpp_http_client.cpp:331-331` → `src/web/uvcpp_http_client.cpp:1781-1781`)→ 装回调(`src/web/uvcpp_http_client.cpp:1783-1783`)
→ `h2_->start(sc, cc)`(`src/web/uvcpp_http_client.cpp:1824-1824`)→ `send()` 分流到 `send_h2`(`src/web/uvcpp_http_client.cpp:489-489`)。

**`set_http2_enabled` 默认是关的**(`src/web/uvcpp_http_client.h:624-624`、
`src/web/uvcpp_http_server.h:357-357`)—— 低层的两条线都要显式打开,
Expand Down Expand Up @@ -349,7 +349,7 @@ void doc_h2_client_submit(uvcpp::uvcpp_h2_connection* conn) {
**二、客户端交付响应只能放 `on_response_end`。** 带 body 的响应里 `on_response` 的
`end_stream` **恒为 false**,而 DATA 的 END_STREAM 不经过任何回调 ——
没有 `on_response_end` 就分不出"响应到头了"和"响应全收完了"
(`src/web/uvcpp_http_client.cpp:1786-1786`、`src/http2/uvcpp_h2_session.h:155-161`)。
(`src/web/uvcpp_http_client.cpp:1795-1795`、`src/http2/uvcpp_h2_session.h:155-161`)。

另外,**服务端侧的 `uvcpp_h2_stream::response` 初值是 `HTTP_STATUS_NONE` 而不是 `200`**
(`src/http2/uvcpp_h2_session.h:71`)。这不是疏漏:流在响应头到达之前被 RST
Expand Down Expand Up @@ -473,7 +473,7 @@ if (rv < 0) { // src/http2/uvcpp_h2_session.cpp:973-973

可不可重试的判定**不在这一层**,在 `web/` 侧:`H2_ERR_REFUSED_STREAM` 才算
`retryable`,`NO_ERROR` 与 `CANCEL` 都算正常收尾
(`src/web/uvcpp_http_client.cpp:1926-1926`)。
(`src/web/uvcpp_http_client.cpp:1935-1935`)。

---

Expand Down
6 changes: 3 additions & 3 deletions doc/http2-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
会把明文整条腿判死,而两个都收等于给混淆代理开后门,RFC 9113 §8.1.1)、连接专属头一律拒、
重复且不一致的 `content-length` 即拒、多份 `cookie` 按 `; ` 拼回原样、
收尾的 trailer 识别成"流的结束信号"(`src/http2/uvcpp_h2_session.cpp:590-590`)。
- **流关闭的错误码分三档**(`src/web/uvcpp_http_client.cpp:1906-1906`,RFC 9113 §8.7):
- **流关闭的错误码分三档**(`src/web/uvcpp_http_client.cpp:1915-1915`,RFC 9113 §8.7):
`NO_ERROR` 是我们自己收摊、`REFUSED_STREAM(7)` 是"这条请求没被处理过"、
`CANCEL(8)` 是"对端不要这条流了" —— 三档都报 `UV_ECANCELED`;其余一律
`UV_EPROTO`(协议失败)。其中**只有 `REFUSED_STREAM`** 会把
Expand Down Expand Up @@ -159,10 +159,10 @@
也是空的,一个字节都不影响发出去的请求。
现在两个方向都兑现了:响应说 `close`(含 `Connection` 逗号列表里不在首项的
`close`)就在交付回调之前清掉 `HTTP_CLIENT_CONNECTED`
(`src/web/uvcpp_http_client.cpp:927-947`),第二次 `send()` 同步拒成
(`src/web/uvcpp_http_client.cpp:936-956`),第二次 `send()` 同步拒成
`UV_ENOTCONN` —— 与 h2 那条 `peer_goaway_received()` 的提前拦截同一形状;
`set_keep_alive(false)` 则让请求真的带上 `connection: close`
(`src/web/uvcpp_http_client.cpp:582-601`)。
(`src/web/uvcpp_http_client.cpp:591-610`)。
用例:`tests/functional/web_http_client_keepalive_func.cpp`。
两件事都属于 h1,与本页的 h2 无关,留在这儿只为了让下次盘查的人不必再核一遍。

Expand Down
Loading
Loading