finchers_core/input/
input.rs1use error::HttpError;
2use failure::Fail;
3use http::{self, header, Request, StatusCode};
4use mime::{self, Mime};
5use std::cell::UnsafeCell;
6
7scoped_thread_local!(static CURRENT_INPUT: Input);
8
9#[derive(Debug)]
13pub struct Input {
14 request: Request<()>,
15 media_type: UnsafeCell<Option<Mime>>,
16}
17
18impl Input {
19 pub fn new(request: Request<()>) -> Input {
24 Input {
25 request,
26 media_type: UnsafeCell::new(None),
27 }
28 }
29
30 pub fn enter_scope<F, R>(&self, f: F) -> R
34 where
35 F: FnOnce() -> R,
36 {
37 CURRENT_INPUT.set(self, f)
38 }
39
40 pub fn with<F, R>(f: F) -> R
45 where
46 F: FnOnce(&Input) -> R,
47 {
48 CURRENT_INPUT.with(|input| f(input))
49 }
50
51 pub fn request(&self) -> &Request<()> {
53 &self.request
54 }
55
56 pub fn media_type(&self) -> Result<Option<&Mime>, InvalidMediaType> {
61 let media_type: &mut Option<Mime> = unsafe { &mut *self.media_type.get() };
63
64 if media_type.is_none() {
65 if let Some(raw) = self.request().headers().get(header::CONTENT_TYPE) {
66 let raw_str = raw.to_str().map_err(|cause| InvalidMediaType::DecodeToStr { cause })?;
67 let mime = raw_str
68 .parse()
69 .map_err(|cause| InvalidMediaType::ParseToMime { cause })?;
70 *media_type = Some(mime);
71 }
72 }
73
74 Ok((&*media_type).as_ref())
75 }
76}
77
78#[derive(Debug, Fail)]
80pub enum InvalidMediaType {
81 #[allow(missing_docs)]
82 #[fail(display = "Content-type is invalid: {}", cause)]
83 DecodeToStr { cause: http::header::ToStrError },
84
85 #[allow(missing_docs)]
86 #[fail(display = "Content-type is invalid: {}", cause)]
87 ParseToMime { cause: mime::FromStrError },
88}
89
90impl HttpError for InvalidMediaType {
91 fn status_code(&self) -> StatusCode {
92 StatusCode::BAD_REQUEST
93 }
94
95 fn as_fail(&self) -> Option<&Fail> {
96 Some(self)
97 }
98}