Skip to main content

br_web_server/
request.rs

1use crate::config::Config;
2use crate::stream::Scheme;
3use crate::{
4    parse_content_type_header_value, split_boundary, Authorization, Connection, ContentType,
5    Encoding, HttpError, Language, Method, Protocol, Upgrade, Uri,
6};
7use chrono::{DateTime, Local};
8use json::{array, object, JsonValue};
9use log::info;
10use std::cmp::PartialEq;
11use std::fs::OpenOptions;
12use std::io::Write;
13use std::path::Path;
14use std::sync::{Arc, Mutex};
15use std::time::Instant;
16use std::{env, fs, io, thread};
17
18const MAX_HEADER_VALUE_LEN: usize = 8192;
19
20/// 请求体
21#[derive(Clone, Debug)]
22pub struct Request {
23    pub config: Config,
24    /// 头行
25    pub header_line: String,
26    /// 协议版本
27    pub protocol: Protocol,
28    /// 当前请求类型
29    pub method: Method,
30    /// 资源标识符
31    pub uri: Uri,
32    /// 源站
33    pub origin: String,
34    /// header信息
35    pub header: JsonValue,
36    /// Cookie信息
37    pub cookie: JsonValue,
38    /// 查询参数
39    pub query: JsonValue,
40    /// 请求参数
41    pub params: JsonValue,
42    /// 认证信息
43    pub authorization: Authorization,
44    /// 处理耗时
45    pub handle_time: f64,
46    /// 请求时间
47    pub datetime: String,
48    /// 请求时间戳
49    pub timestamp: i64,
50    /// 客户端IP
51    pub client_ip: String,
52    /// 代理端IP
53    pub proxy_ip: String,
54    /// 服务端IP
55    pub server_ip: String,
56    // 升级协议
57    pub upgrade: Upgrade,
58    /// 连接方式
59    pub connection: Connection,
60    /// 压缩方式
61    pub accept_encoding: Encoding,
62    /// 开始时间
63    start_time: Instant,
64    /// 请求体数据
65    pub body_data: Vec<u8>,
66    /// 消息体长度
67    content_length: usize,
68    /// 消息体类型
69    pub content_type: ContentType,
70    /// 边界
71    boundary: String,
72    pub scheme: Arc<Mutex<Scheme>>,
73    /// 接受语音
74    pub accept_language: Language,
75}
76
77impl Request {
78    pub fn new(config: Config, scheme: Arc<Mutex<Scheme>>) -> Self {
79        // 获取请求客户端IP
80        let client_ip = scheme.lock().map(|mut s| s.client_ip()).unwrap_or_default();
81        // 获取服务端IP
82        let server_ip = scheme.lock().map(|mut s| s.server_ip()).unwrap_or_default();
83        let local: DateTime<Local> = Local::now();
84        Self {
85            config,
86            header_line: String::new(),
87            protocol: Protocol::Other(String::new()),
88            method: Method::Other(String::new()),
89            uri: Uri::default(),
90            origin: String::new(),
91            header: object! {},
92            cookie: object! {},
93            query: object! {},
94            params: object! {},
95            authorization: Authorization::Other(String::new()),
96            handle_time: 0.0,
97            scheme,
98            start_time: Instant::now(),
99            datetime: local.format("%Y-%m-%d %H:%M:%S").to_string(),
100            timestamp: local.timestamp(),
101            client_ip,
102            server_ip,
103            proxy_ip: String::new(),
104            upgrade: Upgrade::Other(String::new()),
105            connection: Connection::Other(String::new()),
106            accept_encoding: Encoding::None,
107            body_data: vec![],
108            content_length: 0,
109            content_type: ContentType::Other(String::new()),
110            boundary: String::new(),
111            accept_language: Language::ZhCN,
112        }
113    }
114
115    pub fn handle(&mut self) -> Result<(), HttpError> {
116        let mut data = vec![];
117        // 读开始行
118        {
119            self.scheme
120                .lock()
121                .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
122                .read(&mut data)?;
123            if let Some(pos) = data.windows(2).position(|window| window == [13, 10]) {
124                let header_data = data.drain(..pos).collect::<Vec<u8>>();
125                let header_data = String::from_utf8_lossy(header_data.as_slice());
126                data.drain(..2);
127                self.handle_header_line(header_data.trim())?;
128            } else {
129                return Err(HttpError::new(400, "请求行错误"));
130            }
131        }
132
133        // 请求头处理
134        match &self.protocol {
135            Protocol::HTTP1_0 | Protocol::HTTP1_1 => {
136                // 消息头处理
137                {
138                    loop {
139                        if let Some(pos) = data
140                            .windows(4)
141                            .position(|window| window == [13, 10, 13, 10])
142                        {
143                            self.handle_header(data.drain(..pos).collect::<Vec<u8>>())?;
144                            data.drain(..4);
145                            self.body_data = data;
146                            break;
147                        }
148                        self.scheme
149                            .lock()
150                            .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
151                            .read(&mut data)?;
152                    }
153                }
154                // 消息体处理
155                {
156                    if self.content_length > 0 {
157                        if self.content_length > self.config.max_body_size {
158                            return Err(HttpError::new(
159                                413,
160                                &format!(
161                                    "Request body too large: {} > {}",
162                                    self.content_length, self.config.max_body_size
163                                ),
164                            ));
165                        }
166                        loop {
167                            if self.body_data.len() >= self.content_length {
168                                break;
169                            }
170                            self.scheme
171                                .lock()
172                                .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
173                                .read(&mut self.body_data)?;
174                        }
175                        self.handle_body(self.body_data.clone())?;
176                    }
177                }
178                self.handle_time = self.start_time.elapsed().as_micros() as f64 / 1000.0;
179            }
180            Protocol::HTTP2 => {
181                let header = data.drain(..8).collect::<Vec<u8>>();
182                if header.ne(b"\r\nSM\r\n\r\n") {
183                    return Err(HttpError::new(400, "HTTP2格式错误"));
184                }
185                self.scheme
186                    .lock()
187                    .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?
188                    .http2_send_server_settings()?;
189
190                let scheme_arc = self.scheme.clone();
191                let mut scheme = scheme_arc
192                    .lock()
193                    .map_err(|e| HttpError::new(500, &format!("lock: {}", e)))?;
194
195                scheme.http2_handle_header(&mut data, self)?;
196                self.body_data = scheme.http2_handle_body(&mut data, self.clone())?;
197                self.handle_body(self.body_data.clone())?;
198                self.handle_time = self.start_time.elapsed().as_micros() as f64 / 1000.0;
199            }
200            Protocol::HTTP3 => {
201                return Err(HttpError::new(
202                    500,
203                    format!("未支持: HTTP3 {:?}", self.protocol).as_str(),
204                ))
205            }
206            Protocol::Other(e) => {
207                return Err(HttpError::new(
208                    500,
209                    format!("未支持: Other {e} {:?}", self.protocol).as_str(),
210                ))
211            }
212        }
213        Ok(())
214    }
215    /// 处理请求行
216    pub fn handle_header_line(&mut self, line: &str) -> Result<(), HttpError> {
217        self.header_line = br_crypto::encoding::urlencoding_decode(line);
218        if self.header_line.is_empty() {
219            return Err(HttpError::new(400, "请求行错误"));
220        }
221        let mut it = self.header_line.split_whitespace();
222        let method = it.next();
223        let target = it.next();
224        let version = it.next();
225
226        // 处理协议版本
227        self.protocol = match version {
228            None => return Err(HttpError::new(400, "协议版本错误")),
229            Some(e) => Protocol::from(e),
230        };
231        // 根据版本分别处理
232        match &self.protocol {
233            Protocol::HTTP1_0 => {
234                self.method = match method {
235                    None => return Err(HttpError::new(400, "HTTP10请求类型错误")),
236                    Some(e) => Method::from(e),
237                };
238                self.uri = match target {
239                    None => return Err(HttpError::new(400, "HTTP10请求资源错误")),
240                    Some(e) => Uri::from(e),
241                };
242                self.query = self.uri.get_query_params();
243            }
244            Protocol::HTTP1_1 => {
245                self.method = match method {
246                    None => return Err(HttpError::new(400, "HTTP11请求类型错误")),
247                    Some(e) => Method::from(e),
248                };
249                self.uri = match target {
250                    None => return Err(HttpError::new(400, "HTTP11请求资源错误")),
251                    Some(e) => Uri::from(e),
252                };
253                self.query = self.uri.get_query_params();
254            }
255            Protocol::HTTP2 => {}
256            Protocol::HTTP3 => {
257                return Err(HttpError::new(
258                    400,
259                    format!("{:?}协议暂未实现", self.protocol).as_str(),
260                ))
261            }
262            Protocol::Other(name) => {
263                return Err(HttpError::new(400, format!("{name}协议暂未实现").as_str()))
264            }
265        }
266        Ok(())
267    }
268    pub fn handle_header(&mut self, data: Vec<u8>) -> Result<(), HttpError> {
269        let headers = String::from_utf8_lossy(data.as_slice());
270        if self.config.debug {
271            info!("\r\n=================请求头 {:?}=================\r\n{}\r\n{headers}\r\n========================================",thread::current().id(),self.header_line);
272        }
273        match &self.protocol {
274            Protocol::HTTP1_0 => {
275                for item in headers.lines() {
276                    self.header_line_set(item)?;
277                }
278            }
279            Protocol::HTTP1_1 => {
280                for item in headers.lines() {
281                    self.header_line_set(item)?;
282                }
283                if !self.header.has_key("host") {
284                    return Err(HttpError::new(400, "请求头错误"));
285                }
286            }
287            Protocol::HTTP2 => {
288                return Err(HttpError::new(400, "HTTP2格式错误"));
289            }
290            Protocol::HTTP3 => return Err(HttpError::new(400, "暂时未开放")),
291            Protocol::Other(name) => {
292                return Err(HttpError::new(
293                    400,
294                    format!("未知协议格式: {}", name).as_str(),
295                ));
296            }
297        }
298        Ok(())
299    }
300
301    fn header_line_set(&mut self, line: &str) -> Result<(), HttpError> {
302        match line.trim().find(":") {
303            None => return Err(HttpError::new(400, format!("请求头[{line}]错误").as_str())),
304            Some(e) => {
305                let key = line[..e].trim().to_lowercase().clone();
306                let value = line[e + 1..].trim();
307                self.set_header(key.as_str(), value)?;
308            }
309        }
310        Ok(())
311    }
312    pub fn set_header(&mut self, key: &str, value: &str) -> Result<(), HttpError> {
313        self.header[key] = value.into();
314        if value.len() > MAX_HEADER_VALUE_LEN {
315            return Err(HttpError::new(400, "header longer than 8192 characters"));
316        }
317        match key {
318            "origin" => self.origin = value.to_string(),
319            "content-type" => {
320                let (mime, params) = parse_content_type_header_value(value);
321                if !mime.is_empty() {
322                    if mime == "multipart/form-data" {
323                        // 兼容:multipart/form-data;boundary=...(无空格)/ multipart/form-data; boundary="..."
324                        if let Some(b) = params.get("boundary") {
325                            self.boundary = b.to_string();
326                        } else {
327                            // 兜底:历史/非标准格式,避免 panic
328                            let lower = value.to_lowercase();
329                            if let Some(pos) = lower.find("boundary=") {
330                                let raw = &value[pos + "boundary=".len()..];
331                                let raw = raw.split(';').next().unwrap_or(raw).trim();
332                                let raw = raw.trim_matches('"');
333                                self.boundary = raw.to_string();
334                            }
335                        }
336                        self.content_type = ContentType::from("multipart/form-data");
337                    } else {
338                        // 只用主 MIME 类型决定解析方式,忽略 charset 等参数
339                        self.content_type = ContentType::from(mime.as_str());
340                    }
341                }
342                self.header[key] = self.content_type.str().into();
343            }
344            "content-length" => self.content_length = value.parse::<usize>().unwrap_or(0),
345            "accept-language" => self.accept_language = Language::from(value),
346            "authorization" => self.authorization = Authorization::from(value),
347            "upgrade" => self.upgrade = Upgrade::from(value),
348            "connection" => self.connection = Connection::from(value),
349            "accept-encoding" => self.accept_encoding = Encoding::from(value),
350            "cookie" => {
351                let _ = value
352                    .split(';')
353                    .collect::<Vec<&str>>()
354                    .iter()
355                    .map(|&x| {
356                        match x.find('=') {
357                            None => {}
358                            Some(index) => {
359                                let key = x[..index].trim().to_string();
360                                let val = x[index + 1..].trim().to_string();
361                                let _ = self.cookie.insert(key.as_str(), val);
362                            }
363                        }
364                        ""
365                    })
366                    .collect::<Vec<&str>>();
367            }
368            "x-forwarded-for" => self.proxy_ip = value.to_string(),
369            "x-real-ip" => self.client_ip = value.to_string(),
370            _ => {}
371        }
372
373        Ok(())
374    }
375    pub fn handle_body(&mut self, data: Vec<u8>) -> Result<(), HttpError> {
376        if self.config.debug {
377            info!("\r\n=================请求体 {:?}=================\r\n长度: {}\r\n========================================",thread::current().id(),self.content_length);
378        }
379        if data.len() != self.content_length {
380            return Err(HttpError::new(
381                400,
382                format!(
383                    "Content-Length mismatch: header={}, actual={}",
384                    self.content_length,
385                    data.len()
386                )
387                .as_str(),
388            ));
389        }
390        if self.content_length == 0 {
391            return Ok(());
392        }
393        match &self.content_type {
394            ContentType::FormData => {
395                let parts = match split_boundary(data, &self.boundary) {
396                    Ok(e) => e,
397                    Err(_) => return Err(HttpError::new(400, "Invalid boundary marker")),
398                };
399                let mut fields = object! {};
400
401                for part in parts {
402                    let (header, body) = match part
403                        .windows(b"\r\n\r\n".len())
404                        .position(|window| window == b"\r\n\r\n")
405                    {
406                        None => continue,
407                        Some(e) => {
408                            let header = part[..e].to_vec();
409                            let body = part[e + 4..].to_vec();
410                            let body = body[..body.len()].to_vec();
411                            (header, body)
412                        }
413                    };
414                    let headers = String::from_utf8_lossy(header.as_slice());
415                    let mut field_name = "";
416                    let mut filename = "";
417                    let mut content_type = ContentType::Other("".to_string());
418
419                    for header in headers.lines() {
420                        if header.to_lowercase().starts_with("content-disposition:") {
421                            match header.find("filename=\"") {
422                                None => {}
423                                Some(filename_start) => {
424                                    let filename_len = filename_start + 10;
425                                    if let Some(end_offset) = header[filename_len..].find('"') {
426                                        let filename_end = end_offset + filename_len;
427                                        filename = &header[filename_len..filename_end];
428                                    }
429                                }
430                            }
431                            match header.find("name=\"") {
432                                None => {}
433                                Some(name_start) => {
434                                    let name_start = name_start + 6;
435                                    if let Some(end_offset) = header[name_start..].find('"') {
436                                        let name_end = end_offset + name_start;
437                                        field_name = &header[name_start..name_end];
438                                    }
439                                }
440                            }
441                        }
442                        if header.to_lowercase().starts_with("content-type:") {
443                            content_type = ContentType::from(
444                                header
445                                    .to_lowercase()
446                                    .trim_start_matches("content-type:")
447                                    .trim(),
448                            );
449                        }
450                    }
451
452                    if filename.is_empty() {
453                        let text = String::from_utf8_lossy(body.as_slice()).into_owned();
454                        fields[field_name.to_string()] = match text.as_str() {
455                            "true" => JsonValue::Boolean(true),
456                            "false" => JsonValue::Boolean(false),
457                            s => {
458                                if let Ok(n) = s.parse::<i64>() {
459                                    n.into()
460                                } else if let Ok(f) = s.parse::<f64>() {
461                                    f.into()
462                                } else {
463                                    text.into()
464                                }
465                            }
466                        };
467                        continue;
468                    }
469                    let extension = Path::new(filename).extension().and_then(|ext| ext.to_str()); // 转换为 &str
470                    let suffix = extension.unwrap_or("txt");
471                    let filename = if extension.is_none() {
472                        format!("{filename}.txt")
473                    } else {
474                        filename.to_string()
475                    };
476
477                    let mut temp_dir = env::temp_dir();
478                    temp_dir.push(filename.clone());
479                    let Ok(mut temp_file) = fs::File::create(&temp_dir) else {
480                        continue;
481                    };
482                    if temp_file.write(body.as_slice()).is_ok() {
483                        if fields[field_name.to_string()].is_empty() {
484                            fields[field_name.to_string()] = array![];
485                        }
486                        fields[field_name.to_string()]
487                            .push(object! {
488                                id:br_crypto::sha256::encrypt_hex(&body.clone()),
489                                name:filename,
490                                suffix:suffix,
491                                size:body.len(),
492                                type:content_type.str(),
493                                file:temp_dir.to_str()
494                            })
495                            .unwrap_or_else(|e| log::warn!("JSON push failed: {}", e));
496                    }
497                }
498                self.params = fields;
499            }
500            ContentType::FormUrlencoded => {
501                let input = String::from_utf8_lossy(&data);
502                let mut list = object! {};
503                for pair in input.split('&') {
504                    if let Some((key, val)) = pair.split_once('=') {
505                        let key = br_crypto::encoding::urlencoding_decode(key);
506                        let val = br_crypto::encoding::urlencoding_decode(val);
507                        let _ = list.insert(key.as_str(), val);
508                    }
509                }
510                self.params = list;
511            }
512            ContentType::Json => {
513                let text = String::from_utf8_lossy(data.as_slice());
514                self.params = json::parse(text.into_owned().as_str()).unwrap_or(object! {});
515            }
516            ContentType::Xml | ContentType::Html | ContentType::Text | ContentType::Javascript => {
517                let text = String::from_utf8_lossy(data.as_slice());
518                self.params = text.into_owned().into();
519            }
520            ContentType::Other(_) => {}
521            ContentType::Stream => {}
522        }
523        Ok(())
524    }
525    /// 保存日志
526    pub fn save_log(&mut self) -> io::Result<()> {
527        if !self.config.log {
528            return Ok(());
529        }
530        let local: DateTime<Local> = Local::now();
531        let time_dir = local.format("%Y-%m-%d-%H").to_string();
532        let time_dir = time_dir.split('-').collect::<Vec<&str>>();
533
534        let mut res = self
535            .config
536            .root_path
537            .join(self.config.runtime.clone())
538            .join("log");
539        for item in &time_dir {
540            res.push(item);
541        }
542        let parent = res.parent().ok_or_else(|| {
543            io::Error::new(io::ErrorKind::NotFound, "log parent directory not found")
544        })?;
545        fs::create_dir_all(parent)?;
546        let log_file = format!("{}.log", res.to_str().unwrap_or("log"));
547        let mut file = OpenOptions::new()
548            // 允许写入
549            .append(true) // 追加内容到文件末尾
550            .create(true) // 如果文件不存在,则创建
551            .open(log_file)?;
552        let data = format!(
553            "[{}] {} ClientIP: {} {} {} ContentLength: {} ContentType: {} Time: {:?} Thread: {:?}\r\n",
554            self.datetime,
555            self.protocol.str(),
556            self.client_ip,
557            self.method.str(),
558            self.uri.url,
559            self.content_length,
560            self.content_type.clone().str(),
561            self.handle_time,
562            thread::current().id()
563        );
564        file.write_all(data.as_bytes())?;
565        Ok(())
566    }
567}