sfo_http/http_server/
http_server.rs

1use std::fmt::Debug;
2use std::future::Future;
3use std::path::Path;
4use http::{HeaderName, HeaderValue, Method, StatusCode};
5use http::header::COOKIE;
6use serde::de::DeserializeOwned;
7use serde::{Deserialize, Serialize};
8use tokio::io::AsyncRead;
9use crate::errors::HttpResult;
10
11#[derive(Serialize, Deserialize)]
12pub struct HttpServerResult<T>
13{
14    pub err: u16,
15    pub msg: String,
16    pub result: Option<T>
17}
18
19#[async_trait::async_trait]
20pub trait Request: 'static + Send {
21    fn peer_addr(&self) -> Option<String>;
22    fn local_addr(&self) -> Option<String>;
23    fn remote(&self) -> Option<String>;
24    fn host(&self) -> Option<String>;
25    fn path(&self) -> &str;
26    fn method(&self) -> Method;
27    fn content_type(&self) -> Option<String>;
28    fn header(&self,
29              key: impl Into<HeaderName>, ) -> Option<HeaderValue>;
30    fn header_all(&self, key: impl Into<HeaderName>) -> Vec<HeaderValue>;
31    fn param(&self, key: &str) -> HttpResult<&str>;
32    fn query<T: DeserializeOwned>(&self) -> HttpResult<T>;
33    async fn body_string(&mut self) -> HttpResult<String>;
34    async fn body_bytes(&mut self) -> HttpResult<Vec<u8>>;
35    async fn body_json<T: DeserializeOwned>(&mut self) -> HttpResult<T>;
36    async fn body_form<T: DeserializeOwned>(&mut self) -> HttpResult<T>;
37    fn get_cookie(&self, cookie_name: &str) -> Option<String> {
38        let cookie = self.header_all(COOKIE);
39        if cookie.is_empty() {
40            return None;
41        }
42        let cookie_str = match cookie.last().unwrap().to_str() {
43            Ok(v) => v,
44            Err(_) => return None,
45        };
46        let cookie_list: Vec<_> = cookie_str.split(";").collect();
47        let cookie_list: Vec<(String, String)> = cookie_list.into_iter().map(|v| {
48            let cookie_list: Vec<_> = v.split("=").collect();
49            cookie_list
50        }).filter(|v| v.len() == 2).map(|v| (v[0].trim().to_string(), v[1].trim().to_string())).collect();
51
52        for (name, value) in cookie_list.into_iter() {
53            if name.as_str() == cookie_name {
54                return Some(value);
55            }
56        }
57
58        None
59    }
60}
61
62pub trait Response: 'static + Send {
63    fn from_result<T: Serialize, C: Debug + Copy + Sync + Send + 'static + Into<u16>>(ret: sfo_result::Result<T, C>) -> Self;
64    fn new(status: StatusCode) -> Self;
65    fn insert_header(&mut self, name: HeaderName, value: HeaderValue);
66    fn set_content_type(&mut self, content_type: &str) -> HttpResult<()>;
67    fn set_body(&mut self, body: Vec<u8>);
68    fn set_body_read<R: AsyncRead + Send + Unpin + 'static>(&mut self, reader: R);
69}
70
71#[async_trait::async_trait]
72pub trait Endpoint<Req: Request, Resp: Response>: Send + Sync + 'static {
73    async fn call(&self, req: Req) -> HttpResult<Resp>;
74}
75
76#[async_trait::async_trait]
77impl<Req, Resp, F, Fut> Endpoint<Req, Resp> for F
78where
79    Req: Request,
80    Resp: Response,
81    F: 'static + Send + Clone + Sync + Fn(Req) -> Fut,
82    Fut: Future<Output = HttpResult<Resp>> + Send + 'static,
83{
84    async fn call(&self, req: Req) -> HttpResult<Resp> {
85        let fut = (self)(req);
86        fut.await
87    }
88}
89
90pub type HttpMethod = http::Method;
91
92pub trait HttpServer< Req: Request, Resp: Response> {
93    fn serve(&mut self, path: &str, method: HttpMethod, ep: impl Endpoint<Req, Resp>);
94    fn serve_dir(&mut self, path: &str, dir: impl AsRef<Path>) -> HttpResult<()>;
95    fn serve_file(&mut self, path: &str, file: impl AsRef<Path>) -> HttpResult<()>;
96}
97
98#[derive(Debug, Clone)]
99pub struct HttpServerConfig {
100    pub(crate) server_addr: String,
101    pub(crate) port: u16,
102    pub(crate) allow_origins: Vec<String>,
103    pub(crate) allow_methods: Vec<String>,
104    pub(crate) allow_headers: Vec<String>,
105    pub(crate) expose_headers: Vec<String>,
106    pub(crate) max_age: usize,
107    pub(crate) support_credentials: bool,
108}
109
110impl HttpServerConfig {
111    pub fn new(server_addr: impl Into<String>, port: u16) -> Self {
112        Self {
113            server_addr: server_addr.into(),
114            port,
115            allow_origins: vec![],
116            allow_methods: vec![],
117            allow_headers: vec![],
118            expose_headers: vec![],
119            max_age: 3600,
120            support_credentials: false,
121        }
122    }
123
124    pub fn allow_origins(mut self, origin: Vec<String>) -> Self {
125        self.allow_origins = origin;
126        self
127    }
128
129    pub fn allow_any_origin(mut self) -> Self {
130        self.allow_origins = vec!["*".to_string()];
131        self
132    }
133
134    pub fn allow_methods(mut self, methods: Vec<String>) -> Self {
135        self.allow_methods = methods;
136        self
137    }
138
139    pub fn allow_any_methods(mut self) -> Self {
140        self.allow_methods = vec!["*".to_string()];
141        self
142    }
143
144    pub fn allow_headers(mut self, headers: Vec<String>) -> Self {
145        self.allow_headers = headers;
146        self
147    }
148
149    pub fn allow_any_header(mut self) -> Self {
150        self.allow_headers = vec!["*".to_string()];
151        self
152    }
153
154    pub fn expose_headers(mut self, headers: Vec<String>) -> Self {
155        self.expose_headers = headers;
156        self
157    }
158
159    pub fn expose_any_header(mut self) -> Self {
160        self.expose_headers = vec!["*".to_string()];
161        self
162    }
163
164    pub fn max_age(mut self, age: usize) -> Self {
165        self.max_age = age;
166        self
167    }
168
169    pub fn support_credentials(mut self, support: bool) -> Self {
170        self.support_credentials = support;
171        self
172    }
173}