# HG changeset patch # User Alain Mazy # Date 1666206777 -7200 # Node ID f4e828607f0216c39821443d87e1ee10e11ecf81 # Parent c3fefbb11321400a2efb3e69919829997a097a7f Added 'SenderTransferID' option that is added as an HTTP header in outgoing requests in PushMode diff -r c3fefbb11321 -r f4e828607f02 Framework/HttpQueries/DetectTransferPlugin.h --- a/Framework/HttpQueries/DetectTransferPlugin.h Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/HttpQueries/DetectTransferPlugin.h Wed Oct 19 21:12:57 2022 +0200 @@ -61,6 +61,9 @@ virtual void HandleAnswer(const void* answer, size_t size); + virtual void GetHttpHeaders(std::map& headers) const + {/* no headers for this general purpose request*/} + static void Apply(Result& result, size_t threadsCount, unsigned int timeout); diff -r c3fefbb11321 -r f4e828607f02 Framework/HttpQueries/HttpQueriesQueue.cpp --- a/Framework/HttpQueries/HttpQueriesQueue.cpp Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/HttpQueries/HttpQueriesQueue.cpp Wed Oct 19 21:12:57 2022 +0200 @@ -135,6 +135,9 @@ { query->ReadBody(body); } + + std::map headers; + query->GetHttpHeaders(headers); unsigned int retry = 0; @@ -149,19 +152,19 @@ switch (query->GetMethod()) { case Orthanc::HttpMethod_Get: - success = peers_.DoGet(answer, query->GetPeer(), query->GetUri()); + success = peers_.DoGet(answer, query->GetPeer(), query->GetUri(), headers); break; case Orthanc::HttpMethod_Post: - success = peers_.DoPost(answer, query->GetPeer(), query->GetUri(), body); + success = peers_.DoPost(answer, query->GetPeer(), query->GetUri(), body, headers); break; case Orthanc::HttpMethod_Put: - success = peers_.DoPut(query->GetPeer(), query->GetUri(), body); + success = peers_.DoPut(query->GetPeer(), query->GetUri(), body, headers); break; case Orthanc::HttpMethod_Delete: - success = peers_.DoDelete(query->GetPeer(), query->GetUri()); + success = peers_.DoDelete(query->GetPeer(), query->GetUri(), headers); break; default: @@ -171,7 +174,7 @@ catch (Orthanc::OrthancException& e) { LOG(ERROR) << "Unhandled exception during an HTTP query to peer \"" - << query->GetPeer() << "\": " << e.What(); + << query->GetPeer() << " " << query->GetUri() + "\": " << e.What(); success = false; } @@ -221,7 +224,10 @@ } else { - LOG(INFO) << "Reached the maximum number of retries for a HTTP query"; + if (maxRetries > 0) + { + LOG(ERROR) << "Reached the maximum number of retries for a HTTP query to peer " << query->GetPeer() << " " << query->GetUri(); + } { boost::mutex::scoped_lock lock(mutex_); diff -r c3fefbb11321 -r f4e828607f02 Framework/HttpQueries/IHttpQuery.h --- a/Framework/HttpQueries/IHttpQuery.h Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/HttpQueries/IHttpQuery.h Wed Oct 19 21:12:57 2022 +0200 @@ -20,6 +20,7 @@ #pragma once #include +#include #include @@ -43,5 +44,7 @@ virtual void HandleAnswer(const void* answer, size_t size) = 0; + + virtual void GetHttpHeaders(std::map& headers) const = 0; }; } diff -r c3fefbb11321 -r f4e828607f02 Framework/PullMode/BucketPullQuery.h --- a/Framework/PullMode/BucketPullQuery.h Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/PullMode/BucketPullQuery.h Wed Oct 19 21:12:57 2022 +0200 @@ -59,5 +59,8 @@ virtual void HandleAnswer(const void* answer, size_t size); + + virtual void GetHttpHeaders(std::map& headers) const + {} }; } diff -r c3fefbb11321 -r f4e828607f02 Framework/PullMode/PullJob.cpp --- a/Framework/PullMode/PullJob.cpp Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/PullMode/PullJob.cpp Wed Oct 19 21:12:57 2022 +0200 @@ -176,7 +176,10 @@ Orthanc::Toolbox::WriteFastJson(lookup, job_.query_.GetResources()); Json::Value answer; - if (!DoPostPeer(answer, job_.peers_, job_.peerIndex_, URI_LOOKUP, lookup, job_.maxHttpRetries_)) + std::map headers; + job_.query_.GetHttpHeaders(headers); + + if (!DoPostPeer(answer, job_.peers_, job_.peerIndex_, URI_LOOKUP, lookup, job_.maxHttpRetries_, headers)) { LOG(ERROR) << "Cannot retrieve the list of instances to pull from peer \"" << job_.query_.GetPeer() diff -r c3fefbb11321 -r f4e828607f02 Framework/PushMode/BucketPushQuery.cpp --- a/Framework/PushMode/BucketPushQuery.cpp Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/PushMode/BucketPushQuery.cpp Wed Oct 19 21:12:57 2022 +0200 @@ -32,12 +32,14 @@ const std::string& peer, const std::string& transactionUri, size_t bucketIndex, - BucketCompression compression) : + BucketCompression compression, + const std::map& headers) : cache_(cache), bucket_(bucket), peer_(peer), uri_(transactionUri + "/" + boost::lexical_cast(bucketIndex)), - compression_(compression) + compression_(compression), + headers_(headers) { } diff -r c3fefbb11321 -r f4e828607f02 Framework/PushMode/BucketPushQuery.h --- a/Framework/PushMode/BucketPushQuery.h Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/PushMode/BucketPushQuery.h Wed Oct 19 21:12:57 2022 +0200 @@ -32,6 +32,7 @@ std::string peer_; std::string uri_; BucketCompression compression_; + std::map headers_; public: BucketPushQuery(OrthancInstancesCache& cache, @@ -39,7 +40,8 @@ const std::string& peer, const std::string& transactionUri, size_t bucketIndex, - BucketCompression compression); + BucketCompression compression, + const std::map& headers); virtual Orthanc::HttpMethod GetMethod() const { @@ -60,5 +62,10 @@ virtual void HandleAnswer(const void* answer, size_t size); + + virtual void GetHttpHeaders(std::map& headers) const + { + headers = headers_; + } }; } diff -r c3fefbb11321 -r f4e828607f02 Framework/PushMode/PushJob.cpp --- a/Framework/PushMode/PushJob.cpp Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/PushMode/PushJob.cpp Wed Oct 19 21:12:57 2022 +0200 @@ -53,21 +53,23 @@ { Json::Value answer; bool success = false; + std::map headers; + job_.query_.GetHttpHeaders(headers); if (isCommit_) { - success = DoPostPeer(answer, job_.peers_, job_.peerIndex_, transactionUri_ + "/commit", "", job_.maxHttpRetries_); + success = DoPostPeer(answer, job_.peers_, job_.peerIndex_, transactionUri_ + "/commit", "", job_.maxHttpRetries_, headers); } else { - success = DoDeletePeer(job_.peers_, job_.peerIndex_, transactionUri_, job_.maxHttpRetries_); + success = DoDeletePeer(job_.peers_, job_.peerIndex_, transactionUri_, job_.maxHttpRetries_, headers); } if (!success) { if (isCommit_) { - LOG(ERROR) << "Cannot commit push transaction on remote peer: " + LOG(ERROR) << "Cannot commit push transaction on remote peer: " // TODO: add job ID << job_.query_.GetPeer(); } @@ -129,13 +131,16 @@ info_(info), transactionUri_(transactionUri) { + std::map headers; + job_.query_.GetHttpHeaders(headers); + queue_.SetMaxRetries(job.maxHttpRetries_); queue_.Reserve(buckets.size()); for (size_t i = 0; i < buckets.size(); i++) { queue_.Enqueue(new BucketPushQuery(job.cache_, buckets[i], job.query_.GetPeer(), - transactionUri_, i, job.query_.GetCompression())); + transactionUri_, i, job.query_.GetCompression(), headers)); } UpdateInfo(); @@ -212,7 +217,10 @@ virtual StateUpdate* Step() { Json::Value answer; - if (!DoPostPeer(answer, job_.peers_, job_.peerIndex_, URI_PUSH, createTransaction_, job_.maxHttpRetries_)) + std::map headers; + job_.query_.GetHttpHeaders(headers); + + if (!DoPostPeer(answer, job_.peers_, job_.peerIndex_, URI_PUSH, createTransaction_, job_.maxHttpRetries_, headers)) { LOG(ERROR) << "Cannot create a push transaction to peer \"" << job_.query_.GetPeer() diff -r c3fefbb11321 -r f4e828607f02 Framework/TransferQuery.cpp --- a/Framework/TransferQuery.cpp Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/TransferQuery.cpp Wed Oct 19 21:12:57 2022 +0200 @@ -20,6 +20,7 @@ #include "TransferQuery.h" #include +#include "Toolbox.h" namespace OrthancPlugins @@ -74,6 +75,20 @@ { priority_ = 0; } + + if (body.isMember(KEY_SENDER_TRANSFER_ID)) + { + if (body[KEY_SENDER_TRANSFER_ID].type() != Json::stringValue) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, std::string(KEY_SENDER_TRANSFER_ID) + " should be a string"); + } + senderTransferId_ = body[KEY_SENDER_TRANSFER_ID].asString(); + } + else + { + senderTransferId_ = Orthanc::Toolbox::GenerateUuid(); + } + } @@ -89,6 +104,15 @@ } } + const std::string& TransferQuery::GetSenderTransferID() const + { + return senderTransferId_; + } + + void TransferQuery::GetHttpHeaders(std::map& headers) const + { + headers[HEADER_KEY_SENDER_TRANSFER_ID] = senderTransferId_; + } void TransferQuery::Serialize(Json::Value& target) const { @@ -96,7 +120,8 @@ target[KEY_PEER] = peer_; target[KEY_RESOURCES] = resources_; target[KEY_COMPRESSION] = EnumerationToString(compression_); - + target[KEY_SENDER_TRANSFER_ID] = senderTransferId_; + if (hasOriginator_) { target[KEY_ORIGINATOR_UUID] = originator_; diff -r c3fefbb11321 -r f4e828607f02 Framework/TransferQuery.h --- a/Framework/TransferQuery.h Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/TransferQuery.h Wed Oct 19 21:12:57 2022 +0200 @@ -34,6 +34,7 @@ bool hasOriginator_; std::string originator_; int priority_; + std::string senderTransferId_; public: explicit TransferQuery(const Json::Value& body); @@ -65,6 +66,10 @@ return priority_; } + const std::string& GetSenderTransferID() const; + + void GetHttpHeaders(std::map& headers) const; + void Serialize(Json::Value& target) const; }; } diff -r c3fefbb11321 -r f4e828607f02 Framework/TransferToolbox.cpp --- a/Framework/TransferToolbox.cpp Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/TransferToolbox.cpp Wed Oct 19 21:12:57 2022 +0200 @@ -83,7 +83,9 @@ size_t peerIndex, const std::string& uri, const std::string& body, - unsigned int maxRetries) + unsigned int maxRetries, + const std::map& headers +) { unsigned int retry = 0; @@ -91,7 +93,7 @@ { try { - if (peers.DoPost(answer, peerIndex, uri, body)) + if (peers.DoPost(answer, peerIndex, uri, body, headers)) { return true; } @@ -119,19 +121,21 @@ const std::string& peerName, const std::string& uri, const std::string& body, - unsigned int maxRetries) + unsigned int maxRetries, + const std::map& headers) { size_t index; return (peers.LookupName(index, peerName) && - DoPostPeer(answer, peers, index, uri, body, maxRetries)); + DoPostPeer(answer, peers, index, uri, body, maxRetries, headers)); } bool DoDeletePeer(const OrthancPeers& peers, size_t peerIndex, const std::string& uri, - unsigned int maxRetries) + unsigned int maxRetries, + const std::map& headers) { unsigned int retry = 0; @@ -139,7 +143,7 @@ { try { - if (peers.DoDelete(peerIndex, uri)) + if (peers.DoDelete(peerIndex, uri, headers)) { return true; } diff -r c3fefbb11321 -r f4e828607f02 Framework/TransferToolbox.h --- a/Framework/TransferToolbox.h Tue Jul 12 17:49:40 2022 +0200 +++ b/Framework/TransferToolbox.h Wed Oct 19 21:12:57 2022 +0200 @@ -47,6 +47,7 @@ static const char* const KEY_RESOURCES = "Resources"; static const char* const KEY_SIZE = "Size"; static const char* const KEY_URL = "URL"; +static const char* const KEY_SENDER_TRANSFER_ID = "SenderTransferID"; static const char* const URI_CHUNKS = "/transfers/chunks"; static const char* const URI_JOBS = "/jobs"; @@ -57,6 +58,7 @@ static const char* const URI_PUSH = "/transfers/push"; static const char* const URI_SEND = "/transfers/send"; +static const char* const HEADER_KEY_SENDER_TRANSFER_ID = "sender-transfer-id"; namespace OrthancPlugins { @@ -81,17 +83,20 @@ size_t peerIndex, const std::string& uri, const std::string& body, - unsigned int maxRetries); + unsigned int maxRetries, + const std::map& headers); bool DoPostPeer(Json::Value& answer, const OrthancPeers& peers, const std::string& peerName, const std::string& uri, const std::string& body, - unsigned int maxRetries); + unsigned int maxRetries, + const std::map& headers); bool DoDeletePeer(const OrthancPeers& peers, size_t peerIndex, const std::string& uri, - unsigned int maxRetries); + unsigned int maxRetries, + const std::map& headers); } diff -r c3fefbb11321 -r f4e828607f02 NEWS --- a/NEWS Tue Jul 12 17:49:40 2022 +0200 +++ b/NEWS Wed Oct 19 21:12:57 2022 +0200 @@ -1,3 +1,12 @@ +Pending changes in the mainline +=============================== + +* new "SenderTransferID" option when creating a transfer. This id is added as an HTTP Header + ("sender-transfer-id") in every outgoing request that relates to this transfer and can be used + e.g, by a load balancer to route all requests from a single transfer to the same Orthanc. + If no "SenderTransferID" is provided, a UUID is generated by the plugin. This header is only + used in PushMode + Version 1.2 (2022-07-12) ======================== diff -r c3fefbb11321 -r f4e828607f02 Plugin/Plugin.cpp --- a/Plugin/Plugin.cpp Tue Jul 12 17:49:40 2022 +0200 +++ b/Plugin/Plugin.cpp Wed Oct 19 21:12:57 2022 +0200 @@ -452,7 +452,10 @@ Orthanc::Toolbox::WriteFastJson(s, lookup); Json::Value answer; - if (DoPostPeer(answer, peers, query.GetPeer(), URI_PULL, s, context.GetMaxHttpRetries()) && + std::map headers; + query.GetHttpHeaders(headers); + + if (DoPostPeer(answer, peers, query.GetPeer(), URI_PULL, s, context.GetMaxHttpRetries(), headers) && answer.type() == Json::objectValue && answer.isMember(KEY_ID) && answer.isMember(KEY_PATH) && diff -r c3fefbb11321 -r f4e828607f02 Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp --- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp Tue Jul 12 17:49:40 2022 +0200 +++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp Wed Oct 19 21:12:57 2022 +0200 @@ -1885,7 +1885,8 @@ bool OrthancPeers::DoGet(MemoryBuffer& target, size_t index, - const std::string& uri) const + const std::string& uri, + const std::map& headers) const { if (index >= index_.size()) { @@ -1894,10 +1895,12 @@ OrthancPlugins::MemoryBuffer answer; uint16_t status; + PluginHttpHeaders pluginHeaders(headers); + OrthancPluginErrorCode code = OrthancPluginCallPeerApi (GetGlobalContext(), *answer, NULL, &status, peers_, static_cast(index), OrthancPluginHttpMethod_Get, uri.c_str(), - 0, NULL, NULL, NULL, 0, timeout_); + pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), NULL, 0, timeout_); if (code == OrthancPluginErrorCode_Success) { @@ -1913,21 +1916,23 @@ bool OrthancPeers::DoGet(MemoryBuffer& target, const std::string& name, - const std::string& uri) const + const std::string& uri, + const std::map& headers) const { size_t index; return (LookupName(index, name) && - DoGet(target, index, uri)); + DoGet(target, index, uri, headers)); } bool OrthancPeers::DoGet(Json::Value& target, size_t index, - const std::string& uri) const + const std::string& uri, + const std::map& headers) const { MemoryBuffer buffer; - if (DoGet(buffer, index, uri)) + if (DoGet(buffer, index, uri, headers)) { buffer.ToJson(target); return true; @@ -1941,11 +1946,12 @@ bool OrthancPeers::DoGet(Json::Value& target, const std::string& name, - const std::string& uri) const + const std::string& uri, + const std::map& headers) const { MemoryBuffer buffer; - if (DoGet(buffer, name, uri)) + if (DoGet(buffer, name, uri, headers)) { buffer.ToJson(target); return true; @@ -1960,22 +1966,24 @@ bool OrthancPeers::DoPost(MemoryBuffer& target, const std::string& name, const std::string& uri, - const std::string& body) const + const std::string& body, + const std::map& headers) const { size_t index; return (LookupName(index, name) && - DoPost(target, index, uri, body)); + DoPost(target, index, uri, body, headers)); } bool OrthancPeers::DoPost(Json::Value& target, size_t index, const std::string& uri, - const std::string& body) const + const std::string& body, + const std::map& headers) const { MemoryBuffer buffer; - if (DoPost(buffer, index, uri, body)) + if (DoPost(buffer, index, uri, body, headers)) { buffer.ToJson(target); return true; @@ -1990,11 +1998,12 @@ bool OrthancPeers::DoPost(Json::Value& target, const std::string& name, const std::string& uri, - const std::string& body) const + const std::string& body, + const std::map& headers) const { MemoryBuffer buffer; - if (DoPost(buffer, name, uri, body)) + if (DoPost(buffer, name, uri, body, headers)) { buffer.ToJson(target); return true; @@ -2009,7 +2018,8 @@ bool OrthancPeers::DoPost(MemoryBuffer& target, size_t index, const std::string& uri, - const std::string& body) const + const std::string& body, + const std::map& headers) const { if (index >= index_.size()) { @@ -2024,10 +2034,12 @@ OrthancPlugins::MemoryBuffer answer; uint16_t status; + PluginHttpHeaders pluginHeaders(headers); + OrthancPluginErrorCode code = OrthancPluginCallPeerApi (GetGlobalContext(), *answer, NULL, &status, peers_, static_cast(index), OrthancPluginHttpMethod_Post, uri.c_str(), - 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); + pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout_); if (code == OrthancPluginErrorCode_Success) { @@ -2043,7 +2055,8 @@ bool OrthancPeers::DoPut(size_t index, const std::string& uri, - const std::string& body) const + const std::string& body, + const std::map& headers) const { if (index >= index_.size()) { @@ -2058,10 +2071,12 @@ OrthancPlugins::MemoryBuffer answer; uint16_t status; + PluginHttpHeaders pluginHeaders(headers); + OrthancPluginErrorCode code = OrthancPluginCallPeerApi (GetGlobalContext(), *answer, NULL, &status, peers_, static_cast(index), OrthancPluginHttpMethod_Put, uri.c_str(), - 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); + pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout_); if (code == OrthancPluginErrorCode_Success) { @@ -2076,16 +2091,18 @@ bool OrthancPeers::DoPut(const std::string& name, const std::string& uri, - const std::string& body) const + const std::string& body, + const std::map& headers) const { size_t index; return (LookupName(index, name) && - DoPut(index, uri, body)); + DoPut(index, uri, body, headers)); } bool OrthancPeers::DoDelete(size_t index, - const std::string& uri) const + const std::string& uri, + const std::map& headers) const { if (index >= index_.size()) { @@ -2094,10 +2111,12 @@ OrthancPlugins::MemoryBuffer answer; uint16_t status; + PluginHttpHeaders pluginHeaders(headers); + OrthancPluginErrorCode code = OrthancPluginCallPeerApi (GetGlobalContext(), *answer, NULL, &status, peers_, static_cast(index), OrthancPluginHttpMethod_Delete, uri.c_str(), - 0, NULL, NULL, NULL, 0, timeout_); + pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), NULL, 0, timeout_); if (code == OrthancPluginErrorCode_Success) { @@ -2111,11 +2130,12 @@ bool OrthancPeers::DoDelete(const std::string& name, - const std::string& uri) const + const std::string& uri, + const std::map& headers) const { size_t index; return (LookupName(index, name) && - DoDelete(index, uri)); + DoDelete(index, uri, headers)); } #endif diff -r c3fefbb11321 -r f4e828607f02 Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h --- a/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h Tue Jul 12 17:49:40 2022 +0200 +++ b/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h Wed Oct 19 21:12:57 2022 +0200 @@ -755,53 +755,65 @@ bool DoGet(MemoryBuffer& target, size_t index, - const std::string& uri) const; + const std::string& uri, + const std::map& headers) const; bool DoGet(MemoryBuffer& target, const std::string& name, - const std::string& uri) const; + const std::string& uri, + const std::map& headers) const; bool DoGet(Json::Value& target, size_t index, - const std::string& uri) const; + const std::string& uri, + const std::map& headers) const; bool DoGet(Json::Value& target, const std::string& name, - const std::string& uri) const; + const std::string& uri, + const std::map& headers) const; bool DoPost(MemoryBuffer& target, size_t index, const std::string& uri, - const std::string& body) const; + const std::string& body, + const std::map& headers) const; bool DoPost(MemoryBuffer& target, const std::string& name, const std::string& uri, - const std::string& body) const; + const std::string& body, + const std::map& headers) const; bool DoPost(Json::Value& target, size_t index, const std::string& uri, - const std::string& body) const; + const std::string& body, + const std::map& headers) const; bool DoPost(Json::Value& target, const std::string& name, const std::string& uri, - const std::string& body) const; + const std::string& body, + const std::map& headers) const; bool DoPut(size_t index, const std::string& uri, - const std::string& body) const; + const std::string& body, + const std::map& headers) const; bool DoPut(const std::string& name, const std::string& uri, - const std::string& body) const; + const std::string& body, + const std::map& headers) const; bool DoDelete(size_t index, - const std::string& uri) const; + const std::string& uri, + const std::map& headers) const; bool DoDelete(const std::string& name, - const std::string& uri) const; + const std::string& uri, + const std::map& headers) const; }; #endif