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