1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Parses the request body as json if the content-type: json header is set.
//! Note that if there are any errors in parsing the json
//! it will forward an error response to the client.
//! It is recommended you mount this middleware on the root `Router`
use core::Request;
use futures::{future, Future, Stream};
use hyper::{self, header::CONTENT_TYPE};
use proto::{MiddleWare, MiddleWareFuture};
use std::ops::Deref;

pub(crate) struct Json(hyper::Chunk);

impl Deref for Json {
	type Target = hyper::Chunk;

	fn deref(&self) -> &Self::Target {
		&self.0
	}
}

/// Json Body Parser.
///
#[derive(Clone, Debug)]
pub struct BodyParser;

impl MiddleWare<Request> for BodyParser {
	fn call(&self, mut req: Request) -> MiddleWareFuture<Request> {
		let mut isJson = false;
		{
			if let Some(ct) = req.headers().get(CONTENT_TYPE) {
				isJson = {
					let ct = ct.to_str();
					ct.is_ok() && ct.unwrap().contains("json")
				};
			}
		}

		if !isJson {
			return Box::new(future::ok(req));
		}

		let read_body_future = req.body().concat2().then(|result| {
			let json = match result {
				Ok(chunk) => {
					// assert that the chunk length is > 0
					// otherwise bad request.
					if chunk.len() == 0 {
						error!("zero-length json body");
						let error = json!({ "error": "Empty request body" });
						return Err((400, error).into());
					}
					Json(chunk)
				}
				Err(err) => {
					error!("Error reading json body from client: {}", err);
					let error = json!({
						"error": "Could not read request payload"
					});
					return Err((400, error).into());
				}
			};

			req.set(json);
			Ok(req)
		});

		return Box::new(read_body_future);
	}
}