httpservice.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912
  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. #pragma warning (disable : 4786)
  14. #ifdef WIN32
  15. #ifdef ESPHTTP_EXPORTS
  16. #define esp_http_decl __declspec(dllexport)
  17. #endif
  18. #endif
  19. //Jlib
  20. #include "jliball.hpp"
  21. #include "espcontext.hpp"
  22. #include "esphttp.hpp"
  23. //ESP Bindings
  24. #include "http/platform/httpservice.hpp"
  25. #include "http/platform/httptransport.hpp"
  26. #include "htmlpage.hpp"
  27. /***************************************************************************
  28. * CEspHttpServer Implementation
  29. ***************************************************************************/
  30. CEspHttpServer::CEspHttpServer(ISocket& sock, bool viewConfig, int maxRequestEntityLength):m_socket(sock), m_MaxRequestEntityLength(maxRequestEntityLength)
  31. {
  32. IEspContext* ctx = createEspContext();
  33. m_request.setown(new CHttpRequest(sock));
  34. m_request->setMaxRequestEntityLength(maxRequestEntityLength);
  35. m_response.setown(new CHttpResponse(sock));
  36. m_request->setOwnContext(ctx);
  37. m_response->setOwnContext(LINK(ctx));
  38. m_viewConfig=viewConfig;
  39. }
  40. CEspHttpServer::CEspHttpServer(ISocket& sock, CEspApplicationPort* apport, bool viewConfig, int maxRequestEntityLength):m_socket(sock), m_MaxRequestEntityLength(maxRequestEntityLength)
  41. {
  42. IEspContext* ctx = createEspContext();
  43. m_request.setown(new CHttpRequest(sock));
  44. m_request->setMaxRequestEntityLength(maxRequestEntityLength);
  45. m_response.setown(new CHttpResponse(sock));
  46. m_request->setOwnContext(ctx);
  47. m_response->setOwnContext(LINK(ctx));
  48. m_apport = apport;
  49. if (apport->getDefaultBinding())
  50. m_defaultBinding.set(apport->getDefaultBinding()->queryBinding());
  51. m_viewConfig=viewConfig;
  52. }
  53. CEspHttpServer::~CEspHttpServer()
  54. {
  55. try
  56. {
  57. IEspContext* ctx = m_request->queryContext();
  58. if (ctx)
  59. {
  60. //Request is logged only when there is an exception or the request time is very long.
  61. //If the flag of 'EspLogRequests' is set or the log level > LogNormal, the Request should
  62. //has been logged and it should not be logged here.
  63. ctx->setProcessingTime();
  64. if ((ctx->queryHasException() || (ctx->queryProcessingTime() > getSlowProcessingTime())) &&
  65. !getEspLogRequests() && (getEspLogLevel() <= LogNormal))
  66. {
  67. StringBuffer logStr;
  68. logStr.appendf("%s %s", m_request->queryMethod(), m_request->queryPath());
  69. const char* paramStr = m_request->queryParamStr();
  70. if (paramStr && *paramStr)
  71. logStr.appendf("?%s", paramStr);
  72. DBGLOG("Request[%s]", logStr.str());
  73. if (m_request->isSoapMessage())
  74. {
  75. StringBuffer requestStr;
  76. m_request->getContent(requestStr);
  77. if (requestStr.length())
  78. m_request->logSOAPMessage(requestStr.str(), NULL);
  79. }
  80. }
  81. }
  82. m_request.clear();
  83. m_response.clear();
  84. }
  85. catch (...)
  86. {
  87. ERRLOG("In CEspHttpServer::~CEspHttpServer() -- Unknown Exception.");
  88. }
  89. }
  90. typedef enum espAuthState_
  91. {
  92. authUnknown,
  93. authRequired,
  94. authProvided,
  95. authSucceeded,
  96. authPending,
  97. authFailed
  98. } EspAuthState;
  99. bool CEspHttpServer::rootAuth(IEspContext* ctx)
  100. {
  101. if (!m_apport->rootAuthRequired())
  102. return true;
  103. bool ret=false;
  104. EspHttpBinding* thebinding=getBinding();
  105. if (thebinding)
  106. {
  107. thebinding->populateRequest(m_request.get());
  108. if(!thebinding->authRequired(m_request.get()) || thebinding->doAuth(ctx))
  109. ret=true;
  110. else
  111. {
  112. ISecUser *user = ctx->queryUser();
  113. if (user && user->getAuthenticateStatus() == AS_PASSWORD_VALID_BUT_EXPIRED)
  114. {
  115. m_response->redirect(*m_request.get(), "/esp/updatepasswordinput");
  116. ret = true;
  117. }
  118. else
  119. {
  120. DBGLOG("User authentication required");
  121. m_response->sendBasicChallenge(thebinding->getChallengeRealm(), true);
  122. }
  123. }
  124. }
  125. return ret;
  126. }
  127. const char* getSubServiceDesc(sub_service stype)
  128. {
  129. #define DEF_CASE(s) case s: return #s;
  130. switch(stype)
  131. {
  132. DEF_CASE(sub_serv_unknown)
  133. DEF_CASE(sub_serv_root)
  134. DEF_CASE(sub_serv_main)
  135. DEF_CASE(sub_serv_service)
  136. DEF_CASE(sub_serv_method)
  137. DEF_CASE(sub_serv_files)
  138. DEF_CASE(sub_serv_itext)
  139. DEF_CASE(sub_serv_iframe)
  140. DEF_CASE(sub_serv_content)
  141. DEF_CASE(sub_serv_result)
  142. DEF_CASE(sub_serv_index)
  143. DEF_CASE(sub_serv_index_redirect)
  144. DEF_CASE(sub_serv_form)
  145. DEF_CASE(sub_serv_xform)
  146. DEF_CASE(sub_serv_query)
  147. DEF_CASE(sub_serv_instant_query)
  148. DEF_CASE(sub_serv_soap_builder)
  149. DEF_CASE(sub_serv_wsdl)
  150. DEF_CASE(sub_serv_xsd)
  151. DEF_CASE(sub_serv_config)
  152. DEF_CASE(sub_serv_php)
  153. DEF_CASE(sub_serv_getversion)
  154. DEF_CASE(sub_serv_reqsamplexml)
  155. DEF_CASE(sub_serv_respsamplexml)
  156. DEF_CASE(sub_serv_file_upload)
  157. default: return "invalid-type";
  158. }
  159. }
  160. static bool authenticateOptionalFailed(IEspContext& ctx, IEspHttpBinding* binding)
  161. {
  162. #ifdef ENABLE_NEW_SECURITY
  163. if (ctx.queryRequestParameters()->hasProp("internal"))
  164. {
  165. ISecUser* user = ctx.queryUser();
  166. if(!user || user->getStatus()==SecUserStatus_Inhouse || user->getStatus()==SecUserStatus_Unknown)
  167. return false;
  168. ERRLOG("User %s trying to access unauthorized feature: internal", user->getName() ? user->getName() : ctx.queryUserId());
  169. return true;
  170. }
  171. // TODO: handle binding specific optionals
  172. #elif !defined(DISABLE_NEW_SECURITY)
  173. #error Please include esphttp.hpp in this file.
  174. #endif
  175. return false;
  176. }
  177. EspHttpBinding* CEspHttpServer::getBinding()
  178. {
  179. EspHttpBinding* thebinding=NULL;
  180. int ordinality=m_apport->getBindingCount();
  181. if (ordinality==1)
  182. {
  183. CEspBindingEntry *entry = m_apport->queryBindingItem(0);
  184. thebinding = (entry) ? dynamic_cast<EspHttpBinding*>(entry->queryBinding()) : NULL;
  185. }
  186. else if (m_defaultBinding)
  187. thebinding=dynamic_cast<EspHttpBinding*>(m_defaultBinding.get());
  188. return thebinding;
  189. }
  190. int CEspHttpServer::processRequest()
  191. {
  192. try
  193. {
  194. if (m_request->receive(NULL)==-1) // MORE - pass in IMultiException if we want to see exceptions (which are not fatal)
  195. return -1;
  196. }
  197. catch(IEspHttpException* e)
  198. {
  199. m_response->sendException(e);
  200. e->Release();
  201. return 0;
  202. }
  203. catch (IException *e)
  204. {
  205. DBGLOG(e);
  206. e->Release();
  207. return 0;
  208. }
  209. catch (...)
  210. {
  211. DBGLOG("Unknown Exception - reading request [CEspHttpServer::processRequest()]");
  212. return 0;
  213. }
  214. try
  215. {
  216. EspHttpBinding* thebinding=NULL;
  217. StringBuffer method;
  218. m_request->getMethod(method);
  219. EspAuthState authState=authUnknown;
  220. sub_service stype=sub_serv_unknown;
  221. StringBuffer pathEx;
  222. StringBuffer serviceName;
  223. StringBuffer methodName;
  224. m_request->getEspPathInfo(stype, &pathEx, &serviceName, &methodName, false);
  225. ESPLOG(LogNormal,"sub service type: %s. parm: %s", getSubServiceDesc(stype), m_request->queryParamStr());
  226. m_request->updateContext();
  227. IEspContext* ctx = m_request->queryContext();
  228. ctx->setServiceName(serviceName.str());
  229. bool isSoapPost=(stricmp(method.str(), POST_METHOD) == 0 && m_request->isSoapMessage());
  230. if (!isSoapPost)
  231. {
  232. StringBuffer peerStr, pathStr;
  233. const char *userid=ctx->queryUserId();
  234. DBGLOG("%s %s, from %s@%s", method.str(), m_request->getPath(pathStr).str(), (userid) ? userid : "unknown", m_request->getPeer(peerStr).str());
  235. if (m_apport->rootAuthRequired() && (!ctx->queryUserId() || !*ctx->queryUserId()))
  236. {
  237. thebinding = dynamic_cast<EspHttpBinding*>(m_defaultBinding.get());
  238. StringBuffer realmbuf;
  239. if(thebinding)
  240. {
  241. realmbuf.append(thebinding->getChallengeRealm());
  242. }
  243. if(realmbuf.length() == 0)
  244. realmbuf.append("ESP");
  245. DBGLOG("User authentication required");
  246. m_response->sendBasicChallenge(realmbuf.str(), true);
  247. return 0;
  248. }
  249. }
  250. if (!stricmp(method.str(), GET_METHOD))
  251. {
  252. if (stype==sub_serv_root)
  253. {
  254. if (!rootAuth(ctx))
  255. return 0;
  256. if (ctx->queryUser() && (ctx->queryUser()->getAuthenticateStatus() == AS_PASSWORD_VALID_BUT_EXPIRED))
  257. return 0;//allow user to change password
  258. // authenticate optional groups
  259. if (authenticateOptionalFailed(*ctx,NULL))
  260. throw createEspHttpException(401,"Unauthorized Access","Unauthorized Access");
  261. return onGetApplicationFrame(m_request.get(), m_response.get(), ctx);
  262. }
  263. if (!stricmp(serviceName.str(), "esp"))
  264. {
  265. if (!methodName.length())
  266. return 0;
  267. #ifdef _USE_OPENLDAP
  268. if (strieq(methodName.str(), "updatepasswordinput"))//process before authentication check
  269. return onUpdatePasswordInput(m_request.get(), m_response.get());
  270. #endif
  271. if (!rootAuth(ctx) )
  272. return 0;
  273. if (methodName.charAt(methodName.length()-1)=='_')
  274. methodName.setCharAt(methodName.length()-1, 0);
  275. if (!stricmp(methodName.str(), "files"))
  276. {
  277. checkInitEclIdeResponse(m_request, m_response);
  278. return onGetFile(m_request.get(), m_response.get(), pathEx.str());
  279. }
  280. else if (!stricmp(methodName.str(), "xslt"))
  281. return onGetXslt(m_request.get(), m_response.get(), pathEx.str());
  282. else if (!stricmp(methodName.str(), "body"))
  283. return onGetMainWindow(m_request.get(), m_response.get());
  284. else if (!stricmp(methodName.str(), "frame"))
  285. return onGetApplicationFrame(m_request.get(), m_response.get(), ctx);
  286. else if (!stricmp(methodName.str(), "titlebar"))
  287. return onGetTitleBar(m_request.get(), m_response.get());
  288. else if (!stricmp(methodName.str(), "nav"))
  289. return onGetNavWindow(m_request.get(), m_response.get());
  290. else if (!stricmp(methodName.str(), "navdata"))
  291. return onGetDynNavData(m_request.get(), m_response.get());
  292. else if (!stricmp(methodName.str(), "navmenuevent"))
  293. return onGetNavEvent(m_request.get(), m_response.get());
  294. else if (!stricmp(methodName.str(), "soapreq"))
  295. return onGetBuildSoapRequest(m_request.get(), m_response.get());
  296. }
  297. }
  298. #ifdef _USE_OPENLDAP
  299. else if (strieq(method.str(), POST_METHOD) && strieq(serviceName.str(), "esp") && (methodName.length() > 0) && strieq(methodName.str(), "updatepassword"))
  300. {
  301. EspHttpBinding* thebinding = getBinding();
  302. if (thebinding)
  303. thebinding->populateRequest(m_request.get());
  304. return onUpdatePassword(m_request.get(), m_response.get());
  305. }
  306. #endif
  307. if(m_apport != NULL)
  308. {
  309. int ordinality=m_apport->getBindingCount();
  310. bool isSubService = false;
  311. if (ordinality>0)
  312. {
  313. if (ordinality==1)
  314. {
  315. CEspBindingEntry *entry = m_apport->queryBindingItem(0);
  316. thebinding = (entry) ? dynamic_cast<EspHttpBinding*>(entry->queryBinding()) : NULL;
  317. if (thebinding && !isSoapPost && !thebinding->isValidServiceName(*ctx, serviceName.str()))
  318. thebinding=NULL;
  319. }
  320. else
  321. {
  322. EspHttpBinding* lbind=NULL;
  323. for(int index=0; !thebinding && index<ordinality; index++)
  324. {
  325. CEspBindingEntry *entry = m_apport->queryBindingItem(index);
  326. lbind = (entry) ? dynamic_cast<EspHttpBinding*>(entry->queryBinding()) : NULL;
  327. if (lbind)
  328. {
  329. if (!thebinding && lbind->isValidServiceName(*ctx, serviceName.str()))
  330. {
  331. thebinding=lbind;
  332. StringBuffer bindSvcName;
  333. if (stricmp(serviceName, lbind->getServiceName(bindSvcName)))
  334. isSubService = true;
  335. }
  336. }
  337. }
  338. }
  339. if (!thebinding && m_defaultBinding)
  340. thebinding=dynamic_cast<EspHttpBinding*>(m_defaultBinding.get());
  341. if (thebinding)
  342. {
  343. StringBuffer servName(ctx->queryServiceName(NULL));
  344. if (!servName.length())
  345. {
  346. thebinding->getServiceName(servName);
  347. ctx->setServiceName(servName.str());
  348. }
  349. thebinding->populateRequest(m_request.get());
  350. if(thebinding->authRequired(m_request.get()) && !thebinding->doAuth(ctx))
  351. {
  352. authState=authRequired;
  353. if(isSoapPost)
  354. {
  355. authState = authPending;
  356. ctx->setToBeAuthenticated(true);
  357. }
  358. }
  359. else
  360. authState = authSucceeded;
  361. }
  362. }
  363. if (authState==authRequired)
  364. {
  365. ISecUser *user = ctx->queryUser();
  366. if (user && (user->getAuthenticateStatus() == AS_PASSWORD_EXPIRED || user->getAuthenticateStatus() == AS_PASSWORD_VALID_BUT_EXPIRED))
  367. {
  368. DBGLOG("ESP password expired for %s", user->getName());
  369. m_response->setContentType(HTTP_TYPE_TEXT_PLAIN);
  370. m_response->setContent("Your ESP password has expired");
  371. m_response->send();
  372. }
  373. else
  374. {
  375. DBGLOG("User authentication required");
  376. StringBuffer realmbuf;
  377. if(thebinding)
  378. realmbuf.append(thebinding->getChallengeRealm());
  379. if(realmbuf.length() == 0)
  380. realmbuf.append("ESP");
  381. m_response->sendBasicChallenge(realmbuf.str(), !isSoapPost);
  382. }
  383. return 0;
  384. }
  385. // authenticate optional groups
  386. if (authenticateOptionalFailed(*ctx,thebinding))
  387. throw createEspHttpException(401,"Unauthorized Access","Unauthorized Access");
  388. if (thebinding!=NULL)
  389. {
  390. if(stricmp(method.str(), POST_METHOD)==0)
  391. thebinding->handleHttpPost(m_request.get(), m_response.get());
  392. else if(!stricmp(method.str(), GET_METHOD))
  393. {
  394. if (stype==sub_serv_index_redirect)
  395. {
  396. StringBuffer url;
  397. if (isSubService)
  398. {
  399. StringBuffer qSvcName;
  400. thebinding->qualifySubServiceName(*ctx,serviceName,NULL, qSvcName, NULL);
  401. url.append(qSvcName);
  402. }
  403. else
  404. thebinding->getServiceName(url);
  405. url.append('/');
  406. const char* parms = m_request->queryParamStr();
  407. if (parms && *parms)
  408. url.append('?').append(parms);
  409. m_response->redirect(*m_request.get(),url);
  410. }
  411. else
  412. thebinding->onGet(m_request.get(), m_response.get());
  413. }
  414. else
  415. unsupported();
  416. }
  417. else
  418. {
  419. if(!stricmp(method.str(), POST_METHOD))
  420. onPost();
  421. else if(!stricmp(method.str(), GET_METHOD))
  422. onGet();
  423. else
  424. unsupported();
  425. }
  426. ctx->addTraceSummaryTimeStamp("handleHttp");
  427. }
  428. }
  429. catch(IEspHttpException* e)
  430. {
  431. m_response->sendException(e);
  432. e->Release();
  433. return 0;
  434. }
  435. catch (IException *e)
  436. {
  437. DBGLOG(e);
  438. e->Release();
  439. return 0;
  440. }
  441. catch (...)
  442. {
  443. StringBuffer content_type;
  444. __int64 len = m_request->getContentLength();
  445. DBGLOG("Unknown Exception - processing request");
  446. DBGLOG("METHOD: %s, PATH: %s, TYPE: %s, CONTENT-LENGTH: %"I64F"d", m_request->queryMethod(), m_request->queryPath(), m_request->getContentType(content_type).str(), len);
  447. if (len > 0)
  448. m_request->logMessage(LOGCONTENT, "HTTP request content received:\n");
  449. return 0;
  450. }
  451. return 0;
  452. }
  453. int CEspHttpServer::onGetApplicationFrame(CHttpRequest* request, CHttpResponse* response, IEspContext* ctx)
  454. {
  455. time_t modtime = 0;
  456. IProperties *params = request->queryParameters();
  457. const char *inner=(params)?params->queryProp("inner") : NULL;
  458. StringBuffer ifmodifiedsince;
  459. request->getHeader("If-Modified-Since", ifmodifiedsince);
  460. if (inner&&*inner&&ifmodifiedsince.length())
  461. {
  462. response->setStatus(HTTP_STATUS_NOT_MODIFIED);
  463. response->send();
  464. }
  465. else
  466. {
  467. CEspBindingEntry* entry = m_apport->getDefaultBinding();
  468. if(entry)
  469. {
  470. EspHttpBinding *httpbind = dynamic_cast<EspHttpBinding *>(entry->queryBinding());
  471. if(httpbind)
  472. {
  473. const char *page = httpbind->getRootPage(ctx);
  474. if(page && *page)
  475. return onGetFile(request, response, page);
  476. }
  477. }
  478. StringBuffer html;
  479. m_apport->getAppFrameHtml(modtime, inner, html, ctx);
  480. response->setContent(html.length(), html.str());
  481. response->setContentType("text/html; charset=UTF-8");
  482. response->setStatus(HTTP_STATUS_OK);
  483. const char *timestr=ctime(&modtime);
  484. response->addHeader("Last-Modified", timestr);
  485. response->send();
  486. }
  487. return 0;
  488. }
  489. int CEspHttpServer::onGetTitleBar(CHttpRequest* request, CHttpResponse* response)
  490. {
  491. bool rawXml = request->queryParameters()->hasProp("rawxml_");
  492. StringBuffer m_headerHtml(m_apport->getTitleBarHtml(*request->queryContext(), rawXml));
  493. response->setContent(m_headerHtml.length(), m_headerHtml.str());
  494. response->setContentType(rawXml ? HTTP_TYPE_APPLICATION_XML_UTF8 : "text/html; charset=UTF-8");
  495. response->setStatus(HTTP_STATUS_OK);
  496. response->send();
  497. return 0;
  498. }
  499. int CEspHttpServer::onGetNavWindow(CHttpRequest* request, CHttpResponse* response)
  500. {
  501. StringBuffer navContent;
  502. StringBuffer navContentType;
  503. m_apport->getNavBarContent(*request->queryContext(), navContent, navContentType, request->queryParameters()->hasProp("rawxml_"));
  504. response->setContent(navContent.length(), navContent.str());
  505. response->setContentType(navContentType.str());
  506. response->setStatus(HTTP_STATUS_OK);
  507. response->send();
  508. return 0;
  509. }
  510. int CEspHttpServer::onGetDynNavData(CHttpRequest* request, CHttpResponse* response)
  511. {
  512. StringBuffer navContent;
  513. StringBuffer navContentType;
  514. bool bVolatile;
  515. m_apport->getDynNavData(*request->queryContext(), request->queryParameters(), navContent, navContentType, bVolatile);
  516. if (bVolatile)
  517. response->addHeader("Cache-control", "max-age=0");
  518. response->setContent(navContent.length(), navContent.str());
  519. response->setContentType(navContentType.str());
  520. response->setStatus(HTTP_STATUS_OK);
  521. response->send();
  522. return 0;
  523. }
  524. int CEspHttpServer::onGetNavEvent(CHttpRequest* request, CHttpResponse* response)
  525. {
  526. m_apport->onGetNavEvent(*request->queryContext(), request, response);
  527. return 0;
  528. }
  529. int CEspHttpServer::onGetBuildSoapRequest(CHttpRequest* request, CHttpResponse* response)
  530. {
  531. m_apport->onBuildSoapRequest(*request->queryContext(), request, response);
  532. return 0;
  533. }
  534. #ifdef _USE_OPENLDAP
  535. int CEspHttpServer::onUpdatePasswordInput(CHttpRequest* request, CHttpResponse* response)
  536. {
  537. StringBuffer html;
  538. m_apport->onUpdatePasswordInput(*request->queryContext(), html);
  539. response->setContent(html.length(), html.str());
  540. response->setContentType("text/html; charset=UTF-8");
  541. response->setStatus(HTTP_STATUS_OK);
  542. response->send();
  543. return 0;
  544. }
  545. int CEspHttpServer::onUpdatePassword(CHttpRequest* request, CHttpResponse* response)
  546. {
  547. StringBuffer html;
  548. m_apport->onUpdatePassword(*request->queryContext(), request, html);
  549. response->setContent(html.length(), html.str());
  550. response->setContentType("text/html; charset=UTF-8");
  551. response->setStatus(HTTP_STATUS_OK);
  552. response->send();
  553. return 0;
  554. }
  555. #endif
  556. int CEspHttpServer::onGetMainWindow(CHttpRequest* request, CHttpResponse* response)
  557. {
  558. StringBuffer url("../?main");
  559. double ver = request->queryContext()->getClientVersion();
  560. if (ver>0)
  561. url.appendf("&ver_=%g", ver);
  562. response->redirect(*request, url);
  563. return 0;
  564. }
  565. inline void make_env_var(StringArray &env, StringBuffer &var, const char *name, const char *value)
  566. {
  567. env.append(var.clear().append(name).append('=').append(value).str());
  568. }
  569. inline void make_env_var(StringArray &env, StringBuffer &var, const char *name, const StringBuffer &value)
  570. {
  571. env.append(var.clear().append(name).append('=').append(value).str());
  572. }
  573. inline void make_env_var(StringArray &env, StringBuffer &var, const char *name, __int64 value)
  574. {
  575. env.append(var.clear().append(name).append('=').append(value).str());
  576. }
  577. bool skipHeader(const char *name)
  578. {
  579. if (!stricmp(name, "CONTENT_LENGTH"))
  580. return true;
  581. else if (!strcmp(name, "AUTHORIZATION"))
  582. return true;
  583. else if (!strcmp(name, "CONTENT_TYPE"))
  584. return true;
  585. return false;
  586. }
  587. static void httpGetFile(CHttpRequest* request, CHttpResponse* response, const char *urlpath, const char *filepath)
  588. {
  589. StringBuffer mimetype, etag, lastModified;
  590. MemoryBuffer content;
  591. bool modified = true;
  592. request->getHeader("If-None-Match", etag);
  593. request->getHeader("If-Modified-Since", lastModified);
  594. if (httpContentFromFile(filepath, mimetype, content, modified, lastModified, etag))
  595. {
  596. response->CheckModifiedHTTPContent(modified, lastModified.str(), etag.str(), mimetype.str(), content);
  597. }
  598. else
  599. {
  600. DBGLOG("Get File %s: file not found", filepath);
  601. response->setStatus(HTTP_STATUS_NOT_FOUND);
  602. }
  603. response->send();
  604. }
  605. static void httpGetDirectory(CHttpRequest* request, CHttpResponse* response, const char *urlpath, const char *dirpath, bool top, const StringBuffer &tail)
  606. {
  607. Owned<IPropertyTree> tree = createPTree("directory", ipt_none);
  608. tree->setProp("@path", urlpath);
  609. Owned<IDirectoryIterator> dir = createDirectoryIterator(dirpath, NULL);
  610. ForEach(*dir)
  611. {
  612. IPropertyTree *entry = tree->addPropTree(dir->isDir() ? "directory" : "file", createPTree(ipt_none));
  613. StringBuffer s;
  614. entry->setProp("name", dir->getName(s));
  615. if (!dir->isDir())
  616. entry->setPropInt64("size", dir->getFileSize());
  617. CDateTime cdt;
  618. dir->getModifiedTime(cdt);
  619. entry->setProp("modified", cdt.getString(s.clear(), false));
  620. }
  621. const char *fmt = request->queryParameters()->queryProp("format");
  622. StringBuffer out;
  623. StringBuffer contentType;
  624. if (!fmt || strieq(fmt,"html"))
  625. {
  626. contentType.set("text/html");
  627. out.append("<!DOCTYPE html><html><body>");
  628. if (!top)
  629. out.appendf("<a href='%s'>..</a><br/>", tail.length() ? "." : "..");
  630. Owned<IPropertyTreeIterator> it = tree->getElements("*");
  631. ForEach(*it)
  632. {
  633. IPropertyTree &e = it->query();
  634. const char *href=e.queryProp("name");
  635. if (tail.length())
  636. out.appendf("<a href='%s/%s'>%s</a><br/>", tail.str(), href, href);
  637. else
  638. out.appendf("<a href='%s'>%s</a><br/>", href, href);
  639. }
  640. out.append("</body></html>");
  641. }
  642. else if (strieq(fmt, "json"))
  643. {
  644. contentType.set("application/json");
  645. toJSON(tree, out);
  646. }
  647. else if (strieq(fmt, "xml"))
  648. {
  649. contentType.set("application/xml");
  650. toXML(tree, out);
  651. }
  652. response->setStatus(HTTP_STATUS_OK);
  653. response->setContentType(contentType);
  654. response->setContent(out);
  655. response->send();
  656. }
  657. int CEspHttpServer::onGetFile(CHttpRequest* request, CHttpResponse* response, const char *urlpath)
  658. {
  659. if (!request || !response || !urlpath)
  660. return -1;
  661. StringBuffer ext;
  662. StringBuffer tail;
  663. splitFilename(urlpath, NULL, NULL, &tail, &ext);
  664. bool top = !urlpath || !*urlpath;
  665. StringBuffer httpPath;
  666. request->getPath(httpPath).str();
  667. if (httpPath.charAt(httpPath.length()-1)=='/')
  668. tail.clear();
  669. else if (top)
  670. tail.set("./files");
  671. StringBuffer basedir(getCFD());
  672. basedir.append("files/");
  673. StringBuffer fullpath;
  674. makeAbsolutePath(urlpath, basedir.str(), fullpath);
  675. if (*urlpath && strncmp(basedir, fullpath, basedir.length()))
  676. {
  677. DBGLOG("Get File %s: attempted access outside of %s", urlpath, basedir.str());
  678. response->setStatus(HTTP_STATUS_NOT_FOUND);
  679. response->send();
  680. return 0;
  681. }
  682. if (!checkFileExists(fullpath) && !checkFileExists(fullpath.toUpperCase()) && !checkFileExists(fullpath.toLowerCase()))
  683. {
  684. DBGLOG("Get File %s: file not found", urlpath);
  685. response->setStatus(HTTP_STATUS_NOT_FOUND);
  686. response->send();
  687. return 0;
  688. }
  689. if (isDirectory(fullpath))
  690. httpGetDirectory(request, response, urlpath, fullpath, top, tail);
  691. else
  692. httpGetFile(request, response, urlpath, fullpath);
  693. return 0;
  694. }
  695. int CEspHttpServer::onGetXslt(CHttpRequest* request, CHttpResponse* response, const char *path)
  696. {
  697. if (!request || !response || !path)
  698. return -1;
  699. StringBuffer mimetype, etag, lastModified;
  700. MemoryBuffer content;
  701. bool modified = true;
  702. request->getHeader("If-None-Match", etag);
  703. request->getHeader("If-Modified-Since", lastModified);
  704. VStringBuffer filepath("%ssmc_xslt/%s", getCFD(), path);
  705. if (httpContentFromFile(filepath.str(), mimetype, content, modified, lastModified.clear(), etag) ||
  706. httpContentFromFile(filepath.clear().append(getCFD()).append("xslt/").append(path).str(), mimetype, content, modified, lastModified.clear(), etag))
  707. {
  708. response->CheckModifiedHTTPContent(modified, lastModified.str(), etag.str(), mimetype.str(), content);
  709. }
  710. else
  711. {
  712. DBGLOG("Get XSLT %s: file not found", filepath.str());
  713. response->setStatus(HTTP_STATUS_NOT_FOUND);
  714. }
  715. response->send();
  716. return 0;
  717. }
  718. int CEspHttpServer::unsupported()
  719. {
  720. HtmlPage page("Enterprise Services Platform");
  721. StringBuffer espHeader;
  722. espHeader.append("<table border=\"0\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" bgcolor=\"#000000\" height=\"108\">");
  723. espHeader.append("<tr><td width=\"24%\" height=\"24\" bgcolor=\"#000000\"><img border=\"0\" src=\"esp/files_/logo.gif\" width=\"258\" height=\"108\" /></td></tr>");
  724. espHeader.append("<tr><td width=\"24%\" height=\"24\" bgcolor=\"#AA0000\"><p align=\"center\" /><b><font color=\"#FFFFFF\" size=\"5\">Enterprise Services Platform</font></b></td></tr>");
  725. espHeader.append("</table>");
  726. page.appendContent(new CHtmlText(espHeader.str()));
  727. page.appendContent(new CHtmlHeader(H1, "Unsupported http method"));
  728. StringBuffer content;
  729. page.getHtml(content);
  730. m_response->setVersion(HTTP_VERSION);
  731. m_response->setContent(content.length(), content.str());
  732. m_response->setContentType("text/html; charset=UTF-8");
  733. m_response->setStatus(HTTP_STATUS_OK);
  734. m_response->send();
  735. return 0;
  736. }
  737. int CEspHttpServer::onPost()
  738. {
  739. HtmlPage page("Enterprise Services Platform");
  740. StringBuffer espHeader;
  741. espHeader.append("<table border=\"0\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" bgcolor=\"#000000\" height=\"108\">");
  742. espHeader.append("<tr><td width=\"24%\" height=\"24\" bgcolor=\"#000000\"><img border=\"0\" src=\"esp/files_/logo.gif\" width=\"258\" height=\"108\" /></td></tr>");
  743. espHeader.append("<tr><td width=\"24%\" height=\"24\" bgcolor=\"#AA0000\"><p align=\"center\" /><b><font color=\"#FFFFFF\" size=\"5\">Enterprise Services Platform</font></b></td></tr>");
  744. espHeader.append("</table>");
  745. page.appendContent(new CHtmlText(espHeader.str()));
  746. page.appendContent(new CHtmlHeader(H1, "Invalid POST"));
  747. StringBuffer content;
  748. page.getHtml(content);
  749. m_response->setVersion(HTTP_VERSION);
  750. m_response->setContent(content.length(), content.str());
  751. m_response->setContentType("text/html; charset=UTF-8");
  752. m_response->setStatus(HTTP_STATUS_OK);
  753. m_response->send();
  754. return 0;
  755. }
  756. int CEspHttpServer::onGet()
  757. {
  758. if (m_request && m_request->queryParameters()->hasProp("config_") && m_viewConfig)
  759. {
  760. StringBuffer mimetype, etag, lastModified;
  761. MemoryBuffer content;
  762. bool modified = true;
  763. m_request->getHeader("If-None-Match", etag);
  764. m_request->getHeader("If-Modified-Since", lastModified);
  765. httpContentFromFile("esp.xml", mimetype, content, modified, lastModified, etag);
  766. m_response->setVersion(HTTP_VERSION);
  767. m_response->CheckModifiedHTTPContent(modified, lastModified.str(), etag.str(), HTTP_TYPE_APPLICATION_XML_UTF8, content);
  768. m_response->send();
  769. }
  770. else
  771. {
  772. HtmlPage page("Enterprise Services Platform");
  773. page.appendContent(new CHtmlHeader(H1, "Available Services:"));
  774. CHtmlList * list = (CHtmlList *)page.appendContent(new CHtmlList);
  775. EspHttpBinding* lbind=NULL;
  776. int ordinality=m_apport->getBindingCount();
  777. double ver = m_request->queryContext()->getClientVersion();
  778. for(int index=0; index<ordinality; index++)
  779. {
  780. CEspBindingEntry *entry = m_apport->queryBindingItem(index);
  781. lbind = (entry) ? dynamic_cast<EspHttpBinding*>(entry->queryBinding()) : NULL;
  782. if (lbind)
  783. {
  784. StringBuffer srv, srvLink;
  785. lbind->getServiceName(srv);
  786. srvLink.appendf("/%s", srv.str());
  787. if (ver)
  788. srvLink.appendf("?ver_=%g", ver);
  789. list->appendContent(new CHtmlLink(srv.str(), srvLink.str()));
  790. }
  791. }
  792. StringBuffer content;
  793. page.getHtml(content);
  794. m_response->setVersion(HTTP_VERSION);
  795. m_response->setContent(content.length(), content.str());
  796. m_response->setContentType("text/html; charset=UTF-8");
  797. m_response->setStatus(HTTP_STATUS_OK);
  798. m_response->send();
  799. }
  800. return 0;
  801. }