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;
15const DEFAULT_CACHE_MAX_AGE: u64 = 86400;
16#[derive(Clone, Debug)]
18pub struct Response {
19 pub request: Request,
20 pub status: Status,
21 pub headers: JsonValue,
22 pub cookies: JsonValue,
23 pub body: Vec<u8>,
25 pub stream_id: u32,
27 pub key: String,
29 pub version: String,
31 pub factory: fn(out: Websocket) -> Box<dyn Handler>,
32 pub allow_origins: Vec<&'static str>,
34 pub allow_methods: Vec<&'static str>,
36 pub allow_headers: Vec<&'static str>,
38 pub content_type: ContentType,
40 pub committed: bool,
41 pub stream_started: bool,
42 pub stream_finished: bool,
43}
44
45fn sanitize_header_value(value: &str) -> String {
46 value.chars().filter(|c| *c != '\r' && *c != '\n').collect()
47}
48
49impl Response {
50 pub fn new(request: &Request, factory: fn(out: Websocket) -> Box<dyn Handler>) -> Self {
51 Self {
52 request: request.clone(),
53 status: Status::default(),
54 headers: object! {},
55 cookies: object! {},
56 body: vec![],
57 stream_id: 0,
58 key: String::new(),
59 version: String::new(),
60 factory,
61 allow_origins: vec![],
62 allow_methods: vec![],
63 allow_headers: vec![],
64 content_type: ContentType::Other(String::new()),
65 committed: false,
66 stream_started: false,
67 stream_finished: false,
68 }
69 }
70 pub fn is_committed(&self) -> bool {
71 self.committed
72 }
73 pub fn handle(mut self) -> io::Result<()> {
74 match self.request.upgrade {
75 Upgrade::Websocket => {
76 self.handle_protocol_ws()?;
77 return Ok(());
78 }
79 Upgrade::Http | Upgrade::Other(_) => {}
80 Upgrade::H2c => {
81 let _ = self.handle_protocol_h2c();
82 }
83 }
84
85 match self.request.protocol {
86 Protocol::HTTP1_0 => self.handle_protocol_http0()?,
87 Protocol::HTTP1_1 => self.handle_protocol_http1()?,
88 Protocol::HTTP2 => self.handle_protocol_http2()?,
89 Protocol::HTTP3 | Protocol::Other(_) => {}
90 }
91 Ok(())
92 }
93 fn handle_protocol_http0(&mut self) -> io::Result<()> {
94 let websocket = Websocket::http(self.request.clone(), self.clone());
95 let mut factory = (self.factory)(websocket);
96 match self.request.method {
97 Method::OPTIONS => {
98 factory.on_options(self);
99 match self.on_options() {
100 Ok(()) => match self.status(200).send() {
101 Ok(()) => {}
102 Err(e) => {
103 return Err(Error::other(format!(
104 "1004: {} {} {}",
105 self.request.uri.path, e.code, e.body
106 )))
107 }
108 },
109 Err(e) => {
110 return match self.status(e.code).txt(e.body.as_str()).send() {
111 Ok(()) => Ok(()),
112 Err(e2) => Err(Error::other(format!(
113 "1005: {} {} {}",
114 self.request.uri.path, e2.code, e2.body
115 ))),
116 }
117 }
118 }
119 }
120 Method::GET => {
121 if let Ok(e) = self.read_resource() {
122 if self.request.header.has_key("range") {
123 return match self.status(206).range(&e).send() {
124 Ok(()) => Ok(()),
125 Err(e) => Err(Error::other(format!(
126 "1003: {} {} {}",
127 self.request.uri.path, e.code, e.body
128 ))),
129 };
130 }
131 return match self.status(200).file(&e).send() {
132 Ok(_) => Ok(()),
133 Err(e) => Err(Error::other(format!(
134 "1003: {} {} {}",
135 self.request.uri.path, e.code, e.body
136 ))),
137 };
138 }
139 factory.on_request(self.request.clone(), self);
140 if self.is_committed() {
141 return Ok(());
142 }
143 factory.on_response(self);
144 if self.is_committed() {
145 return Ok(());
146 }
147 match self.send() {
148 Ok(()) => {}
149 Err(e) => {
150 return Err(Error::other(format!(
151 "1002: {} {} {}",
152 self.request.uri.path, e.code, e.body
153 )))
154 }
155 }
156 }
157 _ => {
158 factory.on_request(self.request.clone(), self);
159 if self.is_committed() {
160 return Ok(());
161 }
162 factory.on_response(self);
163 if self.is_committed() {
164 return Ok(());
165 }
166 match self.send() {
167 Ok(_) => {}
168 Err(e) => return Err(Error::other(format!("1001: {} {}", e.code, e.body))),
169 }
170 }
171 }
172 Ok(())
173 }
174 fn handle_protocol_http1(&mut self) -> io::Result<()> {
175 self.handle_protocol_http0()
176 }
177 fn handle_protocol_http2(&mut self) -> io::Result<()> {
178 let websocket = Websocket::http(self.request.clone(), self.clone());
179 let mut factory = (self.factory)(websocket);
180
181 match self.request.method {
182 Method::OPTIONS => {
183 factory.on_options(self);
184 match self.send() {
185 Ok(_) => {}
186 Err(e) => return Err(Error::other(format!("2001: {} {}", e.code, e.body))),
187 };
188 }
189 Method::GET => {
190 if let Ok(e) = self.read_resource() {
191 return match self.status(200).file(&e).send() {
192 Ok(_) => Ok(()),
193 Err(e) => Err(Error::other(e.body)),
194 };
195 }
196 factory.on_request(self.request.clone(), self);
197 if self.is_committed() {
198 return Ok(());
199 }
200 factory.on_response(self);
201 if self.is_committed() {
202 return Ok(());
203 }
204 match self.send() {
205 Ok(()) => {}
206 Err(e) => return Err(Error::other(format!("2002: {} {}", e.code, e.body))),
207 }
208 }
209 _ => {
210 factory.on_request(self.request.clone(), self);
211 if self.is_committed() {
212 return Ok(());
213 }
214 factory.on_response(self);
215 if self.is_committed() {
216 return Ok(());
217 }
218 match self.send() {
219 Ok(_) => {}
220 Err(e) => return Err(Error::other(format!("2003: {} {}", e.code, e.body))),
221 }
222 }
223 }
224 Ok(())
225 }
226 fn handle_protocol_ws(&mut self) -> io::Result<()> {
227 let mut websocket = Websocket::new(self.request.clone(), self.clone());
228 let _ = websocket.handle();
229 Ok(())
230 }
231 fn handle_protocol_h2c(&mut self) -> Result<(), HttpError> {
232 self.header("Upgrade", "h2c");
233 self.header("Connection", "Upgrade");
234 match self.status(101).send() {
235 Ok(()) => self.headers.clear(),
236 Err(e) => return Err(e),
237 };
238 self.request.protocol = HTTP2;
239 self.request
240 .scheme
241 .lock()
242 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
243 .http2_send_server_settings()?;
244 let mut data = vec![];
245 self.request
246 .scheme
247 .lock()
248 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
249 .read(&mut data)?;
250
251 let t = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
252 if let Some(pos) = data.windows(t.len()).position(|window| window == t) {
253 let _ = data.drain(..pos).collect::<Vec<u8>>();
254 data.drain(..t.len());
255 } else {
256 return Err(HttpError::new(400, "请求行错误"));
257 }
258 let (_payload, _frame_type, flags, _stream_id) = self
259 .request
260 .scheme
261 .lock()
262 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
263 .http2_packet(&mut data)?;
264 if flags & 0x01 == 0 {
265 self.request
266 .scheme
267 .lock()
268 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
269 .http2_settings_ack()?;
270 }
271 let (_payload, _frame_type, _flags, _stream_id) = self
272 .request
273 .scheme
274 .lock()
275 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
276 .http2_packet(&mut data)?;
277 let (payload, _frame_type, _flags, _stream_id) = self
278 .request
279 .scheme
280 .lock()
281 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
282 .http2_packet(&mut data)?;
283 if payload.len() == 4 {
284 let raw = u32::from_be_bytes(
285 <[u8; 4]>::try_from(&payload[..4])
286 .map_err(|_| HttpError::new(400, "Invalid WindowUpdate frame data"))?,
287 );
288 let increment = raw & 0x7FFF_FFFF; if self.request.config.debug {
290 info!("WindowUpdate: increment = {} {:?}", increment, payload);
291 }
292 } else {
293 return Err(HttpError::new(
294 400,
295 format!("Invalid WindowUpdate frame length: {}", payload.len()).as_str(),
296 ));
297 }
298 Ok(())
299 }
300 fn read_resource(&mut self) -> io::Result<PathBuf> {
303 let sanitized_path = self.request.uri.path.trim_start_matches('/');
305 if sanitized_path.contains("..") {
306 return Err(Error::other(
307 "Invalid path: directory traversal not allowed",
308 ));
309 }
310
311 if self.request.uri.path != "/" {
312 let base_dir = self
313 .request
314 .config
315 .root_path
316 .join(self.request.config.public.clone());
317 let file = base_dir.join(sanitized_path);
318 if let (Ok(canonical_base), Ok(canonical_file)) =
320 (base_dir.canonicalize(), file.canonicalize())
321 {
322 if canonical_file.starts_with(&canonical_base) && file.is_file() {
323 return Ok(file);
324 }
325 }
326 }
327 if self.request.uri.path == "/" {
328 let file = self
329 .request
330 .config
331 .root_path
332 .join("webpage")
333 .join(self.request.config.webpage.clone())
334 .join("index.html");
335 if file.is_file() {
336 return Ok(file);
337 }
338 } else {
339 let base_dir = self
340 .request
341 .config
342 .root_path
343 .join("webpage")
344 .join(self.request.config.webpage.clone());
345 let file = base_dir.join(sanitized_path);
346 if let (Ok(canonical_base), Ok(canonical_file)) =
348 (base_dir.canonicalize(), file.canonicalize())
349 {
350 if canonical_file.starts_with(&canonical_base) && file.is_file() {
351 return Ok(file);
352 }
353 }
354 }
355 Err(Error::other("Not a file"))
356 }
357 pub fn status(&mut self, code: u16) -> &mut Self {
358 self.status.set_code(code);
359 self
360 }
361 pub fn location(&mut self, uri: &str) -> &mut Self {
363 self.header("Location", uri);
364 self
365 }
366 pub fn set_host(&mut self, host: &str) -> &mut Self {
368 self.header("Host", host);
369 self
370 }
371
372 fn sanitize_header_value(value: &str) -> String {
374 sanitize_header_value(value)
375 }
376
377 fn ensure_default_http_headers(&mut self) {
378 self.header("Date", &self.get_date(0));
379
380 if !self.headers.has_key("X-Content-Type-Options") {
381 self.header("X-Content-Type-Options", "nosniff");
382 }
383 if !self.headers.has_key("X-Frame-Options") {
384 self.header("X-Frame-Options", "SAMEORIGIN");
385 }
386 if !self.headers.has_key("X-XSS-Protection") {
387 self.header("X-XSS-Protection", "1; mode=block");
388 }
389 }
390
391 fn build_http1_header_lines(&self) -> Vec<String> {
392 let mut header = vec![format!(
393 "{} {} {}",
394 self.request.protocol.str(),
395 self.status.code,
396 self.status.reason
397 )];
398 for (key, value) in self.headers.entries() {
399 header.push(format!("{key}: {value}"));
400 }
401
402 for (key, value) in self.cookies.entries() {
403 header.push(format!(
404 "Set-Cookie: {key}={value}; Path=/; HttpOnly; SameSite=Lax"
405 ));
406 }
407 header
408 }
409
410 pub fn stream_start(&mut self, content_type: &str) -> Result<(), HttpError> {
411 if self.stream_started {
412 return Ok(());
413 }
414 if !content_type.is_empty() && !self.headers.has_key("Content-Type") {
415 self.header("Content-Type", content_type);
416 }
417 if !self.headers.has_key("Cache-Control") {
418 self.header("Cache-Control", "no-cache");
419 }
420 if !self.headers.has_key("X-Accel-Buffering") {
421 self.header("X-Accel-Buffering", "no");
422 }
423 self.headers.remove("Content-Length");
424 self.headers.remove("content-length");
425 self.ensure_default_http_headers();
426
427 match self.request.protocol {
428 Protocol::HTTP1_0 | Protocol::HTTP1_1 => {
429 self.header("Transfer-Encoding", "chunked");
430 let header = format!("{}\r\n\r\n", self.build_http1_header_lines().join("\r\n"));
431 self.request
432 .scheme
433 .lock()
434 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
435 .write_all(header.as_bytes())?;
436 }
437 Protocol::HTTP2 => {
438 self.stream_id += 1;
439 let frames = self.http2_stream_headers(self.stream_id, 16_384);
440 let mut writer = self
441 .request
442 .scheme
443 .lock()
444 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?;
445 for frame in frames {
446 writer.write_all(&frame)?;
447 }
448 }
449 Protocol::HTTP3 | Protocol::Other(_) => {
450 return Err(HttpError::new(500, "当前协议暂不支持流式输出"));
451 }
452 }
453
454 self.committed = true;
455 self.stream_started = true;
456 self.stream_finished = false;
457 Ok(())
458 }
459
460 pub fn stream_chunk(&mut self, data: &[u8]) -> Result<(), HttpError> {
461 if !self.stream_started {
462 return Err(HttpError::new(500, "流式响应尚未开始"));
463 }
464 if self.stream_finished || data.is_empty() {
465 return Ok(());
466 }
467
468 match self.request.protocol {
469 Protocol::HTTP1_0 | Protocol::HTTP1_1 => {
470 let mut chunk = format!("{:X}\r\n", data.len()).into_bytes();
471 chunk.extend_from_slice(data);
472 chunk.extend_from_slice(b"\r\n");
473 self.request
474 .scheme
475 .lock()
476 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
477 .write_all(&chunk)?;
478 }
479 Protocol::HTTP2 => {
480 let frame = self.build_data_frame(self.stream_id, data, false);
481 self.request
482 .scheme
483 .lock()
484 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
485 .write_all(&frame)?;
486 }
487 Protocol::HTTP3 | Protocol::Other(_) => {
488 return Err(HttpError::new(500, "当前协议暂不支持流式输出"));
489 }
490 }
491 Ok(())
492 }
493
494 pub fn stream_end(&mut self) -> Result<(), HttpError> {
495 if !self.stream_started || self.stream_finished {
496 return Ok(());
497 }
498 match self.request.protocol {
499 Protocol::HTTP1_0 | Protocol::HTTP1_1 => {
500 self.request
501 .scheme
502 .lock()
503 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
504 .write_all(b"0\r\n\r\n")?;
505 }
506 Protocol::HTTP2 => {
507 let frame = self.build_data_frame(self.stream_id, &[], true);
508 self.request
509 .scheme
510 .lock()
511 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
512 .write_all(&frame)?;
513 }
514 Protocol::HTTP3 | Protocol::Other(_) => {
515 return Err(HttpError::new(500, "当前协议暂不支持流式输出"));
516 }
517 }
518 self.stream_finished = true;
519 Ok(())
520 }
521
522 pub fn header(&mut self, key: &str, value: &str) -> &mut Self {
523 self.headers[key] = Self::sanitize_header_value(value).into();
524 self
525 }
526 pub fn cookie(&mut self, key: &str, value: &str) -> &mut Self {
527 self.cookies[key] = value.into();
528 self
529 }
530 pub fn cookie_with_options(&mut self, options: CookieOptions) -> &mut Self {
531 self.cookies[options.name.as_str()] = options.to_header_value().into();
532 self
533 }
534 fn get_date(&self, s: i64) -> String {
535 let utc: DateTime<Utc> = Utc::now();
536 let future = utc + dur::seconds(s); future.format("%a, %d %b %Y %H:%M:%S GMT").to_string()
538 }
539 pub fn html(&mut self, value: &str) -> &mut Self {
541 if self.request.config.charset.is_empty() {
542 self.header(
543 "Content-Type",
544 format!("{};", Extension::form("html").as_str()).as_str(),
545 );
546 } else {
547 self.header(
548 "Content-Type",
549 format!(
550 "{}; charset={}",
551 Extension::form("html").as_str(),
552 self.request.config.charset
553 )
554 .as_str(),
555 );
556 }
557 self.content_type = ContentType::Html;
558 self.body = value.as_bytes().to_vec();
559 self
560 }
561 pub fn txt(&mut self, value: &str) -> &mut Self {
563 if self.request.config.charset.is_empty() {
564 self.header(
565 "Content-Type",
566 Extension::form("txt").as_str().to_string().as_str(),
567 );
568 } else {
569 self.header(
570 "Content-Type",
571 format!(
572 "{}; charset={}",
573 Extension::form("txt").as_str(),
574 self.request.config.charset
575 )
576 .as_str(),
577 );
578 }
579 self.content_type = ContentType::Text;
580 self.body = value.as_bytes().to_vec();
581 self
582 }
583 pub fn json(&mut self, value: JsonValue) -> &mut Self {
585 if self.request.config.charset.is_empty() {
586 self.header(
587 "Content-Type",
588 Extension::form("json").as_str().to_string().as_str(),
589 );
590 } else {
591 self.header(
592 "Content-Type",
593 format!(
594 "{}; charset={}",
595 Extension::form("json").as_str(),
596 self.request.config.charset
597 )
598 .as_str(),
599 );
600 }
601 self.content_type = ContentType::Json;
602 self.body = value.to_string().into_bytes();
603 self
604 }
605 pub fn download(&mut self, filename: &Path) -> &mut Self {
607 let Ok(file) = fs::read(filename) else {
608 self.status(404);
609 return self;
610 };
611 let extension = filename
612 .extension()
613 .and_then(|e| e.to_str())
614 .unwrap_or("")
615 .to_lowercase();
616
617 if self.request.config.charset.is_empty() {
618 self.header(
619 "Content-Type",
620 Extension::form(extension.as_str())
621 .as_str()
622 .to_string()
623 .as_str(),
624 );
625 } else {
626 self.header(
627 "Content-Type",
628 format!(
629 "{}; charset={}",
630 Extension::form(extension.as_str()).as_str(),
631 self.request.config.charset
632 )
633 .as_str(),
634 );
635 }
636
637 let encoded_file_name = br_crypto::encoding::urlencoding_encode(
638 filename
639 .file_name()
640 .and_then(|n| n.to_str())
641 .unwrap_or("download"),
642 );
643 self.header(
644 "Content-Disposition",
645 format!(r"attachment; filename={encoded_file_name}").as_str(),
646 );
647 self.header("Cache-Control", "no-cache");
648 self.header("ETag", br_crypto::md5::encrypt_hex(&file).as_str());
649 self.body = file;
650 self
651 }
652 pub fn range(&mut self, filename: &Path) -> &mut Self {
654 let Ok(file) = fs::read(filename) else {
655 self.status(404);
656 return self;
657 };
658 let range = self.request.header["range"].to_string();
659 let range = range.trim_start_matches("bytes=");
660 let parts: Vec<&str> = range.split('-').collect();
661
662 let range_start = match parts.first().and_then(|s| s.parse::<usize>().ok()) {
663 Some(v) => v,
664 None => {
665 self.status(416);
666 self.header("Content-Range", format!("bytes */{}", file.len()).as_str());
667 return self;
668 }
669 };
670
671 let range_end = if parts.len() > 1 && !parts[1].is_empty() {
672 match parts[1].parse::<usize>() {
673 Ok(v) => v,
674 Err(_) => {
675 self.status(416);
676 self.header("Content-Range", format!("bytes */{}", file.len()).as_str());
677 return self;
678 }
679 }
680 } else {
681 file.len().saturating_sub(1)
682 };
683
684 if file.len() < range_end {
685 self.status(416);
686 self.header("Content-Range", format!("bytes */{}", file.len()).as_str());
687 return self;
688 }
689
690 let extension = filename
691 .extension()
692 .and_then(|e| e.to_str())
693 .unwrap_or("")
694 .to_lowercase();
695
696 if self.request.config.charset.is_empty() {
697 self.header(
698 "Content-Type",
699 Extension::form(extension.as_str())
700 .as_str()
701 .to_string()
702 .as_str(),
703 );
704 } else {
705 self.header(
706 "Content-Type",
707 format!(
708 "{}; charset={}",
709 Extension::form(extension.as_str()).as_str(),
710 self.request.config.charset
711 )
712 .as_str(),
713 );
714 }
715
716 self.header("Accept-Ranges", "bytes");
717 self.header(
718 "content-length",
719 (range_end - range_start + 1).to_string().as_str(),
720 );
721 self.header(
722 "Content-Range",
723 format!("bytes {}-{}/{}", range_start, range_end, file.len()).as_str(),
724 );
725 self.body = file[range_start..=range_end].to_vec();
726 self
727 }
728 pub fn file(&mut self, filename: &Path) -> &mut Self {
735 let Ok(file) = fs::read(filename) else {
736 self.status(404);
737 return self;
738 };
739
740 self.header("Access-Control-Expose-Headers", "Content-Disposition");
741 let extension = match filename.extension() {
742 None => String::new(),
743 Some(e) => e.to_str().unwrap_or("").to_lowercase(),
744 };
745 if self.request.config.charset.is_empty() {
746 self.header(
747 "Content-Type",
748 Extension::form(extension.as_str())
749 .as_str()
750 .to_string()
751 .as_str(),
752 );
753 } else {
754 self.header(
755 "Content-Type",
756 format!(
757 "{}; charset={}",
758 Extension::form(extension.as_str()).as_str(),
759 self.request.config.charset
760 )
761 .as_str(),
762 );
763 }
764
765 self.header(
766 "Content-Disposition",
767 format!(
768 r#"inline; filename="{}""#,
769 filename
770 .file_name()
771 .and_then(|n| n.to_str())
772 .unwrap_or("download")
773 )
774 .as_str(),
775 );
776
777 self.header("Accept-Ranges", "bytes");
778
779 self.header(
780 "Cache-Control",
781 format!("public, max-age={}", DEFAULT_CACHE_MAX_AGE).as_str(),
782 );
783 self.header("Expires", &self.get_date(DEFAULT_CACHE_MAX_AGE as i64));
784 self.body = file;
785 self
786 }
787 pub fn send(&mut self) -> Result<(), HttpError> {
793 match &self.request.protocol {
794 Protocol::HTTP1_0 | Protocol::HTTP1_1 => Ok(self.send_http1()?),
795 Protocol::HTTP2 => Ok(self.send_http2()?),
796 Protocol::HTTP3 => {
797 error!("Other1:{:?} {:?}", thread::current().id(), self.request);
798 Err(HttpError::new(500, "暂未实现HTTP3"))
799 }
800 Protocol::Other(e) => {
801 error!("Other:{:?} {:?}", thread::current().id(), self.request);
802 Err(HttpError::new(
803 500,
804 format!(
805 "暂未实现Other: {} {} {:?}",
806 e,
807 self.request.uri.path,
808 thread::current().id()
809 )
810 .as_str(),
811 ))
812 }
813 }
814 }
815 fn send_http1(&mut self) -> Result<(), HttpError> {
816 let mut header = vec![];
817 header.push(format!(
818 "{} {} {}",
819 self.request.protocol.str(),
820 self.status.code,
821 self.status.reason
822 ));
823 self.ensure_default_http_headers();
824
825 match self.request.method {
826 Method::HEAD => {
827 self.header("Content-Length", self.body.len().to_string().as_str());
828 self.body = vec![];
829 }
830 Method::OPTIONS => {
831 self.body = vec![];
832 }
833 _ => {
834 if self.status.code == 101 {
835 } else {
837 match self.request.accept_encoding {
838 Encoding::Gzip => {
839 self.header(
840 "Content-Encoding",
841 self.request.accept_encoding.clone().str(),
842 );
843 if let Ok(e) = self.request.accept_encoding.compress(&self.body) {
844 self.body = e
845 };
846 self.header("Content-Length", self.body.len().to_string().as_str());
847 }
848 _ => {
849 self.header("Content-Length", self.body.len().to_string().as_str());
850 }
851 }
852 }
853 }
854 };
855
856 for (key, value) in self.headers.entries() {
857 header.push(format!("{key}: {value}"));
858 }
859
860 for (key, value) in self.cookies.entries() {
861 header.push(format!(
862 "Set-Cookie: {key}={value}; Path=/; HttpOnly; SameSite=Lax"
863 ));
864 }
865
866 if self.request.config.debug {
867 info!("\r\n=================响应信息 {:?}=================\r\n{}\r\n===========================================",thread::current().id(),header.join("\r\n"));
868 match self.request.accept_encoding {
869 Encoding::Gzip => {}
870 _ => {
871 match self.content_type {
872 ContentType::Text
873 | ContentType::Html
874 | ContentType::Json
875 | ContentType::FormUrlencoded => {
876 info!("\r\n=================响应体 {:?}=================\r\n{}\r\n===========================================",thread::current().id(),String::from_utf8_lossy(self.body.as_slice()));
877 }
878 _ => {}
879 };
880 }
881 }
882 }
883 let mut headers = format!("{}\r\n\r\n", header.join("\r\n")).into_bytes();
884 headers.extend(self.body.clone());
885 self.request
886 .scheme
887 .lock()
888 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
889 .write_all(headers.as_slice())?;
890 Ok(())
891 }
892 fn send_http2(&mut self) -> Result<(), HttpError> {
893 let max_frame_size: usize = 16_384;
894 self.stream_id += 1;
895 let header_frames = self.http2_header(self.stream_id, max_frame_size);
897 let data_frames = self.http2_body(self.stream_id, true, max_frame_size);
898
899 let mut writer = self
901 .request
902 .scheme
903 .lock()
904 .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?;
905 for f in header_frames.clone() {
906 writer.write_all(&f)?;
907 }
908 for f in data_frames.clone() {
909 writer.write_all(&f)?;
910 }
911 Ok(())
912 }
913
914 fn http2_header(&mut self, stream_id: u32, max_frame_size: usize) -> Vec<Vec<u8>> {
915 let mut headers: Vec<(Vec<u8>, Vec<u8>)> = vec![
916 (
917 b":status".to_vec(),
918 self.status.code.to_string().into_bytes(),
919 ),
920 (b"date".to_vec(), self.get_date(0).into_bytes()),
921 ];
922
923 match self.request.method {
924 Method::HEAD => {
925 self.header("content-length", self.body.len().to_string().as_str());
926 self.body.clear(); }
928 Method::OPTIONS => {
929 self.body.clear();
930 self.header("content-length", "0");
931 }
932 _ => {
933 self.header("content-length", self.body.len().to_string().as_str());
934 }
935 }
936
937 headers.extend(self.headers.entries().map(|(k, v)| {
938 (
939 k.to_string().to_lowercase().into_bytes(),
940 v.to_string().into_bytes(),
941 )
942 }));
943 headers.extend(self.cookies.entries().map(|(k, v)| {
944 (
945 b"set-cookie".to_vec(),
946 format!("{k}={v}; Path=/; HttpOnly; SameSite=Lax").into_bytes(),
947 )
948 }));
949
950 if self.request.config.debug {
951 let dbg = headers
952 .iter()
953 .map(|(n, v)| {
954 format!(
955 "{}: {}",
956 String::from_utf8_lossy(n),
957 String::from_utf8_lossy(v)
958 )
959 })
960 .collect::<Vec<_>>()
961 .join("\r\n");
962 info!("\n=================响应信息 {:?}=================\n{}\n===========================================",
963 std::thread::current().id(), dbg);
964 }
965
966 let mut encoder = Encoder::new();
967 let block = encoder.encode(headers.iter().map(|h| (&h.0[..], &h.1[..])));
969
970 let end_stream = self.body.is_empty();
971 let mut frames = Vec::new();
972 let mut remaining = block.as_slice();
973 let mut first = true;
974
975 while !remaining.is_empty() {
976 let take = remaining.len().min(max_frame_size);
977 let (chunk, rest) = remaining.split_at(take);
978 remaining = rest;
979
980 let is_last = remaining.is_empty();
981 let mut flags = 0u8;
982 if is_last {
983 flags |= FLAG_END_HEADERS;
984 }
985 if is_last && end_stream {
986 flags |= FLAG_END_STREAM;
987 }
988
989 let mut f = Vec::with_capacity(9 + chunk.len());
991 let len = chunk.len();
992 f.push(((len >> 16) & 0xFF) as u8);
993 f.push(((len >> 8) & 0xFF) as u8);
994 f.push((len & 0xFF) as u8);
995 f.push(if first { 0x01 } else { 0x09 }); f.push(flags);
997 f.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
998 f.extend_from_slice(chunk);
999
1000 frames.push(f);
1001 first = false;
1002 }
1003
1004 if frames.is_empty() {
1006 let mut f = vec![
1007 0,
1008 0,
1009 0,
1010 0x01,
1011 FLAG_END_HEADERS | if end_stream { FLAG_END_STREAM } else { 0 },
1012 0,
1013 0,
1014 0,
1015 0,
1016 ];
1017 f[5..9].copy_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
1018 frames.push(f);
1019 }
1020
1021 frames
1022 }
1023 fn http2_body(
1024 &mut self,
1025 stream_id: u32,
1026 end_stream: bool,
1027 max_frame_size: usize,
1028 ) -> Vec<Vec<u8>> {
1029 if self.body.is_empty() {
1030 return Vec::new();
1031 }
1032 let mut frames = Vec::new();
1033 let mut off = 0usize;
1034 let total = self.body.len();
1035
1036 while off < total {
1037 let take = (total - off).min(max_frame_size);
1038 let chunk = &self.body[off..off + take];
1039 off += take;
1040
1041 let last = off == total;
1042 frames.push(self.build_data_frame(stream_id, chunk, last && end_stream));
1043 }
1044 frames
1045 }
1046 fn http2_stream_headers(&mut self, stream_id: u32, max_frame_size: usize) -> Vec<Vec<u8>> {
1047 let mut headers: Vec<(Vec<u8>, Vec<u8>)> = vec![
1048 (
1049 b":status".to_vec(),
1050 self.status.code.to_string().into_bytes(),
1051 ),
1052 (b"date".to_vec(), self.get_date(0).into_bytes()),
1053 ];
1054
1055 headers.extend(self.headers.entries().filter_map(|(k, v)| {
1056 let key = k.to_string().to_lowercase();
1057 if key == "content-length" {
1058 return None;
1059 }
1060 Some((key.into_bytes(), v.to_string().into_bytes()))
1061 }));
1062 headers.extend(self.cookies.entries().map(|(k, v)| {
1063 (
1064 b"set-cookie".to_vec(),
1065 format!("{k}={v}; Path=/; HttpOnly; SameSite=Lax").into_bytes(),
1066 )
1067 }));
1068
1069 let mut encoder = Encoder::new();
1070 let block = encoder.encode(headers.iter().map(|h| (&h.0[..], &h.1[..])));
1071
1072 let mut frames = Vec::new();
1073 let mut remaining = block.as_slice();
1074 let mut first = true;
1075
1076 while !remaining.is_empty() {
1077 let take = remaining.len().min(max_frame_size);
1078 let (chunk, rest) = remaining.split_at(take);
1079 remaining = rest;
1080
1081 let is_last = remaining.is_empty();
1082 let mut flags = 0u8;
1083 if is_last {
1084 flags |= FLAG_END_HEADERS;
1085 }
1086
1087 let mut frame = Vec::with_capacity(9 + chunk.len());
1088 let len = chunk.len();
1089 frame.push(((len >> 16) & 0xFF) as u8);
1090 frame.push(((len >> 8) & 0xFF) as u8);
1091 frame.push((len & 0xFF) as u8);
1092 frame.push(if first { 0x01 } else { 0x09 });
1093 frame.push(flags);
1094 frame.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
1095 frame.extend_from_slice(chunk);
1096 frames.push(frame);
1097 first = false;
1098 }
1099
1100 if frames.is_empty() {
1101 let mut frame = vec![0, 0, 0, 0x01, FLAG_END_HEADERS, 0, 0, 0, 0];
1102 frame[5..9].copy_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
1103 frames.push(frame);
1104 }
1105
1106 frames
1107 }
1108 fn build_data_frame(&self, stream_id: u32, payload: &[u8], end_stream: bool) -> Vec<u8> {
1109 let len = payload.len();
1110 let mut f = Vec::with_capacity(9 + len);
1111 f.push(((len >> 16) & 0xFF) as u8);
1112 f.push(((len >> 8) & 0xFF) as u8);
1113 f.push((len & 0xFF) as u8);
1114 f.push(0x00); f.push(if end_stream { FLAG_END_STREAM } else { 0 });
1116 f.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
1117 if !payload.is_empty() {
1118 f.extend_from_slice(payload);
1119 }
1120 f
1121 }
1122 fn on_options(&mut self) -> Result<(), HttpError> {
1123 if self.allow_origins.is_empty() {
1124 self.header("Access-Control-Allow-Origin", "*");
1125 } else if self.request.header.has_key("origin") {
1126 if self.allow_origins.contains(&self.request.origin.as_str()) {
1127 self.header(
1128 "Access-Control-Allow-Origin",
1129 self.request.origin.to_string().as_str(),
1130 );
1131 } else {
1132 return Err(HttpError::new(403, "Origin not allowed"));
1133 }
1134 } else {
1135 return Err(HttpError::new(403, "Origin not allowed"));
1136 }
1137
1138 if self.allow_headers.is_empty() {
1139 if !self
1140 .request
1141 .header
1142 .has_key("access-control-request-headers")
1143 {
1144 return Err(HttpError::new(403, "headers not allowed"));
1145 }
1146 self.header(
1147 "Access-Control-Allow-Headers",
1148 self.request.header["access-control-request-headers"]
1149 .to_string()
1150 .as_str(),
1151 );
1152 } else if !self
1153 .request
1154 .header
1155 .has_key("access-control-request-headers")
1156 {
1157 let headers = self.allow_headers.join(",");
1158 self.header("Access-Control-Allow-Headers", headers.to_string().as_str());
1159 } else {
1160 let headers = self.allow_headers.join(",");
1161 self.header(
1162 "Access-Control-Allow-Headers",
1163 format!(
1164 "{},{}",
1165 self.request.header["access-control-request-headers"], headers
1166 )
1167 .as_str(),
1168 );
1169 }
1170
1171 if self.allow_methods.is_empty() {
1172 if !self.request.header.has_key("access-control-request-method") {
1173 return Err(HttpError::new(403, "methods not allowed"));
1174 }
1175 self.header(
1176 "Access-Control-Allow-Methods",
1177 self.request.header["access-control-request-method"]
1178 .to_string()
1179 .as_str(),
1180 );
1181 } else {
1182 let methods = self.allow_methods.join(",");
1183 self.header("Access-Control-Allow-Methods", methods.to_string().as_str());
1184 }
1185 self.header(
1186 "Vary",
1187 "Origin, Access-Control-Request-Method, Access-Control-Request-Headers",
1188 );
1189 Ok(())
1190 }
1191}
1192
1193enum Extension {}
1195impl Extension {
1196 pub fn form(extension: &str) -> String {
1197 match extension.to_lowercase().as_str() {
1198 "html" | "htm" => "text/html",
1199 "css" => "text/css",
1200 "js" | "mjs" => "application/javascript",
1201 "json" => "application/json",
1202 "xml" => "application/xml",
1203 "txt" => "text/plain",
1204 "csv" => "text/csv",
1205 "md" => "text/markdown",
1206
1207 "png" => "image/png",
1208 "jpg" | "jpeg" => "image/jpeg",
1209 "gif" => "image/gif",
1210 "svg" => "image/svg+xml",
1211 "webp" => "image/webp",
1212 "ico" => "image/x-icon",
1213 "bmp" => "image/bmp",
1214 "tiff" | "tif" => "image/tiff",
1215 "avif" => "image/avif",
1216
1217 "mp4" => "video/mp4",
1218 "webm" => "video/webm",
1219 "avi" => "video/x-msvideo",
1220 "mov" => "video/quicktime",
1221 "mkv" => "video/x-matroska",
1222
1223 "mp3" => "audio/mpeg",
1224 "wav" => "audio/wav",
1225 "ogg" => "audio/ogg",
1226 "flac" => "audio/flac",
1227 "aac" => "audio/aac",
1228
1229 "woff" => "font/woff",
1230 "woff2" => "font/woff2",
1231 "ttf" => "font/ttf",
1232 "otf" => "font/otf",
1233 "eot" => "application/vnd.ms-fontobject",
1234
1235 "pdf" => "application/pdf",
1236 "doc" => "application/msword",
1237 "docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1238 "xls" => "application/vnd.ms-excel",
1239 "xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1240 "ppt" => "application/vnd.ms-powerpoint",
1241 "pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1242
1243 "zip" => "application/zip",
1244 "rar" => "application/vnd.rar",
1245 "7z" => "application/x-7z-compressed",
1246 "tar" => "application/x-tar",
1247 "gz" => "application/gzip",
1248
1249 "wasm" => "application/wasm",
1250 "map" => "application/json",
1251 _ => "application/octet-stream",
1252 }
1253 .to_string()
1254 }
1255}
1256
1257#[derive(Clone, Debug)]
1258pub struct CookieOptions {
1259 pub name: String,
1260 pub value: String,
1261 pub path: Option<String>,
1262 pub domain: Option<String>,
1263 pub max_age: Option<i64>,
1264 pub expires: Option<String>,
1265 pub secure: bool,
1266 pub http_only: bool,
1267 pub same_site: SameSite,
1268}
1269
1270impl Default for CookieOptions {
1271 fn default() -> Self {
1272 Self {
1273 name: String::new(),
1274 value: String::new(),
1275 path: None,
1276 domain: None,
1277 max_age: None,
1278 expires: None,
1279 secure: true,
1280 http_only: false,
1281 same_site: SameSite::default(),
1282 }
1283 }
1284}
1285
1286#[derive(Clone, Debug, Default)]
1287pub enum SameSite {
1288 Strict,
1289 #[default]
1290 Lax,
1291 None,
1292}
1293
1294impl CookieOptions {
1295 #[must_use]
1296 pub fn new(name: &str, value: &str) -> Self {
1297 Self {
1298 name: name.to_string(),
1299 value: value.to_string(),
1300 path: Some("/".to_string()),
1301 http_only: true,
1302 same_site: SameSite::Lax,
1303 ..Default::default()
1304 }
1305 }
1306
1307 pub fn path(mut self, path: &str) -> Self {
1308 self.path = Some(path.to_string());
1309 self
1310 }
1311
1312 pub fn domain(mut self, domain: &str) -> Self {
1313 self.domain = Some(domain.to_string());
1314 self
1315 }
1316
1317 pub fn max_age(mut self, seconds: i64) -> Self {
1318 self.max_age = Some(seconds);
1319 self
1320 }
1321
1322 pub fn expires(mut self, date: &str) -> Self {
1323 self.expires = Some(date.to_string());
1324 self
1325 }
1326
1327 pub fn secure(mut self, secure: bool) -> Self {
1328 self.secure = secure;
1329 self
1330 }
1331
1332 pub fn http_only(mut self, http_only: bool) -> Self {
1333 self.http_only = http_only;
1334 self
1335 }
1336
1337 pub fn same_site(mut self, same_site: SameSite) -> Self {
1338 self.same_site = same_site;
1339 self
1340 }
1341
1342 #[must_use]
1343 pub fn to_header_value(&self) -> String {
1344 let mut parts = vec![format!(
1345 "{}={}",
1346 sanitize_header_value(&self.name),
1347 sanitize_header_value(&self.value)
1348 )];
1349
1350 if let Some(ref path) = self.path {
1351 parts.push(format!("Path={path}"));
1352 }
1353 if let Some(ref domain) = self.domain {
1354 parts.push(format!("Domain={domain}"));
1355 }
1356 if let Some(max_age) = self.max_age {
1357 parts.push(format!("Max-Age={max_age}"));
1358 }
1359 if let Some(ref expires) = self.expires {
1360 parts.push(format!("Expires={expires}"));
1361 }
1362 if self.secure {
1363 parts.push("Secure".to_string());
1364 }
1365 if self.http_only {
1366 parts.push("HttpOnly".to_string());
1367 }
1368 match self.same_site {
1369 SameSite::Strict => parts.push("SameSite=Strict".to_string()),
1370 SameSite::Lax => parts.push("SameSite=Lax".to_string()),
1371 SameSite::None => parts.push("SameSite=None".to_string()),
1372 }
1373
1374 parts.join("; ")
1375 }
1376}