comparison Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp @ 49:c71a008fc1e3

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