| 288 | type Rejection = ServerFnError; |
| 289 | |
| 290 | fn from_request( |
| 291 | req: Request, |
| 292 | _state: &S, |
| 293 | ) -> impl Future<Output = Result<Self, Self::Rejection>> + Send { |
| 294 | async move { |
| 295 | let (parts, body) = req.into_parts(); |
| 296 | let content_type = parts |
| 297 | .headers |
| 298 | .get("content-type") |
| 299 | .and_then(|v| v.to_str().ok()) |
| 300 | .unwrap_or(""); |
| 301 | |
| 302 | if !content_type.starts_with("text/plain") { |
| 303 | HttpError::bad_request("Invalid content type")?; |
| 304 | } |
| 305 | |
| 306 | let stream = body.into_data_stream(); |
| 307 | |
| 308 | Ok(Self { |
| 309 | stream: Box::pin(stream.map(|byte| match byte { |
| 310 | Ok(bytes) => match String::from_utf8(bytes.to_vec()) { |
| 311 | Ok(string) => Ok(string), |
| 312 | Err(_) => Err(StreamingError::Decoding), |
| 313 | }, |
| 314 | Err(_) => Err(StreamingError::Failed), |
| 315 | })), |
| 316 | encoding: PhantomData, |
| 317 | }) |
| 318 | } |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | impl<S> FromRequest<S> for ByteStream { |