Skip to main content

br_web_server/
response.rs

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/// 响应
16#[derive(Clone, Debug)]
17pub struct Response {
18    pub request: Request,
19    pub status: Status,
20    pub headers: JsonValue,
21    pub cookies: JsonValue,
22    /// 消息体
23    pub body: Vec<u8>,
24    /// HTTP2 使用
25    pub stream_id: u32,
26    /// ws 通信密钥
27    pub key: String,
28    /// ws 版本
29    pub version: String,
30    pub factory: fn(out: Websocket) -> Box<dyn Handler>,
31    /// 允许来源
32    pub allow_origins: Vec<&'static str>,
33    /// 允许方法
34    pub allow_methods: Vec<&'static str>,
35    /// 允许请求头
36    pub allow_headers: Vec<&'static str>,
37    /// 消息体类型
38    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; // 屏蔽最高位保留位
236            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    /// 读取资源文件
248    /// 包含路径遍历保护:确保请求路径不会逃逸根目录
249    fn read_resource(&mut self) -> io::Result<PathBuf> {
250        // 安全检查:防止路径遍历攻击
251        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            // 验证规范化路径仍在基础目录内
266            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            // 验证规范化路径仍在基础目录内
296            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    /// 跳转
313    pub fn location(&mut self, uri: &str) -> &mut Self {
314        self.header("Location", uri);
315        self
316    }
317    /// 设置 HOST
318    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); // 加 3600 秒 = 1 小时
338        future.format("%a, %d %b %Y %H:%M:%S GMT").to_string()
339    }
340    /// HTML 返回
341    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    /// TXT 返回
363    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    /// JSON 返回
385    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    /// 下载 返回
407    ///
408    /// # Panics
409    ///
410    /// This function will panic if:
411    /// - `filename.extension()` returns `None`
412    /// - The extension cannot be converted to a valid UTF-8 string
413    /// - The filename cannot be converted to a valid UTF-8 string
414    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    /// 分片
459    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    /// Serves a file for inline display in the browser.
536    ///
537    /// # 文件返回
538    ///
539    /// This function will panic if the file extension cannot be converted to a string,
540    /// or if the filename cannot be converted to a valid UTF-8 string.
541    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    /// Sends the response over the given scheme.
595    ///
596    /// # Errors
597    ///
598    /// Returns an error if writing the response over the scheme fails.
599    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                    // WebSocket 升级响应不需要 Content-Length
653                } 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        // 先构建所有帧,避免持锁期间借用 self
714        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        // 仅锁一次写端,顺序写出所有帧
718        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(); // HEAD 响应不携带实体
741            }
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        // 2) HPACK 编码
782        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            // 9字节帧头
804            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 }); // HEADERS / CONTINUATION
810            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        // 如果 block 为空(极少见),也要至少发一个空 HEADERS(END_HEADERS [+END_STREAM])
819        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); // DATA
867        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
945/// 文件类型
946enum 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}