1use crate::stream::{Protocol};
2use crate::request::{Request};
3use chrono::{DateTime, Duration as dur, Utc};
4use json::{object, JsonValue};
5use log::{error, info};
6use std::path::{Path, PathBuf};
7use std::{fs, io, thread};
8use std::io::{Error};
9use hpack::Encoder;
10use crate::{ContentType, Encoding, Handler, HttpError, Method, Upgrade};
11use crate::stream::Protocol::HTTP2;
12use crate::websocket::Websocket;
13const FLAG_END_STREAM: u8 = 0x01;
14const FLAG_END_HEADERS: u8 = 0x04;
15#[derive(Clone, Debug)]
17pub struct Response {
18 pub request: Request,
19 pub status: Status,
20 pub headers: JsonValue,
21 pub cookies: JsonValue,
22 pub body: Vec<u8>,
24 pub stream_id: u32,
26 pub key: String,
28 pub version: String,
30 pub factory: fn(out: Websocket) -> Box<dyn Handler>,
31 pub allow_origins: Vec<&'static str>,
33 pub allow_methods: Vec<&'static str>,
35 pub allow_headers: Vec<&'static str>,
37 pub content_type: ContentType,
39}
40impl Response {
41 pub fn new(request: Request, factory: fn(out: Websocket) -> Box<dyn Handler>) -> Self {
42 Self {
43 request: request.clone(),
44 status: Status::default(),
45 headers: object! {},
46 cookies: object! {},
47 body: vec![],
48 stream_id: 0,
49 key: String::new(),
50 version: String::new(),
51 factory,
52 allow_origins: vec![],
53 allow_methods: vec![],
54 allow_headers: vec![],
55 content_type: ContentType::Other(String::new()),
56 }
57 }
58 pub fn handle(mut self) -> io::Result<()> {
59 match self.request.upgrade {
60 Upgrade::Websocket => {
61 self.handle_protocol_ws()?;
62 return Ok(());
63 }
64 Upgrade::Http => {}
65 Upgrade::H2c => {
66 let _ = self.handle_protocol_h2c();
67 }
68 Upgrade::Other(_) => {}
69 }
70
71 match self.request.protocol {
72 Protocol::HTTP1_0 => self.handle_protocol_http0()?,
73 Protocol::HTTP1_1 => self.handle_protocol_http1()?,
74 Protocol::HTTP2 => self.handle_protocol_http2()?,
75 Protocol::HTTP3 => {}
76 Protocol::Other(_) => {}
77 }
78 Ok(())
79 }
80 fn handle_protocol_http0(&mut self) -> io::Result<()> {
81 let websocket = Websocket::http(self.request.clone(), self.clone());
82 let mut factory = (self.factory)(websocket);
83 match self.request.method {
84 Method::OPTIONS => {
85 factory.on_options(self);
86 match self.on_options() {
87 Ok(_) => {
88 match self.status(200).send() {
89 Ok(_) => {}
90 Err(e) => return Err(Error::other(format!("1004: {} {} {}", self.request.uri.path, e.code, e.body))),
91 };
92 }
93 Err(e) => return {
94 self.status(e.code).txt(e.body.as_str()).send().unwrap();
95 Ok(())
96 }
97 };
98 }
99 Method::GET => {
100 if let Ok(e) = self.read_resource() {
101 if self.request.header.has_key("range") {
102 return match self.status(206).range(&e).send() {
103 Ok(_) => Ok(()),
104 Err(e) => Err(Error::other(format!("1003: {} {} {}", self.request.uri.path, e.code, e.body))),
105 };
106 } else {
107 return match self.status(200).file(&e).send() {
108 Ok(_) => Ok(()),
109 Err(e) => Err(Error::other(format!("1003: {} {} {}", self.request.uri.path, e.code, e.body))),
110 };
111 }
112 }
113 factory.on_request(self.request.clone(), self);
114 factory.on_response(self);
115 match self.send() {
116 Ok(_) => {}
117 Err(e) => return Err(Error::other(format!("1002: {} {} {}", self.request.uri.path, e.code, e.body))),
118 }
119 }
120 _ => {
121 factory.on_request(self.request.clone(), self);
122 factory.on_response(self);
123 match self.send() {
124 Ok(_) => {}
125 Err(e) => return Err(Error::other(format!("1001: {} {}", e.code, e.body))),
126 }
127 }
128 }
129 Ok(())
130 }
131 fn handle_protocol_http1(&mut self) -> io::Result<()> {
132 self.handle_protocol_http0()
133 }
134 fn handle_protocol_http2(&mut self) -> io::Result<()> {
135 let websocket = Websocket::http(self.request.clone(), self.clone());
136 let mut factory = (self.factory)(websocket);
137
138 match self.request.method {
139 Method::OPTIONS => {
140 factory.on_options(self);
141 match self.send() {
142 Ok(_) => {}
143 Err(e) => return Err(Error::other(format!("2001: {} {}", e.code, e.body))),
144 };
145 }
146 Method::GET => {
147 if let Ok(e) = self.read_resource() {
148 return match self.status(200).file(&e).send() {
149 Ok(_) => Ok(()),
150 Err(e) => Err(Error::other(e.body)),
151 };
152 }
153 factory.on_request(self.request.clone(), self);
154 factory.on_response(self);
155 match self.send() {
156 Ok(_) => {}
157 Err(e) => return Err(Error::other(format!("2002: {} {}", e.code, e.body))),
158 }
159 }
160 _ => {
161 factory.on_request(self.request.clone(), self);
162 factory.on_response(self);
163 match self.send() {
164 Ok(_) => {}
165 Err(e) => return Err(Error::other(format!("2003: {} {}", e.code, e.body))),
166 }
167 }
168 }
169 Ok(())
170 }
171 fn handle_protocol_ws(&mut self) -> io::Result<()> {
172 let mut websocket = Websocket::new(self.request.clone(), self.clone());
173 let _ = websocket.handle();
174 Ok(())
175 }
176 fn handle_protocol_h2c(&mut self) -> Result<(), HttpError> {
177 self.header("Upgrade", "h2c");
178 self.header("Connection", "Upgrade");
179 match self.status(101).send() {
180 Ok(()) => self.headers.clear(),
181 Err(e) => return Err(e)
182 };
183 self.request.scheme.lock().unwrap().http2_send_server_settings()?;
184 let mut data = vec![];
185 self.request.scheme.lock().unwrap().read(&mut data)?;
186
187 let t = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
188 if let Some(pos) = data.windows(t.len()).position(|window| window == t) {
189 let _ = data.drain(..pos).collect::<Vec<u8>>();
190 data.drain(..t.len());
191 } else {
192 return Err(HttpError::new(400, "请求行错误"));
193 }
194 let (_payload, _frame_type, flags, _stream_id) = self.request.scheme.lock().unwrap().http2_packet(&mut data)?;
195 if flags & 0x01 == 0 {
196 self.request.scheme.lock().unwrap().http2_settings_ack()?;
197 }
198 let (_payload, _frame_type, _flags, _stream_id) = self.request.scheme.lock().unwrap().http2_packet(&mut data)?;
199 let (payload, _frame_type, _flags, _stream_id) = self.request.scheme.lock().unwrap().http2_packet(&mut data)?;
200 if payload.len() == 4 {
201 let raw = u32::from_be_bytes(payload.clone().try_into().unwrap());
202 let increment = raw & 0x7FFF_FFFF; if self.request.config.debug {
204 info!("WindowUpdate: increment = {} {:?}", increment,payload);
205 }
206 } else {
207 return Err(HttpError::new(400, format!("Invalid WindowUpdate frame length: {}", payload.len()).as_str()));
208 }
209 self.request.protocol=HTTP2;
210 Ok(())
211 }
212 fn read_resource(&mut self) -> io::Result<PathBuf> {
214 if self.request.uri.path != "/" {
215 let file = self.request.config.root_path.join(self.request.config.public.clone()).join(self.request.uri.path.trim_start_matches('/'));
216 if file.is_file() {
217 return Ok(file);
218 }
219 }
220 if self.request.uri.path == "/" {
221 let file = self.request.config.root_path.join("webpage").join(self.request.config.webpage.clone()).join("index.html");
222 if file.is_file() {
223 return Ok(file);
224 }
225 } else {
226 let file = self.request.config.root_path.join("webpage").join(self.request.config.webpage.clone()).join(self.request.uri.path.trim_start_matches('/'));
227 if file.is_file() {
228 return Ok(file);
229 }
230 }
231 Err(Error::other("Not a file"))
232 }
233 pub fn status(&mut self, code: u16) -> &mut Self {
234 self.status.set_code(code);
235 self
236 }
237 pub fn location(&mut self, uri: &str) -> &mut Self {
239 self.header("Location", uri);
240 self
241 }
242 pub fn set_host(&mut self, host: &str) -> &mut Self {
244 self.header("Host", host);
245 self
246 }
247
248 pub fn header(&mut self, key: &str, value: &str) -> &mut Self {
249 self.headers[key] = value.into();
250 self
251 }
252 pub fn cookie(&mut self, key: &str, value: &str) -> &mut Self {
253 self.cookies[key] = value.into();
254 self
255 }
256 fn get_date(&self, s: i64) -> String {
257 let utc: DateTime<Utc> = Utc::now();
258 let future = utc + dur::seconds(s); future.format("%a, %d %b %Y %H:%M:%S GMT").to_string()
260 }
261 pub fn html(&mut self, value: &str) -> &mut Self {
263 if self.request.config.charset.is_empty() {
264 self.header("Content-Type", format!("{};", Extension::form("html").as_str()).as_str());
265 } else {
266 self.header("Content-Type", format!("{}; charset={}", Extension::form("html").as_str(), self.request.config.charset).as_str());
267 }
268 self.content_type = ContentType::Html;
269 self.body = value.as_bytes().to_vec();
270 self
271 }
272 pub fn txt(&mut self, value: &str) -> &mut Self {
274 if self.request.config.charset.is_empty() {
275 self.header("Content-Type", Extension::form("txt").as_str().to_string().as_str());
276 } else {
277 self.header("Content-Type", format!("{}; charset={}", Extension::form("txt").as_str(), self.request.config.charset).as_str());
278 }
279 self.content_type = ContentType::Text;
280 self.body = value.as_bytes().to_vec();
281 self
282 }
283 pub fn json(&mut self, value: JsonValue) -> &mut Self {
285 if self.request.config.charset.is_empty() {
286 self.header("Content-Type", Extension::form("json").as_str().to_string().as_str());
287 } else {
288 self.header("Content-Type", format!("{}; charset={}", Extension::form("json").as_str(), self.request.config.charset).as_str());
289 }
290 self.content_type = ContentType::Json;
291 self.body = value.to_string().into_bytes();
292 self
293 }
294 pub fn download(&mut self, filename: &Path) -> &mut Self {
303 let Ok(file) = fs::read(filename) else {
304 self.status(404);
305 return self;
306 };
307 let extension = filename.extension().unwrap().to_str().unwrap().to_lowercase();
308
309 if self.request.config.charset.is_empty() {
310 self.header("Content-Type", Extension::form(extension.as_str()).as_str().to_string().as_str());
311 } else {
312 self.header("Content-Type", format!("{}; charset={}", Extension::form(extension.as_str()).as_str(), self.request.config.charset).as_str());
313 }
314
315 let encoded_file_name = br_crypto::encoding::urlencoding_encode(filename.file_name().unwrap().to_str().unwrap());
316 self.header("Content-Disposition", format!(r"attachment; filename={encoded_file_name}").as_str());
317 self.header("Cache-Control", "no-cache");
318 self.header("ETag", br_crypto::md5::encrypt_hex(&file).as_str());
319 self.body = file;
320 self
321 }
322 pub fn range(&mut self, filename: &Path) -> &mut Self {
324 let Ok(file) = fs::read(filename) else {
325 self.status(404);
326 return self;
327 };
328 let range = self.request.header["range"].to_string();
329 let range = range.trim_start_matches("bytes=");
330 let range = range.split("-").collect::<Vec<&str>>();
331 let range_start = range[0].parse::<usize>().unwrap();
332 let range_end = range[1].parse::<usize>().unwrap();
333
334 if file.len() < range_end {
335 self.status(416);
336 self.header("Content-Range", format!("bytes */{}", file.len()).as_str());
337 return self;
338 }
339
340 let extension = filename.extension().unwrap().to_str().unwrap().to_lowercase();
341
342 if self.request.config.charset.is_empty() {
343 self.header("Content-Type", Extension::form(extension.as_str()).as_str().to_string().as_str());
344 } else {
345 self.header("Content-Type", format!("{}; charset={}", Extension::form(extension.as_str()).as_str(), self.request.config.charset).as_str());
346 }
347
348 self.header("Accept-Ranges", "bytes");
349 self.header("content-length", (range_end - range_start + 1).to_string().as_str());
350 self.header("Content-Range", format!("bytes {}-{}/{}", range_start, range_end, file.len()).as_str());
351 self.body = file[range_start..=range_end].to_vec();
352 self
353 }
354 pub fn file(&mut self, filename: &Path) -> &mut Self {
361 let Ok(file) = fs::read(filename) else {
362 self.status(404);
363 return self;
364 };
365
366 self.header("Access-Control-Expose-Headers", "Content-Disposition");
367 let extension = match filename.extension() {
368 None => String::new(),
369 Some(e) => e.to_str().unwrap().to_lowercase(),
370 };
371 if self.request.config.charset.is_empty() {
372 self.header("Content-Type", Extension::form(extension.as_str()).as_str().to_string().as_str());
373 } else {
374 self.header("Content-Type", format!("{}; charset={}", Extension::form(extension.as_str()).as_str(), self.request.config.charset).as_str());
375 }
376
377 self.header("Content-Disposition", format!(r#"inline; filename="{}""#, filename.file_name().unwrap().to_str().unwrap()).as_str());
378
379 self.header("Accept-Ranges", "bytes");
380
381 self.header("Cache-Control", format!("public, max-age={}", 81400).as_str());
382 self.header("Expires", &self.clone().get_date(81400));
383 self.body = file;
384 self
385 }
386 pub fn send(&mut self) -> Result<(), HttpError> {
392 match &self.request.protocol {
393 Protocol::HTTP1_0 | Protocol::HTTP1_1 => Ok(self.send_http1()?),
394 Protocol::HTTP2 => Ok(self.send_http2()?),
395 Protocol::HTTP3 => {
396 error!("Other1:{:?} {:?}", thread::current().id(),self.request);
397 Err(HttpError::new(500, "暂未实现HTTP3"))
398 }
399 Protocol::Other(e) => {
400 error!("Other:{:?} {:?}", thread::current().id(),self.request);
401 Err(HttpError::new(500, format!("暂未实现Other: {} {} {:?}", e, self.request.uri.path, thread::current().id()).as_str()))
402 }
403 }
404 }
405 fn send_http1(&mut self) -> Result<(), HttpError> {
406 let mut header = vec![];
407 header.push(format!("{} {} {}", self.request.protocol.str(), self.status.code, self.status.reason));
408 self.header("Date", &self.get_date(0));
409
410 match self.request.method {
411 Method::HEAD => {
412 self.header("Content-Length", self.body.len().to_string().as_str());
413 self.body = vec![];
414 }
415 Method::OPTIONS => {
416 self.header("Content-Length", "0");
417 self.body = vec![];
418 }
419 _ => {
420 match self.request.accept_encoding {
421 Encoding::Gzip => {
422 self.header("Content-Encoding", self.request.accept_encoding.clone().str());
423 if let Ok(e) = self.request.accept_encoding.clone().compress(&self.body.clone()) { self.body = e };
424 self.header("Content-Length", self.body.len().to_string().as_str());
425 }
426 _ => { self.header("Content-Length", self.body.len().to_string().as_str()); }
427 }
428 }
429 };
430
431 for (key, value) in self.headers.entries() {
432 header.push(format!("{key}: {value}"));
433 }
434
435 for (key, value) in self.cookies.entries() {
436 header.push(format!("Set-Cookie: {key}={value}; Path=/; HttpOnly; SameSite=Lax"));
437 }
438
439 if self.request.config.debug {
440 info!("\r\n=================响应信息 {:?}=================\r\n{}\r\n===========================================",thread::current().id(),header.join("\r\n"));
441 match self.request.accept_encoding {
442 Encoding::Gzip => {}
443 _ => {
444 match self.content_type {
445 ContentType::Text | ContentType::Html | ContentType::Json | ContentType::FormUrlencoded => {
446 info!("\r\n=================响应体 {:?}=================\r\n{}\r\n===========================================",thread::current().id(),String::from_utf8_lossy(self.body.as_slice()));
447 }
448 _ => {}
449 };
450 }
451 }
452 }
453 let mut headers = format!("{}\r\n\r\n", header.join("\r\n")).into_bytes();
454 headers.extend(self.body.clone());
455 self.request.scheme.lock().unwrap().write(headers.as_slice())?;
456 Ok(())
457 }
458 fn send_http2(&mut self) -> Result<(), HttpError> {
459
460 let max_frame_size: usize = 16_384;
461 self.stream_id += 1;
462 let header_frames = self.http2_header(self.stream_id, max_frame_size);
464 let data_frames = self.http2_body(self.stream_id, true, max_frame_size);
465
466 let mut writer = self.request.scheme.lock().unwrap();
468 for f in header_frames.clone() { writer.write(&f)?; }
469 for f in data_frames.clone() { writer.write(&f)?; }
470 Ok(())
471 }
472
473 fn http2_header(&mut self, stream_id: u32, max_frame_size: usize) -> Vec<Vec<u8>> {
474 let mut headers: Vec<(Vec<u8>, Vec<u8>)> = vec![
475 (b":status".to_vec(), self.status.code.to_string().into_bytes()),
476 (b"date".to_vec(), self.get_date(0).into_bytes()),
477 ];
478
479 match self.request.method {
480 Method::HEAD => {
481 self.header("content-length", self.body.len().to_string().as_str());
482 self.body.clear(); }
484 Method::OPTIONS => {
485 self.body.clear();
486 self.header("content-length", "0");
487 }
488 _ => {
489 self.header("content-length", self.body.len().to_string().as_str());
490 }
491 }
492
493 headers.extend(
494 self.headers.entries().map(|(k, v)| (k.to_string().to_lowercase().into_bytes(), v.to_string().into_bytes()))
495 );
496 headers.extend(
497 self.cookies.entries().map(|(k, v)| (b"set-cookie".to_vec(), format!("{k}={v}; Path=/; HttpOnly; SameSite=Lax").into_bytes()))
498 );
499
500 if self.request.config.debug {
501 let dbg = headers.iter().map(|(n, v)| {
502 format!("{}: {}", String::from_utf8_lossy(n), String::from_utf8_lossy(v))
503 }).collect::<Vec<_>>().join("\r\n");
504 info!("\n=================响应信息 {:?}=================\n{}\n===========================================",
505 std::thread::current().id(), dbg);
506 }
507
508 let mut encoder = Encoder::new();
509 let block = encoder.encode(headers.iter().map(|h| (&h.0[..], &h.1[..])));
511
512 let end_stream = self.body.is_empty();
513 let mut frames = Vec::new();
514 let mut remaining = block.as_slice();
515 let mut first = true;
516
517 while !remaining.is_empty() {
518 let take = remaining.len().min(max_frame_size);
519 let (chunk, rest) = remaining.split_at(take);
520 remaining = rest;
521
522 let is_last = remaining.is_empty();
523 let mut flags = 0u8;
524 if is_last { flags |= FLAG_END_HEADERS; }
525 if is_last && end_stream { flags |= FLAG_END_STREAM; }
526
527 let mut f = Vec::with_capacity(9 + chunk.len());
529 let len = chunk.len();
530 f.push(((len >> 16) & 0xFF) as u8);
531 f.push(((len >> 8) & 0xFF) as u8);
532 f.push((len & 0xFF) as u8);
533 f.push(if first { 0x01 } else { 0x09 }); f.push(flags);
535 f.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
536 f.extend_from_slice(chunk);
537
538 frames.push(f);
539 first = false;
540 }
541
542 if frames.is_empty() {
544 let mut f = vec![0, 0, 0, 0x01, FLAG_END_HEADERS | if end_stream { FLAG_END_STREAM } else { 0 }, 0, 0, 0, 0];
545 f[5..9].copy_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
546 frames.push(f);
547 }
548
549 frames
550 }
551 fn http2_body(&mut self, stream_id: u32, end_stream: bool, max_frame_size: usize) -> Vec<Vec<u8>> {
552 if self.body.is_empty() {
553 return Vec::new();
554 }
555 let mut frames = Vec::new();
556 let mut off = 0usize;
557 let total = self.body.len();
558
559 while off < total {
560 let take = (total - off).min(max_frame_size);
561 let chunk = &self.body[off..off + take];
562 off += take;
563
564 let last = off == total;
565 frames.push(self.build_data_frame(stream_id, chunk, last && end_stream));
566 }
567 frames
568 }
569 fn build_data_frame(&self, stream_id: u32, payload: &[u8], end_stream: bool) -> Vec<u8> {
570 let len = payload.len();
571 let mut f = Vec::with_capacity(9 + len);
572 f.push(((len >> 16) & 0xFF) as u8);
573 f.push(((len >> 8) & 0xFF) as u8);
574 f.push((len & 0xFF) as u8);
575 f.push(0x00); f.push(if end_stream { FLAG_END_STREAM } else { 0 });
577 f.extend_from_slice(&(stream_id & 0x7FFF_FFFF).to_be_bytes());
578 if !payload.is_empty() { f.extend_from_slice(payload); }
579 f
580 }
581 fn on_options(&mut self) -> Result<(), HttpError> {
582 if self.allow_origins.is_empty() {
583 self.header("Access-Control-Allow-Origin", "*");
584 } else if self.request.header.has_key("origin") {
585 if self.allow_origins.contains(&self.request.origin.as_str()) {
586 self.header("Access-Control-Allow-Origin", self.request.origin.to_string().as_str());
587 } else {
588 return Err(HttpError::new(403, "Origin not allowed"));
589 }
590 } else {
591 return Err(HttpError::new(403, "Origin not allowed"));
592 }
593
594 if self.allow_headers.is_empty() {
595 if !self.request.header.has_key("access-control-request-headers") {
596 return Err(HttpError::new(403, "headers not allowed"));
597 }
598 self.header("Access-Control-Allow-Headers", self.request.header["access-control-request-headers"].to_string().as_str());
599 } else if !self.request.header.has_key("access-control-request-headers") {
600 let headers = self.allow_headers.join(",");
601 self.header("Access-Control-Allow-Headers", headers.to_string().as_str());
602 } else {
603 let headers = self.allow_headers.join(",");
604 self.header("Access-Control-Allow-Headers", format!("{},{}", self.request.header["access-control-request-headers"], headers).as_str());
605 }
606
607 if self.allow_methods.is_empty() {
608 if !self.request.header.has_key("access-control-request-method") {
609 return Err(HttpError::new(403, "methods not allowed"));
610 }
611 self.header("Access-Control-Allow-Methods", self.request.header["access-control-request-method"].to_string().as_str());
612 } else {
613 let methods = self.allow_methods.join(",");
614 self.header("Access-Control-Allow-Methods", methods.to_string().as_str());
615 }
616 self.header("Vary", "Origin, Access-Control-Request-Method, Access-Control-Request-Headers");
617 Ok(())
618 }
619}
620#[derive(Clone, Debug)]
621pub struct Status {
622 pub code: u16,
623 reason: String,
624}
625impl Status {
626 pub fn set_code(&mut self, code: u16) {
627 self.code = code;
628 self.reason = match code {
629 100 => "Continue", 101 => "Switching Protocols", 102 => "Processing",
632 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",
648 404 => "Not Found", 405 => "Method Not Allowed", 411 => "Length Required", 413 => "Payload Too Large", 414 => "URI Too Long", 416 => "Range Not Satisfiable",
654 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", _ => "",
664 }.to_string();
665 }
666}
667impl Default for Status {
668 fn default() -> Self {
669 Self {
670 code: 200,
671 reason: "OK".to_string(),
672 }
673 }
674}
675
676enum Extension {}
678impl Extension {
679 pub fn form(extension: &str) -> String {
680 match extension.to_lowercase().as_str() {
681 "html" => "text/html",
682 "css" => "text/css",
683 "js" => "application/javascript",
684 "json" => "application/json",
685 "png" => "image/png",
686
687 "mp4" => "video/mp4",
688 "jpg" | "jpeg" => "image/jpeg",
689 "gif" => "image/gif",
690 "txt" => "text/plain",
691 "pdf" => "application/pdf",
692 "svg" => "image/svg+xml",
693 "woff" => "application/font-woff",
694 "woff2" => "application/font-woff2",
695 "xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
696 _ => "application/octet-stream",
697 }.to_string()
698 }
699}
700
701