comparison Plugins/Samples/Common/OrthancPluginCppWrapper.cpp @ 3387:a48d652f1500

new function OrthancPluginHttpClientChunkedBody(), new class OrthancPlugins::HttpClient
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 05 Jun 2019 17:17:48 +0200
parents 0f721f015b85
children 18cd4951fccc
comparison
equal deleted inserted replaced
3386:af9432e46c07 3387:a48d652f1500
438 bool HttpDelete(const std::string& url, 438 bool HttpDelete(const std::string& url,
439 const std::string& username, 439 const std::string& username,
440 const std::string& password) 440 const std::string& password)
441 { 441 {
442 OrthancPluginErrorCode error = OrthancPluginHttpDelete 442 OrthancPluginErrorCode error = OrthancPluginHttpDelete
443 (GetGlobalContext(), url.c_str(), 443 (GetGlobalContext(), url.c_str(),
444 username.empty() ? NULL : username.c_str(), 444 username.empty() ? NULL : username.c_str(),
445 password.empty() ? NULL : password.c_str()); 445 password.empty() ? NULL : password.c_str());
446 446
447 if (error == OrthancPluginErrorCode_Success) 447 if (error == OrthancPluginErrorCode_Success)
448 { 448 {
449 return true; 449 return true;
450 } 450 }
589 return false; 589 return false;
590 } 590 }
591 591
592 switch (configuration_[key].type()) 592 switch (configuration_[key].type())
593 { 593 {
594 case Json::intValue: 594 case Json::intValue:
595 target = configuration_[key].asInt(); 595 target = configuration_[key].asInt();
596 return true; 596 return true;
597 597
598 case Json::uintValue: 598 case Json::uintValue:
599 target = configuration_[key].asUInt(); 599 target = configuration_[key].asUInt();
600 return true; 600 return true;
601 601
602 default: 602 default:
603 LogError("The configuration option \"" + GetPath(key) + 603 LogError("The configuration option \"" + GetPath(key) +
604 "\" is not an integer as expected"); 604 "\" is not an integer as expected");
605 605
606 ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); 606 ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
607 } 607 }
608 } 608 }
609 609
610 610
611 bool OrthancConfiguration::LookupUnsignedIntegerValue(unsigned int& target, 611 bool OrthancConfiguration::LookupUnsignedIntegerValue(unsigned int& target,
665 return false; 665 return false;
666 } 666 }
667 667
668 switch (configuration_[key].type()) 668 switch (configuration_[key].type())
669 { 669 {
670 case Json::realValue: 670 case Json::realValue:
671 target = configuration_[key].asFloat(); 671 target = configuration_[key].asFloat();
672 return true; 672 return true;
673 673
674 case Json::intValue: 674 case Json::intValue:
675 target = static_cast<float>(configuration_[key].asInt()); 675 target = static_cast<float>(configuration_[key].asInt());
676 return true; 676 return true;
677 677
678 case Json::uintValue: 678 case Json::uintValue:
679 target = static_cast<float>(configuration_[key].asUInt()); 679 target = static_cast<float>(configuration_[key].asUInt());
680 return true; 680 return true;
681 681
682 default: 682 default:
683 LogError("The configuration option \"" + GetPath(key) + 683 LogError("The configuration option \"" + GetPath(key) +
684 "\" is not an integer as expected"); 684 "\" is not an integer as expected");
685 685
686 ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); 686 ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
687 } 687 }
688 } 688 }
689 689
690 690
691 bool OrthancConfiguration::LookupListOfStrings(std::list<std::string>& target, 691 bool OrthancConfiguration::LookupListOfStrings(std::list<std::string>& target,
701 return false; 701 return false;
702 } 702 }
703 703
704 switch (configuration_[key].type()) 704 switch (configuration_[key].type())
705 { 705 {
706 case Json::arrayValue: 706 case Json::arrayValue:
707 {
708 bool ok = true;
709
710 for (Json::Value::ArrayIndex i = 0; ok && i < configuration_[key].size(); i++)
711 { 707 {
712 if (configuration_[key][i].type() == Json::stringValue) 708 bool ok = true;
709
710 for (Json::Value::ArrayIndex i = 0; ok && i < configuration_[key].size(); i++)
713 { 711 {
714 target.push_back(configuration_[key][i].asString()); 712 if (configuration_[key][i].type() == Json::stringValue)
713 {
714 target.push_back(configuration_[key][i].asString());
715 }
716 else
717 {
718 ok = false;
719 }
715 } 720 }
716 else 721
722 if (ok)
717 { 723 {
718 ok = false; 724 return true;
719 } 725 }
726
727 break;
720 } 728 }
721 729
722 if (ok) 730 case Json::stringValue:
723 { 731 if (allowSingleString)
724 return true; 732 {
725 } 733 target.push_back(configuration_[key].asString());
726 734 return true;
727 break; 735 }
728 } 736
729 737 break;
730 case Json::stringValue: 738
731 if (allowSingleString) 739 default:
732 { 740 break;
733 target.push_back(configuration_[key].asString());
734 return true;
735 }
736
737 break;
738
739 default:
740 break;
741 } 741 }
742 742
743 LogError("The configuration option \"" + GetPath(key) + 743 LogError("The configuration option \"" + GetPath(key) +
744 "\" is not a list of strings as expected"); 744 "\" is not a list of strings as expected");
745 745
756 if (LookupListOfStrings(lst, key, allowSingleString)) 756 if (LookupListOfStrings(lst, key, allowSingleString))
757 { 757 {
758 target.clear(); 758 target.clear();
759 759
760 for (std::list<std::string>::const_iterator 760 for (std::list<std::string>::const_iterator
761 it = lst.begin(); it != lst.end(); ++it) 761 it = lst.begin(); it != lst.end(); ++it)
762 { 762 {
763 target.insert(*it); 763 target.insert(*it);
764 } 764 }
765 765
766 return true; 766 return true;
939 uint32_t height, 939 uint32_t height,
940 uint32_t pitch, 940 uint32_t pitch,
941 void* buffer) 941 void* buffer)
942 { 942 {
943 image_ = OrthancPluginCreateImageAccessor 943 image_ = OrthancPluginCreateImageAccessor
944 (GetGlobalContext(), format, width, height, pitch, buffer); 944 (GetGlobalContext(), format, width, height, pitch, buffer);
945 945
946 if (image_ == NULL) 946 if (image_ == NULL)
947 { 947 {
948 LogError("Cannot create an image accessor"); 948 LogError("Cannot create an image accessor");
949 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); 949 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
1141 1141
1142 #endif /* HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 */ 1142 #endif /* HAS_ORTHANC_PLUGIN_FIND_MATCHER == 1 */
1143 1143
1144 void AnswerJson(const Json::Value& value, 1144 void AnswerJson(const Json::Value& value,
1145 OrthancPluginRestOutput* output 1145 OrthancPluginRestOutput* output
1146 ) 1146 )
1147 { 1147 {
1148 Json::StyledWriter writer; 1148 Json::StyledWriter writer;
1149 std::string bodyString = writer.write(value); 1149 std::string bodyString = writer.write(value);
1150 1150
1151 OrthancPluginAnswerBuffer(GetGlobalContext(), output, bodyString.c_str(), bodyString.size(), "application/json"); 1151 OrthancPluginAnswerBuffer(GetGlobalContext(), output, bodyString.c_str(), bodyString.size(), "application/json");
1152 } 1152 }
1153 1153
1154 void AnswerString(const std::string& answer, 1154 void AnswerString(const std::string& answer,
1155 const char* mimeType, 1155 const char* mimeType,
1156 OrthancPluginRestOutput* output 1156 OrthancPluginRestOutput* output
1157 ) 1157 )
1158 { 1158 {
1159 OrthancPluginAnswerBuffer(GetGlobalContext(), output, answer.c_str(), answer.size(), mimeType); 1159 OrthancPluginAnswerBuffer(GetGlobalContext(), output, answer.c_str(), answer.size(), mimeType);
1160 } 1160 }
1161 1161
1162 void AnswerHttpError(uint16_t httpError, OrthancPluginRestOutput *output) 1162 void AnswerHttpError(uint16_t httpError, OrthancPluginRestOutput *output)
1352 } 1352 }
1353 1353
1354 // Parse the version of the Orthanc core 1354 // Parse the version of the Orthanc core
1355 int aa, bb, cc; 1355 int aa, bb, cc;
1356 if ( 1356 if (
1357 #ifdef _MSC_VER 1357 #ifdef _MSC_VER
1358 sscanf_s 1358 sscanf_s
1359 #else 1359 #else
1360 sscanf 1360 sscanf
1361 #endif 1361 #endif
1362 (GetGlobalContext()->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 || 1362 (GetGlobalContext()->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 ||
1363 aa < 0 || 1363 aa < 0 ||
1364 bb < 0 || 1364 bb < 0 ||
1365 cc < 0) 1365 cc < 0)
1366 { 1366 {
1367 return false; 1367 return false;
1368 } 1368 }
1369 1369
1370 unsigned int a = static_cast<unsigned int>(aa); 1370 unsigned int a = static_cast<unsigned int>(aa);
1588 } 1588 }
1589 1589
1590 OrthancPlugins::MemoryBuffer answer; 1590 OrthancPlugins::MemoryBuffer answer;
1591 uint16_t status; 1591 uint16_t status;
1592 OrthancPluginErrorCode code = OrthancPluginCallPeerApi 1592 OrthancPluginErrorCode code = OrthancPluginCallPeerApi
1593 (GetGlobalContext(), *answer, NULL, &status, peers_, 1593 (GetGlobalContext(), *answer, NULL, &status, peers_,
1594 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Get, uri.c_str(), 1594 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Get, uri.c_str(),
1595 0, NULL, NULL, NULL, 0, timeout_); 1595 0, NULL, NULL, NULL, 0, timeout_);
1596 1596
1597 if (code == OrthancPluginErrorCode_Success) 1597 if (code == OrthancPluginErrorCode_Success)
1598 { 1598 {
1599 target.Swap(answer); 1599 target.Swap(answer);
1600 return (status == 200); 1600 return (status == 200);
1712 } 1712 }
1713 1713
1714 OrthancPlugins::MemoryBuffer answer; 1714 OrthancPlugins::MemoryBuffer answer;
1715 uint16_t status; 1715 uint16_t status;
1716 OrthancPluginErrorCode code = OrthancPluginCallPeerApi 1716 OrthancPluginErrorCode code = OrthancPluginCallPeerApi
1717 (GetGlobalContext(), *answer, NULL, &status, peers_, 1717 (GetGlobalContext(), *answer, NULL, &status, peers_,
1718 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(), 1718 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(),
1719 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); 1719 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_);
1720 1720
1721 if (code == OrthancPluginErrorCode_Success) 1721 if (code == OrthancPluginErrorCode_Success)
1722 { 1722 {
1723 target.Swap(answer); 1723 target.Swap(answer);
1724 return (status == 200); 1724 return (status == 200);
1740 } 1740 }
1741 1741
1742 OrthancPlugins::MemoryBuffer answer; 1742 OrthancPlugins::MemoryBuffer answer;
1743 uint16_t status; 1743 uint16_t status;
1744 OrthancPluginErrorCode code = OrthancPluginCallPeerApi 1744 OrthancPluginErrorCode code = OrthancPluginCallPeerApi
1745 (GetGlobalContext(), *answer, NULL, &status, peers_, 1745 (GetGlobalContext(), *answer, NULL, &status, peers_,
1746 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Put, uri.c_str(), 1746 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Put, uri.c_str(),
1747 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); 1747 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_);
1748 1748
1749 if (code == OrthancPluginErrorCode_Success) 1749 if (code == OrthancPluginErrorCode_Success)
1750 { 1750 {
1751 return (status == 200); 1751 return (status == 200);
1752 } 1752 }
1998 { 1998 {
1999 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer); 1999 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer);
2000 } 2000 }
2001 2001
2002 OrthancPluginJob* orthanc = OrthancPluginCreateJob( 2002 OrthancPluginJob* orthanc = OrthancPluginCreateJob(
2003 GetGlobalContext(), job, CallbackFinalize, job->jobType_.c_str(), 2003 GetGlobalContext(), job, CallbackFinalize, job->jobType_.c_str(),
2004 CallbackGetProgress, CallbackGetContent, CallbackGetSerialized, 2004 CallbackGetProgress, CallbackGetContent, CallbackGetSerialized,
2005 CallbackStep, CallbackStop, CallbackReset); 2005 CallbackStep, CallbackStop, CallbackReset);
2006 2006
2007 if (orthanc == NULL) 2007 if (orthanc == NULL)
2008 { 2008 {
2009 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); 2009 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin);
2010 } 2010 }
2053 const boost::posix_time::time_duration diff = stop - start_; 2053 const boost::posix_time::time_duration diff = stop - start_;
2054 OrthancPluginSetMetricsValue(GetGlobalContext(), name_.c_str(), diff.total_milliseconds(), 2054 OrthancPluginSetMetricsValue(GetGlobalContext(), name_.c_str(), diff.total_milliseconds(),
2055 OrthancPluginMetricsType_Timer); 2055 OrthancPluginMetricsType_Timer);
2056 } 2056 }
2057 #endif 2057 #endif
2058
2059
2060
2061 #if HAS_ORTHANC_PLUGIN_HTTP_CHUNKED_BODY == 1
2062 class HttpClient::ChunkedBody : public boost::noncopyable
2063 {
2064 private:
2065 static ChunkedBody& GetObject(void* body)
2066 {
2067 assert(body != NULL);
2068 return *reinterpret_cast<ChunkedBody*>(body);
2069 }
2070
2071 IChunkedBody& body_;
2072 bool done_;
2073 std::string chunk_;
2074
2075 public:
2076 ChunkedBody(IChunkedBody& body) :
2077 body_(body),
2078 done_(false)
2079 {
2080 }
2081
2082 static uint8_t IsDone(void* body)
2083 {
2084 return GetObject(body).done_;
2085 }
2086
2087 static const void* GetChunkData(void* body)
2088 {
2089 return GetObject(body).chunk_.c_str();
2090 }
2091
2092 static uint32_t GetChunkSize(void* body)
2093 {
2094 return static_cast<uint32_t>(GetObject(body).chunk_.size());
2095 }
2096
2097 static OrthancPluginErrorCode Next(void* body)
2098 {
2099 ChunkedBody& that = GetObject(body);
2100
2101 if (that.done_)
2102 {
2103 return OrthancPluginErrorCode_BadSequenceOfCalls;
2104 }
2105 else
2106 {
2107 try
2108 {
2109 that.done_ = !that.body_.ReadNextChunk(that.chunk_);
2110 return OrthancPluginErrorCode_Success;
2111 }
2112 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
2113 {
2114 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
2115 }
2116 catch (...)
2117 {
2118 return OrthancPluginErrorCode_InternalError;
2119 }
2120 }
2121 }
2122 };
2123 #endif
2124
2125 HttpClient::HttpClient() :
2126 httpStatus_(0),
2127 method_(OrthancPluginHttpMethod_Get),
2128 timeout_(0),
2129 pkcs11_(false),
2130 chunkedBody_(NULL)
2131 {
2132 }
2133
2134
2135 void HttpClient::SetCredentials(const std::string& username,
2136 const std::string& password)
2137 {
2138 username_ = username;
2139 password_ = password;
2140 }
2141
2142
2143 void HttpClient::ClearCredentials()
2144 {
2145 username_.empty();
2146 password_.empty();
2147 }
2148
2149
2150 void HttpClient::SetCertificate(const std::string& certificateFile,
2151 const std::string& keyFile,
2152 const std::string& keyPassword)
2153 {
2154 certificateFile_ = certificateFile;
2155 certificateKeyFile_ = keyFile;
2156 certificateKeyPassword_ = keyPassword;
2157 }
2158
2159
2160 void HttpClient::ClearCertificate()
2161 {
2162 certificateFile_.clear();
2163 certificateKeyFile_.clear();
2164 certificateKeyPassword_.clear();
2165 }
2166
2167
2168 void HttpClient::ClearBody()
2169 {
2170 body_.clear();
2171 chunkedBody_ = NULL;
2172 }
2173
2174
2175 void HttpClient::SwapBody(std::string& body)
2176 {
2177 body_.swap(body);
2178 chunkedBody_ = NULL;
2179 }
2180
2181
2182 void HttpClient::SetBody(const std::string& body)
2183 {
2184 body_ = body;
2185 chunkedBody_ = NULL;
2186 }
2187
2188
2189 #if HAS_ORTHANC_PLUGIN_HTTP_CHUNKED_BODY == 1
2190 void HttpClient::SetBody(IChunkedBody& body)
2191 {
2192 body_.clear();
2193 chunkedBody_ = &body;
2194 }
2195 #endif
2196
2197
2198 void HttpClient::Execute()
2199 {
2200 std::vector<const char*> headersKeys;
2201 std::vector<const char*> headersValues;
2202
2203 headersKeys.reserve(headers_.size());
2204 headersValues.reserve(headers_.size());
2205
2206 for (HttpHeaders::const_iterator it = headers_.begin();
2207 it != headers_.end(); ++it)
2208 {
2209 headersKeys.push_back(it->first.c_str());
2210 headersValues.push_back(it->second.c_str());
2211 }
2212
2213 OrthancPluginErrorCode error;
2214
2215 if (chunkedBody_ == NULL)
2216 {
2217 error = OrthancPluginHttpClient(
2218 GetGlobalContext(),
2219 *answerBody_,
2220 *answerHeaders_,
2221 &httpStatus_,
2222 method_,
2223 url_.c_str(),
2224 headersKeys.size(),
2225 headersKeys.empty() ? NULL : &headersKeys[0],
2226 headersValues.empty() ? NULL : &headersValues[0],
2227 body_.empty() ? NULL : body_.c_str(),
2228 body_.size(),
2229 username_.empty() ? NULL : username_.c_str(),
2230 password_.empty() ? NULL : password_.c_str(),
2231 timeout_,
2232 certificateFile_.empty() ? NULL : certificateFile_.c_str(),
2233 certificateFile_.empty() ? NULL : certificateKeyFile_.c_str(),
2234 certificateFile_.empty() ? NULL : certificateKeyPassword_.c_str(),
2235 pkcs11_ ? 1 : 0);
2236 }
2237 else
2238 {
2239 #if HAS_ORTHANC_PLUGIN_HTTP_CHUNKED_BODY != 1
2240 error = OrthancPluginErrorCode_InternalError;
2241 #else
2242 ChunkedBody wrapper(*chunkedBody_);
2243
2244 error = OrthancPluginHttpClientChunkedBody(
2245 GetGlobalContext(),
2246 *answerBody_,
2247 *answerHeaders_,
2248 &httpStatus_,
2249 method_,
2250 url_.c_str(),
2251 headersKeys.size(),
2252 headersKeys.empty() ? NULL : &headersKeys[0],
2253 headersValues.empty() ? NULL : &headersValues[0],
2254 username_.empty() ? NULL : username_.c_str(),
2255 password_.empty() ? NULL : password_.c_str(),
2256 timeout_,
2257 certificateFile_.empty() ? NULL : certificateFile_.c_str(),
2258 certificateFile_.empty() ? NULL : certificateKeyFile_.c_str(),
2259 certificateFile_.empty() ? NULL : certificateKeyPassword_.c_str(),
2260 pkcs11_ ? 1 : 0,
2261 &wrapper,
2262 ChunkedBody::IsDone,
2263 ChunkedBody::GetChunkData,
2264 ChunkedBody::GetChunkSize,
2265 ChunkedBody::Next);
2266 #endif
2267 }
2268
2269 if (error != OrthancPluginErrorCode_Success)
2270 {
2271 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(error);
2272 }
2273 }
2058 } 2274 }