coap_handler_implementations/
typed_resource.rs1use crate::helpers::block2_write_with_cf;
6use crate::Error;
7use coap_handler::Handler;
8use coap_message::{
9 Code as _, MessageOption, MinimalWritableMessage, MutableWritableMessage, ReadableMessage,
10};
11use coap_message_utils::{option_value::Block2RequestData, OptionsExt};
12use coap_numbers::{code, option};
13use core::marker::PhantomData;
14
15use serde::Serialize;
16
17pub struct Empty;
22
23pub trait TypeRenderable {
29 type Get;
31 type Post;
35 type Put;
37
38 fn get(&mut self) -> Result<Self::Get, u8> {
39 Err(code::METHOD_NOT_ALLOWED)
40 }
41 fn post(&mut self, _representation: &Self::Post) -> u8 {
42 code::METHOD_NOT_ALLOWED
43 }
44 fn put(&mut self, _representation: &Self::Put) -> u8 {
45 code::METHOD_NOT_ALLOWED
46 }
47 fn delete(&mut self) -> u8 {
48 code::METHOD_NOT_ALLOWED
49 }
50}
51
52mod sealed {
55 pub trait TypeSerializer {
56 const CF: Option<u16>;
57 }
58
59 pub struct SerdeCBORSerialization;
60 pub struct MiniCBORSerialization0_19;
61 pub struct MiniCBORSerialization0_24;
62 pub struct MiniCBORSerialization0_26;
63}
64use sealed::*;
65
66impl TypeSerializer for SerdeCBORSerialization {
67 const CF: Option<u16> = coap_numbers::content_format::from_str("application/cbor");
68}
69
70pub struct TypeHandler<H, S: TypeSerializer = SerdeCBORSerialization>
82where
83 H: TypeRenderable,
84{
85 handler: H,
86 _phantom: PhantomData<S>,
87}
88
89impl<H, S> TypeHandler<H, S>
90where
91 H: TypeRenderable,
92 S: TypeSerializer,
93{
94 fn check_get_options(request: &impl ReadableMessage) -> Result<Block2RequestData, Error> {
95 let mut block2 = None;
96
97 request
98 .options()
99 .take_block2(&mut block2)
100 .filter(|o| {
101 if o.number() == option::ACCEPT {
102 if let Some(cf) = S::CF {
103 o.value_uint() != Some(cf)
105 } else {
106 true
109 }
110 } else {
111 true
112 }
113 })
114 .ignore_elective_others()?;
115
116 Ok(block2.unwrap_or_default())
117 }
118
119 fn check_delete_options(request: &impl ReadableMessage) -> Result<(), Error> {
120 request.options().ignore_elective_others()
121 }
122
123 fn check_postput_options(request: &impl ReadableMessage) -> Result<(), Error> {
124 let mut cf = Ok(());
125
126 request
127 .options()
128 .filter(|o| {
129 if o.number() == option::CONTENT_FORMAT
130 && (S::CF.is_none() || o.value_uint() != S::CF)
131 {
132 cf = Err(Error::bad_option(option::CONTENT_FORMAT));
133 }
134 true
136 })
137 .ignore_elective_others()?;
138
139 cf
140 }
141}
142
143impl<H> TypeHandler<H, SerdeCBORSerialization>
144where
145 H: TypeRenderable,
146 H::Get: for<'de> serde::Serialize,
147 H::Post: for<'de> serde::Deserialize<'de>,
148 H::Put: for<'de> serde::Deserialize<'de>,
149{
150 pub fn new(handler: H) -> Self {
152 TypeHandler {
153 handler,
154 _phantom: PhantomData,
155 }
156 }
157}
158
159pub struct TypeRequestData(TypeRequestDataE);
161
162enum TypeRequestDataE {
163 Get(Block2RequestData), Done(u8), }
166use self::TypeRequestDataE::{Done, Get};
167
168impl<H> Handler for TypeHandler<H, SerdeCBORSerialization>
172where
173 H: TypeRenderable,
174 H::Get: for<'de> serde::Serialize,
175 H::Post: for<'de> serde::Deserialize<'de>,
176 H::Put: for<'de> serde::Deserialize<'de>,
177{
178 type RequestData = TypeRequestData;
179 type ExtractRequestError = Error;
180 type BuildResponseError<M: MinimalWritableMessage> = M::UnionError;
181
182 fn extract_request_data<M: ReadableMessage>(
183 &mut self,
184 request: &M,
185 ) -> Result<Self::RequestData, Error> {
186 Ok(TypeRequestData(match request.code().into() {
187 code::DELETE => {
188 Self::check_delete_options(request)?;
189 Done(self.handler.delete())
190 }
191 code::GET => Get(Self::check_get_options(request)?),
192 code::POST => {
193 Self::check_postput_options(request)?;
194
195 let parsed: H::Post =
198 serde_cbor::de::from_slice_with_scratch(request.payload(), &mut [])
199 .map_err(|_| Error::bad_request())?;
200 Done(self.handler.post(&parsed))
201 }
202 code::PUT => {
203 Self::check_postput_options(request)?;
204
205 let parsed: H::Put =
206 serde_cbor::de::from_slice_with_scratch(request.payload(), &mut [])
207 .map_err(|_| Error::bad_request())?;
208 Done(self.handler.put(&parsed))
209 }
210 _ => Done(code::METHOD_NOT_ALLOWED),
211 }))
212 }
213
214 fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
215 match &request.0 {
216 Done(_) => 4,
217 Get(block) => (block.size() + 25).into(), }
219 }
220
221 fn build_response<M: MutableWritableMessage>(
222 &mut self,
223 response: &mut M,
224 request: Self::RequestData,
225 ) -> Result<(), Self::BuildResponseError<M>> {
226 match request.0 {
227 Done(r) => response.set_code(M::Code::new(r)?),
228 Get(block2) => {
229 let repr = self.handler.get();
230 match repr {
231 Err(e) => response.set_code(M::Code::new(e)?),
232 Ok(repr) => {
233 response.set_code(M::Code::new(code::CONTENT)?);
234 match block2_write_with_cf(
235 block2,
236 response,
237 |win| repr.serialize(&mut serde_cbor::ser::Serializer::new(win)),
238 SerdeCBORSerialization::CF,
239 ) {
240 Ok(()) => (),
241 Err(_) => {
242 response.set_code(M::Code::new(code::INTERNAL_SERVER_ERROR)?);
244 }
245 }
246 }
247 }
248 }
249 };
250 Ok(())
251 }
252}
253
254trait ToTypedResourceError {
255 fn into_general_error(self, total_len: usize) -> Error;
256}
257
258macro_rules! for_each_minicbor {
259 ($minicbor:ident, $mcstype:ident) => {
260 impl<'b, C> $minicbor::decode::Decode<'b, C> for Empty {
261 fn decode(
262 _d: &mut $minicbor::decode::Decoder<'b>,
263 _ctx: &mut C,
264 ) -> Result<Self, $minicbor::decode::Error> {
265 Err($minicbor::decode::Error::message("No element expected").at(0))
266 }
267
268 fn nil() -> Option<Self> {
269 Some(Empty)
270 }
271 }
272
273 impl<H> Handler for TypeHandler<H, $mcstype>
274 where
275 H: TypeRenderable,
276 H::Get: for<'de> $minicbor::Encode<()>,
277 H::Post: for<'de> $minicbor::Decode<'de, ()>,
278 H::Put: for<'de> $minicbor::Decode<'de, ()>,
279 {
280 type RequestData = TypeRequestData;
281 type ExtractRequestError = Error;
282 type BuildResponseError<M: MinimalWritableMessage> = M::UnionError;
283
284 fn extract_request_data<M: ReadableMessage>(
285 &mut self,
286 request: &M,
287 ) -> Result<Self::RequestData, Error> {
288 Ok(TypeRequestData(match request.code().into() {
289 code::DELETE => {
290 Self::check_delete_options(request)?;
291 Done(self.handler.delete())
292 }
293 code::GET => Get(Self::check_get_options(request)?),
294 code::POST => {
295 use $minicbor::decode::Decode;
296 Self::check_postput_options(request)?;
297
298 let payload = request.payload();
299 match (payload, H::Post::nil()) {
300 (b"", Some(nil)) => Done(self.handler.post(&nil)),
301 (payload, _) => {
302 let parsed: H::Post =
303 $minicbor::decode(payload).map_err(|deserialize_error| {
304 deserialize_error.into_general_error(payload.len())
305 })?;
306 Done(self.handler.post(&parsed))
307 }
308 }
309 }
310 code::PUT => {
311 Self::check_postput_options(request)?;
312
313 let payload = request.payload();
314
315 let parsed: H::Put =
316 $minicbor::decode(payload).map_err(|deserialize_error| {
317 deserialize_error.into_general_error(payload.len())
318 })?;
319 Done(self.handler.put(&parsed))
320 }
321 _ => Done(code::METHOD_NOT_ALLOWED),
322 }))
323 }
324
325 fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
326 match &request.0 {
327 Done(_) => 4,
328 Get(block) => (block.size() + 25).into(), }
330 }
331
332 fn build_response<M: MutableWritableMessage>(
333 &mut self,
334 response: &mut M,
335 request: Self::RequestData,
336 ) -> Result<(), Self::BuildResponseError<M>> {
337 match request.0 {
338 Done(r) => response.set_code(M::Code::new(r)?),
339 Get(block2) => {
340 let repr = self.handler.get();
341 match repr {
342 Err(e) => response.set_code(M::Code::new(e)?),
343 Ok(repr) => {
344 response.set_code(M::Code::new(code::CONTENT)?);
345 match block2_write_with_cf(
346 block2,
347 response,
348 |win| $minicbor::encode(&repr, win),
349 $mcstype::CF,
350 ) {
351 Ok(()) => (),
352 Err(_) => {
353 response
355 .set_code(M::Code::new(code::INTERNAL_SERVER_ERROR)?);
356 }
357 }
358 }
359 }
360 }
361 };
362 Ok(())
363 }
364 }
365
366 impl TypeSerializer for $mcstype {
367 const CF: Option<u16> = coap_numbers::content_format::from_str("application/cbor");
368 }
369 };
370}
371
372for_each_minicbor!(minicbor_0_19, MiniCBORSerialization0_19);
373for_each_minicbor!(minicbor_0_24, MiniCBORSerialization0_24);
374for_each_minicbor!(minicbor_0_26, MiniCBORSerialization0_26);
375
376impl<H> TypeHandler<H, MiniCBORSerialization0_19>
377where
378 H: TypeRenderable,
379 H::Get: for<'de> minicbor_0_19::Encode<()>,
380 H::Post: for<'de> minicbor_0_19::Decode<'de, ()>,
381 H::Put: for<'de> minicbor_0_19::Decode<'de, ()>,
382{
383 pub fn new_minicbor(handler: H) -> Self {
385 TypeHandler {
386 handler,
387 _phantom: PhantomData,
388 }
389 }
390}
391
392impl<H> TypeHandler<H, MiniCBORSerialization0_24>
393where
394 H: TypeRenderable,
395 H::Get: for<'de> minicbor_0_24::Encode<()>,
396 H::Post: for<'de> minicbor_0_24::Decode<'de, ()>,
397 H::Put: for<'de> minicbor_0_24::Decode<'de, ()>,
398{
399 pub fn new_minicbor_0_24(handler: H) -> Self {
401 TypeHandler {
402 handler,
403 _phantom: PhantomData,
404 }
405 }
406}
407
408impl<H> TypeHandler<H, MiniCBORSerialization0_26>
409where
410 H: TypeRenderable,
411 H::Get: for<'de> minicbor_0_24::Encode<()>,
412 H::Post: for<'de> minicbor_0_24::Decode<'de, ()>,
413 H::Put: for<'de> minicbor_0_24::Decode<'de, ()>,
414{
415 pub fn new_minicbor_0_26(handler: H) -> Self {
417 TypeHandler {
418 handler,
419 _phantom: PhantomData,
420 }
421 }
422}
423
424impl ToTypedResourceError for minicbor_0_19::decode::Error {
425 fn into_general_error(self, total_len: usize) -> Error {
426 let mut error = Error::bad_request();
427 if self.is_end_of_input() {
429 error = Error::bad_request_with_rbep(total_len);
430 };
431 if self.is_type_mismatch() {
432 error = error.with_title("Type mismatch")
433 }
434 error
435 }
436}
437
438macro_rules! minicbor_24plus_error {
439 ($minicbor:ident) => {
440 impl ToTypedResourceError for $minicbor::decode::Error {
441 fn into_general_error(self, total_len: usize) -> Error {
442 let mut error = Error::bad_request();
443 if let Some(position) = self.position() {
444 error = Error::bad_request_with_rbep(position);
445 }
446 if self.is_end_of_input() {
447 error = Error::bad_request_with_rbep(total_len);
450 };
451 if self.is_type_mismatch() {
452 error = error.with_title("Type mismatch")
453 }
454 error
455 }
456 }
457 };
458}
459
460minicbor_24plus_error!(minicbor_0_24);
461minicbor_24plus_error!(minicbor_0_26);