You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

501 lines
18 KiB

  1. From a13f3588f78e9ffda5e915f44cbf1957f12513c4 Mon Sep 17 00:00:00 2001
  2. From: Jean-Francois Dockes <jf@dockes.org>
  3. Date: Fri, 13 Mar 2020 09:19:04 +0100
  4. Subject: [PATCH] Quick changes for working with NPUPNP
  5. (Rebased and made default)
  6. Signed-off-by: Rosen Penev <rosenp@gmail.com>
  7. ---
  8. CMakeLists.txt | 43 +++++++++++++++++-------
  9. src/action_request.cc | 11 +++++-
  10. src/device_description_handler.cc | 4 +++
  11. src/file_request_handler.cc | 4 +++
  12. src/iohandler/file_io_handler.cc | 1 -
  13. src/iohandler/io_handler.cc | 1 -
  14. src/iohandler/mem_io_handler.cc | 1 -
  15. src/serve_request_handler.cc | 8 +++++
  16. src/server.cc | 8 +++++
  17. src/transcoding/transcode_ext_handler.cc | 1 -
  18. src/upnp_cds.cc | 11 ++++++
  19. src/upnp_cm.cc | 11 ++++++
  20. src/upnp_mrreg.cc | 7 +++-
  21. src/url_request_handler.cc | 5 ++-
  22. src/util/upnp_clients.cc | 12 +++++++
  23. src/util/upnp_headers.cc | 12 +++++++
  24. src/web/web_request_handler.cc | 4 +++
  25. 17 files changed, 124 insertions(+), 20 deletions(-)
  26. diff --git a/CMakeLists.txt b/CMakeLists.txt
  27. index 8b6db993..b23dad57 100644
  28. --- a/CMakeLists.txt
  29. +++ b/CMakeLists.txt
  30. @@ -35,6 +35,7 @@ if (CONAN_EXPORTED)
  31. endif()
  32. set(CMAKE_VERBOSE_MAKEFILE off CACHE BOOL "Show verbose build commands")
  33. +set(WITH_NPUPNP 0 CACHE BOOL "Use npupnp instead of pupnp")
  34. set(WITH_MAGIC 1 CACHE BOOL "Use libmagic to identify file mime types")
  35. set(WITH_MYSQL 0 CACHE BOOL "Store media information in MySQL DB")
  36. set(WITH_CURL 1 CACHE BOOL "CURL required for online services")
  37. @@ -303,23 +304,39 @@ add_definitions(${LFS_DEFINITIONS})
  38. add_compile_options(${LFS_COMPILE_OPTIONS})
  39. target_link_libraries(libgerbera ${LFS_LIBRARIES})
  40. -find_package (pupnp "1.12.1" REQUIRED)
  41. +if (WITH_NPUPNP)
  42. + find_package(PkgConfig QUIET)
  43. + pkg_check_modules (NPUPNP QUIET libnpupnp>=4.0.11)
  44. + if (NOT NPUPNP_FOUND)
  45. + find_package (NPUPNP REQUIRED)
  46. + endif()
  47. + if (NPUPNP_FOUND)
  48. + include_directories (${NPUPNP_INCLUDE_DIRS})
  49. + set(CMAKE_REQUIRED_LIBRARIES npupnp)
  50. + add_definitions(-DUSING_NPUPNP)
  51. + target_link_libraries (libgerbera ${NPUPNP_LIBRARIES})
  52. + else()
  53. + message(FATAL_ERROR "libnpupnp not found")
  54. + endif()
  55. +else()
  56. + find_package (pupnp "1.12.1" REQUIRED)
  57. -set(CMAKE_REQUIRED_LIBRARIES pupnp::pupnp)
  58. + set(CMAKE_REQUIRED_LIBRARIES pupnp::pupnp)
  59. -check_cxx_symbol_exists(UPNP_ENABLE_IPV6 "upnpconfig.h" UPNP_HAS_IPV6)
  60. -if (NOT UPNP_HAS_IPV6)
  61. - message(FATAL_ERROR "Gerbera requires libupnp with IPv6 support.")
  62. -endif()
  63. + check_cxx_symbol_exists(UPNP_ENABLE_IPV6 "upnpconfig.h" UPNP_HAS_IPV6)
  64. + if (NOT UPNP_HAS_IPV6)
  65. + message(FATAL_ERROR "Gerbera requires libupnp with IPv6 support.")
  66. + endif()
  67. -check_cxx_symbol_exists(UPNP_MINISERVER_REUSEADDR "upnpconfig.h" UPNP_HAS_REUSEADDR)
  68. -if (NOT UPNP_HAS_REUSEADDR)
  69. - message(WARNING [=[
  70. -!! It is strongly recommended to build libupnp with --enable-reuseaddr !!
  71. -Without this option Gerbera will be unable to restart with the same port number.]=])
  72. -endif()
  73. + check_cxx_symbol_exists(UPNP_MINISERVER_REUSEADDR "upnpconfig.h" UPNP_HAS_REUSEADDR)
  74. + if (NOT UPNP_HAS_REUSEADDR)
  75. + message(WARNING [=[
  76. + !! It is strongly recommended to build libupnp with --enable-reuseaddr !!
  77. + Without this option Gerbera will be unable to restart with the same port number.]=])
  78. + endif()
  79. -target_link_libraries (libgerbera pupnp::pupnp)
  80. + target_link_libraries (libgerbera pupnp::pupnp)
  81. +endif()
  82. find_package(fmt REQUIRED)
  83. target_link_libraries(libgerbera fmt::fmt)
  84. diff --git a/src/action_request.cc b/src/action_request.cc
  85. index fab0e910..5677e61e 100644
  86. --- a/src/action_request.cc
  87. +++ b/src/action_request.cc
  88. @@ -65,10 +65,14 @@ std::string ActionRequest::getServiceID() const
  89. std::unique_ptr<pugi::xml_document> ActionRequest::getRequest() const
  90. {
  91. - DOMString cxml = ixmlPrintDocument(UpnpActionRequest_get_ActionRequest(upnp_request));
  92. auto request = std::make_unique<pugi::xml_document>();
  93. +#if defined(USING_NPUPNP)
  94. + auto ret = request->load_string(upnp_request->xmlAction.c_str());
  95. +#else
  96. + DOMString cxml = ixmlPrintDocument(UpnpActionRequest_get_ActionRequest(upnp_request));
  97. auto ret = request->load_string(cxml);
  98. ixmlFreeDOMString(cxml);
  99. +#endif
  100. if (ret.status != pugi::xml_parse_status::status_ok)
  101. throw_std_runtime_error("Unable to parse ixml");
  102. @@ -94,6 +98,10 @@ void ActionRequest::update()
  103. std::string xml = buf.str();
  104. log_debug("ActionRequest::update(): {}", xml.c_str());
  105. +#if defined(USING_NPUPNP)
  106. + UpnpActionRequest_set_xmlResponse(upnp_request, xml);
  107. + UpnpActionRequest_set_ErrCode(upnp_request, errCode);
  108. +#else
  109. IXML_Document* result = nullptr;
  110. int err = ixmlParseBufferEx(xml.c_str(), &result);
  111. @@ -105,6 +113,7 @@ void ActionRequest::update()
  112. UpnpActionRequest_set_ActionResult(upnp_request, result);
  113. UpnpActionRequest_set_ErrCode(upnp_request, errCode);
  114. }
  115. +#endif
  116. } else {
  117. // ok, here there can be two cases
  118. // either the function below already did set an error code,
  119. diff --git a/src/device_description_handler.cc b/src/device_description_handler.cc
  120. index 6aca745e..cf2e8015 100644
  121. --- a/src/device_description_handler.cc
  122. +++ b/src/device_description_handler.cc
  123. @@ -45,7 +45,11 @@ void DeviceDescriptionHandler::getInfo(const char* filename, UpnpFileInfo* info)
  124. {
  125. // We should be able to do the generation here, but libupnp doesnt support the request cookies yet
  126. UpnpFileInfo_set_FileLength(info, -1);
  127. +#if defined(USING_NPUPNP)
  128. UpnpFileInfo_set_ContentType(info, "application/xml");
  129. +#else
  130. + UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString("application/xml"));
  131. +#endif
  132. UpnpFileInfo_set_IsReadable(info, 1);
  133. UpnpFileInfo_set_IsDirectory(info, 0);
  134. }
  135. diff --git a/src/file_request_handler.cc b/src/file_request_handler.cc
  136. index cfa3eaed..915e411b 100644
  137. --- a/src/file_request_handler.cc
  138. +++ b/src/file_request_handler.cc
  139. @@ -238,7 +238,11 @@ void FileRequestHandler::getInfo(const char* filename, UpnpFileInfo* info)
  140. UpnpFileInfo_set_LastModified(info, statbuf.st_mtime);
  141. UpnpFileInfo_set_IsDirectory(info, S_ISDIR(statbuf.st_mode));
  142. +#if defined(USING_NPUPNP)
  143. + UpnpFileInfo_set_ContentType(info, mimeType);
  144. +#else
  145. UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(mimeType.c_str()));
  146. +#endif
  147. headers->writeHeaders(info);
  148. diff --git a/src/iohandler/file_io_handler.cc b/src/iohandler/file_io_handler.cc
  149. index 7e239250..b023e85b 100644
  150. --- a/src/iohandler/file_io_handler.cc
  151. +++ b/src/iohandler/file_io_handler.cc
  152. @@ -32,7 +32,6 @@
  153. #include "file_io_handler.h" // API
  154. #include <cstdio>
  155. -#include <ixml.h>
  156. #include <utility>
  157. #include "cds_objects.h"
  158. diff --git a/src/iohandler/io_handler.cc b/src/iohandler/io_handler.cc
  159. index f9789425..1153ce6b 100644
  160. --- a/src/iohandler/io_handler.cc
  161. +++ b/src/iohandler/io_handler.cc
  162. @@ -31,7 +31,6 @@
  163. #include "io_handler.h" // API
  164. -#include <ixml.h>
  165. #include <unistd.h>
  166. #include "server.h"
  167. diff --git a/src/iohandler/mem_io_handler.cc b/src/iohandler/mem_io_handler.cc
  168. index 5574a16d..223746ef 100644
  169. --- a/src/iohandler/mem_io_handler.cc
  170. +++ b/src/iohandler/mem_io_handler.cc
  171. @@ -35,7 +35,6 @@
  172. #include <cstdlib>
  173. #include <cstring>
  174. #include <ctime>
  175. -#include <ixml.h>
  176. #include <sys/stat.h>
  177. #include <sys/types.h>
  178. #include <unistd.h>
  179. diff --git a/src/serve_request_handler.cc b/src/serve_request_handler.cc
  180. index 59f37252..42d07e94 100644
  181. --- a/src/serve_request_handler.cc
  182. +++ b/src/serve_request_handler.cc
  183. @@ -94,7 +94,11 @@ void ServeRequestHandler::getInfo(const char* filename, UpnpFileInfo* info)
  184. UpnpFileInfo_set_IsReadable(info, 0);
  185. }
  186. +#if defined(USING_NPUPNP)
  187. + UpnpFileInfo_set_ContentType(info, mimetype);
  188. +#else
  189. UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(mimetype.c_str()));
  190. +#endif
  191. } else {
  192. throw_std_runtime_error("Not a regular file: " + path);
  193. }
  194. @@ -158,7 +162,11 @@ std::unique_ptr<IOHandler> ServeRequestHandler::open(const char* filename,
  195. }
  196. +#if defined(USING_NPUPNP)
  197. + info->content_type = mimetype;
  198. +#else
  199. info->content_type = ixmlCloneDOMString(mimetype.c_str());
  200. +#endif
  201. */
  202. } else {
  203. throw_std_runtime_error("Not a regular file: " + path);
  204. diff --git a/src/server.cc b/src/server.cc
  205. index a83c28cd..d4ce3e51 100644
  206. --- a/src/server.cc
  207. +++ b/src/server.cc
  208. @@ -393,9 +393,17 @@ int Server::handleUpnpClientEvent(Upnp_EventType eventType, const void* event)
  209. case UPNP_DISCOVERY_ADVERTISEMENT_ALIVE:
  210. case UPNP_DISCOVERY_SEARCH_RESULT: {
  211. auto d_event = reinterpret_cast<const UpnpDiscovery*>(event);
  212. +#if defined(USING_NPUPNP)
  213. + const char* userAgent = UpnpDiscovery_get_Os_cstr(d_event);
  214. +#else
  215. const char* userAgent = UpnpString_get_String(UpnpDiscovery_get_Os(d_event));
  216. +#endif
  217. const struct sockaddr_storage* destAddr = UpnpDiscovery_get_DestAddr(d_event);
  218. +#if defined(USING_NPUPNP)
  219. + const char* location = UpnpDiscovery_get_Location_cstr(d_event);
  220. +#else
  221. const char* location = UpnpString_get_String(UpnpDiscovery_get_Location(d_event));
  222. +#endif
  223. Clients::addClientByDiscovery(destAddr, userAgent, location);
  224. break;
  225. diff --git a/src/transcoding/transcode_ext_handler.cc b/src/transcoding/transcode_ext_handler.cc
  226. index 67ee79d9..1da59ea2 100644
  227. --- a/src/transcoding/transcode_ext_handler.cc
  228. +++ b/src/transcoding/transcode_ext_handler.cc
  229. @@ -37,7 +37,6 @@
  230. #include <cstring>
  231. #include <fcntl.h>
  232. #include <filesystem>
  233. -#include <ixml.h>
  234. #include <sys/stat.h>
  235. #include <sys/types.h>
  236. #include <unistd.h>
  237. diff --git a/src/upnp_cds.cc b/src/upnp_cds.cc
  238. index 12ffeea2..5c2e1043 100644
  239. --- a/src/upnp_cds.cc
  240. +++ b/src/upnp_cds.cc
  241. @@ -284,6 +284,11 @@ void ContentDirectoryService::processSubscriptionRequest(const std::unique_ptr<S
  242. propset->print(buf, "", 0);
  243. std::string xml = buf.str();
  244. +#if defined(USING_NPUPNP)
  245. + UpnpAcceptSubscriptionXML(
  246. + deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
  247. + DESC_CDS_SERVICE_ID, xml, request->getSubscriptionID().c_str());
  248. +#else
  249. IXML_Document* event = nullptr;
  250. int err = ixmlParseBufferEx(xml.c_str(), &event);
  251. if (err != IXML_SUCCESS) {
  252. @@ -295,6 +300,7 @@ void ContentDirectoryService::processSubscriptionRequest(const std::unique_ptr<S
  253. DESC_CDS_SERVICE_ID, event, request->getSubscriptionID().c_str());
  254. ixmlDocument_free(event);
  255. +#endif
  256. log_debug("end");
  257. }
  258. @@ -313,6 +319,10 @@ void ContentDirectoryService::sendSubscriptionUpdate(const std::string& containe
  259. propset->print(buf, "", 0);
  260. std::string xml = buf.str();
  261. +#if defined(USING_NPUPNP)
  262. + UpnpNotifyXML(deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
  263. + DESC_CDS_SERVICE_ID, xml);
  264. +#else
  265. IXML_Document* event = nullptr;
  266. int err = ixmlParseBufferEx(xml.c_str(), &event);
  267. if (err != IXML_SUCCESS) {
  268. @@ -325,6 +335,7 @@ void ContentDirectoryService::sendSubscriptionUpdate(const std::string& containe
  269. DESC_CDS_SERVICE_ID, event);
  270. ixmlDocument_free(event);
  271. +#endif
  272. log_debug("end");
  273. }
  274. diff --git a/src/upnp_cm.cc b/src/upnp_cm.cc
  275. index aa608480..d7ab40cf 100644
  276. --- a/src/upnp_cm.cc
  277. +++ b/src/upnp_cm.cc
  278. @@ -127,6 +127,11 @@ void ConnectionManagerService::processSubscriptionRequest(const std::unique_ptr<
  279. propset->print(buf, "", 0);
  280. std::string xml = buf.str();
  281. +#if defined(USING_NPUPNP)
  282. + UpnpAcceptSubscriptionXML(
  283. + deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
  284. + DESC_CM_SERVICE_ID, xml, request->getSubscriptionID().c_str());
  285. +#else
  286. IXML_Document* event = nullptr;
  287. int err = ixmlParseBufferEx(xml.c_str(), &event);
  288. if (err != IXML_SUCCESS) {
  289. @@ -138,6 +143,7 @@ void ConnectionManagerService::processSubscriptionRequest(const std::unique_ptr<
  290. DESC_CM_SERVICE_ID, event, request->getSubscriptionID().c_str());
  291. ixmlDocument_free(event);
  292. +#endif
  293. }
  294. void ConnectionManagerService::sendSubscriptionUpdate(const std::string& sourceProtocol_CSV)
  295. @@ -150,6 +156,10 @@ void ConnectionManagerService::sendSubscriptionUpdate(const std::string& sourceP
  296. propset->print(buf, "", 0);
  297. std::string xml = buf.str();
  298. +#if defined(USING_NPUPNP)
  299. + UpnpNotifyXML(deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
  300. + DESC_CM_SERVICE_ID, xml);
  301. +#else
  302. IXML_Document* event = nullptr;
  303. int err = ixmlParseBufferEx(xml.c_str(), &event);
  304. if (err != IXML_SUCCESS) {
  305. @@ -162,4 +172,5 @@ void ConnectionManagerService::sendSubscriptionUpdate(const std::string& sourceP
  306. DESC_CM_SERVICE_ID, event);
  307. ixmlDocument_free(event);
  308. +#endif
  309. }
  310. diff --git a/src/upnp_mrreg.cc b/src/upnp_mrreg.cc
  311. index 16eefaed..ecb49025 100644
  312. --- a/src/upnp_mrreg.cc
  313. +++ b/src/upnp_mrreg.cc
  314. @@ -34,7 +34,6 @@
  315. #include <utility>
  316. #include "config/config_manager.h"
  317. -#include "ixml.h"
  318. #include "server.h"
  319. #include "storage/storage.h"
  320. #include "upnp_xml.h"
  321. @@ -120,6 +119,11 @@ void MRRegistrarService::processSubscriptionRequest(const std::unique_ptr<Subscr
  322. propset->print(buf, "", 0);
  323. std::string xml = buf.str();
  324. +#if defined(USING_NPUPNP)
  325. + UpnpAcceptSubscriptionXML(
  326. + deviceHandle, config->getOption(CFG_SERVER_UDN).c_str(),
  327. + DESC_MRREG_SERVICE_ID, xml, request->getSubscriptionID().c_str());
  328. +#else
  329. IXML_Document* event = nullptr;
  330. int err = ixmlParseBufferEx(xml.c_str(), &event);
  331. if (err != IXML_SUCCESS) {
  332. @@ -131,6 +135,7 @@ void MRRegistrarService::processSubscriptionRequest(const std::unique_ptr<Subscr
  333. DESC_MRREG_SERVICE_ID, event, request->getSubscriptionID().c_str());
  334. ixmlDocument_free(event);
  335. +#endif
  336. }
  337. // TODO: FIXME
  338. diff --git a/src/url_request_handler.cc b/src/url_request_handler.cc
  339. index f2a99c94..7de2227d 100644
  340. --- a/src/url_request_handler.cc
  341. +++ b/src/url_request_handler.cc
  342. @@ -32,7 +32,6 @@
  343. #ifdef HAVE_CURL
  344. #include "url_request_handler.h" // API
  345. -#include <ixml.h>
  346. #include <utility>
  347. #include "config/config_manager.h"
  348. @@ -138,7 +137,11 @@ void URLRequestHandler::getInfo(const char* filename, UpnpFileInfo* info)
  349. // ixmlCloneDOMString(header.c_str()));
  350. // }
  351. +#if defined(USING_NPUPNP)
  352. + UpnpFileInfo_set_ContentType(info, mimeType);
  353. +#else
  354. UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(mimeType.c_str()));
  355. +#endif
  356. log_debug("web_get_info(): end");
  357. /// \todo transcoding for get_info
  358. diff --git a/src/util/upnp_clients.cc b/src/util/upnp_clients.cc
  359. index 6fd40de2..28f0fb16 100644
  360. --- a/src/util/upnp_clients.cc
  361. +++ b/src/util/upnp_clients.cc
  362. @@ -262,6 +262,17 @@ bool Clients::getInfoByType(const std::string& match, ClientMatchType type, cons
  363. bool Clients::downloadDescription(const std::string& location, std::unique_ptr<pugi::xml_document>& xml)
  364. {
  365. +#if defined(USING_NPUPNP)
  366. + std::string description, ct;
  367. + int errCode = UpnpDownloadUrlItem(location, description, ct);
  368. + if (errCode != UPNP_E_SUCCESS) {
  369. + log_debug("Error obtaining client description from {} -- error = {}", location, errCode);
  370. + return false;
  371. + }
  372. + const char* cxml = description.c_str();
  373. + xml = std::make_unique<pugi::xml_document>();
  374. + auto ret = xml->load_string(cxml);
  375. +#else
  376. IXML_Document* descDoc = nullptr;
  377. int errCode = UpnpDownloadXmlDoc(location.c_str(), &descDoc);
  378. if (errCode != UPNP_E_SUCCESS) {
  379. @@ -275,6 +286,7 @@ bool Clients::downloadDescription(const std::string& location, std::unique_ptr<p
  380. ixmlFreeDOMString(cxml);
  381. ixmlDocument_free(descDoc);
  382. +#endif
  383. if (ret.status != pugi::xml_parse_status::status_ok) {
  384. log_debug("Unable to parse xml client description from {}", location);
  385. diff --git a/src/util/upnp_headers.cc b/src/util/upnp_headers.cc
  386. index 6eddedec..b7763444 100644
  387. --- a/src/util/upnp_headers.cc
  388. +++ b/src/util/upnp_headers.cc
  389. @@ -25,11 +25,13 @@
  390. #include "upnp_headers.h" // API
  391. +#if !defined(USING_NPUPNP)
  392. #if (UPNP_VERSION > 11299)
  393. #include <UpnpExtraHeaders.h>
  394. #else
  395. #include <ExtraHeaders.h>
  396. #endif
  397. +#endif
  398. #include <string>
  399. #include "common.h"
  400. @@ -101,18 +103,27 @@ void Headers::writeHeaders(UpnpFileInfo* fileInfo) const
  401. if (headers == nullptr)
  402. return;
  403. +#if defined(USING_NPUPNP)
  404. + std::copy(headers->begin(), headers->end(), std::back_inserter(fileInfo->response_headers));
  405. +#else
  406. auto head = const_cast<UpnpListHead*>(UpnpFileInfo_get_ExtraHeadersList(fileInfo));
  407. for (const auto& iter : *headers) {
  408. UpnpExtraHeaders* h = UpnpExtraHeaders_new();
  409. UpnpExtraHeaders_set_resp(h, formatHeader(iter, false).c_str());
  410. UpnpListInsert(head, UpnpListEnd(head), const_cast<UpnpListHead*>(UpnpExtraHeaders_get_node(h)));
  411. }
  412. +#endif
  413. }
  414. std::unique_ptr<std::map<std::string, std::string>> Headers::readHeaders(UpnpFileInfo* fileInfo)
  415. {
  416. auto ret = std::make_unique<std::map<std::string, std::string>>();
  417. +#if defined(USING_NPUPNP)
  418. + for (const auto& entry : fileInfo->request_headers) {
  419. + ret->insert(entry);
  420. + }
  421. +#else
  422. auto head = const_cast<UpnpListHead*>(UpnpFileInfo_get_ExtraHeadersList(fileInfo));
  423. UpnpListIter pos;
  424. for (pos = UpnpListBegin(head); pos != UpnpListEnd(head); pos = UpnpListNext(head, pos)) {
  425. @@ -121,6 +132,7 @@ std::unique_ptr<std::map<std::string, std::string>> Headers::readHeaders(UpnpFil
  426. auto add = parseHeader(header);
  427. ret->insert(add);
  428. }
  429. +#endif
  430. return ret;
  431. }
  432. diff --git a/src/web/web_request_handler.cc b/src/web/web_request_handler.cc
  433. index 60e2d028..117dcbfa 100644
  434. --- a/src/web/web_request_handler.cc
  435. +++ b/src/web/web_request_handler.cc
  436. @@ -112,7 +112,11 @@ void WebRequestHandler::getInfo(const char* filename, UpnpFileInfo* info)
  437. std::string mimetype = (returnType == "xml") ? MIMETYPE_XML : MIMETYPE_JSON;
  438. std::string contentType = mimetype + "; charset=" + DEFAULT_INTERNAL_CHARSET;
  439. +#if defined(USING_NPUPNP)
  440. + UpnpFileInfo_set_ContentType(info, contentType);
  441. +#else
  442. UpnpFileInfo_set_ContentType(info, ixmlCloneDOMString(contentType.c_str()));
  443. +#endif
  444. Headers headers;
  445. headers.addHeader(std::string { "Cache-Control" }, std::string { "no-cache, must-revalidate" });
  446. headers.writeHeaders(info);