comparison Common/Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp @ 110:37a4b8e2577f

sync orthanc + SDK 1.12.1
author Alain Mazy <am@osimis.io>
date Tue, 10 Oct 2023 15:40:36 +0200
parents f3c44d61e1e1
children a3590caf93a3
comparison
equal deleted inserted replaced
109:2549eecdc996 110:37a4b8e2577f
1 /** 1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store 2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium 4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium 5 * Copyright (C) 2017-2023 Osimis S.A., Belgium
6 * Copyright (C) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
6 * 7 *
7 * This program is free software: you can redistribute it and/or 8 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as 9 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the 10 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version. 11 * License, or (at your option) any later version.
247 { 248 {
248 return CheckHttp(OrthancPluginRestApiGet(GetGlobalContext(), &buffer_, uri.c_str())); 249 return CheckHttp(OrthancPluginRestApiGet(GetGlobalContext(), &buffer_, uri.c_str()));
249 } 250 }
250 } 251 }
251 252
253 // helper class to convert std::map of headers to the plugin SDK C structure
254 class PluginHttpHeaders
255 {
256 private:
257 std::vector<const char*> headersKeys_;
258 std::vector<const char*> headersValues_;
259
260 public:
261 explicit PluginHttpHeaders(const std::map<std::string, std::string>& httpHeaders)
262 {
263 for (std::map<std::string, std::string>::const_iterator
264 it = httpHeaders.begin(); it != httpHeaders.end(); ++it)
265 {
266 headersKeys_.push_back(it->first.c_str());
267 headersValues_.push_back(it->second.c_str());
268 }
269 }
270
271 const char* const* GetKeys()
272 {
273 return (headersKeys_.empty() ? NULL : &headersKeys_[0]);
274 }
275
276 const char* const* GetValues()
277 {
278 return (headersValues_.empty() ? NULL : &headersValues_[0]);
279 }
280
281 uint32_t GetSize()
282 {
283 return static_cast<uint32_t>(headersKeys_.size());
284 }
285 };
286
252 bool MemoryBuffer::RestApiGet(const std::string& uri, 287 bool MemoryBuffer::RestApiGet(const std::string& uri,
253 const std::map<std::string, std::string>& httpHeaders, 288 const std::map<std::string, std::string>& httpHeaders,
254 bool applyPlugins) 289 bool applyPlugins)
255 { 290 {
256 Clear(); 291 Clear();
257 292
258 std::vector<const char*> headersKeys; 293 PluginHttpHeaders headers(httpHeaders);
259 std::vector<const char*> headersValues;
260
261 for (std::map<std::string, std::string>::const_iterator
262 it = httpHeaders.begin(); it != httpHeaders.end(); it++)
263 {
264 headersKeys.push_back(it->first.c_str());
265 headersValues.push_back(it->second.c_str());
266 }
267 294
268 return CheckHttp(OrthancPluginRestApiGet2( 295 return CheckHttp(OrthancPluginRestApiGet2(
269 GetGlobalContext(), &buffer_, uri.c_str(), httpHeaders.size(), 296 GetGlobalContext(), &buffer_, uri.c_str(),
270 (headersKeys.empty() ? NULL : &headersKeys[0]), 297 headers.GetSize(),
271 (headersValues.empty() ? NULL : &headersValues[0]), applyPlugins)); 298 headers.GetKeys(),
299 headers.GetValues(), applyPlugins));
272 } 300 }
273 301
274 bool MemoryBuffer::RestApiPost(const std::string& uri, 302 bool MemoryBuffer::RestApiPost(const std::string& uri,
275 const void* body, 303 const void* body,
276 size_t bodySize, 304 size_t bodySize,
289 { 317 {
290 return CheckHttp(OrthancPluginRestApiPost(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize)); 318 return CheckHttp(OrthancPluginRestApiPost(GetGlobalContext(), &buffer_, uri.c_str(), b, bodySize));
291 } 319 }
292 } 320 }
293 321
322 #if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
323
324 bool MemoryBuffer::RestApiPost(const std::string& uri,
325 const void* body,
326 size_t bodySize,
327 const std::map<std::string, std::string>& httpHeaders,
328 bool applyPlugins)
329 {
330 MemoryBuffer answerHeaders;
331 uint16_t httpStatus;
332
333 PluginHttpHeaders headers(httpHeaders);
334
335 return CheckHttp(OrthancPluginCallRestApi(GetGlobalContext(),
336 &buffer_,
337 *answerHeaders,
338 &httpStatus,
339 OrthancPluginHttpMethod_Post,
340 uri.c_str(),
341 headers.GetSize(), headers.GetKeys(), headers.GetValues(),
342 body, bodySize,
343 applyPlugins));
344 }
345
346
347 bool MemoryBuffer::RestApiPost(const std::string& uri,
348 const Json::Value& body,
349 const std::map<std::string, std::string>& httpHeaders,
350 bool applyPlugins)
351 {
352 std::string s;
353 WriteFastJson(s, body);
354 return RestApiPost(uri, s.c_str(), s.size(), httpHeaders, applyPlugins);
355 }
356 #endif
294 357
295 bool MemoryBuffer::RestApiPut(const std::string& uri, 358 bool MemoryBuffer::RestApiPut(const std::string& uri,
296 const void* body, 359 const void* body,
297 size_t bodySize, 360 size_t bodySize,
298 bool applyPlugins) 361 bool applyPlugins)
508 ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); 571 ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
509 } 572 }
510 } 573 }
511 574
512 575
576 void OrthancString::ToJsonWithoutComments(Json::Value& target) const
577 {
578 if (str_ == NULL)
579 {
580 LogError("Cannot convert an empty memory buffer to JSON");
581 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
582 }
583
584 if (!ReadJsonWithoutComments(target, str_))
585 {
586 LogError("Cannot convert some memory buffer to JSON");
587 ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
588 }
589 }
590
591
513 void MemoryBuffer::DicomToJson(Json::Value& target, 592 void MemoryBuffer::DicomToJson(Json::Value& target,
514 OrthancPluginDicomToJsonFormat format, 593 OrthancPluginDicomToJsonFormat format,
515 OrthancPluginDicomToJsonFlags flags, 594 OrthancPluginDicomToJsonFlags flags,
516 uint32_t maxStringLength) 595 uint32_t maxStringLength)
517 { 596 {
537 const std::string& body, 616 const std::string& body,
538 const std::string& username, 617 const std::string& username,
539 const std::string& password) 618 const std::string& password)
540 { 619 {
541 Clear(); 620 Clear();
621
622 if (body.size() > 0xffffffffu)
623 {
624 LogError("Cannot handle body size > 4GB");
625 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
626 }
627
542 return CheckHttp(OrthancPluginHttpPost(GetGlobalContext(), &buffer_, url.c_str(), 628 return CheckHttp(OrthancPluginHttpPost(GetGlobalContext(), &buffer_, url.c_str(),
543 body.c_str(), body.size(), 629 body.c_str(), body.size(),
544 username.empty() ? NULL : username.c_str(), 630 username.empty() ? NULL : username.c_str(),
545 password.empty() ? NULL : password.c_str())); 631 password.empty() ? NULL : password.c_str()));
546 } 632 }
550 const std::string& body, 636 const std::string& body,
551 const std::string& username, 637 const std::string& username,
552 const std::string& password) 638 const std::string& password)
553 { 639 {
554 Clear(); 640 Clear();
641
642 if (body.size() > 0xffffffffu)
643 {
644 LogError("Cannot handle body size > 4GB");
645 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
646 }
647
555 return CheckHttp(OrthancPluginHttpPut(GetGlobalContext(), &buffer_, url.c_str(), 648 return CheckHttp(OrthancPluginHttpPut(GetGlobalContext(), &buffer_, url.c_str(),
556 body.empty() ? NULL : body.c_str(), 649 body.empty() ? NULL : body.c_str(),
557 body.size(), 650 body.size(),
558 username.empty() ? NULL : username.c_str(), 651 username.empty() ? NULL : username.c_str(),
559 password.empty() ? NULL : password.c_str())); 652 password.empty() ? NULL : password.c_str()));
628 { 721 {
629 LogError("Cannot access the Orthanc configuration"); 722 LogError("Cannot access the Orthanc configuration");
630 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); 723 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
631 } 724 }
632 725
633 str.ToJson(configuration_); 726 str.ToJsonWithoutComments(configuration_);
634 727
635 if (configuration_.type() != Json::objectValue) 728 if (configuration_.type() != Json::objectValue)
636 { 729 {
637 LogError("Unable to read the Orthanc configuration"); 730 LogError("Unable to read the Orthanc configuration");
638 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError); 731 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
654 } 747 }
655 else 748 else
656 { 749 {
657 configuration_ = Json::objectValue; 750 configuration_ = Json::objectValue;
658 } 751 }
752 }
753
754 OrthancConfiguration::OrthancConfiguration(const Json::Value& configuration, const std::string& path) :
755 configuration_(configuration),
756 path_(path)
757 {
659 } 758 }
660 759
661 760
662 std::string OrthancConfiguration::GetPath(const std::string& key) const 761 std::string OrthancConfiguration::GetPath(const std::string& key) const
663 { 762 {
1011 } 1110 }
1012 1111
1013 if (configuration_[key].type() != Json::objectValue) 1112 if (configuration_[key].type() != Json::objectValue)
1014 { 1113 {
1015 LogError("The configuration option \"" + GetPath(key) + 1114 LogError("The configuration option \"" + GetPath(key) +
1016 "\" is not a string as expected"); 1115 "\" is not an object as expected");
1017 1116
1018 ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat); 1117 ORTHANC_PLUGINS_THROW_EXCEPTION(BadFileFormat);
1019 } 1118 }
1020 1119
1021 Json::Value::Members members = configuration_[key].getMemberNames(); 1120 Json::Value::Members members = configuration_[key].getMemberNames();
1357 return true; 1456 return true;
1358 } 1457 }
1359 } 1458 }
1360 1459
1361 1460
1461 bool RestApiGet(Json::Value& result,
1462 const std::string& uri,
1463 const std::map<std::string, std::string>& httpHeaders,
1464 bool applyPlugins)
1465 {
1466 MemoryBuffer answer;
1467
1468 if (!answer.RestApiGet(uri, httpHeaders, applyPlugins))
1469 {
1470 return false;
1471 }
1472 else
1473 {
1474 if (!answer.IsEmpty())
1475 {
1476 answer.ToJson(result);
1477 }
1478 return true;
1479 }
1480 }
1481
1362 1482
1363 bool RestApiGet(Json::Value& result, 1483 bool RestApiGet(Json::Value& result,
1364 const std::string& uri, 1484 const std::string& uri,
1365 bool applyPlugins) 1485 bool applyPlugins)
1366 { 1486 {
1423 answer.ToJson(result); 1543 answer.ToJson(result);
1424 } 1544 }
1425 return true; 1545 return true;
1426 } 1546 }
1427 } 1547 }
1548
1549 #if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
1550 bool RestApiPost(Json::Value& result,
1551 const std::string& uri,
1552 const Json::Value& body,
1553 const std::map<std::string, std::string>& httpHeaders,
1554 bool applyPlugins)
1555 {
1556 MemoryBuffer answer;
1557
1558 if (!answer.RestApiPost(uri, body, httpHeaders, applyPlugins))
1559 {
1560 return false;
1561 }
1562 else
1563 {
1564 if (!answer.IsEmpty())
1565 {
1566 answer.ToJson(result);
1567 }
1568 return true;
1569 }
1570 }
1571 #endif
1428 1572
1429 1573
1430 bool RestApiPost(Json::Value& result, 1574 bool RestApiPost(Json::Value& result,
1431 const std::string& uri, 1575 const std::string& uri,
1432 const Json::Value& body, 1576 const Json::Value& body,
1513 boost::lexical_cast<std::string>(minor) + "." + 1657 boost::lexical_cast<std::string>(minor) + "." +
1514 boost::lexical_cast<std::string>(revision) + 1658 boost::lexical_cast<std::string>(revision) +
1515 " is required)"); 1659 " is required)");
1516 } 1660 }
1517 1661
1662 bool CheckMinimalVersion(const char* version,
1663 unsigned int major,
1664 unsigned int minor,
1665 unsigned int revision)
1666 {
1667 if (!strcmp(version, "mainline"))
1668 {
1669 // Assume compatibility with the mainline
1670 return true;
1671 }
1672
1673 #ifdef _MSC_VER
1674 #define ORTHANC_SCANF sscanf_s
1675 #else
1676 #define ORTHANC_SCANF sscanf
1677 #endif
1678
1679 // Parse the version
1680 int aa, bb, cc = 0;
1681 if ((ORTHANC_SCANF(version, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 &&
1682 ORTHANC_SCANF(version, "%4d.%4d", &aa, &bb) != 2) ||
1683 aa < 0 ||
1684 bb < 0 ||
1685 cc < 0)
1686 {
1687 return false;
1688 }
1689
1690 unsigned int a = static_cast<unsigned int>(aa);
1691 unsigned int b = static_cast<unsigned int>(bb);
1692 unsigned int c = static_cast<unsigned int>(cc);
1693
1694 // Check the major version number
1695
1696 if (a > major)
1697 {
1698 return true;
1699 }
1700
1701 if (a < major)
1702 {
1703 return false;
1704 }
1705
1706 // Check the minor version number
1707 assert(a == major);
1708
1709 if (b > minor)
1710 {
1711 return true;
1712 }
1713
1714 if (b < minor)
1715 {
1716 return false;
1717 }
1718
1719 // Check the patch level version number
1720 assert(a == major && b == minor);
1721
1722 if (c >= revision)
1723 {
1724 return true;
1725 }
1726 else
1727 {
1728 return false;
1729 }
1730 }
1731
1518 1732
1519 bool CheckMinimalOrthancVersion(unsigned int major, 1733 bool CheckMinimalOrthancVersion(unsigned int major,
1520 unsigned int minor, 1734 unsigned int minor,
1521 unsigned int revision) 1735 unsigned int revision)
1522 { 1736 {
1524 { 1738 {
1525 LogError("Bad Orthanc context in the plugin"); 1739 LogError("Bad Orthanc context in the plugin");
1526 return false; 1740 return false;
1527 } 1741 }
1528 1742
1529 if (!strcmp(GetGlobalContext()->orthancVersion, "mainline")) 1743 return CheckMinimalVersion(GetGlobalContext()->orthancVersion,
1530 { 1744 major, minor, revision);
1531 // Assume compatibility with the mainline
1532 return true;
1533 }
1534
1535 // Parse the version of the Orthanc core
1536 int aa, bb, cc;
1537 if (
1538 #ifdef _MSC_VER
1539 sscanf_s
1540 #else
1541 sscanf
1542 #endif
1543 (GetGlobalContext()->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 ||
1544 aa < 0 ||
1545 bb < 0 ||
1546 cc < 0)
1547 {
1548 return false;
1549 }
1550
1551 unsigned int a = static_cast<unsigned int>(aa);
1552 unsigned int b = static_cast<unsigned int>(bb);
1553 unsigned int c = static_cast<unsigned int>(cc);
1554
1555 // Check the major version number
1556
1557 if (a > major)
1558 {
1559 return true;
1560 }
1561
1562 if (a < major)
1563 {
1564 return false;
1565 }
1566
1567
1568 // Check the minor version number
1569 assert(a == major);
1570
1571 if (b > minor)
1572 {
1573 return true;
1574 }
1575
1576 if (b < minor)
1577 {
1578 return false;
1579 }
1580
1581 // Check the patch level version number
1582 assert(a == major && b == minor);
1583
1584 if (c >= revision)
1585 {
1586 return true;
1587 }
1588 else
1589 {
1590 return false;
1591 }
1592 } 1745 }
1593 1746
1594 1747
1595 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0) 1748 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 0)
1596 const char* AutodetectMimeType(const std::string& path) 1749 const char* AutodetectMimeType(const std::string& path)
1759 } 1912 }
1760 1913
1761 1914
1762 bool OrthancPeers::DoGet(MemoryBuffer& target, 1915 bool OrthancPeers::DoGet(MemoryBuffer& target,
1763 size_t index, 1916 size_t index,
1764 const std::string& uri) const 1917 const std::string& uri,
1918 const std::map<std::string, std::string>& headers) const
1765 { 1919 {
1766 if (index >= index_.size()) 1920 if (index >= index_.size())
1767 { 1921 {
1768 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); 1922 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
1769 } 1923 }
1770 1924
1771 OrthancPlugins::MemoryBuffer answer; 1925 OrthancPlugins::MemoryBuffer answer;
1772 uint16_t status; 1926 uint16_t status;
1927 PluginHttpHeaders pluginHeaders(headers);
1928
1773 OrthancPluginErrorCode code = OrthancPluginCallPeerApi 1929 OrthancPluginErrorCode code = OrthancPluginCallPeerApi
1774 (GetGlobalContext(), *answer, NULL, &status, peers_, 1930 (GetGlobalContext(), *answer, NULL, &status, peers_,
1775 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Get, uri.c_str(), 1931 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Get, uri.c_str(),
1776 0, NULL, NULL, NULL, 0, timeout_); 1932 pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), NULL, 0, timeout_);
1777 1933
1778 if (code == OrthancPluginErrorCode_Success) 1934 if (code == OrthancPluginErrorCode_Success)
1779 { 1935 {
1780 target.Swap(answer); 1936 target.Swap(answer);
1781 return (status == 200); 1937 return (status == 200);
1787 } 1943 }
1788 1944
1789 1945
1790 bool OrthancPeers::DoGet(MemoryBuffer& target, 1946 bool OrthancPeers::DoGet(MemoryBuffer& target,
1791 const std::string& name, 1947 const std::string& name,
1792 const std::string& uri) const 1948 const std::string& uri,
1949 const std::map<std::string, std::string>& headers) const
1793 { 1950 {
1794 size_t index; 1951 size_t index;
1795 return (LookupName(index, name) && 1952 return (LookupName(index, name) &&
1796 DoGet(target, index, uri)); 1953 DoGet(target, index, uri, headers));
1797 } 1954 }
1798 1955
1799 1956
1800 bool OrthancPeers::DoGet(Json::Value& target, 1957 bool OrthancPeers::DoGet(Json::Value& target,
1801 size_t index, 1958 size_t index,
1802 const std::string& uri) const 1959 const std::string& uri,
1960 const std::map<std::string, std::string>& headers) const
1803 { 1961 {
1804 MemoryBuffer buffer; 1962 MemoryBuffer buffer;
1805 1963
1806 if (DoGet(buffer, index, uri)) 1964 if (DoGet(buffer, index, uri, headers))
1807 { 1965 {
1808 buffer.ToJson(target); 1966 buffer.ToJson(target);
1809 return true; 1967 return true;
1810 } 1968 }
1811 else 1969 else
1815 } 1973 }
1816 1974
1817 1975
1818 bool OrthancPeers::DoGet(Json::Value& target, 1976 bool OrthancPeers::DoGet(Json::Value& target,
1819 const std::string& name, 1977 const std::string& name,
1820 const std::string& uri) const 1978 const std::string& uri,
1979 const std::map<std::string, std::string>& headers) const
1821 { 1980 {
1822 MemoryBuffer buffer; 1981 MemoryBuffer buffer;
1823 1982
1824 if (DoGet(buffer, name, uri)) 1983 if (DoGet(buffer, name, uri, headers))
1825 { 1984 {
1826 buffer.ToJson(target); 1985 buffer.ToJson(target);
1827 return true; 1986 return true;
1828 } 1987 }
1829 else 1988 else
1834 1993
1835 1994
1836 bool OrthancPeers::DoPost(MemoryBuffer& target, 1995 bool OrthancPeers::DoPost(MemoryBuffer& target,
1837 const std::string& name, 1996 const std::string& name,
1838 const std::string& uri, 1997 const std::string& uri,
1839 const std::string& body) const 1998 const std::string& body,
1999 const std::map<std::string, std::string>& headers) const
1840 { 2000 {
1841 size_t index; 2001 size_t index;
1842 return (LookupName(index, name) && 2002 return (LookupName(index, name) &&
1843 DoPost(target, index, uri, body)); 2003 DoPost(target, index, uri, body, headers));
1844 } 2004 }
1845 2005
1846 2006
1847 bool OrthancPeers::DoPost(Json::Value& target, 2007 bool OrthancPeers::DoPost(Json::Value& target,
1848 size_t index, 2008 size_t index,
1849 const std::string& uri, 2009 const std::string& uri,
1850 const std::string& body) const 2010 const std::string& body,
2011 const std::map<std::string, std::string>& headers) const
1851 { 2012 {
1852 MemoryBuffer buffer; 2013 MemoryBuffer buffer;
1853 2014
1854 if (DoPost(buffer, index, uri, body)) 2015 if (DoPost(buffer, index, uri, body, headers))
1855 { 2016 {
1856 buffer.ToJson(target); 2017 buffer.ToJson(target);
1857 return true; 2018 return true;
1858 } 2019 }
1859 else 2020 else
1864 2025
1865 2026
1866 bool OrthancPeers::DoPost(Json::Value& target, 2027 bool OrthancPeers::DoPost(Json::Value& target,
1867 const std::string& name, 2028 const std::string& name,
1868 const std::string& uri, 2029 const std::string& uri,
1869 const std::string& body) const 2030 const std::string& body,
2031 const std::map<std::string, std::string>& headers) const
1870 { 2032 {
1871 MemoryBuffer buffer; 2033 MemoryBuffer buffer;
1872 2034
1873 if (DoPost(buffer, name, uri, body)) 2035 if (DoPost(buffer, name, uri, body, headers))
1874 { 2036 {
1875 buffer.ToJson(target); 2037 buffer.ToJson(target);
1876 return true; 2038 return true;
1877 } 2039 }
1878 else 2040 else
1883 2045
1884 2046
1885 bool OrthancPeers::DoPost(MemoryBuffer& target, 2047 bool OrthancPeers::DoPost(MemoryBuffer& target,
1886 size_t index, 2048 size_t index,
1887 const std::string& uri, 2049 const std::string& uri,
1888 const std::string& body) const 2050 const std::string& body,
2051 const std::map<std::string, std::string>& headers) const
1889 { 2052 {
1890 if (index >= index_.size()) 2053 if (index >= index_.size())
1891 { 2054 {
1892 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); 2055 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
2056 }
2057
2058 if (body.size() > 0xffffffffu)
2059 {
2060 LogError("Cannot handle body size > 4GB");
2061 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
1893 } 2062 }
1894 2063
1895 OrthancPlugins::MemoryBuffer answer; 2064 OrthancPlugins::MemoryBuffer answer;
1896 uint16_t status; 2065 uint16_t status;
2066 PluginHttpHeaders pluginHeaders(headers);
2067
1897 OrthancPluginErrorCode code = OrthancPluginCallPeerApi 2068 OrthancPluginErrorCode code = OrthancPluginCallPeerApi
1898 (GetGlobalContext(), *answer, NULL, &status, peers_, 2069 (GetGlobalContext(), *answer, NULL, &status, peers_,
1899 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(), 2070 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(),
1900 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); 2071 pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout_);
1901 2072
1902 if (code == OrthancPluginErrorCode_Success) 2073 if (code == OrthancPluginErrorCode_Success)
1903 { 2074 {
1904 target.Swap(answer); 2075 target.Swap(answer);
1905 return (status == 200); 2076 return (status == 200);
1911 } 2082 }
1912 2083
1913 2084
1914 bool OrthancPeers::DoPut(size_t index, 2085 bool OrthancPeers::DoPut(size_t index,
1915 const std::string& uri, 2086 const std::string& uri,
1916 const std::string& body) const 2087 const std::string& body,
2088 const std::map<std::string, std::string>& headers) const
1917 { 2089 {
1918 if (index >= index_.size()) 2090 if (index >= index_.size())
1919 { 2091 {
1920 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); 2092 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
2093 }
2094
2095 if (body.size() > 0xffffffffu)
2096 {
2097 LogError("Cannot handle body size > 4GB");
2098 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
1921 } 2099 }
1922 2100
1923 OrthancPlugins::MemoryBuffer answer; 2101 OrthancPlugins::MemoryBuffer answer;
1924 uint16_t status; 2102 uint16_t status;
2103 PluginHttpHeaders pluginHeaders(headers);
2104
1925 OrthancPluginErrorCode code = OrthancPluginCallPeerApi 2105 OrthancPluginErrorCode code = OrthancPluginCallPeerApi
1926 (GetGlobalContext(), *answer, NULL, &status, peers_, 2106 (GetGlobalContext(), *answer, NULL, &status, peers_,
1927 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Put, uri.c_str(), 2107 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Put, uri.c_str(),
1928 0, NULL, NULL, body.empty() ? NULL : body.c_str(), body.size(), timeout_); 2108 pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout_);
1929 2109
1930 if (code == OrthancPluginErrorCode_Success) 2110 if (code == OrthancPluginErrorCode_Success)
1931 { 2111 {
1932 return (status == 200); 2112 return (status == 200);
1933 } 2113 }
1938 } 2118 }
1939 2119
1940 2120
1941 bool OrthancPeers::DoPut(const std::string& name, 2121 bool OrthancPeers::DoPut(const std::string& name,
1942 const std::string& uri, 2122 const std::string& uri,
1943 const std::string& body) const 2123 const std::string& body,
2124 const std::map<std::string, std::string>& headers) const
1944 { 2125 {
1945 size_t index; 2126 size_t index;
1946 return (LookupName(index, name) && 2127 return (LookupName(index, name) &&
1947 DoPut(index, uri, body)); 2128 DoPut(index, uri, body, headers));
1948 } 2129 }
1949 2130
1950 2131
1951 bool OrthancPeers::DoDelete(size_t index, 2132 bool OrthancPeers::DoDelete(size_t index,
1952 const std::string& uri) const 2133 const std::string& uri,
2134 const std::map<std::string, std::string>& headers) const
1953 { 2135 {
1954 if (index >= index_.size()) 2136 if (index >= index_.size())
1955 { 2137 {
1956 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange); 2138 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_ParameterOutOfRange);
1957 } 2139 }
1958 2140
1959 OrthancPlugins::MemoryBuffer answer; 2141 OrthancPlugins::MemoryBuffer answer;
1960 uint16_t status; 2142 uint16_t status;
2143 PluginHttpHeaders pluginHeaders(headers);
2144
1961 OrthancPluginErrorCode code = OrthancPluginCallPeerApi 2145 OrthancPluginErrorCode code = OrthancPluginCallPeerApi
1962 (GetGlobalContext(), *answer, NULL, &status, peers_, 2146 (GetGlobalContext(), *answer, NULL, &status, peers_,
1963 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Delete, uri.c_str(), 2147 static_cast<uint32_t>(index), OrthancPluginHttpMethod_Delete, uri.c_str(),
1964 0, NULL, NULL, NULL, 0, timeout_); 2148 pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), NULL, 0, timeout_);
1965 2149
1966 if (code == OrthancPluginErrorCode_Success) 2150 if (code == OrthancPluginErrorCode_Success)
1967 { 2151 {
1968 return (status == 200); 2152 return (status == 200);
1969 } 2153 }
1973 } 2157 }
1974 } 2158 }
1975 2159
1976 2160
1977 bool OrthancPeers::DoDelete(const std::string& name, 2161 bool OrthancPeers::DoDelete(const std::string& name,
1978 const std::string& uri) const 2162 const std::string& uri,
2163 const std::map<std::string, std::string>& headers) const
1979 { 2164 {
1980 size_t index; 2165 size_t index;
1981 return (LookupName(index, name) && 2166 return (LookupName(index, name) &&
1982 DoDelete(index, uri)); 2167 DoDelete(index, uri, headers));
1983 } 2168 }
1984 #endif 2169 #endif
1985 2170
1986 2171
1987 2172
2014 return 0; 2199 return 0;
2015 } 2200 }
2016 } 2201 }
2017 2202
2018 2203
2204 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 11, 3)
2205 static OrthancPluginErrorCode CopyStringToMemoryBuffer(OrthancPluginMemoryBuffer* target,
2206 const std::string& source)
2207 {
2208 if (OrthancPluginCreateMemoryBuffer(globalContext_, target, source.size()) != OrthancPluginErrorCode_Success)
2209 {
2210 return OrthancPluginErrorCode_NotEnoughMemory;
2211 }
2212 else
2213 {
2214 if (!source.empty())
2215 {
2216 memcpy(target->data, source.c_str(), source.size());
2217 }
2218
2219 return OrthancPluginErrorCode_Success;
2220 }
2221 }
2222 #endif
2223
2224
2225 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 11, 3)
2226 OrthancPluginErrorCode OrthancJob::CallbackGetContent(OrthancPluginMemoryBuffer* target,
2227 void* job)
2228 {
2229 assert(job != NULL);
2230 OrthancJob& that = *reinterpret_cast<OrthancJob*>(job);
2231 return CopyStringToMemoryBuffer(target, that.content_);
2232 }
2233 #else
2019 const char* OrthancJob::CallbackGetContent(void* job) 2234 const char* OrthancJob::CallbackGetContent(void* job)
2020 { 2235 {
2021 assert(job != NULL); 2236 assert(job != NULL);
2022 2237
2023 try 2238 try
2027 catch (...) 2242 catch (...)
2028 { 2243 {
2029 return 0; 2244 return 0;
2030 } 2245 }
2031 } 2246 }
2032 2247 #endif
2033 2248
2249
2250 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 11, 3)
2251 int32_t OrthancJob::CallbackGetSerialized(OrthancPluginMemoryBuffer* target,
2252 void* job)
2253 {
2254 assert(job != NULL);
2255 OrthancJob& that = *reinterpret_cast<OrthancJob*>(job);
2256
2257 if (that.hasSerialized_)
2258 {
2259 if (CopyStringToMemoryBuffer(target, that.serialized_) == OrthancPluginErrorCode_Success)
2260 {
2261 return 1;
2262 }
2263 else
2264 {
2265 return -1;
2266 }
2267 }
2268 else
2269 {
2270 return 0;
2271 }
2272 }
2273 #else
2034 const char* OrthancJob::CallbackGetSerialized(void* job) 2274 const char* OrthancJob::CallbackGetSerialized(void* job)
2035 { 2275 {
2036 assert(job != NULL); 2276 assert(job != NULL);
2037 2277
2038 try 2278 try
2051 catch (...) 2291 catch (...)
2052 { 2292 {
2053 return 0; 2293 return 0;
2054 } 2294 }
2055 } 2295 }
2296 #endif
2056 2297
2057 2298
2058 OrthancPluginJobStepStatus OrthancJob::CallbackStep(void* job) 2299 OrthancPluginJobStepStatus OrthancJob::CallbackStep(void* job)
2059 { 2300 {
2060 assert(job != NULL); 2301 assert(job != NULL);
2182 if (job == NULL) 2423 if (job == NULL)
2183 { 2424 {
2184 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer); 2425 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_NullPointer);
2185 } 2426 }
2186 2427
2187 OrthancPluginJob* orthanc = OrthancPluginCreateJob( 2428 OrthancPluginJob* orthanc =
2188 GetGlobalContext(), job, CallbackFinalize, job->jobType_.c_str(), 2429 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 11, 3)
2189 CallbackGetProgress, CallbackGetContent, CallbackGetSerialized, 2430 OrthancPluginCreateJob2
2190 CallbackStep, CallbackStop, CallbackReset); 2431 #else
2432 OrthancPluginCreateJob
2433 #endif
2434 (GetGlobalContext(), job, CallbackFinalize, job->jobType_.c_str(),
2435 CallbackGetProgress, CallbackGetContent, CallbackGetSerialized,
2436 CallbackStep, CallbackStop, CallbackReset);
2191 2437
2192 if (orthanc == NULL) 2438 if (orthanc == NULL)
2193 { 2439 {
2194 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin); 2440 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(OrthancPluginErrorCode_Plugin);
2195 } 2441 }
2481 { 2727 {
2482 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); 2728 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
2483 } 2729 }
2484 catch (...) 2730 catch (...)
2485 { 2731 {
2486 return OrthancPluginErrorCode_InternalError; 2732 return OrthancPluginErrorCode_Plugin;
2487 } 2733 }
2488 } 2734 }
2489 } 2735 }
2490 }; 2736 };
2491 2737
2567 } 2813 }
2568 2814
2569 2815
2570 void HttpClient::ClearCredentials() 2816 void HttpClient::ClearCredentials()
2571 { 2817 {
2572 username_.empty(); 2818 username_.clear();
2573 password_.empty(); 2819 password_.clear();
2574 } 2820 }
2575 2821
2576 2822
2577 void HttpClient::SetCertificate(const std::string& certificateFile, 2823 void HttpClient::SetCertificate(const std::string& certificateFile,
2578 const std::string& keyFile, 2824 const std::string& keyFile,
2881 { 3127 {
2882 HeadersWrapper headers(headers_); 3128 HeadersWrapper headers(headers_);
2883 3129
2884 MemoryBuffer answerBodyBuffer, answerHeadersBuffer; 3130 MemoryBuffer answerBodyBuffer, answerHeadersBuffer;
2885 3131
3132 if (body.size() > 0xffffffffu)
3133 {
3134 LogError("Cannot handle body size > 4GB");
3135 ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
3136 }
3137
2886 OrthancPluginErrorCode error = OrthancPluginHttpClient( 3138 OrthancPluginErrorCode error = OrthancPluginHttpClient(
2887 GetGlobalContext(), 3139 GetGlobalContext(),
2888 *answerBodyBuffer, 3140 *answerBodyBuffer,
2889 *answerHeadersBuffer, 3141 *answerHeadersBuffer,
2890 &httpStatus, 3142 &httpStatus,
3497 result->toFree_ = true; 3749 result->toFree_ = true;
3498 return result.release(); 3750 return result.release();
3499 } 3751 }
3500 } 3752 }
3501 #endif 3753 #endif
3754
3755
3756 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 1)
3757 DicomInstance* DicomInstance::Load(const std::string& instanceId,
3758 OrthancPluginLoadDicomInstanceMode mode)
3759 {
3760 OrthancPluginDicomInstance* instance = OrthancPluginLoadDicomInstance(
3761 GetGlobalContext(), instanceId.c_str(), mode);
3762
3763 if (instance == NULL)
3764 {
3765 ORTHANC_PLUGINS_THROW_EXCEPTION(Plugin);
3766 }
3767 else
3768 {
3769 boost::movelib::unique_ptr<DicomInstance> result(new DicomInstance(instance));
3770 result->toFree_ = true;
3771 return result.release();
3772 }
3773 }
3774 #endif
3775
3776
3777 #if HAS_ORTHANC_PLUGIN_WEBDAV == 1
3778 static std::vector<std::string> WebDavConvertPath(uint32_t pathSize,
3779 const char* const* pathItems)
3780 {
3781 std::vector<std::string> result(pathSize);
3782
3783 for (uint32_t i = 0; i < pathSize; i++)
3784 {
3785 result[i] = pathItems[i];
3786 }
3787
3788 return result;
3789 }
3790 #endif
3791
3792
3793 #if HAS_ORTHANC_PLUGIN_WEBDAV == 1
3794 static OrthancPluginErrorCode WebDavIsExistingFolder(uint8_t* isExisting,
3795 uint32_t pathSize,
3796 const char* const* pathItems,
3797 void* payload)
3798 {
3799 IWebDavCollection& that = *reinterpret_cast<IWebDavCollection*>(payload);
3800
3801 try
3802 {
3803 *isExisting = (that.IsExistingFolder(WebDavConvertPath(pathSize, pathItems)) ? 1 : 0);
3804 return OrthancPluginErrorCode_Success;
3805 }
3806 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
3807 {
3808 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
3809 }
3810 catch (...)
3811 {
3812 return OrthancPluginErrorCode_Plugin;
3813 }
3814 }
3815 #endif
3816
3817
3818 #if HAS_ORTHANC_PLUGIN_WEBDAV == 1
3819 static OrthancPluginErrorCode WebDavListFolder(uint8_t* isExisting,
3820 OrthancPluginWebDavCollection* collection,
3821 OrthancPluginWebDavAddFile addFile,
3822 OrthancPluginWebDavAddFolder addFolder,
3823 uint32_t pathSize,
3824 const char* const* pathItems,
3825 void* payload)
3826 {
3827 IWebDavCollection& that = *reinterpret_cast<IWebDavCollection*>(payload);
3828
3829 try
3830 {
3831 std::list<IWebDavCollection::FileInfo> files;
3832 std::list<IWebDavCollection::FolderInfo> subfolders;
3833
3834 if (!that.ListFolder(files, subfolders, WebDavConvertPath(pathSize, pathItems)))
3835 {
3836 *isExisting = 0;
3837 }
3838 else
3839 {
3840 *isExisting = 1;
3841
3842 for (std::list<IWebDavCollection::FileInfo>::const_iterator
3843 it = files.begin(); it != files.end(); ++it)
3844 {
3845 OrthancPluginErrorCode code = addFile(
3846 collection, it->GetName().c_str(), it->GetContentSize(),
3847 it->GetMimeType().c_str(), it->GetDateTime().c_str());
3848
3849 if (code != OrthancPluginErrorCode_Success)
3850 {
3851 return code;
3852 }
3853 }
3854
3855 for (std::list<IWebDavCollection::FolderInfo>::const_iterator it =
3856 subfolders.begin(); it != subfolders.end(); ++it)
3857 {
3858 OrthancPluginErrorCode code = addFolder(
3859 collection, it->GetName().c_str(), it->GetDateTime().c_str());
3860
3861 if (code != OrthancPluginErrorCode_Success)
3862 {
3863 return code;
3864 }
3865 }
3866 }
3867
3868 return OrthancPluginErrorCode_Success;
3869 }
3870 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
3871 {
3872 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
3873 }
3874 catch (...)
3875 {
3876 return OrthancPluginErrorCode_Plugin;
3877 }
3878 }
3879 #endif
3880
3881
3882 #if HAS_ORTHANC_PLUGIN_WEBDAV == 1
3883 static OrthancPluginErrorCode WebDavRetrieveFile(OrthancPluginWebDavCollection* collection,
3884 OrthancPluginWebDavRetrieveFile retrieveFile,
3885 uint32_t pathSize,
3886 const char* const* pathItems,
3887 void* payload)
3888 {
3889 IWebDavCollection& that = *reinterpret_cast<IWebDavCollection*>(payload);
3890
3891 try
3892 {
3893 std::string content, mime, dateTime;
3894
3895 if (that.GetFile(content, mime, dateTime, WebDavConvertPath(pathSize, pathItems)))
3896 {
3897 return retrieveFile(collection, content.empty() ? NULL : content.c_str(),
3898 content.size(), mime.c_str(), dateTime.c_str());
3899 }
3900 else
3901 {
3902 // Inexisting file
3903 return OrthancPluginErrorCode_Success;
3904 }
3905 }
3906 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
3907 {
3908 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
3909 }
3910 catch (...)
3911 {
3912 return OrthancPluginErrorCode_InternalError;
3913 }
3914 }
3915 #endif
3916
3917
3918 #if HAS_ORTHANC_PLUGIN_WEBDAV == 1
3919 static OrthancPluginErrorCode WebDavStoreFileCallback(uint8_t* isReadOnly, /* out */
3920 uint32_t pathSize,
3921 const char* const* pathItems,
3922 const void* data,
3923 uint64_t size,
3924 void* payload)
3925 {
3926 IWebDavCollection& that = *reinterpret_cast<IWebDavCollection*>(payload);
3927
3928 try
3929 {
3930 if (static_cast<uint64_t>(static_cast<size_t>(size)) != size)
3931 {
3932 ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
3933 }
3934
3935 *isReadOnly = (that.StoreFile(WebDavConvertPath(pathSize, pathItems), data,
3936 static_cast<size_t>(size)) ? 1 : 0);
3937 return OrthancPluginErrorCode_Success;
3938 }
3939 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
3940 {
3941 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
3942 }
3943 catch (...)
3944 {
3945 return OrthancPluginErrorCode_InternalError;
3946 }
3947 }
3948 #endif
3949
3950
3951 #if HAS_ORTHANC_PLUGIN_WEBDAV == 1
3952 static OrthancPluginErrorCode WebDavCreateFolderCallback(uint8_t* isReadOnly, /* out */
3953 uint32_t pathSize,
3954 const char* const* pathItems,
3955 void* payload)
3956 {
3957 IWebDavCollection& that = *reinterpret_cast<IWebDavCollection*>(payload);
3958
3959 try
3960 {
3961 *isReadOnly = (that.CreateFolder(WebDavConvertPath(pathSize, pathItems)) ? 1 : 0);
3962 return OrthancPluginErrorCode_Success;
3963 }
3964 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
3965 {
3966 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
3967 }
3968 catch (...)
3969 {
3970 return OrthancPluginErrorCode_InternalError;
3971 }
3972 }
3973 #endif
3974
3975
3976 #if HAS_ORTHANC_PLUGIN_WEBDAV == 1
3977 static OrthancPluginErrorCode WebDavDeleteItemCallback(uint8_t* isReadOnly, /* out */
3978 uint32_t pathSize,
3979 const char* const* pathItems,
3980 void* payload)
3981 {
3982 IWebDavCollection& that = *reinterpret_cast<IWebDavCollection*>(payload);
3983
3984 try
3985 {
3986 *isReadOnly = (that.DeleteItem(WebDavConvertPath(pathSize, pathItems)) ? 1 : 0);
3987 return OrthancPluginErrorCode_Success;
3988 }
3989 catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e)
3990 {
3991 return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
3992 }
3993 catch (...)
3994 {
3995 return OrthancPluginErrorCode_InternalError;
3996 }
3997 }
3998 #endif
3999
4000
4001 #if HAS_ORTHANC_PLUGIN_WEBDAV == 1
4002 void IWebDavCollection::Register(const std::string& uri,
4003 IWebDavCollection& collection)
4004 {
4005 OrthancPluginErrorCode code = OrthancPluginRegisterWebDavCollection(
4006 GetGlobalContext(), uri.c_str(), WebDavIsExistingFolder, WebDavListFolder, WebDavRetrieveFile,
4007 WebDavStoreFileCallback, WebDavCreateFolderCallback, WebDavDeleteItemCallback, &collection);
4008
4009 if (code != OrthancPluginErrorCode_Success)
4010 {
4011 ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
4012 }
4013 }
4014 #endif
4015
4016 void GetHttpHeaders(std::map<std::string, std::string>& result, const OrthancPluginHttpRequest* request)
4017 {
4018 result.clear();
4019
4020 for (uint32_t i = 0; i < request->headersCount; ++i)
4021 {
4022 result[request->headersKeys[i]] = request->headersValues[i];
4023 }
4024 }
3502 } 4025 }