vibeio_http/h1/
zerocopy.rs1#[cfg(all(target_os = "linux", feature = "h1-zerocopy"))]
2use http::Response;
3use http_body::Body;
4#[cfg(all(target_os = "linux", feature = "h1-zerocopy"))]
5use http_body_util::Empty;
6
7#[cfg(all(target_os = "linux", feature = "h1-zerocopy"))]
8use super::{Http1, HttpProtocol};
9
10#[derive(Clone)]
11pub(super) struct ZerocopyResponse {
12 pub(super) handle: super::RawHandle,
13}
14
15unsafe impl Send for ZerocopyResponse {}
16unsafe impl Sync for ZerocopyResponse {}
17
18pub unsafe fn install_zerocopy(response: &mut http::Response<impl Body>, handle: super::RawHandle) {
33 response
34 .extensions_mut()
35 .insert(ZerocopyResponse { handle });
36}
37
38#[cfg(all(target_os = "linux", feature = "h1-zerocopy"))]
52pub struct Http1Zerocopy<Io> {
53 pub(super) inner: Http1<Io>,
54}
55
56#[cfg(all(target_os = "linux", feature = "h1-zerocopy"))]
57impl<Io> HttpProtocol for Http1Zerocopy<Io>
58where
59 for<'a> Io: tokio::io::AsyncRead
60 + tokio::io::AsyncWrite
61 + vibeio::io::AsInnerRawHandle<'a>
62 + Unpin
63 + 'static,
64{
65 fn handle_with_error_fn<F, Fut, ResB, ResBE, ResE, EF, EFut, EResB, EResBE, EResE>(
66 self,
67 request_fn: F,
68 error_fn: EF,
69 ) -> impl std::future::Future<Output = Result<(), std::io::Error>>
70 where
71 F: Fn(http::Request<super::Incoming>) -> Fut + 'static,
72 Fut: std::future::Future<Output = Result<Response<ResB>, ResE>> + 'static,
73 ResB: Body<Data = bytes::Bytes, Error = ResBE> + Unpin + 'static,
74 ResE: std::error::Error,
75 ResBE: std::error::Error,
76 EF: FnOnce(bool) -> EFut,
77 EFut: std::future::Future<Output = Result<Response<EResB>, EResE>>,
78 EResB: Body<Data = bytes::Bytes, Error = EResBE> + Unpin + 'static,
79 EResE: std::error::Error,
80 EResBE: std::error::Error,
81 {
82 self.inner.handle_with_error_fn_and_zerocopy(
83 request_fn,
84 error_fn,
85 Some(move |fd, io, len| async move {
86 use std::os::fd::BorrowedFd;
87
88 let fd = unsafe { BorrowedFd::borrow_raw(fd) };
89 let _ = vibeio::io::sendfile_exact(&fd, io, len).await?;
90 Ok(())
91 }),
92 )
93 }
94
95 fn handle<F, Fut, ResB, ResBE, ResE>(
96 self,
97 request_fn: F,
98 ) -> impl std::future::Future<Output = Result<(), std::io::Error>>
99 where
100 F: Fn(http::Request<super::Incoming>) -> Fut + 'static,
101 Fut: std::future::Future<Output = Result<Response<ResB>, ResE>> + 'static,
102 ResB: Body<Data = bytes::Bytes, Error = ResBE> + Unpin + 'static,
103 ResE: std::error::Error,
104 ResBE: std::error::Error,
105 {
106 self.handle_with_error_fn(request_fn, |is_timeout| async move {
107 let mut response = Response::builder();
108 if is_timeout {
109 response = response.status(http::StatusCode::REQUEST_TIMEOUT);
110 } else {
111 response = response.status(http::StatusCode::BAD_REQUEST);
112 }
113 response.body(Empty::new())
114 })
115 }
116}