tower_web/extract/
serde.rs1use codegen::CallSite;
4use extract::{Context, Error, Extract, ExtractFuture};
5use http::status::StatusCode;
6use util::buf_stream::{self, BufStream};
7
8use futures::{Future, Poll};
9use headers::{ContentType, HeaderMapExt};
10use mime::Mime;
11use serde::de::DeserializeOwned;
12use serde_urlencoded;
13use serde_json;
14
15#[derive(Debug)]
21pub struct SerdeFuture<T, B> {
22 state: State<T, B>,
23 is_json: bool,
24}
25
26#[derive(Debug)]
27enum State<T, B> {
28 Complete(Result<T, Option<Error>>),
29 Body(buf_stream::Collect<B, Vec<u8>>),
30}
31
32impl<B: BufStream> Extract<B> for serde_json::Value {
33 type Future = SerdeFuture<Self, B>;
34
35 fn extract(ctx: &Context) -> Self::Future {
36 Self::Future::new_extract(ctx)
37 }
38
39 fn extract_body(ctx: &Context, body: B) -> Self::Future {
40 Self::Future::new_extract_body(ctx, body)
41 }
42
43 fn requires_body(callsite: &CallSite) -> bool {
44 self::requires_body(callsite)
45 }
46}
47
48#[doc(hidden)]
49pub fn requires_body(callsite: &CallSite) -> bool {
50 use codegen::Source::Body;
51
52 match callsite.source() {
53 Body => true,
54 _ => false,
55 }
56}
57
58impl<T, B> SerdeFuture<T, B>
59where T: DeserializeOwned,
60 B: BufStream,
61{
62 pub fn new_extract(ctx: &Context) -> Self {
64 use codegen::Source::*;
65
66 match ctx.callsite().source() {
67 Capture(_) => {
68 unimplemented!();
69 }
70 Header(_) => {
71 unimplemented!();
72 }
73 QueryString => {
74 let query = ctx.request().uri()
75 .path_and_query()
76 .and_then(|path_and_query| path_and_query.query())
77 .unwrap_or("");
78
79 let res = serde_urlencoded::from_str(query)
80 .map_err(|err| {
81 use std::error::Error as E;
82
83 if query.is_empty() {
84 Some(Error::missing_argument())
85 } else {
86 Some(Error::invalid_argument(&err.description()))
87 }
88 });
89
90 let state = State::Complete(res);
91
92 SerdeFuture { state, is_json: false }
93 }
94 Body => {
95 unimplemented!();
96 }
97 Unknown => {
98 unimplemented!();
99 }
100 }
101 }
102
103 pub fn new_extract_body(ctx: &Context, body: B) -> Self {
105 use codegen::Source::*;
106
107 match ctx.callsite().source() {
108 Capture(_) => {
109 unimplemented!("Capture");
110 }
111 Header(_) => {
112 unimplemented!("Header");
113 }
114 QueryString => {
115 unimplemented!("QueryString");
116 }
117 Body => {
118 if let Some(value) = ctx.request().headers().typed_get::<ContentType>() {
119 let mime = Mime::from(value);
120
121 match (mime.type_().as_str(), mime.subtype().as_str()) {
122 ("application", "json") => {
123 let state = State::Body(body.collect());
124
125 SerdeFuture { state, is_json: true }
126 }
127 ("application", "x-www-form-urlencoded") => {
128 let state = State::Body(body.collect());
129
130 SerdeFuture { state, is_json: false }
131 }
132 _ => {
133 let err = ::Error::from(StatusCode::BAD_REQUEST).into();
134 let state = State::Complete(Err(Some(err)));
135
136 SerdeFuture { state, is_json: false }
137 }
138 }
139 } else {
140 let err = ::Error::from(StatusCode::BAD_REQUEST).into();
141 let state = State::Complete(Err(Some(err)));
142
143 SerdeFuture { state, is_json: false }
144 }
145 }
146 Unknown => {
147 unimplemented!("Unknown");
148 }
149 }
150 }
151}
152
153impl<T, B> ExtractFuture for SerdeFuture<T, B>
154where T: DeserializeOwned,
155 B: BufStream,
156{
157 type Item = T;
158
159 fn poll(&mut self) -> Poll<(), Error> {
160 use self::State::*;
161
162 loop {
163 let res = match self.state {
164 Complete(Err(ref mut e)) => {
165 return Err(e.take().unwrap());
166 }
167 Complete(Ok(_)) => {
168 return Ok(().into());
169 }
170 Body(ref mut collect) => {
171 let res = collect.poll()
172 .map_err(|_| Error::internal_error());
174
175 let res = try_ready!(res);
176
177 if self.is_json == true {
178 ::serde_json::from_slice(&res[..])
179 .map_err(|_| {
180 Some(Error::internal_error())
182 })
183 } else {
184 ::serde_urlencoded::from_bytes(&res[..])
185 .map_err(|_| {
186 Some(Error::internal_error())
188 })
189 }
190 }
191 };
192
193 self.state = State::Complete(res);
194 }
195 }
196
197 fn extract(self) -> T {
198 use self::State::Complete;
199
200 match self.state {
201 Complete(Ok(res)) => res,
202 _ => panic!("invalid state"),
203 }
204 }
205}