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