1use std::io;
2use std::fmt;
3use std::pin::Pin;
4
5use tokio::fs::File;
6
7use crate::core::connection::HttpConnection;
8use crate::util::escape;
9
10pub trait HttpUpgrade: Send {
16 fn upgrade(&mut self, conn: &mut dyn HttpConnection) -> impl Future<Output = io::Result<()>> + Send;
21}
22
23pub trait HttpUpgradeRaw: Send {
25 fn upgrade_raw<'a>(&'a mut self, conn: &'a mut dyn HttpConnection) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'a>>;
27}
28
29impl<T: HttpUpgrade> HttpUpgradeRaw for T {
30 fn upgrade_raw<'a>(&'a mut self, conn: &'a mut dyn HttpConnection) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'a>> {
31 Box::pin(self.upgrade(conn))
32 }
33}
34
35#[non_exhaustive]
37pub enum HttpBody {
38 Empty,
40 Bytes(Vec<u8>),
42 File { file: File, len: u64 },
44 Upgrade(Box<dyn HttpUpgradeRaw>),
46}
47
48impl fmt::Debug for HttpBody {
49 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 HttpBody::Empty => fmt.write_str("HttpBody::Empty"),
52 HttpBody::Bytes(v) => write!(fmt, r#"HttpBody::Bytes(b"{}")"#, escape::to_utf8(v)),
53 HttpBody::File { file, len } => fmt.debug_struct("HttpBody::File").field("file", file).field("len", len).finish(),
54 HttpBody::Upgrade(_) => fmt.write_str("HttpBody::Upgrade(..)"),
55 }
56 }
57}
58
59impl From<Vec<u8>> for HttpBody {
60 fn from(v: Vec<u8>) -> HttpBody {
61 HttpBody::Bytes(v)
62 }
63}
64
65impl From<String> for HttpBody {
66 fn from(s: String) -> HttpBody {
67 HttpBody::Bytes(s.into_bytes())
68 }
69}
70
71impl From<&str> for HttpBody {
72 fn from(s: &str) -> HttpBody {
73 HttpBody::Bytes(s.to_string().into_bytes())
74 }
75}