actix_msgpack/
lib.rs

1mod constants;
2mod content_type_handler;
3mod error_handler;
4mod msgpack;
5mod msgpack_config;
6mod msgpack_error;
7mod msgpack_extractor_future;
8mod msgpack_message;
9mod msgpack_response_builder;
10
11pub(crate) use constants::DEFAULT_PAYLOAD_LIMIT;
12pub use content_type_handler::ContentTypeHandler;
13pub use error_handler::ErrorHandler;
14pub use msgpack::MsgPack;
15pub use msgpack_config::MsgPackConfig;
16pub(crate) use msgpack_config::DEFAULT_CONFIG;
17pub use msgpack_error::MsgPackError;
18pub use msgpack_extractor_future::MsgPackExtractorFuture;
19pub use msgpack_message::MsgPackMessage;
20pub use msgpack_response_builder::MsgPackResponseBuilder;
21
22#[cfg(test)]
23mod tests {
24	use super::*;
25	use actix_web::{
26		body::MessageBody,
27		error::InternalError,
28		http::{header, Method, StatusCode},
29		test::{call_service, init_service, TestRequest},
30		web::{self, Bytes},
31		App, HttpRequest, HttpResponse, Responder,
32	};
33	use mime::{APPLICATION_JSON, APPLICATION_MSGPACK};
34	use serde::{Deserialize, Serialize};
35
36	impl PartialEq for MsgPackError {
37		fn eq(&self, other: &MsgPackError) -> bool {
38			match *self {
39				MsgPackError::Overflow => {
40					matches!(*other, MsgPackError::Overflow)
41				},
42				MsgPackError::ContentType => {
43					matches!(*other, MsgPackError::ContentType)
44				},
45				_ => false,
46			}
47		}
48	}
49
50	#[derive(Debug, Serialize, Deserialize, PartialEq)]
51	pub struct Data {
52		payload: bool,
53	}
54
55	#[actix_web::test]
56	async fn check_content_type() {
57		// Pass empty Content-Type
58		let (req, mut payload) = TestRequest::default().to_http_parts();
59		let msgpack = MsgPackMessage::<Data>::new(&req, &mut payload, None).await;
60
61		assert_eq!(msgpack.err().unwrap(), MsgPackError::ContentType);
62
63		// Pass non-msgpack Content-Type
64		let (req, mut payload) = TestRequest::default()
65			.insert_header((header::CONTENT_TYPE, APPLICATION_JSON))
66			.to_http_parts();
67		let msgpack = MsgPackMessage::<Data>::new(&req, &mut payload, None).await;
68
69		assert_eq!(msgpack.err().unwrap(), MsgPackError::ContentType);
70
71		// Pass correct Content-Type
72		let (req, mut payload) = TestRequest::default()
73			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
74			.to_http_parts();
75		let msgpack = MsgPackMessage::<Data>::new(&req, &mut payload, None).await;
76
77		assert_ne!(msgpack.err().unwrap(), MsgPackError::ContentType);
78	}
79
80	#[actix_web::test]
81	async fn check_default_limit() {
82		// Pass min limit
83		let (req, mut payload) = TestRequest::default()
84			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
85			.insert_header((header::CONTENT_LENGTH, 0))
86			.to_http_parts();
87		let msgpack = MsgPackMessage::<()>::new(&req, &mut payload, None).await;
88
89		assert_ne!(msgpack.err().unwrap(), MsgPackError::Overflow);
90
91		// Pass max limit
92		let (req, mut payload) = TestRequest::default()
93			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
94			.insert_header((header::CONTENT_LENGTH, DEFAULT_PAYLOAD_LIMIT))
95			.to_http_parts();
96		let msgpack = MsgPackMessage::<()>::new(&req, &mut payload, None).await;
97
98		assert_ne!(msgpack.err().unwrap(), MsgPackError::Overflow);
99
100		// Pass more than default limit
101		let (req, mut payload) = TestRequest::default()
102			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
103			.insert_header((header::CONTENT_LENGTH, DEFAULT_PAYLOAD_LIMIT + 1))
104			.to_http_parts();
105		let msgpack = MsgPackMessage::<()>::new(&req, &mut payload, None).await;
106
107		assert_eq!(msgpack.err().unwrap(), MsgPackError::Overflow);
108	}
109
110	#[actix_web::test]
111	async fn check_custom_limit() {
112		const LIMIT: usize = 10;
113
114		// Pass max limit
115		let (req, mut payload) = TestRequest::default()
116			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
117			.insert_header((header::CONTENT_LENGTH, LIMIT))
118			.to_http_parts();
119		let msgpack = MsgPackMessage::<()>::new(&req, &mut payload, None).limit(LIMIT).await;
120
121		assert_ne!(msgpack.err().unwrap(), MsgPackError::Overflow);
122
123		// Pass more than limit
124		let (req, mut payload) = TestRequest::default()
125			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
126			.insert_header((header::CONTENT_LENGTH, LIMIT + 1))
127			.to_http_parts();
128		let msgpack = MsgPackMessage::<()>::new(&req, &mut payload, None).limit(LIMIT).await;
129
130		assert_eq!(msgpack.err().unwrap(), MsgPackError::Overflow);
131	}
132
133	#[actix_web::test]
134	async fn check_body() {
135		// Pass empty body
136		let (req, mut payload) = TestRequest::post()
137			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
138			.to_http_parts();
139
140		let msgpack = MsgPackMessage::<()>::new(&req, &mut payload, None).await;
141
142		assert!(matches!(msgpack.err().unwrap(), MsgPackError::Payload(..)));
143
144		// Pass invalid body
145		let data = Bytes::from_static(&[0x81]);
146		let (req, mut payload) = TestRequest::post()
147			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
148			.insert_header((header::CONTENT_LENGTH, 1))
149			.set_payload(data)
150			.to_http_parts();
151		let msgpack = MsgPackMessage::<()>::new(&req, &mut payload, None).await;
152
153		assert!(matches!(msgpack.err().unwrap(), MsgPackError::Deserialize(..)));
154
155		// Pass correct body
156		let data =
157			Bytes::from_static(&[0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3]);
158		let (req, mut payload) = TestRequest::post()
159			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
160			.insert_header((header::CONTENT_LENGTH, 10))
161			.set_payload(data)
162			.to_http_parts();
163		let msgpack = MsgPackMessage::<Data>::new(&req, &mut payload, None).await;
164
165		assert_eq!(msgpack.ok().unwrap(), Data { payload: true })
166	}
167
168	#[actix_web::test]
169	async fn check_body_limit() {
170		// Pass body length == Content-Length value header
171		let data =
172			Bytes::from_static(&[0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3]);
173		let (req, mut payload) = TestRequest::post()
174			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
175			.insert_header((header::CONTENT_LENGTH, 10))
176			.set_payload(data)
177			.to_http_parts();
178		let msgpack = MsgPackMessage::<Data>::new(&req, &mut payload, None).await;
179
180		assert_eq!(msgpack.ok().unwrap(), Data { payload: true });
181
182		// Pass body length < Content-Length value header
183		let data =
184			Bytes::from_static(&[0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3]);
185		let (req, mut payload) = TestRequest::post()
186			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
187			.insert_header((header::CONTENT_LENGTH, 11))
188			.set_payload(data)
189			.to_http_parts();
190		let msgpack = MsgPackMessage::<Data>::new(&req, &mut payload, None).await;
191
192		assert_eq!(msgpack.ok().unwrap(), Data { payload: true });
193
194		// Pass body length > Content-Length value header
195		let data =
196			Bytes::from_static(&[0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3]);
197		let (req, mut payload) = TestRequest::post()
198			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
199			.insert_header((header::CONTENT_LENGTH, 1))
200			.set_payload(data)
201			.to_http_parts();
202		let msgpack = MsgPackMessage::<Data>::new(&req, &mut payload, None).await;
203
204		assert_eq!(msgpack.ok().unwrap(), Data { payload: true });
205
206		// Pass body and don't pass Content-Length header
207		let data =
208			Bytes::from_static(&[0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3]);
209		let (req, mut payload) = TestRequest::post()
210			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
211			.set_payload(data)
212			.to_http_parts();
213		let msgpack = MsgPackMessage::<Data>::new(&req, &mut payload, None).await;
214
215		assert_eq!(msgpack.ok().unwrap(), Data { payload: true });
216	}
217
218	#[actix_web::test]
219	async fn check_responses() {
220		// Response with msgpack responder
221		async fn service(_: HttpRequest) -> HttpResponse {
222			let payload = Data { payload: true };
223			HttpResponse::Ok().msgpack(payload)
224		}
225
226		let request = TestRequest::post()
227			.uri("/")
228			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
229			.to_http_request();
230		let response = service(request).await;
231
232		assert_eq!(response.status(), StatusCode::OK);
233		assert_eq!(
234			response.into_body().try_into_bytes().unwrap(),
235			vec![0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3]
236		);
237	}
238
239	#[actix_web::test]
240	async fn check_responder() {
241		// Pass correct payload
242		let request = TestRequest::default().to_http_request();
243		let payload = MsgPack(Bytes::from_static(&[
244			0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3,
245		]));
246		let response = payload.clone().respond_to(&request);
247
248		assert_eq!(response.status(), StatusCode::OK);
249		assert_eq!(
250			response.into_body().try_into_bytes().unwrap(),
251			vec![0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3]
252		);
253	}
254
255	#[actix_web::test]
256	async fn check_empty_error_handler() {
257		async fn service(_: MsgPack<Data>) -> HttpResponse {
258			HttpResponse::Ok().finish()
259		}
260
261		let app = init_service(
262			App::new().app_data(MsgPackConfig::default()).route("/", web::post().to(service)),
263		)
264		.await;
265		let request = TestRequest::default()
266			.method(Method::POST)
267			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
268			.to_request();
269		let response = call_service(&app, request).await;
270
271		assert_eq!(response.status(), StatusCode::BAD_REQUEST);
272	}
273
274	#[actix_web::test]
275	async fn check_error_handler() {
276		async fn service(_: MsgPack<Data>) -> HttpResponse {
277			HttpResponse::Ok().finish()
278		}
279
280		let mut config = MsgPackConfig::default();
281		config.error_handler(|err, _req| {
282			InternalError::from_response(err, HttpResponse::NotAcceptable().finish()).into()
283		});
284		let app =
285			init_service(App::new().app_data(config).route("/", web::post().to(service))).await;
286
287		let request = TestRequest::default()
288			.method(Method::POST)
289			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
290			.to_request();
291		let response = call_service(&app, request).await;
292
293		assert_eq!(response.status(), StatusCode::NOT_ACCEPTABLE);
294	}
295
296	#[actix_web::test]
297	async fn check_custom_content_type() {
298		async fn service(_: MsgPack<Data>) -> HttpResponse {
299			HttpResponse::Ok().finish()
300		}
301
302		let payload =
303			Bytes::from_static(&[0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3]);
304
305		let mut config = MsgPackConfig::default();
306		config.content_type(|mime_type| mime_type == APPLICATION_JSON);
307
308		let app =
309			init_service(App::new().app_data(config).route("/", web::post().to(service))).await;
310
311		let request = TestRequest::default()
312			.method(Method::POST)
313			.set_payload(payload)
314			.insert_header((header::CONTENT_TYPE, APPLICATION_JSON))
315			.to_request();
316		let response = call_service(&app, request).await;
317
318		assert_eq!(response.status(), StatusCode::OK);
319	}
320
321	#[actix_web::test]
322	async fn check_default_content_type() {
323		async fn service(_: MsgPack<Data>) -> HttpResponse {
324			HttpResponse::Ok().finish()
325		}
326
327		let payload =
328			Bytes::from_static(&[0x81, 0xa7, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0xc3]);
329
330		let config = MsgPackConfig::default();
331
332		let app =
333			init_service(App::new().app_data(config).route("/", web::post().to(service))).await;
334
335		let request = TestRequest::default()
336			.method(Method::POST)
337			.set_payload(payload)
338			.insert_header((header::CONTENT_TYPE, APPLICATION_MSGPACK))
339			.to_request();
340		let response = call_service(&app, request).await;
341
342		assert_eq!(response.status(), StatusCode::OK);
343	}
344}