tower_http/services/fs/
mod.rs1use bytes::Bytes;
4use futures_core::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 future::ResponseFuture as ServeFileSystemResponseFuture,
21 Backend,
22 DefaultServeDirFallback,
23 File,
24 Metadata,
25 ResponseBody as ServeFileSystemResponseBody,
27 ServeDir,
28 TokioBackend,
29 TokioFile,
30 },
31 serve_file::ServeFile,
32};
33
34pin_project! {
35 #[derive(Debug)]
38 pub struct AsyncReadBody<T> {
39 #[pin]
40 reader: ReaderStream<T>,
41 }
42}
43
44impl<T> AsyncReadBody<T>
45where
46 T: AsyncRead,
47{
48 pub fn with_capacity(read: T, capacity: usize) -> Self {
51 Self {
52 reader: ReaderStream::with_capacity(read, capacity),
53 }
54 }
55
56 fn with_capacity_limited(
57 read: T,
58 capacity: usize,
59 max_read_bytes: u64,
60 ) -> AsyncReadBody<Take<T>> {
61 AsyncReadBody {
62 reader: ReaderStream::with_capacity(read.take(max_read_bytes), capacity),
63 }
64 }
65}
66
67impl<T> Body for AsyncReadBody<T>
68where
69 T: AsyncRead,
70{
71 type Data = Bytes;
72 type Error = io::Error;
73
74 fn poll_frame(
75 self: Pin<&mut Self>,
76 cx: &mut Context<'_>,
77 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
78 match std::task::ready!(self.project().reader.poll_next(cx)) {
79 Some(Ok(chunk)) => Poll::Ready(Some(Ok(Frame::data(chunk)))),
80 Some(Err(err)) => Poll::Ready(Some(Err(err))),
81 None => Poll::Ready(None),
82 }
83 }
84}