1#[cfg(feature = "client")]
2pub mod client;
3mod client_response;
4pub mod config;
5pub mod request;
6pub mod response;
7pub mod stream;
8pub mod url;
9pub mod websocket;
10
11use crate::config::Config;
12use crate::request::Request;
13use crate::response::Response;
14use crate::stream::Scheme;
15use crate::websocket::{CloseCode, ErrorCode, Message, Websocket};
16use fs::read;
17use log::{error, info, warn};
18
19use rustls_pemfile::certs;
20
21use flate2::read::GzDecoder;
22use flate2::write::GzEncoder;
23use flate2::Compression;
24use json::{object, JsonValue};
25use rustls::{ServerConfig, ServerConnection, StreamOwned};
26use std::fmt::Debug;
27use std::io::{BufReader, Error, Read, Write};
28use std::net::TcpListener;
29use std::path::PathBuf;
30use std::sync::atomic::{AtomicUsize, Ordering};
31use std::sync::{Arc, Mutex};
32use std::time::Duration;
33use std::{fs, io, thread};
34
35#[derive(Clone, Debug)]
37pub struct WebServer;
38
39struct ConnectionGuard(Arc<AtomicUsize>);
40
41impl Drop for ConnectionGuard {
42 fn drop(&mut self) {
43 self.0.fetch_sub(1, Ordering::Relaxed);
44 }
45}
46
47impl WebServer {
48 pub fn new_service(config: Config, factory: fn(out: Websocket) -> Box<dyn Handler>) {
50 loop {
51 match WebServer::service(config.clone(), factory) {
52 Ok(()) => {}
53 Err(e) => error!("服务器错误: {}[{}]: {}", file!(), line!(), e),
54 }
55 warn!("服务器 1秒后重启");
56 thread::sleep(Duration::from_secs(1));
57 }
58 }
59 fn service(config: Config, factory: fn(out: Websocket) -> Box<dyn Handler>) -> io::Result<()> {
60 info!("==================== 网络服务 服务信息 ====================");
61 info!("日志记录: {}", if config.log { "开启" } else { "关闭" });
62 info!("调试模式: {}", if config.debug { "开启" } else { "关闭" });
63 info!("监听地址: {}", config.host);
64 info!(
65 "服务地址: {}://{}",
66 if config.https { "https" } else { "http" },
67 config.host
68 );
69 info!("根 目 录: {}", config.root_path.to_str().unwrap_or(""));
70 info!("访问目录: {}", config.public);
71 info!("运行目录: {}", config.runtime);
72 info!("SSL/TLS: {}", if config.https { "开启" } else { "关闭" });
73
74 if config.https {
75 info!("证书目录KEY: {:?}", config.tls.key);
76 info!("证书目录PEM: {:?}", config.tls.certs);
77 }
78
79 let listener = TcpListener::bind(config.host.clone())?;
80 info!("==================== 网络服务 启动成功 ====================");
81
82 let acceptor = Self::ssl(config.clone())?;
83 let connection_count = Arc::new(AtomicUsize::new(0));
84 for stream in listener.incoming() {
85 match stream {
86 Ok(stream) => {
87 let current = connection_count.load(Ordering::Relaxed);
88 if current >= config.max_connections {
89 warn!(
90 "连接数已达上限 ({}/{}), 拒绝新连接",
91 current, config.max_connections
92 );
93 drop(stream);
94 continue;
95 }
96 connection_count.fetch_add(1, Ordering::Relaxed);
97 let config_new = config.clone();
98 let acceptor_new = acceptor.clone();
99 let conn_count = connection_count.clone();
100 thread::spawn(move || -> io::Result<()> {
101 let _guard = ConnectionGuard(conn_count);
102 stream.set_nonblocking(false)?;
103 stream
104 .set_read_timeout(Some(Duration::from_secs(config_new.read_timeout)))
105 .unwrap_or_default();
106 stream
107 .set_write_timeout(Some(Duration::from_secs(config_new.write_timeout)))
108 .unwrap_or_default();
109
110 let scheme = if config_new.https {
111 let acceptor = acceptor_new
112 .ok_or_else(|| Error::other("TLS acceptor not configured"))?;
113 let conn = match ServerConnection::new(acceptor) {
114 Ok(e) => e,
115 Err(e) => {
116 return Err(Error::other(e.to_string()));
117 }
118 };
119 Scheme::Https(Arc::new(Mutex::new(StreamOwned::new(conn, stream))))
120 } else {
121 Scheme::Http(Arc::new(Mutex::new(stream)))
122 };
123
124 let mut request =
125 Request::new(config_new.clone(), Arc::new(Mutex::new(scheme.clone())));
126 let response = match request.handle() {
127 Ok(()) => Response::new(&request.clone(), factory),
128 Err(e) => {
129 return Err(Error::other(e.body.as_str()));
131 }
132 };
133 match response.handle() {
134 Ok(()) => {}
135 Err(e) => {
136 return Err(Error::other(e));
138 }
139 };
140
141 match request.save_log() {
142 Ok(()) => {}
143 Err(_) => error!("日志记录错误"),
144 }
145 Ok(())
146 });
147 }
148 Err(e) => return Err(e),
149 }
150 }
151 Ok(())
152 }
153 fn ssl(config: Config) -> io::Result<Option<Arc<ServerConfig>>> {
154 if config.https {
155 if !config.tls.key.is_file() {
156 return Err(Error::other(
157 format!("private.key 不存在: {:?}", config.tls.key.clone()).as_str(),
158 ));
159 }
160 if !config.tls.certs.is_file() {
161 return Err(Error::other(
162 format!("certificate.pem 不存在: {:?}", config.tls.certs).as_str(),
163 ));
164 }
165 let t = read(config.tls.key)?;
166 let mut reader = BufReader::new(t.as_slice());
167 let key = rustls_pemfile::private_key(&mut reader)
168 .map_err(|e| Error::other(format!("failed to parse private key: {}", e)))?
169 .ok_or_else(|| Error::other("no private key found in key file"))?;
170 let t = read(config.tls.certs)?;
171 let mut reader = BufReader::new(t.as_slice());
172 let certs = certs(&mut reader)
173 .collect::<Result<Vec<_>, _>>()?
174 .as_slice()
175 .to_owned();
176
177 let config = match ServerConfig::builder()
178 .with_no_client_auth()
180 .with_single_cert(certs, key)
182 {
183 Ok(e) => e,
184 Err(e) => return Err(Error::other(e)),
185 };
186
187 Ok(Some(Arc::new(config)))
188 } else {
203 Ok(None)
204 }
205 }
206}
207
208pub trait HandlerClone {
209 fn clone_box(&self) -> Box<dyn Handler>;
210}
211
212impl<T> HandlerClone for T
214where
215 T: 'static + Handler + Clone,
216{
217 fn clone_box(&self) -> Box<dyn Handler> {
218 Box::new(self.clone())
219 }
220}
221
222impl Clone for Box<dyn Handler> {
224 fn clone(&self) -> Box<dyn Handler> {
225 self.clone_box()
226 }
227}
228pub trait Handler: Send + Sync + HandlerClone + Debug {
229 fn on_request(&mut self, _request: Request, _response: &mut Response);
231 fn on_options(&mut self, response: &mut Response) {
233 response.allow_origins = vec![];
234 response.allow_methods = vec!["GET", "POST", "PUT", "DELETE", "OPTIONS"];
235 response.allow_headers = vec!["Authorization", "X-Forwarded-For", "X-Real-IP"];
236 response.header("Access-Control-Expose-Headers", "Content-Disposition");
237 response.header("Access-Control-Max-Age", 86400.to_string().as_str());
238 }
239 fn on_response(&mut self, response: &mut Response) {
241 if !response.headers.has_key("Access-Control-Allow-Origin") {
242 response.header("Access-Control-Allow-Origin", "*");
243 }
244 }
245
246 fn on_frame(&mut self) -> Result<(), HttpError> {
247 Ok(())
248 }
249 fn on_open(&mut self) -> Result<(), HttpError> {
251 Ok(())
252 }
253 fn on_message(&mut self, _msg: Message) -> Result<(), HttpError> {
255 Ok(())
256 }
257 fn on_close(&mut self, _code: CloseCode, _reason: &str) {}
259 fn on_error(&mut self, _err: ErrorCode) {}
261 fn on_shutdown(&mut self) {}
263}
264
265#[derive(Clone, Debug)]
266pub enum Connection {
267 KeepAlive,
269 Close,
271 Other(String),
272}
273impl Connection {
274 pub fn from(value: &str) -> Self {
275 match value.to_lowercase().as_str() {
276 "keep-alive" => Self::KeepAlive,
277 "close" => Self::Close,
278 _ => Self::Other(value.to_string()),
279 }
280 }
281 pub fn str(&self) -> &str {
282 match self {
283 Connection::KeepAlive => "keep-alive",
284 Connection::Close => "close",
285 Connection::Other(name) => name,
286 }
287 }
288}
289#[derive(Clone, Debug)]
290pub enum Upgrade {
291 Websocket,
292 Http,
293 H2c,
294 Other(String),
295}
296impl Upgrade {
297 #[must_use]
298 pub fn from(name: &str) -> Self {
299 match name.to_lowercase().as_str() {
300 "websocket" => Upgrade::Websocket,
301 "http" => Upgrade::Http,
302 "h2c" => Upgrade::H2c,
303 _ => Upgrade::Other(name.to_lowercase().as_str().to_string()),
304 }
305 }
306 #[must_use]
307 pub fn str(&self) -> &str {
308 match self {
309 Upgrade::Websocket => "websocket",
310 Upgrade::Http => "http",
311 Upgrade::H2c => "h2c",
312 Upgrade::Other(name) => name,
313 }
314 }
315}
316
317#[derive(Clone, Debug, Default)]
319pub struct Uri {
320 pub uri: String,
322 pub url: String,
324 pub query: String,
326 pub fragment: String,
328 pub path: String,
330 pub path_segments: Vec<String>,
332}
333impl Uri {
334 #[must_use]
335 pub fn from(url: &str) -> Self {
336 let mut decoded_url = br_crypto::encoding::urlencoding_decode(url);
337 let fragment = match decoded_url.rfind('#') {
338 None => String::new(),
339 Some(index) => decoded_url.drain(index..).collect::<String>(),
340 };
341
342 let query = match decoded_url.rfind('?') {
343 None => String::new(),
344 Some(index) => decoded_url
345 .drain(index..)
346 .collect::<String>()
347 .trim_start_matches("?")
348 .to_string(),
349 };
350
351 let path_segments = decoded_url
352 .split('/')
353 .map(|x| x.to_string())
354 .filter(|x| !x.is_empty())
355 .collect::<Vec<String>>();
356 Self {
357 uri: decoded_url.clone(),
358 url: url.to_string(),
359 query,
360 fragment,
361 path: decoded_url.clone(),
362 path_segments,
363 }
364 }
365 #[must_use]
367 pub fn get_query_params(&self) -> JsonValue {
368 let text = self.query.split('&').collect::<Vec<&str>>();
369 let mut params = object! {};
370 for item in text {
371 if let Some(index) = item.find('=') {
372 let key = item[..index].to_string();
373 let value = item[index + 1..].to_string();
374 let _ = params.insert(key.as_str(), value);
375 }
376 }
377 params
378 }
379 #[must_use]
380 pub fn to_json(&self) -> JsonValue {
381 object! {
382 url: self.url.clone(),
383 query: self.query.clone(),
384 fragment: self.fragment.clone(),
385 path: self.path.clone(),
386 path_segments: self.path_segments.clone()
387 }
388 }
389}
390
391#[derive(Clone, Debug)]
393pub enum Method {
394 POST,
396 GET,
398 HEAD,
400 PUT,
402 DELETE,
404 OPTIONS,
406 PATCH,
407 TRACE,
408 VIEW,
409 CONNECT,
410 PROPFIND,
411 PRI,
413 Other(String),
415}
416
417impl Method {
418 #[must_use]
419 pub fn from(name: &str) -> Self {
420 match name.to_lowercase().as_str() {
421 "post" => Self::POST,
422 "get" => Self::GET,
423 "head" => Self::HEAD,
424 "put" => Self::PUT,
425 "delete" => Self::DELETE,
426 "options" => Self::OPTIONS,
427 "patch" => Self::PATCH,
428 "trace" => Self::TRACE,
429 "view" => Self::VIEW,
430 "propfind" => Self::PROPFIND,
431 "connect" => Self::CONNECT,
432 "pri" => Self::PRI,
433 _ => Self::Other(name.to_lowercase()),
434 }
435 }
436 #[must_use]
437 pub fn str(&self) -> &str {
438 match self {
439 Self::POST => "POST",
440 Self::GET => "GET",
441 Self::HEAD => "HEAD",
442 Self::PUT => "PUT",
443 Self::DELETE => "DELETE",
444 Self::OPTIONS => "OPTIONS",
445 Self::PATCH => "PATCH",
446 Self::TRACE => "TRACE",
447 Self::VIEW => "VIEW",
448 Self::PROPFIND => "PROPFIND",
449 Self::PRI => "PRI",
450 Self::CONNECT => "CONNECT",
451 Method::Other(e) => e.as_str(),
452 }
453 }
454}
455
456#[derive(Debug, Clone)]
457pub struct HttpError {
458 pub code: u16,
459 pub body: String,
460}
461
462impl HttpError {
463 #[must_use]
465 pub fn new(code: u16, body: &str) -> Self {
466 Self {
467 code,
468 body: body.to_string(),
469 }
470 }
471}
472#[derive(Debug, Clone)]
474pub enum ContentType {
475 FormData,
476 FormUrlencoded,
477 Json,
478 Xml,
479 Javascript,
480 Text,
481 Html,
482 Stream,
483 Other(String),
484}
485impl ContentType {
486 #[must_use]
487 pub fn from(name: &str) -> Self {
488 match name {
489 "multipart/form-data" => Self::FormData,
490 "application/x-www-form-urlencoded" => Self::FormUrlencoded,
491 "application/json" => Self::Json,
492 "application/xml" | "text/xml" => Self::Xml,
493 "application/javascript" => Self::Javascript,
494 "application/octet-stream" => Self::Stream,
495 "text/html" => Self::Html,
496 "text/plain" => Self::Text,
497 _ => Self::Other(name.to_string()),
498 }
499 }
500 #[must_use]
501 pub fn str(&self) -> &str {
502 match self {
503 ContentType::FormData => "multipart/form-data",
504 ContentType::FormUrlencoded => "application/x-www-form-urlencoded",
505 ContentType::Json => "application/json",
506 ContentType::Xml => "application/xml",
507 ContentType::Javascript => "application/javascript",
508 ContentType::Text => "text/plain",
509 ContentType::Html => "text/html",
510 ContentType::Other(name) => name.as_str(),
511 ContentType::Stream => "application/octet-stream",
512 }
513 }
514}
515
516pub(crate) fn parse_content_type_header_value(
525 value: &str,
526) -> (String, std::collections::HashMap<String, String>) {
527 let mut it = value.split(';');
528 let mime = it.next().unwrap_or("").trim().to_lowercase();
529
530 let mut params = std::collections::HashMap::<String, String>::new();
531 for raw in it {
532 let raw = raw.trim();
533 if raw.is_empty() {
534 continue;
535 }
536 if let Some((k, v)) = raw.split_once('=') {
537 let key = k.trim().to_lowercase();
538 let mut val = v.trim();
539 if val.len() >= 2 && val.starts_with('"') && val.ends_with('"') {
540 val = &val[1..val.len() - 1];
541 }
542 params.insert(key, val.to_string());
543 } else {
544 params.insert(raw.to_lowercase(), String::new());
546 }
547 }
548
549 (mime, params)
550}
551#[derive(Clone, Debug)]
553pub enum Authorization {
554 Basic(String, String),
555 Bearer(String),
556 Digest(JsonValue),
557 Other(String),
558}
559impl Authorization {
560 #[must_use]
561 pub fn from(data: &str) -> Self {
562 let authorization = data.split_whitespace().collect::<Vec<&str>>();
563 let mode = authorization[0].to_lowercase();
564 match mode.as_str() {
565 "basic" => {
566 let text = br_crypto::base64::decode(&authorization[1].to_string());
567 let text: Vec<&str> = text.split(':').collect();
568 Self::Basic(text[0].to_string(), text[1].to_string())
569 }
570 "bearer" => Self::Bearer(authorization[1].to_string()),
571 "digest" => {
572 let text = authorization[1..].concat().clone();
573 let text = text.split(',').collect::<Vec<&str>>();
574 let mut params = object! {};
575 for item in &text {
576 let Some(index) = item.find('=') else {
577 continue;
578 };
579 let key = item[..index].to_string();
580 let value = item[index + 2..item.len() - 1].to_string();
581 let _ = params.insert(key.as_str(), value);
582 }
583 Self::Digest(params)
584 }
585 _ => Self::Other(data.to_string()),
586 }
587 }
588 #[must_use]
589 pub fn str(&self) -> JsonValue {
590 match self {
591 Self::Basic(key, value) => {
592 let mut data = object! {};
593 data[key.as_str()] = value.clone().into();
594 data
595 }
596 Self::Bearer(e) => e.clone().into(),
597 Self::Digest(e) => e.clone(),
598 Self::Other(name) => name.clone().into(),
599 }
600 }
601}
602#[derive(Clone, Debug)]
604pub enum Content {
605 FormUrlencoded(JsonValue),
606 FormData(JsonValue),
607 Json(JsonValue),
608 Text(JsonValue),
609 Xml(JsonValue),
610 None,
611}
612impl Content {}
613#[derive(Clone, Debug)]
614pub enum FormData {
615 File(String, PathBuf),
616 Field(JsonValue),
617}
618
619#[derive(Clone, Debug)]
621pub enum Language {
622 ZhCN,
623 ZhHans,
624 En,
625 Other(String),
626}
627impl Language {
628 #[must_use]
629 pub fn from(name: &str) -> Self {
630 let binding = name.split(',').collect::<Vec<&str>>()[0]
631 .trim()
632 .to_lowercase();
633 let name = binding.as_str();
634 match name {
635 "zh-cn" => Self::ZhCN,
636 "zh-hans" => Self::ZhHans,
637 "en" => Self::En,
638 _ => Self::Other(name.to_string()),
639 }
640 }
641 #[must_use]
642 pub fn str(&self) -> &str {
643 match self {
644 Language::ZhCN => "zh-CN",
645 Language::ZhHans => "zh-Hans",
646 Language::En => "en",
647 Language::Other(e) => e.as_str(),
648 }
649 }
650}
651
652#[derive(Clone, Debug)]
654pub enum Encoding {
655 Gzip,
656 Deflate,
657 Br,
658 Bzip2,
659 None,
660}
661impl Encoding {
662 #[must_use]
663 pub fn from(s: &str) -> Encoding {
664 match s.to_lowercase().as_str() {
665 x if x.contains("gzip") => Encoding::Gzip,
666 x if x.contains("deflate") => Encoding::Deflate,
667 x if x.contains("br") => Encoding::Br,
668 x if x.contains("bzip2") => Encoding::Bzip2,
669 _ => Encoding::None,
670 }
671 }
672 #[must_use]
673 pub fn str(&self) -> &str {
674 match self {
675 Encoding::Gzip => "gzip",
676 Encoding::Deflate => "deflate",
677 Encoding::Br => "br",
678 Encoding::Bzip2 => "bzip2",
679 Encoding::None => "",
680 }
681 }
682 pub fn compress(&mut self, data: &[u8]) -> Result<Vec<u8>, String> {
684 match self {
685 Encoding::Gzip => {
686 let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
687 match encoder.write_all(data) {
688 Ok(()) => {}
689 Err(e) => {
690 return Err(format!("Failed to compress file {}", e));
691 }
692 };
693 match encoder.finish() {
694 Ok(e) => Ok(e),
695 Err(e) => Err(format!("Failed to compress file {}", e)),
696 }
697 }
698 _ => Ok(data.to_vec()),
699 }
700 }
701 pub fn decompress(&mut self, data: &[u8]) -> Result<Vec<u8>, String> {
703 match self {
704 Encoding::Gzip => {
705 let mut d = GzDecoder::new(data);
706 let mut s = String::new();
707 match d.read_to_string(&mut s) {
708 Ok(_) => {}
709 Err(e) => {
710 return Err(format!("Failed to decompress file {}", e));
711 }
712 };
713 Ok(s.as_bytes().to_vec())
714 }
715 Encoding::Br => {
716 let mut decompressed = Vec::new();
717 let mut reader = brotli::Decompressor::new(data, 4096);
718 reader
719 .read_to_end(&mut decompressed)
720 .map_err(|e| format!("brotli decompress error: {e}"))?;
721 Ok(decompressed)
722 }
723 _ => Ok(data.to_vec()),
724 }
725 }
726}
727
728#[derive(Clone, Debug)]
730pub enum Protocol {
731 HTTP1_0,
732 HTTP1_1,
733 HTTP2,
734 HTTP3,
735 Other(String),
736}
737
738impl Protocol {
739 #[must_use]
740 pub fn from(name: &str) -> Self {
741 match name.to_lowercase().as_str() {
742 "http/1.0" => Protocol::HTTP1_0,
743 "http/1.1" => Protocol::HTTP1_1,
744 "http/2.0" | "http/2" => Protocol::HTTP2,
745 "http/3.0" | "http/3" => Protocol::HTTP3,
746 _ => Protocol::Other(name.to_lowercase()),
747 }
748 }
749 #[must_use]
750 pub fn str(&self) -> &str {
751 match self {
752 Protocol::HTTP1_0 => "HTTP/1.0",
753 Protocol::HTTP1_1 => "HTTP/1.1",
754 Protocol::HTTP2 => "HTTP/2.0",
755 Protocol::HTTP3 => "HTTP/3.0",
756 Protocol::Other(protocol) => protocol.as_str(),
757 }
758 }
759}
760#[derive(Clone, Debug)]
762pub struct Status {
763 pub code: u16,
764 reason: String,
765}
766impl Status {
767 pub fn set_code(&mut self, code: u16) {
768 self.code = code;
769 self.reason = match code {
770 100 => "Continue", 101 => "Switching Protocols", 102 => "Processing",
773 103 => "Early Hints", 200 => "OK", 201 => "Created", 202 => "Accepted", 204 => "No Content", 206 => "Partial Content", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 307 => "Temporary Redirect", 308 => "Permanent Redirect", 400 => "Bad Request", 401 => "Unauthorized", 403 => "Forbidden",
789 404 => "Not Found", 405 => "Method Not Allowed", 411 => "Length Required", 413 => "Payload Too Large", 414 => "URI Too Long", 416 => "Range Not Satisfiable",
795 429 => "Too Many Requests", 431 => "Request Header Fields Too Large", 500 => "Internal Server Error", 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable", 504 => "Gateway Time-out", 505 => "HTTP Version Not Supported", _ => "",
805 }
806 .to_string();
807 }
808 #[must_use]
809 pub fn from(code: u16, reason: &str) -> Self {
810 Status {
811 code,
812 reason: reason.to_string(),
813 }
814 }
815}
816impl Default for Status {
817 fn default() -> Self {
818 Self {
819 code: 200,
820 reason: "OK".to_string(),
821 }
822 }
823}
824
825#[derive(Debug)]
826pub enum TransferEncoding {
827 Chunked,
828 Other(String),
829}
830impl TransferEncoding {
831 pub fn from(name: &str) -> TransferEncoding {
832 match name.to_lowercase().as_str() {
833 "chunked" => TransferEncoding::Chunked,
834 _ => TransferEncoding::Other(name.to_string()),
835 }
836 }
837}
838
839pub fn split_boundary(mut data: Vec<u8>, boundary: &str) -> Result<Vec<Vec<u8>>, String> {
840 let boundary = format!("--{boundary}");
841 let boundary_bytes = boundary.as_bytes();
842 let mut list = vec![];
843 loop {
844 if let Some(n) = data
845 .windows(boundary_bytes.len())
846 .position(|x| x == boundary_bytes)
847 {
848 let drain_end = n + boundary_bytes.len();
850 if drain_end > data.len() {
851 return Err("格式错误: boundary 超出数据范围".to_string());
852 }
853 data.drain(..drain_end);
854 if data.is_empty() || data.starts_with(b"--\r\n") || data.starts_with(b"--") {
855 break;
856 }
857 if data.starts_with(b"\r\n") {
859 data.drain(..2);
860 }
861 } else {
862 return Err("格式错误: 未找到 boundary".to_string());
863 }
864 if let Some(n) = data
865 .windows(boundary_bytes.len())
866 .position(|x| x == boundary_bytes)
867 {
868 if n > 0 {
869 let content_end = if n >= 2 && data[n - 2..n] == *b"\r\n" {
871 n - 2
872 } else {
873 n
874 };
875 list.push(data[..content_end].to_vec());
876 }
877 data.drain(..n);
878 } else {
879 return Err("格式错误: 未找到结束 boundary".to_string());
880 }
881 }
882 Ok(list)
883}