use crate::fault::SOAP_NS;
use crate::response::ACK_INTERACTION;
use crate::xml;
pub const OPERATION: &str = "SendHl7V3Message";
pub const TARGET_NS: &str = "urn:hl7-3-soap:service";
#[must_use]
pub fn for_address(address: &str) -> String {
for_address_in(address, TARGET_NS)
}
#[must_use]
pub fn for_address_in(address: &str, target_namespace: &str) -> String {
TEMPLATE
.replace("@TARGET_NS@", &xml::escape(target_namespace))
.replace("@OPERATION@", OPERATION)
.replace("@ACK_INTERACTION@", ACK_INTERACTION)
.replace("@ADDRESS@", &xml::escape(address))
}
const TEMPLATE: &str = r###"<?xml version="1.0" encoding="UTF-8"?>
<definitions name="Hl7V3SoapServer"
targetNamespace="@TARGET_NS@"
xmlns:tns="@TARGET_NS@"
xmlns:v3="urn:hl7-org:v3"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema targetNamespace="@TARGET_NS@" elementFormDefault="qualified">
<!-- The payload is deliberately unconstrained here; the server
validates it against the HL7 v3 schemas it holds. -->
<xsd:element name="@OPERATION@">
<xsd:complexType>
<xsd:sequence>
<xsd:any namespace="##other" processContents="lax"
minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<message name="@OPERATION@Request">
<part name="parameters" element="tns:@OPERATION@"/>
</message>
<message name="@OPERATION@Response">
<!-- The real HL7 v3 acknowledgement interaction, not a shape this
crate invented — see response.rs. -->
<part name="parameters" element="v3:@ACK_INTERACTION@"/>
</message>
<portType name="Hl7V3SoapServerPortType">
<operation name="@OPERATION@">
<input message="tns:@OPERATION@Request"/>
<output message="tns:@OPERATION@Response"/>
</operation>
</portType>
<binding name="Hl7V3SoapServerBinding" type="tns:Hl7V3SoapServerPortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="@OPERATION@">
<soap:operation soapAction="@TARGET_NS@/@OPERATION@"/>
<input><soap:body use="literal"/></input>
<output><soap:body use="literal"/></output>
</operation>
</binding>
<service name="Hl7V3SoapServer">
<port name="Hl7V3SoapServerPort" binding="tns:Hl7V3SoapServerBinding">
<soap:address location="@ADDRESS@"/>
</port>
</service>
</definitions>
"###;
#[must_use]
pub fn envelope_namespace() -> &'static str {
SOAP_NS
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_address_is_the_one_that_was_asked_for() {
let wsdl = for_address("http://localhost:8080/soap");
assert!(wsdl.contains(r#"location="http://localhost:8080/soap""#));
let other = for_address("https://prod.example.nhs.uk/soap");
assert!(other.contains(r#"location="https://prod.example.nhs.uk/soap""#));
}
#[test]
fn an_address_cannot_break_the_document() {
let wsdl = for_address(r#"http://x/"><evil/>"#);
assert!(!wsdl.contains("<evil/>"));
assert!(xml::parse(&wsdl).is_ok());
}
#[test]
fn it_is_well_formed_and_describes_the_operation() {
let wsdl = for_address("http://localhost/soap");
let root = xml::parse(&wsdl).unwrap();
assert_eq!(root.local_name(), "definitions");
assert!(root.find("portType").is_some());
assert!(root.find("binding").is_some());
assert!(root.find("service").is_some());
assert!(wsdl.contains(&format!(r#"<operation name="{OPERATION}">"#)));
assert!(wsdl.contains(&format!(r#"element="v3:{ACK_INTERACTION}""#)));
}
}