1use crate::{ReadError, ReadErrorKind, UploadStore};
5use base_http::{
6 Fields, Request,
7 body::{BodyFrame, ReadableBody},
8};
9use base_scheduler::Cancellation;
10use base_web_content::{
11 Accepted, ContentError, ContentEvent, ContentHandles, ContentParser, ParameterRules, Rejection,
12};
13use base_web_media_type::MediaType;
14
15#[derive(Clone, Copy, Debug, Default)]
17#[non_exhaustive]
18pub struct ReadOptions {
19 pub parameter_rules: Option<ParameterRules>,
21}
22
23pub async fn read_content<T, B, S>(
31 request: &mut Request<B>,
32 store: &mut S,
33 cancellation: &Cancellation,
34) -> Result<Accepted<T, S::Handle>, ReadError<B::Error, S::Error>>
35where
36 T: ContentHandles<S::Handle>,
37 B: ReadableBody,
38 S: UploadStore,
39{
40 read_content_with(request, store, &ReadOptions::default(), cancellation).await
41}
42
43pub async fn read_content_with<T, B, S>(
45 request: &mut Request<B>,
46 store: &mut S,
47 options: &ReadOptions,
48 cancellation: &Cancellation,
49) -> Result<Accepted<T, S::Handle>, ReadError<B::Error, S::Error>>
50where
51 T: ContentHandles<S::Handle>,
52 B: ReadableBody,
53 S: UploadStore,
54{
55 let parser = match parser(request, options) {
56 Ok(parser) => parser,
57 Err(kind) => {
58 request.body.close(None);
59 return Err(ReadError::new(kind));
60 }
61 };
62 let mut reader = Reader {
63 parser,
64 store,
65 upload: None,
66 };
67 let stopped = reader.read_body(&mut request.body, cancellation).await;
68 let Reader {
69 parser,
70 store,
71 upload,
72 } = reader;
73 if stopped.is_err() {
74 request.body.close(None);
75 }
76 let mut cleanup = Vec::new();
77 if let Some(upload) = upload {
78 if let Err(error) = store.abort(upload).await {
79 cleanup.push(error);
80 }
81 }
82 let rejected = match parser.finish() {
84 Ok(accepted) => return Ok(accepted),
85 Err(rejected) => rejected,
86 };
87 for handle in rejected.handles {
88 if let Err(error) = store.remove(handle).await {
89 cleanup.push(error);
90 }
91 }
92 let kind = match stopped {
94 Err(Stop::Body(error)) => ReadErrorKind::Body(error),
95 Err(Stop::Store(error)) => ReadErrorKind::Store(error),
96 Ok(()) | Err(Stop::Content) => ReadErrorKind::Rejected(rejected.reason),
97 };
98 Err(ReadError { kind, cleanup })
99}
100
101fn parser<T, H, B, S>(
103 request: &Request<B>,
104 options: &ReadOptions,
105) -> Result<ContentParser<T, H>, ReadErrorKind<B::Error, S>>
106where
107 T: ContentHandles<H>,
108 B: ReadableBody,
109{
110 let media_type = media_type(&request.fields).ok_or(ReadErrorKind::InvalidMediaType)?;
111 let mut parser = ContentParser::<T, H>::new(media_type.as_ref())
112 .map_err(|error| ReadErrorKind::Rejected(Rejection::Error(error)))?;
113 if let Some(rules) = options.parameter_rules {
114 parser = parser.with_parameter_rules(rules);
115 }
116 let limit = parser.body_size_limit();
117 match request.length() {
118 Some(length) if length > limit as u64 => Err(ReadErrorKind::ContentTooLarge {
119 length,
120 limit: limit as u64,
121 }),
122 _ => Ok(parser),
123 }
124}
125
126fn media_type(fields: &Fields) -> Option<Option<MediaType>> {
128 let mut values = fields.values("content-type");
129 let Some(value) = values.next() else {
130 return Some(None);
131 };
132 if values.next().is_some() {
133 return None;
134 }
135 let text = std::str::from_utf8(value).ok()?;
136 MediaType::parse(text).ok().map(Some)
137}
138
139enum Stop<B, S> {
141 Content,
143 Body(B),
144 Store(S),
145}
146
147fn content<B, S>(_: ContentError) -> Stop<B, S> {
149 Stop::Content
150}
151
152enum Step {
154 Continue,
155 Incomplete,
156 End,
157}
158
159struct Reader<'s, T, S: UploadStore> {
160 parser: ContentParser<T, S::Handle>,
161 store: &'s mut S,
162 upload: Option<S::Upload>,
164}
165
166impl<T, S: UploadStore> Reader<'_, T, S> {
167 async fn read_body<B: ReadableBody>(
169 &mut self,
170 body: &mut B,
171 cancellation: &Cancellation,
172 ) -> Result<(), Stop<B::Error, S::Error>> {
173 let mut retained = Vec::new();
174 loop {
175 let frame = body.read(cancellation).await.map_err(Stop::Body)?;
176 let end = frame.is_end();
177 if let BodyFrame::Data { data, .. } = frame {
178 let data = data.as_ref();
179 if retained.is_empty() {
180 let consumed = self.parse(data, false, cancellation).await?;
181 retained.extend_from_slice(&data[consumed..]);
182 } else {
183 retained.extend_from_slice(data);
184 let consumed = self.parse(&retained, false, cancellation).await?;
185 retained.drain(..consumed);
186 }
187 }
188 if end {
189 return self.parse(&retained, true, cancellation).await.map(drop);
190 }
191 }
192 }
193
194 async fn parse<B>(
196 &mut self,
197 input: &[u8],
198 end: bool,
199 cancellation: &Cancellation,
200 ) -> Result<usize, Stop<B, S::Error>> {
201 let mut offset = 0;
202 loop {
203 let rest = &input[offset..];
204 let parsed = match end {
205 false => self.parser.parse(rest),
206 true => self.parser.parse_end(rest),
207 }
208 .map_err(content)?;
209 offset += parsed.consumed;
210 match self
211 .handle(parsed.event, cancellation)
212 .await
213 .map_err(Stop::Store)?
214 {
215 Step::Continue => {}
216 Step::End if !end && offset < input.len() => {}
218 Step::Incomplete | Step::End => return Ok(offset),
220 }
221 }
222 }
223
224 async fn handle(
226 &mut self,
227 event: ContentEvent<'_>,
228 cancellation: &Cancellation,
229 ) -> Result<Step, S::Error> {
230 match event {
231 ContentEvent::Upload(head) => {
232 self.upload = Some(self.store.create(&head, cancellation).await?);
233 }
234 ContentEvent::UploadContent(content) => {
235 let upload = self.upload.as_mut().expect("content follows its upload");
236 self.store.write(upload, content, cancellation).await?;
237 }
238 ContentEvent::UploadEnd => {
239 let upload = self.upload.as_mut().expect("an upload ends after it began");
240 let handle = self.store.finish(upload, cancellation).await?;
241 self.upload = None;
242 self.parser.store(handle);
243 }
244 ContentEvent::End => return Ok(Step::End),
245 ContentEvent::Incomplete => return Ok(Step::Incomplete),
246 }
247 Ok(Step::Continue)
248 }
249}