1use std::{sync::{self, Arc}, net::SocketAddr, convert::Infallible, pin::Pin, task::{Context, Poll}, io::{BufWriter, Write}, fs::{File, self}, collections::HashMap};
2
3use crate::web_server::{Factories, ChiteyError};
4
5use super::util::{TlsCertsKey, throw_chitey_internal_server_error, cors_builder};
6use bytes::{BytesMut, BufMut, Bytes};
7use futures_util::{ready, Future, TryStreamExt};
8use http::{Request, Response, StatusCode, HeaderValue};
9use hyper::{server::{conn::{AddrIncoming, AddrStream}, accept::Accept}, service::{make_service_fn, service_fn}, Server, Body};
10use mime::Mime;
11use rustls::ServerConfig;
12use tokio::io::{AsyncRead, ReadBuf, self, AsyncWrite};
13use urlpattern::UrlPatternMatchInput;
14
15#[derive(Clone)]
21pub struct HttpsServerOpt {
22 pub listen: SocketAddr,
23}
24
25pub async fn launch_https_server (tls_cert_key: TlsCertsKey, https_server_opt: HttpsServerOpt, factories: Factories) -> Result<(), ChiteyError> {
26 let TlsCertsKey{certs, key} = tls_cert_key;
27 let HttpsServerOpt{listen} = https_server_opt;
28
29 let tls_config = {
30 let mut cfg = rustls::ServerConfig::builder()
32 .with_safe_defaults()
33 .with_no_client_auth()
34 .with_single_cert(certs, key).unwrap(); cfg.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
38 sync::Arc::new(cfg)
39 };
40
41 let incoming = AddrIncoming::bind(&listen)
42 .map_err(|e| ChiteyError::InternalServerError(format!("Incoming failed: {:?}", e))).expect("error");
43 let make_service = make_service_fn(move |_| {
44 let factories = factories.clone();
45 let service = service_fn(move |req| {
46 handle_https_service_wrap(req, factories.clone())
47 });
48
49 async move { Ok::<_, Infallible>(service) }
50 });
51 let https_server = Server::builder(HyperAcceptor::new(tls_config, incoming)).serve(make_service);
52
53 println!("Starting to serve on https://{}.", listen);
58 match https_server.await {
59 Ok(_) => Ok(()),
60 Err(e) => Err(ChiteyError::InternalServerError(e.to_string())),
61 }
62}
63
64pub struct HyperAcceptor {
65 config: Arc<ServerConfig>,
66 incoming: AddrIncoming,
67}
68
69impl HyperAcceptor {
70 #[inline]
71 pub fn new(config: Arc<ServerConfig>, incoming: AddrIncoming) -> HyperAcceptor {
72 HyperAcceptor { config, incoming }
73 }
74}
75
76enum State {
77 Handshaking(tokio_rustls::Accept<AddrStream>),
78 Streaming(tokio_rustls::server::TlsStream<AddrStream>),
79}
80
81pub struct HyperStream {
85 state: State,
86}
87
88impl HyperStream {
89 #[inline]
90 fn new(stream: AddrStream, config: Arc<ServerConfig>) -> HyperStream {
91 let accept = tokio_rustls::TlsAcceptor::from(config).accept(stream);
92 HyperStream {
93 state: State::Handshaking(accept),
94 }
95 }
96}
97
98impl AsyncRead for HyperStream {
99 #[inline]
100 fn poll_read(
101 self: Pin<&mut Self>,
102 cx: &mut Context,
103 buf: &mut ReadBuf,
104 ) -> Poll<io::Result<()>> {
105 let pin = self.get_mut();
107 match pin.state {
108 State::Handshaking(ref mut accept) => match ready!(Pin::new(accept).poll(cx)) {
109 Ok(mut stream) => {
110 let result = Pin::new(&mut stream).poll_read(cx, buf);
111 pin.state = State::Streaming(stream);
112 result
113 }
114 Err(err) => Poll::Ready(Err(err)),
115 },
116 State::Streaming(ref mut stream) => Pin::new(stream).poll_read(cx, buf),
117 }
118 }
119}
120
121impl AsyncWrite for HyperStream {
122 #[inline]
123 fn poll_write(
124 self: Pin<&mut Self>,
125 cx: &mut Context<'_>,
126 buf: &[u8],
127 ) -> Poll<io::Result<usize>> {
128 let pin = self.get_mut();
129 match pin.state {
130 State::Handshaking(ref mut accept) => match ready!(Pin::new(accept).poll(cx)) {
131 Ok(mut stream) => {
132 let result = Pin::new(&mut stream).poll_write(cx, buf);
133 pin.state = State::Streaming(stream);
134 result
135 }
136 Err(err) => Poll::Ready(Err(err)),
137 },
138 State::Streaming(ref mut stream) => Pin::new(stream).poll_write(cx, buf),
139 }
140 }
141
142 #[inline]
143 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
144 match self.state {
145 State::Handshaking(_) => Poll::Ready(Ok(())),
146 State::Streaming(ref mut stream) => Pin::new(stream).poll_flush(cx),
147 }
148 }
149
150 #[inline]
151 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
152 match self.state {
153 State::Handshaking(_) => Poll::Ready(Ok(())),
154 State::Streaming(ref mut stream) => Pin::new(stream).poll_shutdown(cx),
155 }
156 }
157}
158
159impl Accept for HyperAcceptor {
160 type Conn = HyperStream;
161 type Error = io::Error;
162
163 #[inline]
164 fn poll_accept(
165 self: Pin<&mut Self>,
166 cx: &mut Context<'_>,
167 ) -> Poll<Option<Result<Self::Conn, Self::Error>>> {
168 let pin = self.get_mut();
169 match ready!(Pin::new(&mut pin.incoming).poll_accept(cx)) {
170 Some(Ok(sock)) => Poll::Ready(Some(Ok(HyperStream::new(sock, pin.config.clone())))),
171 Some(Err(e)) => Poll::Ready(Some(Err(e))),
172 None => Poll::Ready(None),
173 }
174 }
175}
176
177#[inline]
178async fn handle_https_service_wrap(req: Request<Body>, factories: Factories) -> Result<Response<Body>, ChiteyError> {
179 match handle_https_service(req, factories.clone()).await {
180 Ok(v) => Ok(v),
181 Err(e) => {
182 tracing::error!("https: {}", e);
183 Err(e)
184 },
185 }
186}
187
188#[inline]
189async fn handle_https_service(req: Request<Body>, factories: Factories) -> Result<Response<Body>, ChiteyError> {
190 if req.uri().path().contains("..") {
191 let builder = cors_builder()
192 .header("Alt-Svc", "h3=\":443\"; ma=2592000")
193 .status(StatusCode::NOT_FOUND);
194 return match builder.body(Body::empty()) {
195 Ok(v) => Ok(v),
196 Err(e) => Err(ChiteyError::InternalServerError(e.to_string())),
197 }
198 }
199
200 let url = throw_chitey_internal_server_error(req.uri().to_string().parse())?;
201 let input = UrlPatternMatchInput::Url(url);
202 {
203 let method = req.method().clone();
204 let req_contain_key = req.headers().contains_key("Another-Header");
205 for (res, factory) in factories.factories {
206 if res.guard == method {
208 if let Ok(Some(_)) = res.rdef.exec(input.clone()) {
209 let factory_loc = factory.lock().await;
210 if factory_loc.analyze_types(input.clone()) {
211 return match factory_loc.handler_func(input.clone(), (req, false, factories.contexts.clone())).await {
212 Ok(mut resp) => {
213 if req_contain_key {
214 resp.headers_mut().append("Another-Header", HeaderValue::from_static("Ack"));
215 }
216 resp.headers_mut().append("Alt-Svc", HeaderValue::from_static("h3=\":443\"; ma=2592000"));
217 Ok(resp)
218 },
219 Err(e) => Err(ChiteyError::InternalServerError(e.to_string())),
220 }
221 }
222 };
223 }
224 }
225 }
226
227 let builder = cors_builder()
228 .header("Alt-Svc", "h3=\":443\"; ma=2592000")
229 .status(StatusCode::NOT_FOUND);
230
231 match builder.body(Body::from(Bytes::copy_from_slice(b"page not found"))) {
232 Ok(v) => Ok(v),
234 Err(e) => Err(ChiteyError::InternalServerError(e.to_string())),
235 }
236}
237
238pub async fn process_upload(id:String, builder:http::response::Builder, req: Request<Body>) -> Result<Response<Body>, http::Error>{
240 let content_type_option = req.headers().get("content-type");
242 if content_type_option.is_none() {
243 return builder.body(Body::from(""));
244 }
245 let content_type = content_type_option.unwrap();
246 let mime_type_result: Result<mime::Mime, _> = match content_type.to_str() {
247 Ok(s) => s
248 .parse()
249 .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err)),
250 Err(err) => Err(std::io::Error::new(std::io::ErrorKind::Other, err)),
251 };
252 if mime_type_result.is_err() {
253 return builder.body(Body::from(""));
254 }
255 let mime_type = mime_type_result.unwrap();
256 if mime_type.essence_str() != "multipart/form-data" {
257 return builder.body(Body::from(""));
258 }
259 let a = parse_mpart(req, mime_type).await;
260 dbg!(&a);
261 builder.status(StatusCode::OK).body(Body::from(format!("uploadID: {}",id)))
262}
263
264async fn parse_mpart(req: Request<Body>, mime_type: Mime) -> HashMap<String, String>{
268 let mut a = HashMap::new();
269 let boundary = mime_type.get_param("boundary").map(|v| v.to_string()).ok_or_else(|| std::io::Error::new(std::io::ErrorKind::Other, "boundary not found")).unwrap();
270 let (_parts, body) = req.into_parts();
271 let mut multipart_stream = mpart_async::server::MultipartStream::new(boundary, body);
272 while let Ok(Some(mut field)) = multipart_stream.try_next().await {
273 let name = field.name().unwrap().to_string();
274 if let Ok(_filename) = field.filename() {
275 const UPLOAD_DIRNAME: &str = "upload";
276 if fs::create_dir_all(UPLOAD_DIRNAME).is_err(){
277 continue;
279 }
280 let filename = chrono::Utc::now().format("%Y%m%d%H%M%S").to_string();
281 let filename = format!("{UPLOAD_DIRNAME}/{filename}.dat");
282 let mut writer = BufWriter::new(File::create(&filename).unwrap());
283 while let Ok(Some(bytes)) = field.try_next().await {
285 writer.write_all(&bytes).unwrap();
287 }
288 a.insert(name, filename);
290 }else{
291 let mut buffer = BytesMut::new();
292 while let Ok(Some(bytes)) = field.try_next().await {
293 buffer.put(bytes);
294 }
295 let value = String::from_utf8(buffer.to_vec()).unwrap();
296 a.insert(name, value);
297 }
298
299 }
300 a
301}