fire_http/fs/
memory_files.rs1use super::static_files::CachingBuilder;
2use super::{file, partial_file, Caching, Range};
3use crate::header::Method;
4use crate::into::IntoResponse;
5use crate::routes::{ParamsNames, PathParams, RoutePath};
6use crate::util::PinnedFuture;
7use crate::{Error, IntoRoute, Request, Resources, Response, Route};
8
9use std::io;
10use std::time::Duration;
11
12pub fn serve_memory_file(
13 path: &'static str,
14 bytes: &'static [u8],
15 req: &Request,
16 caching: Option<Caching>,
17) -> io::Result<Response> {
18 if matches!(&caching, Some(c) if c.if_none_match(req.header())) {
20 return Ok(caching.unwrap().into_response());
21 }
22
23 let range = Range::parse(req.header());
24
25 let mut res = match range {
26 Some(range) => {
27 partial_file::serve_memory_partial_file(path, bytes, range)?
28 }
29 None => file::serve_memory_file(path, bytes)?,
30 };
31
32 if let Some(caching) = caching {
34 caching.complete_header(&mut res.header);
35 }
36
37 Ok(res)
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub struct MemoryFile {
55 uri: &'static str,
56 path: &'static str,
57 bytes: &'static [u8],
58 caching: CachingBuilder,
59}
60
61impl MemoryFile {
62 pub const fn new(
64 uri: &'static str,
65 path: &'static str,
66 bytes: &'static [u8],
67 ) -> Self {
68 Self {
69 uri,
70 path,
71 bytes,
72 caching: CachingBuilder::Default,
73 }
74 }
75
76 pub const fn no_cache(
77 uri: &'static str,
78 path: &'static str,
79 bytes: &'static [u8],
80 ) -> Self {
81 Self {
82 uri,
83 path,
84 bytes,
85 caching: CachingBuilder::None,
86 }
87 }
88
89 pub const fn cache_with_age(
90 uri: &'static str,
91 path: &'static str,
92 bytes: &'static [u8],
93 max_age: Duration,
94 ) -> Self {
95 Self {
96 uri,
97 path,
98 bytes,
99 caching: CachingBuilder::MaxAge(max_age),
100 }
101 }
102}
103
104impl IntoRoute for MemoryFile {
105 type IntoRoute = MemoryFileRoute;
106
107 fn into_route(self) -> MemoryFileRoute {
108 MemoryFileRoute {
109 uri: self.uri,
110 path: self.path,
111 bytes: self.bytes,
112 caching: self.caching.into(),
113 }
114 }
115}
116
117#[doc(hidden)]
118pub struct MemoryFileRoute {
119 uri: &'static str,
120 path: &'static str,
121 bytes: &'static [u8],
122 caching: Option<Caching>,
123}
124
125impl Route for MemoryFileRoute {
126 fn validate_requirements(&self, _params: &ParamsNames, _data: &Resources) {}
127
128 fn path(&self) -> RoutePath {
129 RoutePath {
130 method: Some(Method::GET),
131 path: self.uri.into(),
132 }
133 }
134
135 fn call<'a>(
136 &'a self,
137 req: &'a mut Request,
138 _params: &'a PathParams,
139 _data: &'a Resources,
140 ) -> PinnedFuture<'a, crate::Result<Response>> {
141 let caching = self.caching.clone();
142
143 PinnedFuture::new(async move {
144 serve_memory_file(self.path, self.bytes, &req, caching)
145 .map_err(Error::from_client_io)
146 })
147 }
148}