tower_async_http/services/fs/
mod.rs1use bytes::Bytes;
4use futures_util::Stream;
5use http_body::{Body, Frame};
6use pin_project_lite::pin_project;
7use std::{
8 io,
9 pin::Pin,
10 task::{Context, Poll},
11};
12use tokio::io::{AsyncRead, AsyncReadExt, Take};
13use tokio_util::io::ReaderStream;
14
15mod serve_dir;
16mod serve_file;
17
18pub use self::{
19 serve_dir::{
20 DefaultServeDirFallback,
21 ResponseBody as ServeFileSystemResponseBody,
23 ServeDir,
24 },
25 serve_file::ServeFile,
26};
27
28pin_project! {
29 #[derive(Debug)]
32 pub struct AsyncReadBody<T> {
33 #[pin]
34 reader: ReaderStream<T>,
35 }
36}
37
38impl<T> AsyncReadBody<T>
39where
40 T: AsyncRead,
41{
42 fn with_capacity(read: T, capacity: usize) -> Self {
45 Self {
46 reader: ReaderStream::with_capacity(read, capacity),
47 }
48 }
49
50 fn with_capacity_limited(
51 read: T,
52 capacity: usize,
53 max_read_bytes: u64,
54 ) -> AsyncReadBody<Take<T>> {
55 AsyncReadBody {
56 reader: ReaderStream::with_capacity(read.take(max_read_bytes), capacity),
57 }
58 }
59}
60
61impl<T> Body for AsyncReadBody<T>
62where
63 T: AsyncRead,
64{
65 type Data = Bytes;
66 type Error = io::Error;
67
68 fn poll_frame(
69 self: Pin<&mut Self>,
70 cx: &mut Context<'_>,
71 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
72 match std::task::ready!(self.project().reader.poll_next(cx)) {
73 Some(Ok(chunk)) => Poll::Ready(Some(Ok(Frame::data(chunk)))),
74 Some(Err(err)) => Poll::Ready(Some(Err(err))),
75 None => Poll::Ready(None),
76 }
77 }
78}