1use crate::request::Request;
2use crate::websocket::Websocket;
3use crate::Protocol::HTTP2;
4use crate::Status;
5use crate::{ContentType, Encoding, Handler, HttpError, Method, Protocol, Upgrade};
6use chrono::{DateTime, Duration as dur, Utc};
7use hpack::Encoder;
8use json::{object, JsonValue};
9use log::{error, info};
10use std::io::Error;
11use std::path::{Path, PathBuf};
12use std::{fs, io, thread};
13const FLAG_END_STREAM: u8 = 0x01;
14const FLAG_END_HEADERS: u8 = 0x04;
15#[derive(Clone, Debug)]
17pub struct Response {
18 pub request: Request,
19 pub status: Status,
20 pub headers: JsonValue,
21 pub cookies: JsonValue,
22 pub body: Vec<u8>,
24 pub stream_id: u32,
26 pub key: String,
28 pub version: String,
30 pub factory: fn(out: Websocket) -> Box<dyn Handler>,
31 pub allow_origins: Vec<&'static str>,
33 pub allow_methods: Vec<&'static str>,
35 pub allow_headers: Vec<&'static str>,
37 pub content_type: ContentType,
39}
40impl Response {
41 pub fn new(request: &Request, factory: fn(out: Websocket) -> Box<dyn Handler>) -> Self {
42 Self {
43 request: request.clone(),
44 status: Status::default(),
45 headers: object! {},
46 cookies: object! {},
47 body: vec![],
48 stream_id: 0,
49 key: String::new(),
50 version: String::new(),
51 factory,
52 allow_origins: vec![],
53 allow_methods: vec![],
54 allow_headers: vec![],
55 content_type: ContentType::Other(String::new()),
56 }
57 }
58 pub fn handle(mut self) -> io::Result<()> {
59 match self.request.upgrade {
60 Upgrade::Websocket => {
61 self.handle_protocol_ws()?;
62 return Ok(());
63 }
64 Upgrade::Http | Upgrade::Other(_) => {}
65 Upgrade::H2c => {
66 let _ = self.handle_protocol_h2c();
67 }
68 }
69
70 match self.request.protocol {
71 Protocol::HTTP1_0 => self.handle_protocol_http0()?,
72 Protocol::HTTP1_1 => self.handle_protocol_http1()?,
73 Protocol::HTTP2 => self.handle_protocol_http2()?,
74 Protocol::HTTP3 | Protocol::Other(_) => {}
75 }
76 Ok(())
77 }
78 fn handle_protocol_http0(&mut self) -> io::Result<()> {
79 let websocket = Websocket::http(self.request.clone(), self.clone());
80 let mut factory = (self.factory)(websocket);
81 match self.request.method {
82 Method::OPTIONS => {
83 factory.on_options(self);
84 match self.on_options() {
85 Ok(()) => match self.status(200).send() {
86 Ok(()) => {}
87 Err(e) => {
88 return Err(Error::other(format!(
89 "1004: {} {} {}",
90 self.request.uri.path, e.code, e.body
91 )))
92 }
93 },
94 Err(e) => {
95 return {
96 self.status(e.code).txt(e.body.as_str()).send().unwrap();
97 Ok(())
98 }
99 }
100 }
101 }
102 Method::GET => {
103 if let Ok(e) = self.read_resource() {
104 if self.request.header.has_key("range") {
105 return match self.status(206).range(&e).send() {
106 Ok(()) => Ok(()),
107 Err(e) => Err(Error::other(format!(
108 "1003: {} {} {}",
109 self.request.uri.path, e.code, e.body
110 ))),
111 };
112 }
113 return match self.status(200).file(&e).send() {
114 Ok(_) => Ok(()),
115 Err(e) => Err(Error::other(format!(
116 "1003: {} {} {}",
117 self.request.uri.path, e.code, e.body
118 ))),
119 };
120 }
121 factory.on_request(self.request.clone(), self);
122 factory.on_response(self);
123 match self.send() {
124 Ok(()) => {}
125 Err(e) => {
126 return Err(Error::other(format!(
127 "1002: {} {} {}",
128 self.request.uri.path, e.code, e.body
129 )))
130 }
131 }
132 }
133 _ => {
134 factory.on_request(self.request.clone(), self);
135 factory.on_response(self);
136 match self.send() {
137 Ok(_) => {}
138 Err(e) => return Err(Error::other(format!("1001: {} {}", e.code, e.body))),
139 }
140 }
141 }
142 Ok(())
143 }
144 fn handle_protocol_http1(&mut self) -> io::Result<()> {
145 self.handle_protocol_http0()
146 }
147 fn handle_protocol_http2(&mut self) -> io::Result<()> {
148 let websocket = Websocket::http(self.request.clone(), self.clone());
149 let mut factory = (self.factory)(websocket);
150
151 match self.request.method {
152 Method::OPTIONS => {
153 factory.on_options(self);
154 match self.send() {
155 Ok(_) => {}
156 Err(e) => return Err(Error::other(format!("2001: {} {}", e.code, e.body))),
157 };
158 }
159 Method::GET => {
160 if let Ok(e) = self.read_resource() {
161 return match self.status(200).file(&e).send() {
162 Ok(_) => Ok(()),
163 Err(e) => Err(Error::other(e.body)),
164 };
165 }
166 factory.on_request(self.request.clone(), self);
167 factory.on_response(self);
168 match self.send() {
169 Ok(()) => {}
170 Err(e) => return Err(Error::other(format!("2002: {} {}", e.code, e.body))),
171 }
172 }
173 _ => {
174 factory.on_request(self.request.clone(), self);
175 factory.on_response(self);
176 match self.send() {
177 Ok(_) => {}
178 Err(e) => return Err(Error::other(format!("2003: {} {}", e.code, e.body))),
179 }
180 }
181 }
182 Ok(())
183 }
184 fn handle_protocol_ws(&mut self) -> io::Result<()> {
185 let mut websocket = Websocket::new(self.request.clone(), self.clone());
186 let _ = websocket.handle();
187 Ok(())
188 }
189 fn handle_protocol_h2c(&mut self) -> Result<(), HttpError> {
190 self.header("Upgrade", "h2c");
191 self.header("Connection", "Upgrade");
192 match self.status(101).send() {
193 Ok(()) => self.headers.clear(),
194 Err(e) => return Err(e),
195 };
196 self.request.protocol = HTTP2;
197 self.request
198 .scheme
199 .lock()
200 .unwrap()
201 .http2_send_server_settings()?;
202 let mut data = vec![];
203 self.request.scheme.lock().unwrap().read(&mut data)?;
204
205 let t = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
206 if let Some(pos) = data.windows(t.len()).position(|window| window == t) {
207 let _ = data.drain(..pos).collect::<Vec<u8>>();
208 data.drain(..t.len());
209 } else {
210 return Err(HttpError::new(400, "请求行错误"));
211 }
212 let (_payload, _frame_type, flags, _stream_id) = self
213 .request
214 .scheme
215 .lock()
216 .unwrap()
217 .http2_packet(&mut data)?;
218 if flags & 0x01 == 0 {
219 self.request.scheme.lock().unwrap().http2_settings_ack()?;
220 }
221 let (_payload, _frame_type, _flags, _stream_id) = self
222 .request
223 .scheme
224 .lock()
225 .unwrap()
226 .http2_packet(&mut data)?;
227 let (payload, _frame_type, _flags, _stream_id) = self
228 .request
229 .scheme
230 .lock()
231 .unwrap()
232 .http2_packet(&mut data)?;
233 if payload.len() == 4 {
234 let raw = u32::from_be_bytes(payload.clone().try_into().unwrap());
235 let increment = raw & 0x7FFF_FFFF; if self.request.config.debug {
237 info!("WindowUpdate: increment = {} {:?}", increment, payload);
238 }
239 } else {
240 return Err(HttpError::new(
241 400,
242 format!("Invalid WindowUpdate frame length: {}", payload.len()).as_str(),
243 ));
244 }
245 Ok(())
246 }
247 fn read_resource(&mut self) -> io::Result<PathBuf> {
250 let sanitized_path = self.request.uri.path.trim_start_matches('/');
252 if sanitized_path.contains("..") {
253 return Err(Error::other(
254 "Invalid path: directory traversal not allowed",
255 ));
256 }
257
258 if self.request.uri.path != "/" {
259 let base_dir = self
260 .request
261 .config
262 .root_path
263 .join(self.request.config.public.clone());
264 let file = base_dir.join(sanitized_path);
265 if let (Ok(canonical_base), Ok(canonical_file)) =
267 (base_dir.canonicalize(), file.canonicalize())
268 {
269 if canonical_file.starts_with(&canonical_base) && file.is_file() {
270 return Ok(file);
271 }
272 } else if file.is_file() {
273 return Ok(file);
274 }
275 }
276 if self.request.uri.path == "/" {
277 let file = self
278 .request
279 .config
280 .root_path
281 .join("webpage")
282 .join(self.request.config.webpage.clone())
283 .join("index.html");
284 if file.is_file() {
285 return Ok(file);
286 }
287 } else {
288 let base_dir = self
289 .request
290 .config
291 .root_path
292 .join("webpage")
293 .join(self.request.config.webpage.clone());
294 let file = base_dir.join(sanitized_path);
295 if let (Ok(canonical_base), Ok(canonical_file)) =
297 (base_dir.canonicalize(), file.canonicalize())
298 {
299 if canonical_file.starts_with(&canonical_base) && file.is_file() {
300 return Ok(file);
301 }
302 } else if file.is_file() {
303 return Ok(file);
304 }
305 }
306 Err(Error::other("Not a file"))
307 }
308 pub fn status(&mut self, code: u16) -> &mut Self {
309 self.status.set_code(code);
310 self
311 }
312 pub fn location(&mut self, uri: &str) -> &mut Self {
314 self.header("Location", uri);
315 self
316 }
317 pub fn set_host(&mut self, host: &str) -> &mut Self {
319 self.header("Host", host);
320 self
321 }
322
323 pub fn header(&mut self, key: &str, value: &str) -> &mut Self {
324 self.headers[key] = value.into();
325 self
326 }
327 pub fn cookie(&mut self, key: &str, value: &str) -> &mut Self {
328 self.cookies[key] = value.into();
329 self
330 }
331 pub fn cookie_with_options(&mut self, options: CookieOptions) -> &mut Self {
332 self.cookies[options.name.as_str()] = options.to_header_value().into();
333 self
334 }
335 fn get_date(&self, s: i64) -> String {
336 let utc: DateTime<Utc> = Utc::now();
337 let future = utc + dur::seconds(s); future.format("%a, %d %b %Y %H:%M:%S GMT").to_string()
339 }
340 pub fn html(&mut self, value: &str) -> &mut Self {
342 if self.request.config.charset.is_empty() {
343 self.header(
344 "Content-Type",
345 format!("{};", Extension::form("html").as_str()).as_str(),
346 );
347 } else {
348 self.header(
349 "Content-Type",
350 format!(
351 "{}; charset={}",
352 Extension::form("html").as_str(),
353 self.request.config.charset
354 )
355 .as_str(),
356 );
357 }
358 self.content_type = ContentType::Html;
359 self.body = value.as_bytes().to_vec();
360 self
361 }
362 pub fn txt(&mut self, value: &str) -> &mut Self {
364 if self.request.config.charset.is_empty() {
365 self.header(
366 "Content-Type",
367 Extension::form("txt").as_str().to_string().as_str(),
368 );
369 } else {
370 self.header(
371 "Content-Type",
372 format!(
373 "{}; charset={}",
374 Extension::form("txt").as_str(),
375 self.request.config.charset
376 )
377 .as_str(),
378 );
379 }
380 self.content_type = ContentType::Text;
381 self.body = value.as_bytes().to_vec();
382 self
383 }
384 pub fn json(&mut self, value: JsonValue) -> &mut Self {
386 if self.request.config.charset.is_empty() {
387 self.header(
388 "Content-Type",
389 Extension::form("json").as_str().to_string().as_str(),
390 );
391 } else {
392 self.header(
393 "Content-Type",
394 format!(
395 "{}; charset={}",
396 Extension::form("json").as_str(),
397 self.request.config.charset
398 )
399 .as_str(),
400 );
401 }
402 self.content_type = ContentType::Json;
403 self.body = value.to_string().into_bytes();
404 self
405 }
406 pub fn download(&mut self, filename: &Path) -> &mut Self {
415 let Ok(file) = fs::read(filename) else {
416 self.status(404);
417 return self;
418 };
419 let extension = filename
420 .extension()
421 .unwrap()
422 .to_str()
423 .unwrap()
424 .to_lowercase();
425
426 if self.request.config.charset.is_empty() {
427 self.header(
428 "Content-Type",
429 Extension::form(extension.as_str())
430 .as_str()
431 .to_string()
432 .as_str(),
433 );
434 } else {
435 self.header(
436 "Content-Type",
437 format!(
438 "{}; charset={}",
439 Extension::form(extension.as_str()).as_str(),
440 self.request.config.charset
441 )
442 .as_str(),
443 );
444 }
445
446 let encoded_file_name = br_crypto::encoding::urlencoding_encode(
447 filename.file_name().unwrap().to_str().unwrap(),
448 );
449 self.header(
450 "Content-Disposition",
451 format!(r"attachment; filename={encoded_file_name}").as_str(),
452 );
453 self.header("Cache-Control", "no-cache");
454 self.header("ETag", br_crypto::md5::encrypt_hex(&file).as_str());
455 self.body = file;
456 self
457 }
458 pub fn range(&mut self, filename: &Path) -> &mut Self {
460 let Ok(file) = fs::read(filename) else {
461 self.status(404);
462 return self;
463 };
464 let range = self.request.header["range"].to_string();
465 let range = range.trim_start_matches("bytes=");
466 let parts: Vec<&str> = range.split('-').collect();
467
468 let range_start = match parts.first().and_then(|s| s.parse::<usize>().ok()) {
469 Some(v) => v,
470 None => {
471 self.status(416);
472 self.header("Content-Range", format!("bytes */{}", file.len()).as_str());
473 return self;
474 }
475 };
476
477 let range_end = if parts.len() > 1 && !parts[1].is_empty() {
478 match parts[1].parse::<usize>() {
479 Ok(v) => v,
480 Err(_) => {
481 self.status(416);
482 self.header("Content-Range", format!("bytes */{}", file.len()).as_str());
483 return self;
484 }
485 }
486 } else {
487 file.len().saturating_sub(1)
488 };
489
490 if file.len() < range_end {
491 self.status(416);
492 self.header("Content-Range", format!("bytes */{}", file.len()).as_str());
493 return self;
494 }
495
496 let extension = filename
497 .extension()
498 .unwrap()
499 .to_str()
500 .unwrap()
501 .to_lowercase();
502
503 if self.request.config.charset.is_empty() {
504 self.header(
505 "Content-Type",
506 Extension::form(extension.as_str())
507 .as_str()
508 .to_string()
509 .as_str(),
510 );
511 } else {
512 self.header(
513 "Content-Type",
514 format!(
515 "{}; charset={}",
516 Extension::form(extension.as_str()).as_str(),
517 self.request.config.charset
518 )
519 .as_str(),
520 );
521 }
522
523 self.header("Accept-Ranges", "bytes");
524 self.header(
525 "content-length",
526 (range_end - range_start + 1).to_string().as_str(),
527 );
528 self.header(
529 "Content-Range",
530 format!("bytes {}-{}/{}", range_start, range_end, file.len()).as_str(),
531 );
532 self.body = file[range_start..=range_end].to_vec();
533 self
534 }
535 pub fn file(&mut self, filename: &Path) -> &mut Self {
542 let Ok(file) = fs::read(filename) else {
543 self.status(404);
544 return self;
545 };
546
547 self.header("Access-Control-Expose-Headers", "Content-Disposition");
548 let extension = match filename.extension() {
549 None => String::new(),
550 Some(e) => e.to_str().unwrap().to_lowercase(),
551 };
552 if self.request.config.charset.is_empty() {
553 self.header(
554 "Content-Type",
555 Extension::form(extension.as_str())
556 .as_str()
557 .to_string()
558 .as_str(),
559 );
560 } else {
561 self.header(
562 "Content-Type",
563 format!(
564 "{}; charset={}",
565 Extension::form(extension.as_str()).as_str(),
566 self.request.config.charset
567 )
568 .as_str(),
569 );
570 }
571
572 self.header(
573 "Content-Disposition",
574 format!(
575 r#"inline; filename="{}""#,
576 filename
577 .file_name()
578 .and_then(|n| n.to_str())
579 .unwrap_or("download")
580 )
581 .as_str(),
582 );
583
584 self.header("Accept-Ranges", "bytes");
585
586 self.header(
587 "Cache-Control",
588 format!("public, max-age={}", 81400).as_str(),
589 );
590 self.header("Expires", &self.clone().get_date(81400));
591 self.body = file;
592 self
593 }
594 pub fn send(&mut self) -> Result<(), HttpError> {
600 match &self.request.protocol {
601 Protocol::HTTP1_0 | Protocol::HTTP1_1 => Ok(self.send_http1()?),
602 Protocol::HTTP2 => Ok(self.send_http2()?),
603 Protocol::HTTP3 => {
604 error!("Other1:{:?} {:?}", thread::current().id(), self.request);
605 Err(HttpError::new(500, "暂未实现HTTP3"))
606 }
607 Protocol::Other(e) => {
608 error!("Other:{:?} {:?}", thread::current().id(), self.request);
609 Err(HttpError::new(
610 500,
611 format!(
612 "暂未实现Other: {} {} {:?}",
613 e,
614 self.request.uri.path,
615 thread::current().id()
616 )
617 .as_str(),
618 ))
619 }
620 }
621 }
622 fn send_http1(&mut self) -> Result<(), HttpError> {
623 let mut header = vec![];
624 header.push(format!(
625 "{} {} {}",
626 self.request.protocol.str(),
627 self.status.code,
628 self.status.reason
629 ));
630 self.header("Date", &self.get_date(0));
631
632 if !self.headers.has_key("X-Content-Type-Options") {
633 self.header("X-Content-Type-Options", "nosniff");
634 }
635 if !self.headers.has_key("X-Frame-Options") {
636 self.header("X-Frame-Options", "SAMEORIGIN");
637 }
638 if !self.headers.has_key("X-XSS-Protection") {
639 self.header("X-XSS-Protection", "1; mode=block");
640 }
641
642 match self.request.method {
643 Method::HEAD => {
644 self.header("Content-Length", self.body.len().to_string().as_str());
645 self.body = vec![];
646 }
647 Method::OPTIONS => {
648 self.body = vec![];
649 }
650 _ => {
651 if self.status.code == 101 {
652 } else {
654 match self.request.accept_encoding {
655 Encoding::Gzip => {
656 self.header(
657 "Content-Encoding",
658 self.request.accept_encoding.clone().str(),
659 );
660 if let Ok(e) = self.request.accept_encoding.compress(&self.body.clone())
661 {
662 self.body = e
663 };
664 self.header("Content-Length", self.body.len().to_string().as_str());
665 }
666 _ => {
667 self.header("Content-Length", self.body.len().to_string().as_str());
668 }
669 }
670 }
671 }
672 };
673
674 for (key, value) in self.headers.entries() {
675 header.push(format!("{key}: {value}"));
676 }
677
678 for (key, value) in self.cookies.entries() {
679 header.push(format!(
680 "Set-Cookie: {key}={value}; Path=/; HttpOnly; SameSite=Lax"
681 ));
682 }
683
684 if self.request.config.debug {
685 info!("\r\n=================响应信息 {:?}=================\r\n{}\r\n===========================================",thread::current().id(),header.join("\r\n"));
686 match self.request.accept_encoding {
687 Encoding::Gzip => {}
688 _ => {
689 match self.content_type {
690 ContentType::Text
691 | ContentType::Html
692 | ContentType::Json
693 | ContentType::FormUrlencoded => {
694 info!("\r\n=================响应体 {:?}=================\r\n{}\r\n===========================================",thread::current().id(),String::from_utf8_lossy(self.body.as_slice()));
695 }
696 _ => {}
697 };
698 }
699 }
700 }
701 let mut headers = format!("{}\r\n\r\n", header.join("\r\n")).into_bytes();
702 headers.extend(self.body.clone());
703 self.request
704 .scheme
705 .lock()
706 .unwrap()
707 .write_all(headers.as_slice())?;
708 Ok(())
709 }
710 fn send_http2(&mut self) -> Result<(), HttpError> {
711 let max_frame_size: usize = 16_384;
712 self.stream_id += 1;
713 let header_frames = self.http2_header(self.stream_id, max_frame_size);
715 let data_frames = self.http2_body(self.stream_id, true, max_frame_size);
716
717 let mut writer = self.request.scheme.lock().unwrap();
719 for f in header_frames.clone() {
720 writer.write_all(&f)?;
721 }
722 for f in data_frames.clone() {
723 writer.write_all(&f)?;
724 }
725 Ok(())
726 }
727
728 fn http2_header(&mut self, stream_id: u32, max_frame_size: usize) -> Vec<Vec<u8>> {
729 let mut headers: Vec<(Vec<u8>, Vec<u8>)> = vec![
730 (
731 b":status".to_vec(),
732 self.status.code.to_string().into_bytes(),
733 ),
734 (b"date".to_vec(), self.get_date(0).into_bytes()),
735 ];
736
737 match self.request.method {
738 Method::HEAD => {
739 self.header("content-length", self.body.len().to_string().as_str());
740 self.body.clear(); }
742 Method::OPTIONS => {
743 self.body.clear();
744 self.header("content-length", "0");
745 }
746 _ => {
747 self.header("content-length", self.body.len().to_string().as_str());
748 }
749 }
750
751 headers.extend(self.headers.entries().map(|(k, v)| {
752 (
753 k.to_string().to_lowercase().into_bytes(),
754 v.to_string().into_bytes(),
755 )
756 }));
757 headers.extend(self.cookies.entries().map(|(k, v)| {
758 (
759 b"set-cookie".to_vec(),
760 format!("{k}={v}; Path=/; HttpOnly; SameSite=Lax").into_bytes(),
761 )
762 }));
763
764 if self.request.config.debug {
765 let dbg = headers
766 .iter()
767 .map(|(n, v)| {
768 format!(
769 "{}: {}",
770 String::from_utf8_lossy(n),
771 String::from_utf8_lossy(v)
772 )
773 })
774 .collect::<Vec<_>>()
775 .join("\r\n");
776 info!("\n=================响应信息 {:?}=================\n{}\n===========================================",
777 std::thread::current().id(), dbg);
778 }
779
780 let mut encoder = Encoder::new();
781 let block = encoder.encode(headers.iter().map(|h| (&h.0[..], &h.1[..])));
783
784 let end_stream = self.body.is_empty();
785 let mut frames = Vec::new();
786 let mut remaining = block.as_slice();
787 let mut first = true;
788
789 while !remaining.is_empty() {
790 let take = remaining.len().min(max_frame_size);
791 let (chunk, rest) = remaining.split_at(take);
792 remaining = rest;
793
794 let is_last = remaining.is_empty();
795 let mut flags = 0u8;
796 if is_last {
797 flags |= FLAG_END_HEADERS;
798 }
799 if is_last && end_stream {
800 flags |= FLAG_END_STREAM;
801 }
802
803 let mut f = Vec::with_capacity(9 + chunk.len());
805 let len = chunk.len();
806 f.push(((len >> 16) & 0xFF) as u8);
807 f.push(((len >> 8) & 0xFF) as u8);
808 f.push((len & 0xFF) as u8);
809 f.push(if first { 0x01 } else { 0x09 }); f.push(flags);
811 f.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
812 f.extend_from_slice(chunk);
813
814 frames.push(f);
815 first = false;
816 }
817
818 if frames.is_empty() {
820 let mut f = vec![
821 0,
822 0,
823 0,
824 0x01,
825 FLAG_END_HEADERS | if end_stream { FLAG_END_STREAM } else { 0 },
826 0,
827 0,
828 0,
829 0,
830 ];
831 f[5..9].copy_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
832 frames.push(f);
833 }
834
835 frames
836 }
837 fn http2_body(
838 &mut self,
839 stream_id: u32,
840 end_stream: bool,
841 max_frame_size: usize,
842 ) -> Vec<Vec<u8>> {
843 if self.body.is_empty() {
844 return Vec::new();
845 }
846 let mut frames = Vec::new();
847 let mut off = 0usize;
848 let total = self.body.len();
849
850 while off < total {
851 let take = (total - off).min(max_frame_size);
852 let chunk = &self.body[off..off + take];
853 off += take;
854
855 let last = off == total;
856 frames.push(self.build_data_frame(stream_id, chunk, last && end_stream));
857 }
858 frames
859 }
860 fn build_data_frame(&self, stream_id: u32, payload: &[u8], end_stream: bool) -> Vec<u8> {
861 let len = payload.len();
862 let mut f = Vec::with_capacity(9 + len);
863 f.push(((len >> 16) & 0xFF) as u8);
864 f.push(((len >> 8) & 0xFF) as u8);
865 f.push((len & 0xFF) as u8);
866 f.push(0x00); f.push(if end_stream { FLAG_END_STREAM } else { 0 });
868 f.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
869 if !payload.is_empty() {
870 f.extend_from_slice(payload);
871 }
872 f
873 }
874 fn on_options(&mut self) -> Result<(), HttpError> {
875 if self.allow_origins.is_empty() {
876 self.header("Access-Control-Allow-Origin", "*");
877 } else if self.request.header.has_key("origin") {
878 if self.allow_origins.contains(&self.request.origin.as_str()) {
879 self.header(
880 "Access-Control-Allow-Origin",
881 self.request.origin.to_string().as_str(),
882 );
883 } else {
884 return Err(HttpError::new(403, "Origin not allowed"));
885 }
886 } else {
887 return Err(HttpError::new(403, "Origin not allowed"));
888 }
889
890 if self.allow_headers.is_empty() {
891 if !self
892 .request
893 .header
894 .has_key("access-control-request-headers")
895 {
896 return Err(HttpError::new(403, "headers not allowed"));
897 }
898 self.header(
899 "Access-Control-Allow-Headers",
900 self.request.header["access-control-request-headers"]
901 .to_string()
902 .as_str(),
903 );
904 } else if !self
905 .request
906 .header
907 .has_key("access-control-request-headers")
908 {
909 let headers = self.allow_headers.join(",");
910 self.header("Access-Control-Allow-Headers", headers.to_string().as_str());
911 } else {
912 let headers = self.allow_headers.join(",");
913 self.header(
914 "Access-Control-Allow-Headers",
915 format!(
916 "{},{}",
917 self.request.header["access-control-request-headers"], headers
918 )
919 .as_str(),
920 );
921 }
922
923 if self.allow_methods.is_empty() {
924 if !self.request.header.has_key("access-control-request-method") {
925 return Err(HttpError::new(403, "methods not allowed"));
926 }
927 self.header(
928 "Access-Control-Allow-Methods",
929 self.request.header["access-control-request-method"]
930 .to_string()
931 .as_str(),
932 );
933 } else {
934 let methods = self.allow_methods.join(",");
935 self.header("Access-Control-Allow-Methods", methods.to_string().as_str());
936 }
937 self.header(
938 "Vary",
939 "Origin, Access-Control-Request-Method, Access-Control-Request-Headers",
940 );
941 Ok(())
942 }
943}
944
945enum Extension {}
947impl Extension {
948 pub fn form(extension: &str) -> String {
949 match extension.to_lowercase().as_str() {
950 "html" | "htm" => "text/html",
951 "css" => "text/css",
952 "js" | "mjs" => "application/javascript",
953 "json" => "application/json",
954 "xml" => "application/xml",
955 "txt" => "text/plain",
956 "csv" => "text/csv",
957 "md" => "text/markdown",
958
959 "png" => "image/png",
960 "jpg" | "jpeg" => "image/jpeg",
961 "gif" => "image/gif",
962 "svg" => "image/svg+xml",
963 "webp" => "image/webp",
964 "ico" => "image/x-icon",
965 "bmp" => "image/bmp",
966 "tiff" | "tif" => "image/tiff",
967 "avif" => "image/avif",
968
969 "mp4" => "video/mp4",
970 "webm" => "video/webm",
971 "avi" => "video/x-msvideo",
972 "mov" => "video/quicktime",
973 "mkv" => "video/x-matroska",
974
975 "mp3" => "audio/mpeg",
976 "wav" => "audio/wav",
977 "ogg" => "audio/ogg",
978 "flac" => "audio/flac",
979 "aac" => "audio/aac",
980
981 "woff" => "font/woff",
982 "woff2" => "font/woff2",
983 "ttf" => "font/ttf",
984 "otf" => "font/otf",
985 "eot" => "application/vnd.ms-fontobject",
986
987 "pdf" => "application/pdf",
988 "doc" => "application/msword",
989 "docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
990 "xls" => "application/vnd.ms-excel",
991 "xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
992 "ppt" => "application/vnd.ms-powerpoint",
993 "pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
994
995 "zip" => "application/zip",
996 "rar" => "application/vnd.rar",
997 "7z" => "application/x-7z-compressed",
998 "tar" => "application/x-tar",
999 "gz" => "application/gzip",
1000
1001 "wasm" => "application/wasm",
1002 "map" => "application/json",
1003 _ => "application/octet-stream",
1004 }
1005 .to_string()
1006 }
1007}
1008
1009#[derive(Clone, Debug, Default)]
1010pub struct CookieOptions {
1011 pub name: String,
1012 pub value: String,
1013 pub path: Option<String>,
1014 pub domain: Option<String>,
1015 pub max_age: Option<i64>,
1016 pub expires: Option<String>,
1017 pub secure: bool,
1018 pub http_only: bool,
1019 pub same_site: SameSite,
1020}
1021
1022#[derive(Clone, Debug, Default)]
1023pub enum SameSite {
1024 Strict,
1025 #[default]
1026 Lax,
1027 None,
1028}
1029
1030impl CookieOptions {
1031 #[must_use]
1032 pub fn new(name: &str, value: &str) -> Self {
1033 Self {
1034 name: name.to_string(),
1035 value: value.to_string(),
1036 path: Some("/".to_string()),
1037 http_only: true,
1038 same_site: SameSite::Lax,
1039 ..Default::default()
1040 }
1041 }
1042
1043 pub fn path(mut self, path: &str) -> Self {
1044 self.path = Some(path.to_string());
1045 self
1046 }
1047
1048 pub fn domain(mut self, domain: &str) -> Self {
1049 self.domain = Some(domain.to_string());
1050 self
1051 }
1052
1053 pub fn max_age(mut self, seconds: i64) -> Self {
1054 self.max_age = Some(seconds);
1055 self
1056 }
1057
1058 pub fn expires(mut self, date: &str) -> Self {
1059 self.expires = Some(date.to_string());
1060 self
1061 }
1062
1063 pub fn secure(mut self, secure: bool) -> Self {
1064 self.secure = secure;
1065 self
1066 }
1067
1068 pub fn http_only(mut self, http_only: bool) -> Self {
1069 self.http_only = http_only;
1070 self
1071 }
1072
1073 pub fn same_site(mut self, same_site: SameSite) -> Self {
1074 self.same_site = same_site;
1075 self
1076 }
1077
1078 #[must_use]
1079 pub fn to_header_value(&self) -> String {
1080 let mut parts = vec![format!("{}={}", self.name, self.value)];
1081
1082 if let Some(ref path) = self.path {
1083 parts.push(format!("Path={path}"));
1084 }
1085 if let Some(ref domain) = self.domain {
1086 parts.push(format!("Domain={domain}"));
1087 }
1088 if let Some(max_age) = self.max_age {
1089 parts.push(format!("Max-Age={max_age}"));
1090 }
1091 if let Some(ref expires) = self.expires {
1092 parts.push(format!("Expires={expires}"));
1093 }
1094 if self.secure {
1095 parts.push("Secure".to_string());
1096 }
1097 if self.http_only {
1098 parts.push("HttpOnly".to_string());
1099 }
1100 match self.same_site {
1101 SameSite::Strict => parts.push("SameSite=Strict".to_string()),
1102 SameSite::Lax => parts.push("SameSite=Lax".to_string()),
1103 SameSite::None => parts.push("SameSite=None".to_string()),
1104 }
1105
1106 parts.join("; ")
1107 }
1108}