use crate::fault::{Fault, SOAP_NS};
use crate::xml::{self, Element};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Envelope {
root: Element,
}
pub fn parse(xml_text: &str) -> Result<Envelope, Fault> {
let root = xml::parse(xml_text).map_err(|_| Fault::client("Malformed SOAP XML request."))?;
if root.local_name() != "Envelope" {
return Err(Fault::client("SOAP Envelope element is missing."));
}
Ok(Envelope { root })
}
impl Envelope {
#[must_use]
pub fn root(&self) -> &Element {
&self.root
}
#[must_use]
pub fn header(&self) -> Option<&Element> {
self.root.child("Header")
}
pub fn body(&self) -> Result<&Element, Fault> {
self.root
.child("Body")
.ok_or_else(|| Fault::client("SOAP Body element is missing."))
}
pub fn payload(&self) -> Result<&Element, Fault> {
let body = self.body()?;
match body.children.as_slice() {
[only] => Ok(only),
_ => Err(Fault::client(
"SOAP Body must contain exactly one business payload element.",
)),
}
}
}
#[must_use]
pub fn wrap_xml(payload_xml: &str) -> String {
format!(
concat!(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
r#"<soapenv:Envelope xmlns:soapenv="{}">"#,
"<soapenv:Header/>",
"<soapenv:Body>{}</soapenv:Body>",
"</soapenv:Envelope>",
),
SOAP_NS, payload_xml
)
}
#[cfg(test)]
mod tests {
use super::*;
const ENVELOPE: &str = r#"<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<PRPA_IN201305UV02 xmlns="urn:hl7-org:v3">
<id root="2.16.840.1.113883.19.5" extension="CTRL1"/>
</PRPA_IN201305UV02>
</soapenv:Body>
</soapenv:Envelope>"#;
#[test]
fn reads_the_payload_out_of_the_body() {
let envelope = parse(ENVELOPE).unwrap();
assert_eq!(
envelope.payload().unwrap().local_name(),
"PRPA_IN201305UV02"
);
assert!(envelope.header().is_some());
}
#[test]
fn a_body_with_no_single_payload_is_a_fault() {
let none = parse(r#"<Envelope><Body></Body></Envelope>"#).unwrap();
assert_eq!(none.payload().unwrap_err().status, 400);
let two = parse(r#"<Envelope><Body><A/><B/></Body></Envelope>"#).unwrap();
assert!(
two.payload()
.unwrap_err()
.reason
.contains("exactly one business payload")
);
}
#[test]
fn a_missing_body_is_a_fault() {
let envelope = parse(r#"<Envelope><Header/></Envelope>"#).unwrap();
assert!(envelope.body().unwrap_err().reason.contains("Body"));
}
#[test]
fn something_that_is_not_an_envelope_is_a_fault() {
assert!(
parse("<NotAnEnvelope/>")
.unwrap_err()
.reason
.contains("Envelope")
);
assert!(
parse("not xml at all")
.unwrap_err()
.reason
.contains("Malformed")
);
}
#[test]
fn a_wrapped_payload_round_trips() {
let envelope = wrap_xml(
r#"<PRPA_IN201305UV02><id root="2.16.840.1.113883.19.5" extension="9"/></PRPA_IN201305UV02>"#,
);
let parsed = parse(&envelope).unwrap();
assert_eq!(parsed.payload().unwrap().local_name(), "PRPA_IN201305UV02");
}
}