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