PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::ihe::xds::document_source::impl Class Reference
Collaboration diagram for kcenon::pacs::ihe::xds::document_source::impl:
Collaboration graph

Public Member Functions

 impl (http_options opts, signing_material signing)
 
void set_audit_sink (std::shared_ptr< kcenon::pacs::security::xds_audit_sink > sink)
 
kcenon::common::Result< submit_response > submit (const submission_set &s)
 

Private Member Functions

kcenon::common::Result< submit_response > parse_registry_response (const std::string &body, const std::string &submission_set_uid)
 
void audit (const submission_set &s, const std::vector< std::string > &document_uids, const kcenon::common::Result< submit_response > &r)
 

Private Attributes

http_options opts_
 
signing_material signing_
 
std::shared_ptr< kcenon::pacs::security::xds_audit_sink > audit_sink_
 

Static Private Attributes

static constexpr std::size_t kMaxRegistryResponseBytes
 

Detailed Description

Definition at line 45 of file document_source.cpp.

Constructor & Destructor Documentation

◆ impl()

kcenon::pacs::ihe::xds::document_source::impl::impl ( http_options opts,
signing_material signing )
inline

Definition at line 47 of file document_source.cpp.

48 : opts_(std::move(opts)), signing_(std::move(signing)) {}

Member Function Documentation

◆ audit()

void kcenon::pacs::ihe::xds::document_source::impl::audit ( const submission_set & s,
const std::vector< std::string > & document_uids,
const kcenon::common::Result< submit_response > & r )
inlineprivate

Definition at line 194 of file document_source.cpp.

196 {
197 if (!audit_sink_) return;
198 kcenon::pacs::security::xds_iti41_event e;
199 e.source_id = s.source_id;
200 e.destination_endpoint = opts_.endpoint;
201 e.patient_id = s.patient_id;
202 e.submission_set_unique_id = s.submission_set_unique_id;
203 e.document_unique_ids = document_uids;
204 if (r.is_ok()) {
206 } else {
207 e.outcome =
209 e.failure_description = r.error().message;
210 }
211 audit_sink_->on_iti41_submit(e);
212 }
std::shared_ptr< kcenon::pacs::security::xds_audit_sink > audit_sink_

References audit_sink_, kcenon::pacs::ihe::xds::http_options::endpoint, opts_, kcenon::pacs::ihe::xds::submission_set::patient_id, kcenon::pacs::security::serious_failure, kcenon::pacs::ihe::xds::submission_set::source_id, kcenon::pacs::ihe::xds::submission_set::submission_set_unique_id, and kcenon::pacs::security::success.

Referenced by submit().

Here is the caller graph for this function:

◆ parse_registry_response()

kcenon::common::Result< submit_response > kcenon::pacs::ihe::xds::document_source::impl::parse_registry_response ( const std::string & body,
const std::string & submission_set_uid )
inlineprivate

Definition at line 128 of file document_source.cpp.

129 {
130 if (body.size() > kMaxRegistryResponseBytes) {
131 return kcenon::common::make_error<submit_response>(
133 "RegistryResponse exceeds 8 MiB cap (" +
134 std::to_string(body.size()) + " bytes) - rejected to "
135 "bound pugixml memory footprint",
136 std::string(error_source));
137 }
138 pugi::xml_document doc;
139 auto parse = doc.load_buffer(body.data(), body.size(),
140 pugi::parse_default, pugi::encoding_utf8);
141 if (!parse) {
142 return kcenon::common::make_error<submit_response>(
144 std::string("failed to parse RegistryResponse: ") +
145 parse.description(),
146 std::string(error_source));
147 }
148
149 auto registry_response =
150 doc.select_node(
151 "//*[local-name()='RegistryResponse' or "
152 "local-name()='RegistryResponseType']")
153 .node();
154 if (!registry_response) {
155 return kcenon::common::make_error<submit_response>(
157 "response contains no RegistryResponse element",
158 std::string(error_source));
159 }
160
161 const std::string status =
162 registry_response.attribute("status").as_string();
163 if (status.empty()) {
164 return kcenon::common::make_error<submit_response>(
166 "RegistryResponse is missing status attribute",
167 std::string(error_source));
168 }
169
170 static constexpr std::string_view success_status =
171 "urn:oasis:names:tc:ebxml-regrep:ResponseStatusType:Success";
172 static constexpr std::string_view partial_success_status =
173 "urn:oasis:names:tc:ebxml-regrep:ResponseStatusType:PartialSuccess";
174
175 submit_response out;
176 out.registry_response_status = status;
177 out.submission_set_unique_id = submission_set_uid;
178
179 if (status == success_status) {
180 return out;
181 }
182 if (status == partial_success_status) {
183 return kcenon::common::make_error<submit_response>(
184 static_cast<int>(error_code::registry_partial_success),
185 "registry reported PartialSuccess: " + status,
186 std::string(error_source));
187 }
188 return kcenon::common::make_error<submit_response>(
190 "registry reported non-success status: " + status,
191 std::string(error_source));
192 }
static constexpr std::size_t kMaxRegistryResponseBytes
constexpr dicom_tag status
Status.
constexpr std::string_view error_source
Short identifier used as the "source" field of make_error.
Definition errors.h:95
std::string out

References kcenon::pacs::ihe::xds::error_source, kMaxRegistryResponseBytes, out, kcenon::pacs::ihe::xds::registry_failure_response, kcenon::pacs::ihe::xds::registry_partial_success, kcenon::pacs::ihe::xds::transport_invalid_response, and kcenon::pacs::ihe::xds::transport_response_too_large.

Referenced by submit().

Here is the caller graph for this function:

◆ set_audit_sink()

void kcenon::pacs::ihe::xds::document_source::impl::set_audit_sink ( std::shared_ptr< kcenon::pacs::security::xds_audit_sink > sink)
inline

Definition at line 50 of file document_source.cpp.

51 {
52 audit_sink_ = std::move(sink);
53 }

References audit_sink_.

Referenced by kcenon::pacs::ihe::xds::document_source::set_audit_sink().

Here is the caller graph for this function:

◆ submit()

kcenon::common::Result< submit_response > kcenon::pacs::ihe::xds::document_source::impl::submit ( const submission_set & s)
inline

Definition at line 55 of file document_source.cpp.

55 {
56 // Collect document unique ids up-front so an audit event can
57 // reference them even when submission fails before the wire
58 // payload is built.
59 std::vector<std::string> document_uids;
60 document_uids.reserve(s.documents.size());
61 for (const auto& d : s.documents) {
62 document_uids.push_back(d.unique_id);
63 }
64
65 auto do_audit = [&](const kcenon::common::Result<submit_response>& r) {
66 audit(s, document_uids, r);
67 return r;
68 };
69
70 std::vector<std::string> cids;
71 cids.reserve(s.documents.size());
72 for (std::size_t i = 0; i < s.documents.size(); ++i) {
73 cids.push_back(make_cid(i));
74 }
75
76 auto env_result = detail::build_iti41_envelope(s, cids);
77 if (env_result.is_err()) {
78 return do_audit(kcenon::common::make_error<submit_response>(
79 env_result.error()));
80 }
81 auto env = env_result.value();
82
83 auto sign_result = detail::sign_envelope(
86 if (sign_result.is_err()) {
87 return do_audit(kcenon::common::make_error<submit_response>(
88 sign_result.error()));
89 }
90
91 std::vector<detail::mtom_part> parts;
92 parts.reserve(s.documents.size());
93 for (std::size_t i = 0; i < s.documents.size(); ++i) {
94 detail::mtom_part p;
95 p.content_id = cids[i];
96 p.mime_type = s.documents[i].mime_type;
97 p.content = s.documents[i].content;
98 parts.push_back(std::move(p));
99 }
100
101 auto mtom_result = detail::package_mtom(env.xml, parts);
102 if (mtom_result.is_err()) {
103 return do_audit(kcenon::common::make_error<submit_response>(
104 mtom_result.error()));
105 }
106 auto mtom = mtom_result.value();
107
108 auto http_result =
109 detail::http_post(opts_, mtom.content_type, mtom.body);
110 if (http_result.is_err()) {
111 return do_audit(kcenon::common::make_error<submit_response>(
112 http_result.error()));
113 }
114 auto response = http_result.value();
115
116 return do_audit(parse_registry_response(response.body,
117 s.submission_set_unique_id));
118 }
kcenon::common::Result< submit_response > parse_registry_response(const std::string &body, const std::string &submission_set_uid)
void audit(const submission_set &s, const std::vector< std::string > &document_uids, const kcenon::common::Result< submit_response > &r)
kcenon::common::Result< packaged_mtom > package_mtom(const std::string &envelope_xml, const std::vector< mtom_part > &parts)
Assemble a multipart/related MTOM body.
kcenon::common::Result< http_response > http_post(const http_options &opts, const std::string &content_type, const std::string &body)
POST body to opts.endpoint with the given Content-Type.
kcenon::common::Result< bool > sign_envelope(built_envelope &env, std::string_view cert_pem, std::string_view key_pem, std::string_view key_password)
Sign the body + timestamp of env in place.
kcenon::common::Result< built_envelope > build_iti41_envelope(const submission_set &s, const std::vector< std::string > &cid_refs)
Build a SOAP envelope for ITI-41 from submission metadata and a list of content-id references for MTO...

References audit(), kcenon::pacs::ihe::xds::detail::build_iti41_envelope(), kcenon::pacs::ihe::xds::signing_material::certificate_pem, kcenon::pacs::ihe::xds::detail::mtom_part::content, kcenon::pacs::ihe::xds::detail::mtom_part::content_id, kcenon::pacs::ihe::xds::submission_set::documents, kcenon::pacs::ihe::xds::detail::http_post(), kcenon::pacs::ihe::xds::detail::mtom_part::mime_type, opts_, kcenon::pacs::ihe::xds::detail::package_mtom(), parse_registry_response(), kcenon::pacs::ihe::xds::signing_material::private_key_password, kcenon::pacs::ihe::xds::signing_material::private_key_pem, kcenon::pacs::ihe::xds::detail::sign_envelope(), signing_, and kcenon::pacs::ihe::xds::submission_set::submission_set_unique_id.

Here is the call graph for this function:

Member Data Documentation

◆ audit_sink_

std::shared_ptr<kcenon::pacs::security::xds_audit_sink> kcenon::pacs::ihe::xds::document_source::impl::audit_sink_
private

Definition at line 216 of file document_source.cpp.

Referenced by audit(), and set_audit_sink().

◆ kMaxRegistryResponseBytes

std::size_t kcenon::pacs::ihe::xds::document_source::impl::kMaxRegistryResponseBytes
staticconstexprprivate
Initial value:
=
8 * 1024 * 1024

Definition at line 125 of file document_source.cpp.

Referenced by parse_registry_response().

◆ opts_

http_options kcenon::pacs::ihe::xds::document_source::impl::opts_
private

Definition at line 214 of file document_source.cpp.

Referenced by audit(), and submit().

◆ signing_

signing_material kcenon::pacs::ihe::xds::document_source::impl::signing_
private

Definition at line 215 of file document_source.cpp.

Referenced by submit().


The documentation for this class was generated from the following file: