Skip to main content

onvif_server/
error.rs

1use soap_server::fault::SoapFault;
2
3/// ONVIF-specific error type that maps to SOAP faults with the ONVIF ter: namespace.
4///
5/// Every `into_soap_fault()` call produces a detail field containing
6/// `xmlns:ter="http://www.onvif.org/ver10/error"` as required by the ONVIF spec.
7#[derive(Debug, thiserror::Error)]
8pub enum OnvifError {
9    /// The requested action has not yet been implemented.
10    #[error("Action not implemented")]
11    NotImplemented,
12    /// The caller supplied an invalid argument value.
13    #[error("Invalid argument: {0}")]
14    InvalidArgument(String),
15    /// The device does not support the requested action.
16    #[error("Action not supported")]
17    ActionNotSupported,
18}
19
20impl OnvifError {
21    /// Convert this error into a `SoapFault` with an ONVIF-namespaced detail element.
22    ///
23    /// The `xmlns:ter` declaration is embedded in the detail string because
24    /// soap-server's envelope does not inject it automatically.
25    pub fn into_soap_fault(self) -> SoapFault {
26        match self {
27            OnvifError::NotImplemented | OnvifError::ActionNotSupported => {
28                let subcode = "ter:ActionNotSupported";
29                let detail = format!(
30                    r#"<ter:fault xmlns:ter="http://www.onvif.org/ver10/error"><ter:subcode>{subcode}</ter:subcode></ter:fault>"#
31                );
32                // The detail is well-formed XML, so route it via detail_xml: the SOAP 1.2
33                // renderer only emits detail_xml inside <env:Detail> (the text `detail`
34                // field is dropped as element-only, per F-3). Using `detail` here would
35                // silently lose the ter: subcode on the wire for every ONVIF fault.
36                SoapFault::receiver("Action not supported").with_detail_xml(detail)
37            }
38            OnvifError::InvalidArgument(msg) => {
39                let subcode = "ter:InvalidArgVal";
40                let detail = format!(
41                    r#"<ter:fault xmlns:ter="http://www.onvif.org/ver10/error"><ter:subcode>{subcode}</ter:subcode></ter:fault>"#
42                );
43                SoapFault::sender(msg).with_detail_xml(detail)
44            }
45        }
46    }
47}
48
49/// Convenience function returning `Err(OnvifError::NotImplemented)`.
50///
51/// Service trait implementations use this as a one-liner stub until the
52/// real implementation is added.
53pub fn not_implemented<T>() -> Result<T, OnvifError> {
54    Err(OnvifError::NotImplemented)
55}