False `SendRequest` readiness for HTTP/1 connections
维护者通常 1 天内回复
评估
- 难度
- 4/5
- 预计耗时
- 1-2 天
- 新手友好度
- 55/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- rust
调研方向
Start with the reproduction in the issue and compare the readiness behavior against hyper versions before and after 1.12. Then trace how http1::SendRequest readiness interacts with the connection dispatch queue, using #4207 and #4208 for context. Done when readiness stays pending while a request is in flight and the reproduction no longer observes immediate cancellation.
由索引模型根据 Issue 内容生成。
描述
Version
hyper 1.12
Platform
Darwin 25.6.0
Summary
I believe to have found a readiness race in hyper 1.12 (and at the time of writing master), possibly as a result of the fix for #4207.
http1::SendRequest can signal readiness while a request is still in flight. Using it to send a request results in the request being cancelled immediately.
I have tried to conjure a minimal reproduction example in this gist. With it, you can also set the hyper dependency to <1.12 and observe that the repro test no longer detects the issue.
Code Sample
use std::future::Future;
use std::future::poll_fn;
use std::io;
use std::pin::Pin;
use std::pin::pin;
use std::task::Context;
use std::task::Poll;
use hyper::Request;
use hyper::client::conn::http1;
use hyper::rt::Read;
use hyper::rt::ReadBufCursor;
use hyper::rt::Write;
// Accept writes, but never respond or close: the first request stays in flight.
struct SilentPeer;
impl Read for SilentPeer {
fn poll_read(
self: Pin<&mut Self>,
_: &mut Context<'_>,
_: ReadBufCursor<'_>,
) -> Poll<io::Result<()>> {
Poll::Pending
}
}
impl Write for SilentPeer {
fn poll_write(
self: Pin<&mut Self>,
_: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
Poll::Ready(Ok(buf.len()))
}
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
}
#[tokio::test]
async fn successful_readiness_must_not_be_withdrawn_before_send() {
let (mut sender, connection) = http1::handshake::<_, String>(SilentPeer).await.unwrap();
let mut connection = pin!(connection);
poll_fn(|cx| {
assert!(connection.as_mut().poll(cx).is_pending());
Poll::Ready(())
})
.await;
sender.ready().await.unwrap();
// Retain this future: dropping it would cancel the request.
let _first = sender.send_request(Request::new(String::new()));
poll_fn(|cx| {
// Force the dispatch queue to report Pending despite the queued request.
while let Poll::Ready(budget) = tokio::task::coop::poll_proceed(cx) {
budget.made_progress();
}
assert!(connection.as_mut().poll(cx).is_pending());
match sender.poll_ready(cx) {
Poll::Pending => return Poll::Ready(()), // No false readiness: correct.
Poll::Ready(result) => result.unwrap(), // False readiness!
}
// Model the connection task running on another worker before our send.
let mut driver = pin!(tokio::task::unconstrained(connection.as_mut()));
assert!(driver.as_mut().poll(cx).is_pending());
assert!(
!sender.is_closed(),
"the peer has not closed the connection"
);
let mut second = pin!(sender.send_request(Request::new(String::new())));
let result = second.as_mut().poll(cx);
assert!(
!matches!(result, Poll::Ready(Err(_))),
"send_request failed after poll_ready returned Ready(Ok(())): {result:?}"
);
Poll::Ready(())
})
.await;
}
Expected Behavior
The http1::SendRequest indicates Poll::Pending until it is ready.
Actual Behavior
The http1::SendRequest indicates Poll::Ready and the http1::SendRequest::send_request future fails immediately with an error indicating request cancellation.
Additional Context
Possibly related issues:
- #4207
Possibly related pull requests:
- #4208
- 主要语言
- Rust
- 星标
- 16.4k
- 派生
- 1.8k
- 平均合并
- 1 天 13 小时
- 30 天内合并 PR
- 12
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
hyperium/hyper 的其他 Issue
-
C-feature
难度 1/5 1 小时以内 新手友好度 65/100
hyperium/hyper#2652 · 4 个 reaction ·
维护者通常 1 天内回复
-
C-feature
难度 5/5 一周以上 新手友好度 35/100
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 48/100
维护者通常 1 天内回复
-
can't upgrade request that came in with `Connection: close, Upgrade`可能已有人在做 @akasakariko 于 2 天前认领。 未关闭C-bug
难度 3/5 1-2 天 新手友好度 62/100
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 52/100
维护者通常 1 天内回复
相似的 Issue
-
bug
难度 2/5 1-3 小时 新手友好度 78/100
swc-project/swc-next#1165 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 73/100
Alive24/shea-symphony#574 ·
-
bug tests Windows
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
documentation good first issue help wanted
难度 2/5 1-3 小时 新手友好度 74/100
dev-five-git/devup-ui#879 ·
维护者通常 11 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 77/100
farion1231/cc-switch#9038 · 1 条评论 ·
维护者通常 1 天内回复