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
42pub 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 #[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 #[inline]
126 pub fn new(io: Io, options: options::Http1Options) -> Self {
127 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 #[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 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 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 self.read_buf.advance(begin_search + pos + 2);
303 break len;
304 }
305 }
306 };
307 let mut read = 0;
309 if len == 0 && would_have_trailers {
310 return Ok(bytes::Bytes::new()); }
312 let mut just_started = true;
313 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); Ok(chunk)
347 }
348
349 #[inline]
350 async fn read_trailers(&mut self) -> Result<Option<HeaderMap>, std::io::Error> {
351 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 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 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 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 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 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 let (request, body_tx, send_continue_body) = {
472 let Some((head, headers)) = self.get_head().await? else {
473 return Ok(None);
474 };
475 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 let (body_tx, body_rx) = kanal::bounded_async(2);
495
496 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 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 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 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 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 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; 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 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 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 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) = ¤t_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 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 return Ok(());
949 }
950 Err(_) if self.connection_idle => {
951 return Ok(());
953 }
954 Err(_) => {
955 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 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 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 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 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 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 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 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 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 self.write_response(response, version, write_trailers, zerocopy_fn.as_mut())
1145 .await?;
1146
1147 if was_upgraded {
1148 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 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#[inline]
1268fn search_header_body_separator(slice: &[u8]) -> Option<(usize, usize)> {
1269 if slice.len() < 2 {
1270 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#[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}