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
70
/// A minimal stateless testing CoAP server interface.
use coap_message::{MinimalWritableMessage, MutableWritableMessage, ReadableMessage};

/// A CoAP request handler. This gets called by a CoAP server implementation that the handler is
/// assigned to; the server has the handler [processes the request's
/// data](Self::extract_request_data) into a RequestData structure, possibly calls [asks for the
/// expected length](Self::estimate_length) before allocating a response message, and then asks the
/// handler to [populate the allocated response message](Self::build_response) with data persisted
/// in the RequestData structure.
///
/// Both data extraction and response building are fallible operations. In the error case, it is up
/// to the CoAP server implementation to reset the message into a state into which the error can be
/// [rendered](coap_message::error::RenderableOnMinimal::render). There is currently no trait
/// method in [`coap_message`] that describes how that would be done, but the CoAP implementation
/// knows the concrete type and can use its methods directly.
pub trait Handler {
    /// Type constructed in [`extract_request_data()`](Self::extract_request_data) passed on to
    /// [`build_response()`](Self::build_response).
    ///
    /// This type can usually be made very compact, with exceptions for POST style requests where
    /// not only do request and response have large payloads, but also both are needed at the same
    /// time.
    type RequestData;

    /// Error type for [`extract_request_data()`](Self::extract_request_data).
    ///
    /// Typical types to use here are [core::convert::Infallible] (which, due to the possibility of
    /// unknown critical CoAP options, is only practical when their presence is carried in the
    /// extracted data) or types provided by libraries (eg.
    /// [coap-handler-implementations::Error](https://docs.rs/coap-handler-implementations/0.5.0/coap_handler_implementations/struct.Error.html)).
    type ExtractRequestError: core::fmt::Debug + coap_message::error::RenderableOnMinimal;
    /// Error type for [writing response data](Self::build_response).
    ///
    /// This is generic over writable messages because the most typical errors to show up here are
    /// generated when writing to the messages. A suitable type here is `M::UnionError`.
    // FIXME could we carry an error type in here instead of the message? if so, does the same
    // apply to render?
    type BuildResponseError<M: MinimalWritableMessage>: core::fmt::Debug
        + coap_message::error::RenderableOnMinimal;

    /// Process an incoming request.
    ///
    /// Unless the server implementation performs request deduplication, this may be called
    /// multiple times per request. Whether a server performs request deduplication (and thus the
    /// handlers need to be idempotent, which is best practice in CoAP anyway) is not expressed in
    /// the type system.
    ///
    /// Effects of requests may already be performed at this step -- to the point where
    /// [Self::RequestData] is `()` to indicate success.
    fn extract_request_data<M: ReadableMessage>(
        &mut self,
        request: &M,
    ) -> Result<Self::RequestData, Self::ExtractRequestError>;
    /// Estimate an upper bound for the number of bytes in the response
    ///
    /// Sizes are counted as in UDP after the header, i.e., encoded options plus payload indicator
    /// plus payload.
    fn estimate_length(&mut self, request: &Self::RequestData) -> usize;
    /// Build a response for the request
    ///
    /// While this is typically called exactly once per request, it can also be called not at all
    /// (eg. if a TCP connection was dropped between parsing the request and sending the response)
    /// or multiple times (if the response was sent in a CON, needed to be retransmitted, and the
    /// RequestData is Clone).
    fn build_response<M: MutableWritableMessage>(
        &mut self,
        response: &mut M,
        request: Self::RequestData,
    ) -> Result<(), Self::BuildResponseError<M>>;
}