Skip to main content

vibeio_http/h1/
mod.rs

1mod options;
2mod tests;
3mod writebuf;
4mod zerocopy;
5
6pub use options::*;
7pub use zerocopy::*;
8
9#[cfg(unix)]
10pub(crate) type RawHandle = std::os::fd::RawFd;
11#[cfg(windows)]
12pub(crate) type RawHandle = std::os::windows::io::RawHandle;
13
14use std::{
15    future::Future,
16    io::IoSlice,
17    mem::MaybeUninit,
18    pin::Pin,
19    str::FromStr,
20    sync::{
21        atomic::{AtomicBool, Ordering},
22        Arc,
23    },
24    task::{Context, Poll},
25    time::UNIX_EPOCH,
26};
27
28use bytes::{Buf, Bytes, BytesMut};
29use http::{header, HeaderMap, HeaderName, HeaderValue, Method, Request, Response, Uri, Version};
30use http_body::Body;
31use http_body_util::{BodyExt, Empty};
32use kanal::AsyncReceiver;
33use memchr::{memchr3_iter, memmem};
34use tokio::io::{AsyncReadExt, AsyncWriteExt};
35use tokio_util::sync::CancellationToken;
36
37use crate::{h1::writebuf::WriteBuf, EarlyHints, HttpProtocol, Incoming, Upgrade, Upgraded};
38
39const HEX_DIGITS: &[u8; 16] = b"0123456789ABCDEF";
40const WRITE_BUF_BATCH_THRESHOLD: usize = 16384;
41
42/// An HTTP/1.x connection handler.
43///
44/// `Http1` wraps an async I/O stream (`Io`) and provides a complete
45/// HTTP/1.0 and HTTP/1.1 server implementation, including:
46///
47/// - Request head parsing (via [`httparse`])
48/// - Streaming request bodies (content-length and chunked transfer-encoding)
49/// - Chunked response encoding and trailer support
50/// - `100 Continue` and `103 Early Hints` interim responses
51/// - HTTP connection upgrades (e.g. WebSocket)
52/// - Optional zero-copy response sending on Linux (see `Http1::zerocopy`)
53/// - Keep-alive connection reuse
54/// - Graceful shutdown via a [`CancellationToken`]
55///
56/// # Construction
57///
58/// ```rust,ignore
59/// let http1 = Http1::new(tcp_stream, Http1Options::default());
60/// ```
61///
62/// # Serving requests
63///
64/// Use the [`HttpProtocol`] trait methods ([`handle`](HttpProtocol::handle) /
65/// [`handle_with_error_fn`](HttpProtocol::handle_with_error_fn)) to drive the
66/// connection to completion:
67///
68/// ```rust,ignore
69/// http1.handle(|req| async move {
70///     Ok::<_, Infallible>(Response::new(Full::new(Bytes::from("Hello!"))))
71/// }).await?;
72/// ```
73pub struct Http1<Io> {
74    io: Io,
75    options: options::Http1Options,
76    cancel_token: Option<CancellationToken>,
77    parsed_headers: Box<[MaybeUninit<httparse::Header<'static>>]>,
78    date_header_value_cached: Option<(String, std::time::SystemTime)>,
79    cached_headers: Option<HeaderMap>,
80    read_buf: BytesMut,
81    response_head_buf: Vec<u8>,
82    write_buf: WriteBuf,
83    connection_idle: bool,
84}
85
86#[cfg(all(target_os = "linux", feature = "h1-zerocopy"))]
87impl<Io> Http1<Io>
88where
89    for<'a> Io: tokio::io::AsyncRead
90        + tokio::io::AsyncWrite
91        + vibeio::io::AsInnerRawHandle<'a>
92        + Unpin
93        + 'static,
94{
95    /// Converts this `Http1` into an [`Http1Zerocopy`] that uses emulated
96    /// sendfile (Linux only) to send response bodies without copying data
97    /// through user space.
98    ///
99    /// The response body must have a `ZerocopyResponse` extension installed
100    /// (via [`install_zerocopy`]) containing the file descriptor to send from.
101    /// Responses without that extension are sent normally.
102    ///
103    /// Only available on Linux (`target_os = "linux"`), and only when `Io`
104    /// implements [`vibeio::io::AsInnerRawHandle`].
105    #[inline]
106    pub fn zerocopy(self) -> Http1Zerocopy<Io> {
107        Http1Zerocopy { inner: self }
108    }
109}
110
111impl<Io> Http1<Io>
112where
113    Io: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + 'static,
114{
115    /// Creates a new `Http1` connection handler wrapping the given I/O stream.
116    ///
117    /// The `options` value controls limits, timeouts, and optional features;
118    /// see [`Http1Options`] for details.
119    ///
120    /// # Example
121    ///
122    /// ```rust,ignore
123    /// let http1 = Http1::new(tcp_stream, Http1Options::default());
124    /// ```
125    #[inline]
126    pub fn new(io: Io, options: options::Http1Options) -> Self {
127        // Safety: u8 is a primitive type, so we can safely assume initialization
128        let read_buf = BytesMut::with_capacity(options.max_header_size);
129        let parsed_headers: Box<[MaybeUninit<httparse::Header<'static>>]> =
130            Box::new_uninit_slice(options.max_header_count);
131        Self {
132            io,
133            options,
134            cancel_token: None,
135            parsed_headers,
136            date_header_value_cached: None,
137            cached_headers: None,
138            read_buf,
139            response_head_buf: Vec::with_capacity(1024),
140            write_buf: WriteBuf::new(),
141            connection_idle: false,
142        }
143    }
144
145    #[inline]
146    fn get_date_header_value(&mut self) -> &str {
147        let now = std::time::SystemTime::now();
148        if self.date_header_value_cached.as_ref().is_none_or(|v| {
149            v.1.duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs())
150                != now.duration_since(UNIX_EPOCH).ok().map(|d| d.as_secs())
151        }) {
152            let value = httpdate::fmt_http_date(now).to_string();
153            self.date_header_value_cached = Some((value, now));
154        }
155        self.date_header_value_cached
156            .as_ref()
157            .map(|v| v.0.as_str())
158            .unwrap_or("")
159    }
160
161    /// Attaches a [`CancellationToken`] for graceful shutdown.
162    ///
163    /// After the current in-flight request has been fully handled and its
164    /// response written, the connection loop checks whether the token has been
165    /// cancelled. If it has, the loop exits cleanly instead of waiting for the
166    /// next request.
167    ///
168    /// This allows the server to drain active connections without abruptly
169    /// closing them mid-response.
170    #[inline]
171    pub fn graceful_shutdown_token(mut self, token: CancellationToken) -> Self {
172        self.cancel_token = Some(token);
173        self
174    }
175
176    #[inline]
177    async fn fill_buf(&mut self) -> Result<usize, std::io::Error> {
178        if self.read_buf.remaining() < 1024 {
179            self.read_buf.reserve(1024);
180        }
181        let spare_capacity = self.read_buf.spare_capacity_mut();
182        // Safety: The buffer is are read only after the request head has been parsed
183        let n = self
184            .io
185            .read(unsafe {
186                &mut *std::ptr::slice_from_raw_parts_mut(
187                    spare_capacity.as_mut_ptr() as *mut u8,
188                    spare_capacity.len(),
189                )
190            })
191            .await?;
192        if n == 0 {
193            return Ok(0);
194        }
195        unsafe { self.read_buf.set_len(self.read_buf.len() + n) };
196        Ok(n)
197    }
198
199    #[inline]
200    async fn read_body_fn(
201        &mut self,
202        body_tx: kanal::AsyncSender<Result<http_body::Frame<bytes::Bytes>, std::io::Error>>,
203        content_length: u64,
204        send_continue_body: &Option<Arc<AtomicBool>>,
205        continue_sent: &mut bool,
206        version: Version,
207    ) -> Result<(), std::io::Error> {
208        let mut remaining = content_length;
209        let mut just_started = true;
210        while remaining > 0 {
211            if !*continue_sent
212                && send_continue_body
213                    .as_ref()
214                    .is_some_and(|b| b.load(Ordering::Relaxed))
215            {
216                *continue_sent = true;
217                self.write_100_continue(version).await?;
218            }
219
220            let have_to_read_buf = !just_started || self.read_buf.is_empty();
221            just_started = false;
222            if have_to_read_buf {
223                let n = self.fill_buf().await?;
224                if n == 0 {
225                    break;
226                }
227            }
228            let chunk = self
229                .read_buf
230                .split_to(
231                    self.read_buf
232                        .len()
233                        .min(remaining.min(usize::MAX as u64) as usize),
234                )
235                .freeze();
236            remaining -= chunk.len() as u64;
237
238            let _ = body_tx.send(Ok(http_body::Frame::data(chunk))).await;
239        }
240        Ok(())
241    }
242
243    #[inline]
244    async fn read_body_chunk(
245        &mut self,
246        would_have_trailers: bool,
247        send_continue_body: &Option<Arc<AtomicBool>>,
248        continue_sent: &mut bool,
249        version: Version,
250    ) -> Result<bytes::Bytes, std::io::Error> {
251        let len = {
252            // Safety: u8 is a primitive type, so we can safely assume initialization
253            let mut len_buf_pos: usize = 0;
254            let mut just_started = true;
255            loop {
256                if len_buf_pos >= 48 {
257                    return Err(std::io::Error::new(
258                        std::io::ErrorKind::InvalidData,
259                        "chunk length buffer overflow",
260                    ));
261                }
262
263                let begin_search = len_buf_pos.saturating_sub(1);
264
265                let have_to_read_buf = !just_started || self.read_buf.is_empty();
266                just_started = false;
267                if have_to_read_buf {
268                    if !*continue_sent
269                        && send_continue_body
270                            .as_ref()
271                            .is_some_and(|b| b.load(Ordering::Relaxed))
272                    {
273                        *continue_sent = true;
274                        self.write_100_continue(version).await?;
275                    }
276                    let n = self.fill_buf().await?;
277                    if n == 0 {
278                        return Err(std::io::Error::new(
279                            std::io::ErrorKind::UnexpectedEof,
280                            "unexpected EOF",
281                        ));
282                    }
283                    len_buf_pos += n;
284                } else {
285                    len_buf_pos += self.read_buf.len();
286                }
287
288                if let Some(pos) =
289                    memmem::find(&self.read_buf[begin_search..len_buf_pos.min(48)], b"\r\n")
290                {
291                    let numbers = std::str::from_utf8(&self.read_buf[..begin_search + pos])
292                        .map_err(|_| {
293                            std::io::Error::new(
294                                std::io::ErrorKind::InvalidData,
295                                "invalid chunk length",
296                            )
297                        })?;
298                    let len = usize::from_str_radix(numbers, 16).map_err(|_| {
299                        std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid chunk length")
300                    })?;
301                    // Ignore the trailing CRLF
302                    self.read_buf.advance(begin_search + pos + 2);
303                    break len;
304                }
305            }
306        };
307        // Safety: u8 is a primitive type, so we can safely assume initialization
308        let mut read = 0;
309        if len == 0 && would_have_trailers {
310            return Ok(bytes::Bytes::new()); // Empty terminating chunk
311        }
312        let mut just_started = true;
313        // + 2, because we need to read the trailing CRLF
314        let Some(len_plus_two) = len.checked_add(2) else {
315            return Err(std::io::Error::new(
316                std::io::ErrorKind::InvalidData,
317                "chunk length too large",
318            ));
319        };
320        while read < len_plus_two {
321            let have_to_read_buf = !just_started || self.read_buf.is_empty();
322            just_started = false;
323            if have_to_read_buf {
324                if !*continue_sent
325                    && send_continue_body
326                        .as_ref()
327                        .is_some_and(|b| b.load(Ordering::Relaxed))
328                {
329                    *continue_sent = true;
330                    self.write_100_continue(version).await?;
331                }
332                let n = self.fill_buf().await?;
333                if n == 0 {
334                    return Err(std::io::Error::new(
335                        std::io::ErrorKind::UnexpectedEof,
336                        "unexpected EOF",
337                    ));
338                }
339                read += n;
340            } else {
341                read += self.read_buf.len();
342            }
343        }
344        let chunk = self.read_buf.split_to(len).freeze();
345        self.read_buf.advance(2); // Ignore the trailing CRLF
346        Ok(chunk)
347    }
348
349    #[inline]
350    async fn read_trailers(&mut self) -> Result<Option<HeaderMap>, std::io::Error> {
351        // Safety: u8 is a primitive type, so we can safely assume initialization
352        let mut bytes_read: usize = 0;
353        let mut just_started = true;
354        while bytes_read < self.options.max_header_size {
355            let old_bytes_read = bytes_read;
356            let begin_search = old_bytes_read.saturating_sub(3);
357
358            let have_to_read_buf = !just_started || self.read_buf.is_empty();
359            just_started = false;
360            if have_to_read_buf {
361                let n = self.fill_buf().await?;
362                if n == 0 {
363                    return Err(std::io::Error::new(
364                        std::io::ErrorKind::UnexpectedEof,
365                        "unexpected EOF",
366                    ));
367                }
368                bytes_read = (old_bytes_read + n).min(self.options.max_header_size);
369            } else {
370                bytes_read =
371                    (old_bytes_read + self.read_buf.len()).min(self.options.max_header_size)
372            }
373
374            if bytes_read >= 2 && self.read_buf[0] == b'\r' && self.read_buf[1] == b'\n' {
375                // No trailers, return None
376                return Ok(None);
377            }
378
379            if let Some(separator_index) =
380                memmem::find(&self.read_buf[begin_search..bytes_read], b"\r\n\r\n")
381            {
382                let to_parse_length = begin_search + separator_index + 4;
383                let buf_ro = self.read_buf.split_to(to_parse_length).freeze();
384
385                // Parse trailers using `httparse` crate's header parsing
386                let mut httparse_trailers =
387                    vec![httparse::EMPTY_HEADER; self.options.max_header_count].into_boxed_slice();
388                let status = httparse::parse_headers(&buf_ro, &mut httparse_trailers)
389                    .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
390                if let httparse::Status::Complete((_, trailers)) = status {
391                    let mut trailers_constructed = HeaderMap::new();
392                    for header in trailers {
393                        if header == &httparse::EMPTY_HEADER {
394                            // No more headers...
395                            break;
396                        }
397                        let name = HeaderName::from_bytes(header.name.as_bytes())
398                            .map_err(|e| std::io::Error::other(e.to_string()))?;
399                        let value_start = header.value.as_ptr() as usize - buf_ro.as_ptr() as usize;
400                        let value_len = header.value.len();
401                        // Safety: the header value is already validated by httparse
402                        let value = unsafe {
403                            HeaderValue::from_maybe_shared_unchecked(
404                                buf_ro.slice(value_start..(value_start + value_len)),
405                            )
406                        };
407                        trailers_constructed.append(name, value);
408                    }
409
410                    return Ok(Some(trailers_constructed));
411                } else {
412                    return Err(std::io::Error::new(
413                        std::io::ErrorKind::InvalidInput,
414                        "trailer headers incomplete",
415                    ));
416                }
417            }
418        }
419        Err(std::io::Error::new(
420            std::io::ErrorKind::InvalidData,
421            "request too large",
422        ))
423    }
424
425    #[inline]
426    async fn read_chunked_body_fn(
427        &mut self,
428        body_tx: kanal::AsyncSender<Result<http_body::Frame<bytes::Bytes>, std::io::Error>>,
429        would_have_trailers: bool,
430        send_continue_body: &Option<Arc<AtomicBool>>,
431        continue_sent: &mut bool,
432        version: Version,
433    ) -> Result<(), std::io::Error> {
434        loop {
435            let chunk = self
436                .read_body_chunk(
437                    would_have_trailers,
438                    send_continue_body,
439                    continue_sent,
440                    version,
441                )
442                .await?;
443            if chunk.is_empty() {
444                break;
445            }
446
447            let _ = body_tx.send(Ok(http_body::Frame::data(chunk))).await;
448        }
449        if would_have_trailers {
450            // Trailers
451            let trailers = self.read_trailers().await?;
452            if let Some(trailers) = trailers {
453                let _ = body_tx.send(Ok(http_body::Frame::trailers(trailers))).await;
454            }
455        }
456        Ok(())
457    }
458
459    #[inline]
460    async fn read_request(
461        &mut self,
462    ) -> Result<
463        Option<(
464            Request<Incoming>,
465            kanal::AsyncSender<Result<http_body::Frame<bytes::Bytes>, std::io::Error>>,
466            Option<Arc<AtomicBool>>,
467        )>,
468        std::io::Error,
469    > {
470        // Parse HTTP request using httparse
471        let (request, body_tx, send_continue_body) = {
472            let Some((head, headers)) = self.get_head().await? else {
473                return Ok(None);
474            };
475            // Safety: The headers are read only after the request head has been parsed
476            let headers = unsafe {
477                std::mem::transmute::<
478                    &mut [MaybeUninit<httparse::Header<'static>>],
479                    &mut [MaybeUninit<httparse::Header<'_>>],
480                >(headers)
481            };
482            let mut req = httparse::Request::new(&mut []);
483            let status = req
484                .parse_with_uninit_headers(&head, headers)
485                .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
486            if status.is_partial() {
487                return Err(std::io::Error::new(
488                    std::io::ErrorKind::InvalidData,
489                    "partial request head",
490                ));
491            }
492
493            // Convert httparse HTTP request to `http` one
494            let (body_tx, body_rx) = kanal::bounded_async(2);
495
496            // Detect 100-continue and create flag before building the body
497            let is_100_continue = self.options.send_continue_response
498                && req.headers.iter().any(|h| {
499                    h.name.eq_ignore_ascii_case("expect")
500                        && h.value.eq_ignore_ascii_case(b"100-continue")
501                });
502            let send_continue_body = is_100_continue.then(|| Arc::new(AtomicBool::new(false)));
503
504            let request_body = Http1Body {
505                inner: Box::pin(body_rx),
506                send_continue_body: send_continue_body.clone(),
507            };
508            let mut request = Request::new(Incoming::H1(request_body));
509            match req.version {
510                Some(0) => *request.version_mut() = http::Version::HTTP_10,
511                Some(1) => *request.version_mut() = http::Version::HTTP_11,
512                _ => *request.version_mut() = http::Version::HTTP_11,
513            };
514            if let Some(method) = req.method {
515                *request.method_mut() = Method::from_bytes(method.as_bytes())
516                    .map_err(|e| std::io::Error::other(e.to_string()))?;
517            }
518            if let Some(path) = req.path {
519                *request.uri_mut() =
520                    Uri::from_str(path).map_err(|e| std::io::Error::other(e.to_string()))?;
521            }
522            let mut header_map = self.cached_headers.take().unwrap_or_default();
523            header_map.clear();
524            let additional_capacity = req.headers.len().saturating_sub(header_map.capacity());
525            if additional_capacity > 0 {
526                header_map.reserve(additional_capacity);
527            }
528            for header in req.headers {
529                if header == &httparse::EMPTY_HEADER {
530                    // No more headers...
531                    break;
532                }
533                let name = HeaderName::from_bytes(header.name.as_bytes())
534                    .map_err(|e| std::io::Error::other(e.to_string()))?;
535                let value_start = header.value.as_ptr() as usize - head.as_ptr() as usize;
536                let value_len = header.value.len();
537                // Safety: the header value is already validated by httparse
538                let value = unsafe {
539                    HeaderValue::from_maybe_shared_unchecked(
540                        head.slice(value_start..(value_start + value_len)),
541                    )
542                };
543                header_map.append(name, value);
544            }
545            *request.headers_mut() = header_map;
546
547            (request, body_tx, send_continue_body)
548        };
549        Ok(Some((request, body_tx, send_continue_body)))
550    }
551
552    #[inline]
553    async fn get_head(
554        &mut self,
555    ) -> Result<Option<(Bytes, &mut [MaybeUninit<httparse::Header<'static>>])>, std::io::Error>
556    {
557        let mut request_line_read = false;
558        let mut bytes_read: usize = 0;
559        let mut whitespace_trimmed = None;
560        let mut just_started = true;
561        while bytes_read < self.options.max_header_size {
562            let old_bytes_read = bytes_read;
563            let begin_search = old_bytes_read.saturating_sub(3);
564
565            let have_to_read_buf = !just_started || self.read_buf.is_empty();
566            just_started = false;
567            if have_to_read_buf {
568                let n = self.fill_buf().await?;
569                if n == 0 {
570                    if whitespace_trimmed.is_none() {
571                        return Ok(None);
572                    }
573                    return Err(std::io::Error::new(
574                        std::io::ErrorKind::UnexpectedEof,
575                        "unexpected EOF",
576                    ));
577                } else {
578                    self.connection_idle = false;
579                }
580                bytes_read = (old_bytes_read + n).min(self.options.max_header_size);
581            } else {
582                bytes_read =
583                    (old_bytes_read + self.read_buf.len()).min(self.options.max_header_size)
584            }
585
586            if whitespace_trimmed.is_none() {
587                whitespace_trimmed = self.read_buf[old_bytes_read..bytes_read]
588                    .iter()
589                    .position(|b| !b.is_ascii_whitespace());
590            }
591
592            if let Some(whitespace_trimmed) = whitespace_trimmed {
593                // Validate first line (request line) before checking for header/body separator
594                if !request_line_read {
595                    let memchr = memchr3_iter(
596                        b' ',
597                        b'\r',
598                        b'\n',
599                        &self.read_buf[whitespace_trimmed..bytes_read],
600                    );
601                    let mut spaces = 0;
602                    for separator_index in memchr {
603                        if self.read_buf[whitespace_trimmed + separator_index] == b' ' {
604                            if spaces >= 2 {
605                                return Err(std::io::Error::new(
606                                    std::io::ErrorKind::InvalidInput,
607                                    "bad request first line",
608                                ));
609                            }
610                            spaces += 1;
611                        } else if spaces == 2 {
612                            request_line_read = true;
613                            break;
614                        } else {
615                            return Err(std::io::Error::new(
616                                std::io::ErrorKind::InvalidInput,
617                                "bad request first line",
618                            ));
619                        }
620                    }
621                }
622
623                if request_line_read {
624                    let begin_search = begin_search.max(whitespace_trimmed);
625                    if let Some((separator_index, separator_len)) =
626                        search_header_body_separator(&self.read_buf[begin_search..bytes_read])
627                    {
628                        let to_parse_length =
629                            begin_search + separator_index + separator_len - whitespace_trimmed;
630                        self.read_buf.advance(whitespace_trimmed);
631                        let head = self.read_buf.split_to(to_parse_length);
632                        return Ok(Some((head.freeze(), &mut self.parsed_headers)));
633                    }
634                }
635            }
636        }
637        Err(std::io::Error::new(
638            std::io::ErrorKind::InvalidData,
639            "request too large",
640        ))
641    }
642
643    #[inline]
644    async fn write_response<Z, ZFut>(
645        &mut self,
646        mut response: Response<
647            impl Body<Data = bytes::Bytes, Error = impl std::error::Error> + Unpin,
648        >,
649        version: Version,
650        write_trailers: bool,
651        zerocopy_fn: Option<Z>,
652    ) -> Result<(), std::io::Error>
653    where
654        Z: FnMut(RawHandle, &'static Io, u64) -> ZFut,
655        ZFut: std::future::Future<Output = Result<(), std::io::Error>>,
656    {
657        // Date header
658        if self.options.send_date_header {
659            response.headers_mut().insert(
660                header::DATE,
661                HeaderValue::from_str(self.get_date_header_value())
662                    .map_err(|e| std::io::Error::other(e.to_string()))?,
663            );
664        }
665
666        // If the body has a size hint, set the Content-Length header if it's not already set
667        if let Some(suggested_content_length) = response.body().size_hint().exact() {
668            let headers = response.headers_mut();
669            if !headers.contains_key(header::CONTENT_LENGTH) {
670                headers.insert(header::CONTENT_LENGTH, suggested_content_length.into());
671            }
672        }
673
674        let chunked = response
675            .headers()
676            .get(header::TRANSFER_ENCODING)
677            .map(|v| {
678                v.to_str().ok().is_some_and(|s| {
679                    s.split(',')
680                        .any(|s| s.trim().eq_ignore_ascii_case("chunked"))
681                })
682            })
683            .unwrap_or_else(|| {
684                response
685                    .headers()
686                    .get(header::CONTENT_LENGTH)
687                    .and_then(|v| v.to_str().ok())
688                    .is_none_or(|s| s.parse::<u64>().is_err())
689            });
690
691        if chunked {
692            response.headers_mut().insert(
693                header::TRANSFER_ENCODING,
694                HeaderValue::from_static("chunked"),
695            );
696            while response
697                .headers_mut()
698                .remove(header::CONTENT_LENGTH)
699                .is_some()
700            {}
701        }
702
703        let (parts, mut body) = response.into_parts();
704
705        self.response_head_buf.clear();
706        let estimated_head_len = 30 + parts.headers.len() * 30; // Similar to Hyper's heuristic
707        if self.response_head_buf.capacity() < estimated_head_len {
708            self.response_head_buf
709                .reserve(estimated_head_len - self.response_head_buf.capacity());
710        }
711        let head = &mut self.response_head_buf;
712        if version == Version::HTTP_10 {
713            head.extend_from_slice(b"HTTP/1.0 ");
714        } else {
715            head.extend_from_slice(b"HTTP/1.1 ");
716        }
717        let status = parts.status;
718        head.extend_from_slice(status.as_str().as_bytes());
719        if let Some(canonical_reason) = status.canonical_reason() {
720            head.extend_from_slice(b" ");
721            head.extend_from_slice(canonical_reason.as_bytes());
722        }
723        head.extend_from_slice(b"\r\n");
724        for (name, value) in &parts.headers {
725            head.extend_from_slice(name.as_str().as_bytes());
726            head.extend_from_slice(b": ");
727            head.extend_from_slice(value.as_bytes());
728            head.extend_from_slice(b"\r\n");
729        }
730        head.extend_from_slice(b"\r\n");
731        unsafe {
732            self.write_buf.push(IoSlice::new(head));
733        }
734
735        if !chunked {
736            if let Some(content_length) = parts
737                .headers
738                .get(header::CONTENT_LENGTH)
739                .and_then(|v| v.to_str().ok())
740                .and_then(|s| s.parse::<u64>().ok())
741            {
742                if let Some(zero_copy) = parts.extensions.get::<ZerocopyResponse>() {
743                    if let Some(mut zerocopy_fn) = zerocopy_fn {
744                        // Zerocopy
745                        unsafe {
746                            self.write_buf
747                                .flush(&mut self.io, self.options.enable_vectored_write)
748                                .await?
749                        };
750                        zerocopy_fn(
751                            zero_copy.handle,
752                            // Safety: the lifetime of the static reference is bound by the lifetime of the Io struct
753                            unsafe { std::mem::transmute::<&Io, &'static Io>(&self.io) },
754                            content_length,
755                        )
756                        .await?;
757                        self.io.flush().await?;
758                        let reclaimed_headers = parts.headers;
759                        self.cached_headers = Some(reclaimed_headers);
760                        return Ok(());
761                    }
762                }
763            }
764        }
765
766        let mut trailers_written = false;
767        while let Some(chunk) = body.frame().await {
768            let chunk = chunk.map_err(|e| std::io::Error::other(e.to_string()))?;
769            match chunk.into_data() {
770                Ok(data) => {
771                    if chunked {
772                        let mut chunk_size_buf = [0u8; 18];
773                        let chunk_size = write_chunk_size(&mut chunk_size_buf, data.len());
774                        self.write_buf.push_copy(chunk_size);
775                        self.write_buf.push_bytes(data);
776                        unsafe {
777                            self.write_buf.push(IoSlice::new(b"\r\n"));
778                        }
779                    } else {
780                        self.write_buf.push_bytes(data);
781                    }
782                    while self.write_buf.len() >= WRITE_BUF_BATCH_THRESHOLD {
783                        let bytes_written = unsafe {
784                            self.write_buf
785                                .write(&mut self.io, self.options.enable_vectored_write)
786                                .await?
787                        };
788                        if bytes_written == 0 {
789                            return Err(std::io::ErrorKind::WriteZero.into());
790                        }
791                    }
792                }
793                Err(chunk) => {
794                    if let Ok(trailers) = chunk.into_trailers() {
795                        if write_trailers {
796                            unsafe {
797                                self.write_buf.push(IoSlice::new(b"0\r\n"));
798                                for (name, value) in &trailers {
799                                    self.write_buf.push_copy(name.as_str().as_bytes());
800                                    self.write_buf.push(IoSlice::new(b": "));
801                                    self.write_buf.push_copy(value.as_bytes());
802                                    self.write_buf.push(IoSlice::new(b"\r\n"));
803                                }
804                                self.write_buf.push(IoSlice::new(b"\r\n"));
805                            }
806                            trailers_written = true;
807                        }
808                        break;
809                    }
810                }
811            };
812        }
813        if chunked && !trailers_written {
814            // Terminating chunk
815            unsafe {
816                self.write_buf.push(IoSlice::new(b"0\r\n\r\n"));
817            }
818        }
819        unsafe {
820            self.write_buf
821                .flush(&mut self.io, self.options.enable_vectored_write)
822                .await?;
823        }
824        self.io.flush().await?;
825        let reclaimed_headers = parts.headers;
826        self.cached_headers = Some(reclaimed_headers);
827
828        Ok(())
829    }
830
831    #[inline]
832    async fn write_100_continue(&mut self, version: Version) -> Result<(), std::io::Error> {
833        if version == Version::HTTP_10 {
834            self.io.write_all(b"HTTP/1.0 100 Continue\r\n\r\n").await?;
835        } else {
836            self.io.write_all(b"HTTP/1.1 100 Continue\r\n\r\n").await?;
837        }
838        self.io.flush().await?;
839
840        Ok(())
841    }
842
843    #[inline]
844    async fn write_early_hints(
845        &mut self,
846        version: Version,
847        headers: http::HeaderMap,
848    ) -> Result<(), std::io::Error> {
849        let mut head = Vec::new();
850        if version == Version::HTTP_10 {
851            head.extend_from_slice(b"HTTP/1.0 103 Early Hints\r\n");
852        } else {
853            head.extend_from_slice(b"HTTP/1.1 103 Early Hints\r\n");
854        }
855        let mut current_header_name = None;
856        for (name, value) in headers {
857            if let Some(name) = name {
858                current_header_name = Some(name);
859            };
860            if let Some(current_header_name) = &current_header_name {
861                head.extend_from_slice(current_header_name.as_str().as_bytes());
862                if value.is_empty() {
863                    head.extend_from_slice(b":\r\n");
864                    continue;
865                }
866                head.extend_from_slice(b": ");
867                head.extend_from_slice(value.as_bytes());
868                head.extend_from_slice(b"\r\n");
869            }
870        }
871        head.extend_from_slice(b"\r\n");
872
873        self.io.write_all(&head).await?;
874
875        Ok(())
876    }
877
878    #[inline]
879    pub(crate) async fn handle_with_error_fn_and_zerocopy<
880        F,
881        Fut,
882        ResB,
883        ResBE,
884        ResE,
885        EF,
886        EFut,
887        EResB,
888        EResBE,
889        EResE,
890        ZF,
891        ZFut,
892    >(
893        mut self,
894        request_fn: F,
895        error_fn: EF,
896        mut zerocopy_fn: Option<ZF>,
897    ) -> Result<(), std::io::Error>
898    where
899        F: Fn(Request<Incoming>) -> Fut + 'static,
900        Fut: std::future::Future<Output = Result<Response<ResB>, ResE>> + 'static,
901        ResB: Body<Data = bytes::Bytes, Error = ResBE> + Unpin + 'static,
902        ResE: std::error::Error,
903        ResBE: std::error::Error,
904        EF: FnOnce(bool) -> EFut,
905        EFut: std::future::Future<Output = Result<Response<EResB>, EResE>>,
906        EResB: Body<Data = bytes::Bytes, Error = EResBE> + Unpin + 'static,
907        EResE: std::error::Error,
908        EResBE: std::error::Error,
909        ZF: FnMut(RawHandle, &'static Io, u64) -> ZFut,
910        ZFut: std::future::Future<Output = Result<(), std::io::Error>>,
911    {
912        let mut keep_alive = true;
913
914        while keep_alive {
915            let (mut request, body_tx, send_continue_body) = match if let Some(timeout) =
916                self.options.header_read_timeout
917            {
918                vibeio::time::timeout(timeout, async {
919                    if let Some(token) = self.cancel_token.clone() {
920                        token.run_until_cancelled(self.read_request()).await
921                    } else {
922                        Some(self.read_request().await)
923                    }
924                })
925                .await
926            } else {
927                Ok(Some(self.read_request().await))
928            } {
929                Ok(Some(Ok(Some(d)))) => d,
930                Ok(Some(Ok(None))) => {
931                    return Ok(());
932                }
933                Ok(Some(Err(e))) => {
934                    // Parse error
935                    if let Ok(mut response) = error_fn(false).await {
936                        response
937                            .headers_mut()
938                            .insert(header::CONNECTION, HeaderValue::from_static("close"));
939
940                        let _ = self
941                            .write_response(response, Version::HTTP_11, false, zerocopy_fn.as_mut())
942                            .await;
943                    }
944                    return Err(e);
945                }
946                Ok(None) => {
947                    // Graceful shutdown
948                    return Ok(());
949                }
950                Err(_) if self.connection_idle => {
951                    // Idle connection
952                    return Ok(());
953                }
954                Err(_) => {
955                    // Timeout error
956                    if let Ok(mut response) = error_fn(true).await {
957                        response
958                            .headers_mut()
959                            .insert(header::CONNECTION, HeaderValue::from_static("close"));
960
961                        let _ = self
962                            .write_response(response, Version::HTTP_11, false, zerocopy_fn.as_mut())
963                            .await;
964                    }
965                    return Err(std::io::Error::new(
966                        std::io::ErrorKind::TimedOut,
967                        "header read timeout",
968                    ));
969                }
970            };
971
972            // Connection header detection
973            let connection_header_split = request
974                .headers()
975                .get(header::CONNECTION)
976                .and_then(|v| v.to_str().ok())
977                .map(|v| v.split(",").map(|v| v.trim()));
978            let is_connection_close = connection_header_split
979                .clone()
980                .is_some_and(|mut split| split.any(|v| v.eq_ignore_ascii_case("close")));
981            let is_connection_keep_alive = connection_header_split
982                .is_some_and(|mut split| split.any(|v| v.eq_ignore_ascii_case("keep-alive")));
983            keep_alive = !is_connection_close
984                && (is_connection_keep_alive || request.version() == http::Version::HTTP_11);
985
986            let version = request.version();
987            let is_100_continue = send_continue_body.is_some();
988
989            // 103 Early Hints
990            let early_hints_fut = if self.options.enable_early_hints {
991                let (early_hints, mut early_hints_rx) = EarlyHints::new_lazy();
992                request.extensions_mut().insert(early_hints);
993                // Safety: the function below is used only in futures_util::future::select
994                // Also, another function that would borrow self would read data,
995                // while this function would write data
996                let mut_self = unsafe { std::mem::transmute::<&mut Self, &mut Self>(&mut self) };
997                futures_util::future::Either::Left(async move {
998                    while let Some((headers, sender)) =
999                        std::future::poll_fn(|cx| early_hints_rx.poll_recv(cx)).await
1000                    {
1001                        sender
1002                            .into_inner()
1003                            .send(mut_self.write_early_hints(version, headers).await)
1004                            .ok();
1005                    }
1006                    futures_util::future::pending::<Result<(), std::io::Error>>().await
1007                })
1008            } else {
1009                futures_util::future::Either::Right(futures_util::future::pending::<
1010                    Result<(), std::io::Error>,
1011                >())
1012            };
1013
1014            // Content-Length header
1015            let content_length = request
1016                .headers()
1017                .get(header::CONTENT_LENGTH)
1018                .and_then(|v| v.to_str().ok())
1019                .and_then(|v| v.parse::<u64>().ok())
1020                .unwrap_or(0);
1021            let chunked = request
1022                .headers()
1023                .get(header::TRANSFER_ENCODING)
1024                .and_then(|v| v.to_str().ok())
1025                .is_some_and(|v| {
1026                    v.split(',')
1027                        .any(|v| v.trim().eq_ignore_ascii_case("chunked"))
1028                });
1029            let has_trailers = request
1030                .headers()
1031                .get(header::TRAILER)
1032                .map(|v| v.to_str().ok().is_some_and(|s| !s.is_empty()))
1033                .unwrap_or(false);
1034            let write_trailers = request
1035                .headers()
1036                .get(header::TE)
1037                .and_then(|v| v.to_str().ok())
1038                .map(|v| {
1039                    v.split(',')
1040                        .any(|v| v.trim().eq_ignore_ascii_case("trailers"))
1041                })
1042                .unwrap_or(false);
1043
1044            // Install HTTP upgrade
1045            let (upgrade_tx, upgrade_rx) = oneshot::async_channel();
1046            let upgrade = Upgrade::new(upgrade_rx);
1047            let upgraded = upgrade.upgraded.clone();
1048            request.extensions_mut().insert(upgrade);
1049
1050            // Get HTTP response
1051            let mut continue_sent = false;
1052            let mut response = {
1053                let read_body_fut = async {
1054                    if chunked {
1055                        self.read_chunked_body_fn(
1056                            body_tx,
1057                            has_trailers,
1058                            &send_continue_body,
1059                            &mut continue_sent,
1060                            version,
1061                        )
1062                        .await
1063                    } else {
1064                        self.read_body_fn(
1065                            body_tx,
1066                            content_length,
1067                            &send_continue_body,
1068                            &mut continue_sent,
1069                            version,
1070                        )
1071                        .await
1072                    }
1073                };
1074                let read_body_fut_pin = std::pin::pin!(read_body_fut);
1075                let request_fut = request_fn(request);
1076                let request_fut_pin = std::pin::pin!(request_fut);
1077                let early_hints_fut_pin = std::pin::pin!(early_hints_fut);
1078
1079                let select_read_body_either =
1080                    futures_util::future::select(request_fut_pin, early_hints_fut_pin);
1081                let select_either =
1082                    futures_util::future::select(read_body_fut_pin, select_read_body_either).await;
1083
1084                let (response, body_fut) = match select_either {
1085                    futures_util::future::Either::Left((result, request_fut)) => {
1086                        result?;
1087                        (
1088                            match request_fut.await {
1089                                futures_util::future::Either::Left((response, _)) => response,
1090                                futures_util::future::Either::Right((_, _)) => unreachable!(),
1091                            },
1092                            None,
1093                        )
1094                    }
1095                    futures_util::future::Either::Right((response, read_body_fut)) => (
1096                        match response {
1097                            futures_util::future::Either::Left((response, _)) => response,
1098                            futures_util::future::Either::Right((_, _)) => unreachable!(),
1099                        },
1100                        Some(read_body_fut),
1101                    ),
1102                };
1103
1104                // Drain away remaining body
1105                if let Some(body_fut) = body_fut {
1106                    body_fut.await?;
1107                }
1108
1109                response.map_err(|e| std::io::Error::other(e.to_string()))?
1110            };
1111
1112            // Response-triggered 100 Continue
1113            if !continue_sent
1114                && is_100_continue
1115                && !response.status().is_client_error()
1116                && !response.status().is_server_error()
1117            {
1118                self.write_100_continue(version).await?;
1119            }
1120
1121            let mut was_upgraded = false;
1122            if upgraded.load(std::sync::atomic::Ordering::Relaxed) {
1123                was_upgraded = true;
1124                response
1125                    .headers_mut()
1126                    .insert(header::CONNECTION, HeaderValue::from_static("upgrade"));
1127            } else if keep_alive {
1128                if version == Version::HTTP_10
1129                    || response.headers().contains_key(header::CONNECTION)
1130                {
1131                    response
1132                        .headers_mut()
1133                        .insert(header::CONNECTION, HeaderValue::from_static("keep-alive"));
1134                }
1135            } else if version == Version::HTTP_11
1136                || response.headers().contains_key(header::CONNECTION)
1137            {
1138                response
1139                    .headers_mut()
1140                    .insert(header::CONNECTION, HeaderValue::from_static("close"));
1141            }
1142
1143            // Write response to IO
1144            self.write_response(response, version, write_trailers, zerocopy_fn.as_mut())
1145                .await?;
1146
1147            if was_upgraded {
1148                // HTTP upgrade
1149                let frozen_buf = self.read_buf.freeze();
1150                let _ = upgrade_tx.send(Upgraded::new(
1151                    self.io,
1152                    if frozen_buf.is_empty() {
1153                        None
1154                    } else {
1155                        Some(frozen_buf)
1156                    },
1157                ));
1158                return Ok(());
1159            }
1160
1161            if self.cancel_token.as_ref().is_some_and(|t| t.is_cancelled()) {
1162                // Graceful shutdown requested, break out of loop
1163                break;
1164            }
1165
1166            self.connection_idle = true;
1167        }
1168        Ok(())
1169    }
1170}
1171
1172impl<Io> HttpProtocol for Http1<Io>
1173where
1174    Io: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + 'static,
1175{
1176    #[inline]
1177    fn handle_with_error_fn<F, Fut, ResB, ResBE, ResE, EF, EFut, EResB, EResBE, EResE>(
1178        self,
1179        request_fn: F,
1180        error_fn: EF,
1181    ) -> impl std::future::Future<Output = Result<(), std::io::Error>>
1182    where
1183        F: Fn(Request<Incoming>) -> Fut + 'static,
1184        Fut: std::future::Future<Output = Result<Response<ResB>, ResE>> + 'static,
1185        ResB: Body<Data = bytes::Bytes, Error = ResBE> + Unpin + 'static,
1186        ResE: std::error::Error,
1187        ResBE: std::error::Error,
1188        EF: FnOnce(bool) -> EFut,
1189        EFut: std::future::Future<Output = Result<Response<EResB>, EResE>>,
1190        EResB: Body<Data = bytes::Bytes, Error = EResBE> + Unpin + 'static,
1191        EResE: std::error::Error,
1192        EResBE: std::error::Error,
1193    {
1194        #[allow(clippy::type_complexity)]
1195        let no_zerocopy: Option<
1196            Box<
1197                dyn FnMut(
1198                    RawHandle,
1199                    &Io,
1200                    u64,
1201                ) -> Box<
1202                    dyn std::future::Future<Output = Result<(), std::io::Error>>
1203                        + Unpin
1204                        + Send
1205                        + Sync,
1206                >,
1207            >,
1208        > = None;
1209        self.handle_with_error_fn_and_zerocopy(request_fn, error_fn, no_zerocopy)
1210    }
1211
1212    #[inline]
1213    fn handle<F, Fut, ResB, ResBE, ResE>(
1214        self,
1215        request_fn: F,
1216    ) -> impl std::future::Future<Output = Result<(), std::io::Error>>
1217    where
1218        F: Fn(Request<Incoming>) -> Fut + 'static,
1219        Fut: std::future::Future<Output = Result<Response<ResB>, ResE>> + 'static,
1220        ResB: Body<Data = bytes::Bytes, Error = ResBE> + Unpin + 'static,
1221        ResE: std::error::Error,
1222        ResBE: std::error::Error,
1223    {
1224        self.handle_with_error_fn(request_fn, |is_timeout| async move {
1225            let mut response = Response::builder();
1226            if is_timeout {
1227                response = response.status(http::StatusCode::REQUEST_TIMEOUT);
1228            } else {
1229                response = response.status(http::StatusCode::BAD_REQUEST);
1230            }
1231            response.body(Empty::new())
1232        })
1233    }
1234}
1235
1236pub(crate) struct Http1Body {
1237    #[allow(clippy::type_complexity)]
1238    inner: Pin<Box<AsyncReceiver<Result<http_body::Frame<bytes::Bytes>, std::io::Error>>>>,
1239    send_continue_body: Option<Arc<AtomicBool>>,
1240}
1241
1242impl Body for Http1Body {
1243    type Data = bytes::Bytes;
1244    type Error = std::io::Error;
1245
1246    #[inline]
1247    fn poll_frame(
1248        self: Pin<&mut Self>,
1249        cx: &mut Context<'_>,
1250    ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
1251        match std::pin::pin!(self.inner.recv()).poll(cx) {
1252            Poll::Ready(Ok(Ok(frame))) => Poll::Ready(Some(Ok(frame))),
1253            Poll::Ready(Ok(Err(e))) => Poll::Ready(Some(Err(e))),
1254            Poll::Ready(Err(_)) => Poll::Ready(None),
1255            Poll::Pending => {
1256                if let Some(scb) = self.send_continue_body.as_ref() {
1257                    scb.store(true, Ordering::Relaxed);
1258                }
1259                Poll::Pending
1260            }
1261        }
1262    }
1263}
1264
1265/// Searches for the header/body separator in a given slice.
1266/// Returns the index of the separator and the length of the separator.
1267#[inline]
1268fn search_header_body_separator(slice: &[u8]) -> Option<(usize, usize)> {
1269    if slice.len() < 2 {
1270        // Slice too short
1271        return None;
1272    }
1273    for (i, b) in slice.iter().copied().enumerate() {
1274        if b == b'\r' {
1275            if slice[i + 1..].chunks(3).next() == Some(&b"\n\r\n"[..]) {
1276                return Some((i, 4));
1277            }
1278        } else if b == b'\n' && slice.get(i + 1) == Some(&b'\n') {
1279            return Some((i, 2));
1280        }
1281    }
1282    None
1283}
1284
1285/// Writes the chunk size to the given buffer in hexadecimal format, followed by `\r\n`.
1286#[inline]
1287fn write_chunk_size(dst: &mut [u8; 18], len: usize) -> &[u8] {
1288    let mut n = len;
1289    let mut pos = dst.len() - 2;
1290    loop {
1291        pos -= 1;
1292        dst[pos] = HEX_DIGITS[n & 0xF];
1293        n >>= 4;
1294        if n == 0 {
1295            break;
1296        }
1297    }
1298    dst[dst.len() - 2] = b'\r';
1299    dst[dst.len() - 1] = b'\n';
1300    &dst[pos..]
1301}