ws_fsBinding.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "ws_fsService.hpp"
  14. #include "ws_fsBinding.hpp"
  15. #include "TpWrapper.hpp"
  16. #include "jwrapper.hpp"
  17. #include "dfuwu.hpp"
  18. #include "dadfs.hpp"
  19. #include "exception_util.hpp"
  20. #define FILE_SPRAY_URL "FileSprayAccess"
  21. #define FILE_DESPRAY_URL "FileDesprayAccess"
  22. int CFileSpraySoapBindingEx::onGetInstantQuery(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *service, const char *method)
  23. {
  24. if (strieq(method, "DownloadFile"))
  25. {
  26. return downloadFile(context, request, response);
  27. }
  28. #ifndef _CONTAINERIZED
  29. //The code below should be only for legacy ECLWatch.
  30. bool permission = true;
  31. bool bDownloadFile = false;
  32. bool bProcess;
  33. StringBuffer sourceLogicalFile;
  34. StringBuffer methodbuf;
  35. StringBuffer submethod;
  36. StringBuffer xsltFileName(getCFD());
  37. xsltFileName.append("smc_xslt/");
  38. if (stricmp(method, "SprayFixedInput")==0)
  39. {
  40. if (!context.validateFeatureAccess(FILE_SPRAY_URL, SecAccess_Write, false))
  41. permission = false;
  42. bProcess = true;
  43. xsltFileName.append("fs_sprayForm.xslt");
  44. methodbuf.append("SprayFixed");
  45. }
  46. else if(stricmp(method, "SprayVariableInput")==0)
  47. {
  48. if (!context.validateFeatureAccess(FILE_SPRAY_URL, SecAccess_Write, false))
  49. permission = false;
  50. bProcess = true;
  51. xsltFileName.append("fs_sprayForm.xslt");
  52. methodbuf.append("SprayVariable");
  53. request->getParameter("submethod", submethod);
  54. }
  55. else if (stricmp(method, "DesprayInput")==0)
  56. {
  57. if (!context.validateFeatureAccess(FILE_DESPRAY_URL, SecAccess_Write, false))
  58. permission = false;
  59. request->getParameter("sourceLogicalName", sourceLogicalFile);
  60. xsltFileName.append("fs_desprayCopyForm.xslt");
  61. methodbuf.append("Despray");
  62. bProcess = true;
  63. }
  64. else if (stricmp(method, "CopyInput") == 0)
  65. {
  66. if (!context.validateFeatureAccess(FILE_SPRAY_URL, SecAccess_Write, false))
  67. permission = false;
  68. request->getParameter("sourceLogicalName", sourceLogicalFile);
  69. xsltFileName.append("fs_desprayCopyForm.xslt");
  70. methodbuf.append("Copy");
  71. bProcess = true;
  72. }
  73. else if (stricmp(method, "RenameInput") == 0)
  74. {
  75. if (!context.validateFeatureAccess(FILE_SPRAY_URL, SecAccess_Write, false))
  76. permission = false;
  77. request->getParameter("sourceLogicalName", sourceLogicalFile);
  78. xsltFileName.append("fs_renameForm.xslt");
  79. methodbuf.append("Rename");
  80. bProcess = true;
  81. }
  82. else
  83. bProcess = false;
  84. if (bProcess)
  85. {
  86. if (bDownloadFile)
  87. return 0;
  88. StringBuffer xml;
  89. Owned<IProperties> params(createProperties());
  90. if (!permission)
  91. {
  92. context.setAuthStatus(AUTH_STATUS_NOACCESS);
  93. params->setProp("@method", methodbuf.str());
  94. xml.append("<Environment><ErrorMessage>Permission denied.</ErrorMessage></Environment>");
  95. }
  96. else
  97. {
  98. if(submethod.length() > 0)
  99. params->setProp("@submethod", submethod.str());
  100. params->setProp("@method", methodbuf.str());
  101. if (*sourceLogicalFile.str())
  102. {
  103. params->setProp("@sourceLogicalName", sourceLogicalFile.str());
  104. Owned<IUserDescriptor> userdesc;
  105. StringBuffer username;
  106. context.getUserID(username);
  107. if(username.length() > 0)
  108. {
  109. const char* passwd = context.queryPassword();
  110. userdesc.setown(createUserDescriptor());
  111. userdesc->set(username.str(), passwd, context.querySignature());
  112. try
  113. {
  114. if (stricmp(method, "CopyInput") == 0)
  115. {
  116. Owned<IDistributedFile> df = queryDistributedFileDirectory().lookup(sourceLogicalFile.str(), userdesc.get(), false, false, false, nullptr, defaultPrivilegedUser);
  117. if(!df)
  118. {
  119. throw MakeStringException(ECLWATCH_FILE_NOT_EXIST,"Could not find file %s.",sourceLogicalFile.str());
  120. }
  121. const char *kind = df->queryAttributes().queryProp("@kind");
  122. if (kind && strcmp(kind,"key")==0)
  123. {
  124. params->setProp("@compressflag", 0);
  125. }
  126. else if(df->isCompressed())
  127. {
  128. params->setProp("@compressflag", 2);
  129. }
  130. else
  131. {
  132. params->setProp("@compressflag", 1);
  133. }
  134. }
  135. }
  136. catch (IException *E)
  137. {
  138. Owned<IXslProcessor> xslp = getXslProcessor();
  139. if (!xslp)
  140. throw E;
  141. Owned<IMultiException> me = MakeMultiException();
  142. me->append(*E);
  143. response->handleExceptions(xslp, me, "FileSpray", method, StringBuffer(getCFD()).append("./smc_xslt/exceptions.xslt").str(), false);
  144. return 0;
  145. }
  146. }
  147. }
  148. else
  149. {
  150. params->setProp("@compressflag", 1);
  151. }
  152. StringBuffer wuid;
  153. request->getParameter("wuid", wuid);
  154. Owned<IPropertyTree> pTree = createPTreeForXslt(context.getClientVersion(), method, wuid.str());
  155. toXML(pTree, xml, false);
  156. }
  157. IProperties* requestparams = request->queryParameters();
  158. if(requestparams && requestparams->hasProp("rawxml_"))
  159. {
  160. response->setContent(xml.str());
  161. response->setContentType(HTTP_TYPE_APPLICATION_XML);
  162. }
  163. else{
  164. StringBuffer htmlbuf;
  165. xsltTransform(xml.str(), xsltFileName.str(), params, htmlbuf);
  166. response->setContent(htmlbuf.str());
  167. response->setContentType(HTTP_TYPE_TEXT_HTML_UTF8);
  168. }
  169. response->send();
  170. return 0;
  171. }
  172. else
  173. #endif
  174. return CFileSpraySoapBinding::onGetInstantQuery(context, request, response, service, method);
  175. }
  176. #ifndef _CONTAINERIZED //The code here is used by legacy ECLWatch.
  177. IPropertyTree* CFileSpraySoapBindingEx::createPTreeForXslt(double clientVersion, const char* method, const char* dfuwuid)
  178. {
  179. Owned<IPropertyTree> pRoot = createPTreeFromXMLString("<Environment/>");
  180. Owned<IEnvironmentFactory> factory = getEnvironmentFactory(true);
  181. Owned<IConstEnvironment> constEnv = factory->openEnvironment();
  182. Owned<IPropertyTree> pEnvRoot = &constEnv->getPTree();
  183. IPropertyTree* pEnvSoftware = pEnvRoot->queryPropTree("Software");
  184. IPropertyTree* pSoftware = pRoot->addPropTree("Software", createPTree("Software"));
  185. if (pEnvSoftware)
  186. {
  187. StringBuffer dfuwuidSourcePartIP, wuxml;
  188. if(dfuwuid && *dfuwuid)
  189. {
  190. Owned<IDFUWorkUnitFactory> dfuwu_factory = getDFUWorkUnitFactory();
  191. Owned<IConstDFUWorkUnit> dfuwu = dfuwu_factory->openWorkUnit(dfuwuid, false);
  192. if(dfuwu)
  193. {
  194. dfuwu->toXML(wuxml);
  195. Owned<IPropertyTree> wu = createPTreeFromXMLString(wuxml.str());
  196. if (wu)
  197. {
  198. const char* ip = wu->queryProp("Source/Part/@node");
  199. if (ip && *ip)
  200. dfuwuidSourcePartIP.append(ip);
  201. }
  202. }
  203. }
  204. appendDropZones(clientVersion, constEnv, dfuwuidSourcePartIP.str(), pSoftware);
  205. //For Spray files on Thor Cluster, fetch all the group names for all the thor instances (and dedup them)
  206. BoolHash uniqueThorClusterGroupNames;
  207. Owned<IPropertyTreeIterator> it =pEnvSoftware->getElements("ThorCluster");
  208. ForEach(*it)
  209. {
  210. StringBuffer thorClusterGroupName;
  211. IPropertyTree& cluster = it->query();
  212. getClusterGroupName(cluster, thorClusterGroupName);
  213. if (!thorClusterGroupName.length())
  214. continue;
  215. bool* found = uniqueThorClusterGroupNames.getValue(thorClusterGroupName.str());
  216. if (found && *found)
  217. continue;
  218. uniqueThorClusterGroupNames.setValue(thorClusterGroupName.str(), true);
  219. IPropertyTree* newClusterTree = pSoftware->addPropTree("ThorCluster", &it->get());
  220. newClusterTree->setProp("@name", thorClusterGroupName.str()); //set group name into @name for spray target
  221. }
  222. it.setown(pEnvSoftware->getElements("EclAgentProcess"));
  223. ForEach(*it)
  224. {
  225. IPropertyTree &cluster = it->query();
  226. const char* name = cluster.queryProp("@name");
  227. if (!name||!*name)
  228. continue;
  229. unsigned ins = 0;
  230. Owned<IPropertyTreeIterator> insts = cluster.getElements("Instance");
  231. ForEach(*insts)
  232. {
  233. const char *na = insts->query().queryProp("@netAddress");
  234. if (!na || !*na)
  235. {
  236. insts->query().setProp("@gname", name);
  237. continue;
  238. }
  239. SocketEndpoint ep(na);
  240. if (ep.isNull())
  241. continue;
  242. ins++;
  243. StringBuffer gname("hthor__");
  244. //StringBuffer gname;
  245. gname.append(name);
  246. if (ins>1)
  247. gname.append('_').append(ins);
  248. insts->query().setProp("@gname", gname.str());
  249. }
  250. pSoftware->addPropTree("EclAgentProcess", &it->get());
  251. }
  252. if (stricmp(method, "CopyInput") == 0) //Limit for this method only
  253. {
  254. it.setown(pEnvSoftware->getElements("RoxieCluster"));
  255. ForEach(*it)
  256. pSoftware->addPropTree("RoxieCluster", &it->get());
  257. }
  258. if (wuxml.length() > 0)
  259. pSoftware->addPropTree("DfuWorkunit", createPTreeFromXMLString(wuxml.str()));
  260. }
  261. return pRoot.getClear();
  262. }
  263. //For every ECLWatchVisible dropzones, read: dropZoneName, directory, and, if available, computer.
  264. //For every Servers/Server in ECLWatchVisible dropzones, read: directory,
  265. // server name, and hostname(or IP). Create dropzone("@name", "@directory", "@computer",
  266. // "@netAddress", "@linux", "@sourceNode") tree into pSoftware.
  267. void CFileSpraySoapBindingEx::appendDropZones(double clientVersion, IConstEnvironment* env, const char* dfuwuidSourcePartIP, IPropertyTree* softwareTree)
  268. {
  269. Owned<IConstDropZoneInfoIterator> dropZoneItr = env->getDropZoneIterator();
  270. ForEach(*dropZoneItr)
  271. {
  272. IConstDropZoneInfo& dropZoneInfo = dropZoneItr->query();
  273. if (!dropZoneInfo.isECLWatchVisible()) //This code is used by ECLWatch. So, skip the DZs not for ECLWatch.
  274. continue;
  275. SCMStringBuffer dropZoneName, directory, computerName;
  276. dropZoneInfo.getName(dropZoneName);
  277. dropZoneInfo.getDirectory(directory);
  278. if (!dropZoneName.length() || !directory.length())
  279. continue;
  280. bool isLinux = getPathSepChar(directory.str()) == '/' ? true : false;
  281. Owned<IConstDropZoneServerInfoIterator> dropZoneServerItr = dropZoneInfo.getServers();
  282. ForEach(*dropZoneServerItr)
  283. {
  284. IConstDropZoneServerInfo& dropZoneServer = dropZoneServerItr->query();
  285. StringBuffer name, server, networkAddress;
  286. dropZoneServer.getName(name);
  287. dropZoneServer.getServer(server);
  288. if (name.isEmpty() || server.isEmpty())
  289. continue;
  290. IPropertyTree* dropZone = softwareTree->addPropTree("DropZone", createPTree());
  291. dropZone->setProp("@name", dropZoneName.str());
  292. dropZone->setProp("@computer", name.str());
  293. dropZone->setProp("@directory", directory.str());
  294. if (isLinux)
  295. dropZone->setProp("@linux", "true");
  296. IpAddress ipAddr;
  297. ipAddr.ipset(server.str());
  298. ipAddr.getIpText(networkAddress);
  299. if (!ipAddr.isNull())
  300. {
  301. dropZone->addProp("@netAddress", networkAddress);
  302. if (!isEmptyString(dfuwuidSourcePartIP))
  303. {
  304. IpAddress ip(dfuwuidSourcePartIP);
  305. if (ip.ipequals(ipAddr))
  306. dropZone->addProp("@sourceNode", "1");
  307. }
  308. }
  309. }
  310. }
  311. }
  312. void CFileSpraySoapBindingEx::xsltTransform(const char* xml, const char* sheet, IProperties *params, StringBuffer& ret)
  313. {
  314. StringBuffer xsl;
  315. if (!checkFileExists(sheet))
  316. throw MakeStringException(ECLWATCH_FILE_NOT_EXIST, "Cannot open stylesheet %s",sheet);
  317. Owned<IXslProcessor> proc = getXslProcessor();
  318. Owned<IXslTransform> trans = proc->createXslTransform();
  319. trans->setXmlSource(xml, strlen(xml));
  320. trans->loadXslFromFile(sheet);
  321. if (params)
  322. {
  323. Owned<IPropertyIterator> it = params->getIterator();
  324. for (it->first(); it->isValid(); it->next())
  325. {
  326. const char *key = it->getPropKey();
  327. //set parameter in the XSL transform skipping over the @ prefix, if any
  328. const char* paramName = *key == '@' ? key+1 : key;
  329. trans->setParameter(paramName, StringBuffer().append('\'').append(params->queryProp(key)).append('\'').str());
  330. }
  331. }
  332. trans->transform(ret);
  333. }
  334. #endif
  335. int CFileSpraySoapBindingEx::downloadFile(IEspContext &context, CHttpRequest* request, CHttpResponse* response)
  336. {
  337. try
  338. {
  339. if (!context.validateFeatureAccess(FILE_SPRAY_URL, SecAccess_Full, false))
  340. throw MakeStringException(ECLWATCH_FILE_SPRAY_ACCESS_DENIED, "Failed to download file. Permission denied.");
  341. StringBuffer netAddressStr, osStr, pathStr, nameStr;
  342. request->getParameter("NetAddress", netAddressStr);
  343. request->getParameter("OS", osStr);
  344. request->getParameter("Path", pathStr);
  345. request->getParameter("Name", nameStr);
  346. #if 0
  347. StringArray files;
  348. IProperties* params = request->queryParameters();
  349. Owned<IPropertyIterator> iter = params->getIterator();
  350. if (iter && iter->first())
  351. {
  352. while (iter->isValid())
  353. {
  354. const char *keyname=iter->getPropKey();
  355. if (!keyname || strncmp(keyname, "Names", 5))
  356. continue;
  357. files.append(params->queryProp(iter->getPropKey()));
  358. iter->next();
  359. }
  360. }
  361. #endif
  362. if (netAddressStr.length() < 1)
  363. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Network address not specified.");
  364. if (pathStr.length() < 1)
  365. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Path not specified.");
  366. if (nameStr.length() < 1)
  367. throw MakeStringException(ECLWATCH_INVALID_INPUT,"File name not specified.");
  368. char pathSep = '/';
  369. if ((osStr.length() > 1) && (atoi(osStr.str())== OS_WINDOWS))
  370. {
  371. pathSep = '\\';
  372. }
  373. pathStr.replace(pathSep=='\\'?'/':'\\', pathSep);
  374. if (*(pathStr.str() + pathStr.length() -1) != pathSep)
  375. pathStr.append( pathSep );
  376. if (!validateDropZonePath(nullptr, netAddressStr, pathStr)) //The pathStr should be the absolute path for the dropzone.
  377. throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Invalid file path %s", pathStr.str());
  378. StringBuffer fullName;
  379. fullName.appendf("%s%s", pathStr.str(), nameStr.str());
  380. StringBuffer headerStr("attachment;");
  381. headerStr.appendf("filename=%s", nameStr.str());
  382. RemoteFilename rfn;
  383. rfn.setRemotePath(fullName.str());
  384. SocketEndpoint ep(netAddressStr.str());
  385. rfn.setIp(ep);
  386. Owned<IFile> rFile = createIFile(rfn);
  387. if (!rFile)
  388. throw MakeStringException(ECLWATCH_CANNOT_OPEN_FILE,"Cannot open file %s.",fullName.str());
  389. OwnedIFileIO rIO = rFile->openShared(IFOread,IFSHfull);
  390. if (!rIO)
  391. throw MakeStringException(ECLWATCH_CANNOT_READ_FILE,"Cannot read file %s.",fullName.str());
  392. IFileIOStream* ioS = createIOStream(rIO);
  393. context.addCustomerHeader("Content-disposition", headerStr.str());
  394. response->setContent(ioS);
  395. response->setContentType(HTTP_TYPE_OCTET_STREAM);
  396. response->send();
  397. }
  398. catch(IException* e)
  399. {
  400. Owned<IXslProcessor> xslp = getXslProcessor();
  401. if (!xslp)
  402. throw e;
  403. Owned<IMultiException> me = MakeMultiException();
  404. me->append(*e);
  405. response->handleExceptions(xslp, me, "FileSpray", "DownloadFile", StringBuffer(getCFD()).append("./smc_xslt/exceptions.xslt"));
  406. }
  407. return 0;
  408. }
  409. int CFileSpraySoapBindingEx::onStartUpload(IEspContext& ctx, CHttpRequest* request, CHttpResponse* response, const char* serv, const char* method)
  410. {
  411. StringBuffer netAddress, path;
  412. request->getParameter("NetAddress", netAddress);
  413. request->getParameter("Path", path);
  414. if (!validateDropZonePath(nullptr, netAddress, path)) //The path should be the absolute path for the dropzone.
  415. throw makeStringExceptionV(ECLWATCH_INVALID_INPUT, "Invalid Landing Zone path %s", path.str());
  416. return EspHttpBinding::onStartUpload(ctx, request, response, serv, method);
  417. }
  418. int CFileSpraySoapBindingEx::onFinishUpload(IEspContext &ctx, CHttpRequest* request, CHttpResponse* response, const char *service, const char *method, StringArray& fileNames, StringArray& files, IMultiException *me)
  419. {
  420. if (!me || (me->ordinality()==0))
  421. {
  422. if (ctx.getResponseFormat()==ESPSerializationANY)
  423. {
  424. StringBuffer newUrl, netAddress, path;
  425. request->getParameter("NetAddress", netAddress);
  426. request->getParameter("Path", path);
  427. newUrl.appendf("/FileSpray/DropZoneFiles?NetAddress=%s&Path=%s", netAddress.str(), path.str());
  428. response->redirect(*request, newUrl.str());
  429. }
  430. else
  431. {
  432. IArrayOf<IEspDFUActionResult> results;
  433. Owned<CUploadFilesResponse> esp_response = new CUploadFilesResponse("FileSpray");
  434. ForEachItemIn(i, fileNames)
  435. {
  436. const char* fileName = fileNames.item(i);
  437. Owned<IEspDFUActionResult> res = createDFUActionResult("", "");
  438. res->setID(fileName);
  439. res->setAction("Upload File");
  440. res->setResult("Success");
  441. results.append(*res.getLink());
  442. }
  443. if (!results.length())
  444. {
  445. Owned<IEspDFUActionResult> res = createDFUActionResult("", "");
  446. res->setID("<N/A>");
  447. res->setAction("Upload File");
  448. res->setResult("No file uploaded");
  449. results.append(*res.getLink());
  450. }
  451. esp_response->setUploadFileResults(results);
  452. MemoryBuffer content;
  453. StringBuffer mimetype;
  454. esp_response->appendContent(&ctx,content, mimetype);
  455. response->setContent(content.length(), content.toByteArray());
  456. response->setContentType(mimetype.str());
  457. response->send();
  458. }
  459. }
  460. else
  461. {
  462. StringBuffer msg;
  463. IWARNLOG("Exception(s) in EspHttpBinding::onStartUpload - %s", me->errorMessage(msg).append('\n').str());
  464. if ((ctx.getResponseFormat() == ESPSerializationXML) || (ctx.getResponseFormat() == ESPSerializationJSON))
  465. response->handleExceptions(NULL, me, "FileSpray", "UploadFile", NULL, false);
  466. else
  467. return EspHttpBinding::onFinishUpload(ctx, request, response, service, method, fileNames, files, me);
  468. }
  469. return 0;
  470. }