httpclient.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  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 ESPHTTP_EXPORTS
  15. #define esp_http_decl DECL_EXPORT
  16. #else
  17. #define esp_http_decl DECL_IMPORT
  18. #endif
  19. //Jlib
  20. #include "jliball.hpp"
  21. //ESP Bindings
  22. #include "httpclient.ipp"
  23. #include "http/platform/httptransport.ipp"
  24. #include "securesocket.hpp"
  25. #include "bindutil.hpp"
  26. #include "espplugin.ipp"
  27. #include "SOAP/Platform/soapmessage.hpp"
  28. /*************************************************************************
  29. CHttpClient Implementation
  30. **************************************************************************/
  31. #define URL_MAX 512
  32. #define HTTP_CLIENT_DEFAULT_CONNECT_TIMEOUT 3000
  33. CHttpClientContext::CHttpClientContext()
  34. {
  35. }
  36. CHttpClientContext::CHttpClientContext(IPropertyTree* config) : m_config(config)
  37. {
  38. }
  39. CHttpClientContext::~CHttpClientContext()
  40. {
  41. }
  42. IHttpClient* CHttpClientContext::createHttpClient(const char* proxy, const char* url)
  43. {
  44. CHttpClient* client = new CHttpClient(proxy, url);
  45. if(url != NULL && Utils::strncasecmp(url, "HTTPS://", 8) == 0)
  46. {
  47. CriticalBlock b(m_sscrit);
  48. if(m_ssctx.get() == NULL)
  49. {
  50. StringBuffer libName;
  51. IEspPlugin *pplg = loadPlugin(libName.append(SharedObjectPrefix).append(SSLIB).append(SharedObjectExtension));
  52. if (!pplg)
  53. throw MakeStringException(-1, "dll/shared-object %s can't be loaded", libName.str());
  54. if(m_config.get() == NULL)
  55. {
  56. createSecureSocketContext_t xproc = NULL;
  57. xproc = (createSecureSocketContext_t) pplg->getProcAddress("createSecureSocketContext");
  58. if (xproc)
  59. m_ssctx.setown(xproc(ClientSocket));
  60. else
  61. throw MakeStringException(-1, "procedure createSecureSocketContext can't be loaded");
  62. }
  63. else
  64. {
  65. createSecureSocketContextEx2_t xproc = NULL;
  66. xproc = (createSecureSocketContextEx2_t) pplg->getProcAddress("createSecureSocketContextEx2");
  67. if (xproc)
  68. m_ssctx.setown(xproc(m_config.get(),ClientSocket));
  69. else
  70. throw MakeStringException(-1, "procedure createSecureSocketContext can't be loaded");
  71. }
  72. if(m_ssctx.get() == NULL)
  73. throw MakeStringException(-1, "SecureSocketContext can't be created");
  74. }
  75. client->setSsCtx(m_ssctx.get());
  76. }
  77. #ifdef COOKIE_HANDLING
  78. client->m_context = this;
  79. if(url && *url)
  80. {
  81. ReadLockBlock rblock(m_rwlock);
  82. StringBuffer host, protocol, user, passwd, port, path;
  83. Utils::SplitURL(url, protocol, user, passwd, host, port, path);
  84. if(host.length() > 0)
  85. {
  86. ForEachItemIn(x, m_cookies)
  87. {
  88. CEspCookie* cookie = &m_cookies.item(x);
  89. if(!cookie)
  90. continue;
  91. const char* chost = cookie->getHost();
  92. if(chost && stricmp(chost, host.str()) == 0)
  93. {
  94. //TODO: is it better to clone the cookie?
  95. client->m_request_cookies.append(*LINK(cookie));
  96. }
  97. }
  98. }
  99. }
  100. #endif
  101. return client;
  102. }
  103. CHttpClient::CHttpClient(const char *proxy, const char* url) : m_proxy(proxy), m_url(url), m_disableKeepAlive(false), m_timeout(0)
  104. {
  105. StringBuffer protocol,username,password, host, port, path;
  106. Utils::SplitURL(url, protocol,username,password, host, port, path);
  107. m_protocol.set(protocol.str());
  108. m_host.set(host.str());
  109. if(port.length() > 0)
  110. m_port = atoi(port.str());
  111. else
  112. if(Utils::strncasecmp(url, "HTTPS://", 8) == 0)
  113. m_port = 443;
  114. else
  115. m_port = 80;
  116. m_path.set(path.str());
  117. m_socket = NULL;
  118. }
  119. CHttpClient::~CHttpClient()
  120. {
  121. if(m_socket)
  122. {
  123. try
  124. {
  125. m_socket->shutdown();
  126. m_socket->close();
  127. m_socket->Release();
  128. }
  129. catch(...)
  130. {
  131. }
  132. }
  133. }
  134. void CHttpClient::setSsCtx(ISecureSocketContext* ctx)
  135. {
  136. m_ssctx = ctx;
  137. }
  138. void CHttpClient::setUserID(const char* userid)
  139. {
  140. m_userid.set(userid);
  141. }
  142. void CHttpClient::setPassword(const char* password)
  143. {
  144. m_password.set(password);
  145. }
  146. void CHttpClient::setRealm(const char* realm)
  147. {
  148. m_realm.set(realm);
  149. }
  150. void CHttpClient::setProxy(const char* proxy)
  151. {
  152. m_proxy.clear().append(proxy);
  153. }
  154. void CHttpClient::setTimeOut(unsigned int timeout)
  155. {
  156. m_timeout = timeout;
  157. }
  158. int CHttpClient::connect(StringBuffer& errmsg)
  159. {
  160. SocketEndpoint ep;
  161. if(m_proxy.length() == 0)
  162. {
  163. if(m_host.length() <= 0)
  164. throw MakeStringException(-1, "host not specified");
  165. if (!ep.set(m_host.get(), m_port))
  166. {
  167. errmsg.appendf("Bad host name/ip: %s", m_host.get());
  168. ERRLOG("%s", errmsg.str());
  169. return -1;
  170. }
  171. //TODO: should it be 443 for HTTPS??
  172. if (ep.port==0)
  173. ep.port=80;
  174. }
  175. else
  176. {
  177. if (!ep.set(m_proxy.str()))
  178. {
  179. errmsg.appendf("Bad proxy name/ip: %s", m_proxy.str());
  180. ERRLOG("%s", errmsg.str());
  181. return -1;
  182. }
  183. //TODO: should it be 443 for HTTPS??
  184. if (ep.port==0)
  185. ep.port=80;
  186. }
  187. try
  188. {
  189. if(m_timeout)
  190. m_socket = ISocket::connect_timeout(ep,m_timeout);
  191. else
  192. m_socket = ISocket::connect_timeout(ep, HTTP_CLIENT_DEFAULT_CONNECT_TIMEOUT);
  193. if(strcmp(m_protocol.get(), "HTTPS") == 0)
  194. {
  195. ISecureSocket* securesocket = m_ssctx->createSecureSocket(m_socket);
  196. int res = securesocket->secure_connect();
  197. if(res < 0)
  198. {
  199. m_socket->shutdown();
  200. m_socket->close();
  201. m_socket->Release();
  202. m_socket = NULL;
  203. }
  204. else
  205. {
  206. m_socket = securesocket;
  207. }
  208. }
  209. }
  210. catch(IException *e)
  211. {
  212. StringBuffer url;
  213. ERRLOG("Error connecting to %s", ep.getUrlStr(url).str());
  214. DBGLOG(e);
  215. e->Release();
  216. m_socket = NULL;
  217. return -1;
  218. }
  219. catch(...)
  220. {
  221. StringBuffer url;
  222. ERRLOG("Unknown exception connecting to %s", ep.getUrlStr(url).str());
  223. m_socket = NULL;
  224. return -1;
  225. }
  226. if(m_socket == NULL)
  227. {
  228. StringBuffer urlstr;
  229. DBGLOG(">>Can't connect to %s", ep.getUrlStr(urlstr).str());
  230. return -1;
  231. }
  232. return 0;
  233. }
  234. int CHttpClient::sendRequest(const char* method, const char* contenttype, StringBuffer& request, StringBuffer& response)
  235. {
  236. StringBuffer errmsg;
  237. if(connect(errmsg) < 0)
  238. {
  239. response.append(errmsg);
  240. return -1;
  241. }
  242. Owned<CHttpRequest> httprequest;
  243. Owned<CHttpResponse> httpresponse;
  244. httprequest.setown(new CHttpRequest(*m_socket));
  245. httpresponse.setown(new CHttpResponse(*m_socket));
  246. httprequest->setMethod(method);
  247. httprequest->setVersion("HTTP/1.1");
  248. if(m_proxy.length() <= 0)
  249. {
  250. httprequest->setPath(m_path.get());
  251. }
  252. else
  253. {
  254. httprequest->setPath(m_url.get());
  255. }
  256. httprequest->setHost(m_host.get());
  257. httprequest->setPort(m_port);
  258. httprequest->setContentType(contenttype);
  259. if(m_userid.length() > 0)
  260. {
  261. StringBuffer uidpair;
  262. uidpair.append(m_userid.get()).append(":").append(m_password.get());
  263. StringBuffer result;
  264. Utils::base64encode(uidpair.str(), uidpair.length(), result);
  265. StringBuffer authhdr("Basic ");
  266. //Remove the \n from the end of the encoded string.
  267. //Should it even be there??
  268. result.setCharAt(result.length() - 1,0);
  269. authhdr.append(result.str());
  270. httprequest->addHeader("Authorization", authhdr.str());
  271. }
  272. if(m_realm.length() > 0)
  273. {
  274. StringBuffer authheader;
  275. authheader.append("Basic realm=\"").append(m_realm).append("\"");
  276. httprequest->addHeader("WWW-Authenticate", authheader.str());
  277. }
  278. if (getEspLogLevel()>LogNormal)
  279. {
  280. DBGLOG("Content type: %s", contenttype);
  281. DBGLOG("Request content: %s", request.str());
  282. }
  283. httprequest->setContent(request.str());
  284. #ifdef COOKIE_HANDLING
  285. ForEachItemIn(x, m_request_cookies)
  286. {
  287. CEspCookie* cookie = &m_request_cookies.item(x);
  288. if(cookie)
  289. httprequest->addCookie(LINK(cookie));
  290. }
  291. #endif
  292. if(m_timeout)
  293. httpresponse->setTimeOut(m_timeout);
  294. httprequest->send();
  295. httpresponse->receive(false, NULL); // MORE - pass in IMultiException if we want to see exceptions (which are not fatal)
  296. #ifdef COOKIE_HANDLING
  297. if(m_context)
  298. {
  299. IArrayOf<CEspCookie>& cookies = httpresponse->queryCookies();
  300. ForEachItemIn(x, cookies)
  301. {
  302. CEspCookie* cookie = &cookies.item(x);
  303. if(!cookie)
  304. continue;
  305. cookie->setHost(m_host.get());
  306. m_context->addCookie(cookie);
  307. }
  308. }
  309. #endif
  310. httpresponse->getContent(response);
  311. if (getEspLogLevel()>LogNormal)
  312. DBGLOG("Response content: %s", response.str());
  313. return 0;
  314. }
  315. int CHttpClient::sendRequest(IProperties *headers, const char* method, const char* contenttype, StringBuffer& request, StringBuffer& response, StringBuffer& responseStatus, bool alwaysReadContent)
  316. {
  317. StringBuffer errmsg;
  318. if(connect(errmsg) < 0)
  319. {
  320. response.append(errmsg);
  321. return -1;
  322. }
  323. Owned<CHttpRequest> httprequest;
  324. Owned<CHttpResponse> httpresponse;
  325. httprequest.setown(new CHttpRequest(*m_socket));
  326. httpresponse.setown(new CHttpResponse(*m_socket));
  327. httprequest->setMethod(method);
  328. httprequest->setVersion("HTTP/1.1");
  329. if(m_proxy.length() <= 0)
  330. {
  331. httprequest->setPath(m_path.get());
  332. }
  333. else
  334. {
  335. httprequest->setPath(m_url.get());
  336. }
  337. httprequest->setHost(m_host.get());
  338. httprequest->setPort(m_port);
  339. httprequest->setContentType(contenttype);
  340. if (headers)
  341. {
  342. Owned<IPropertyIterator> iter = headers->getIterator();
  343. ForEach(*iter.get())
  344. {
  345. const char *key = iter->getPropKey();
  346. if (key && *key)
  347. {
  348. const char *value = headers->queryProp(key);
  349. if (value && *value)
  350. httprequest->addHeader(key, value);
  351. }
  352. }
  353. }
  354. if(m_userid.length() > 0)
  355. {
  356. StringBuffer uidpair;
  357. uidpair.append(m_userid.get()).append(":").append(m_password.get());
  358. StringBuffer result;
  359. Utils::base64encode(uidpair.str(), uidpair.length(), result);
  360. StringBuffer authhdr("Basic ");
  361. //Remove the \n from the end of the encoded string.
  362. //Should it even be there??
  363. result.setCharAt(result.length() - 1,0);
  364. authhdr.append(result.str());
  365. httprequest->addHeader("Authorization", authhdr.str());
  366. }
  367. if(m_realm.length() > 0)
  368. {
  369. StringBuffer authheader;
  370. authheader.append("Basic realm=\"").append(m_realm).append("\"");
  371. httprequest->addHeader("WWW-Authenticate", authheader.str());
  372. }
  373. if (getEspLogLevel()>LogNormal)
  374. {
  375. DBGLOG("Content type: %s", contenttype);
  376. DBGLOG("Request content: %s", request.str());
  377. }
  378. httprequest->setContent(request.str());
  379. Owned<IMultiException> me = MakeMultiException();
  380. //httprequest->sendWithoutContentType();
  381. #ifdef COOKIE_HANDLING
  382. ForEachItemIn(x, m_request_cookies)
  383. {
  384. CEspCookie* cookie = &m_request_cookies.item(x);
  385. if(cookie)
  386. httprequest->addCookie(LINK(cookie));
  387. }
  388. #endif
  389. if(m_timeout)
  390. httpresponse->setTimeOut(m_timeout);
  391. httprequest->send();
  392. httpresponse->receive(alwaysReadContent, me); // MORE - pass in IMultiException if we want to see exceptions (which are not fatal)
  393. #ifdef COOKIE_HANDLING
  394. if(m_context)
  395. {
  396. IArrayOf<CEspCookie>& cookies = httpresponse->queryCookies();
  397. ForEachItemIn(x, cookies)
  398. {
  399. CEspCookie* cookie = &cookies.item(x);
  400. if(!cookie)
  401. continue;
  402. cookie->setHost(m_host.get());
  403. m_context->addCookie(cookie);
  404. }
  405. }
  406. #endif
  407. httpresponse->getContent(response);
  408. httpresponse->getStatus(responseStatus);
  409. //const char* dstxml = "c:\\debug02.jpg";
  410. //int ofile = open(dstxml, _O_WRONLY | _O_CREAT | _O_BINARY);
  411. //if(ofile != -1)
  412. //{
  413. //write(ofile, response.str(), response.length());
  414. //close(ofile);
  415. //}
  416. if (getEspLogLevel()>LogNormal)
  417. DBGLOG("Response content: %s", response.str());
  418. return 0;
  419. }
  420. int CHttpClient::sendRequest(const char* method, const char* contenttype, StringBuffer& request, StringBuffer& response, StringBuffer& responseStatus, bool alwaysReadContent)
  421. {
  422. return sendRequest(NULL, method, contenttype, request, response, responseStatus, alwaysReadContent);
  423. }
  424. // since an element may have namespace specified in its tag, don't look for trailing '>'
  425. // in its start tag
  426. static const char* getElementText(const char* str, const char* beginTag/*like '<A'*/, const char* endTag/*like '</A>'*/,
  427. int& textLen)
  428. {
  429. const char* element = strstr(str, beginTag);//element points to '<A...'
  430. if (element)
  431. {
  432. const char* endStartTag = strchr(element, '>');/* > of start tag <A...>*/
  433. const char* beginEndTag = strstr(element, endTag);
  434. if (endStartTag && beginEndTag && endStartTag++ < beginEndTag)
  435. {
  436. textLen = beginEndTag - endStartTag;
  437. return endStartTag;
  438. }
  439. }
  440. textLen = 0;
  441. return NULL;
  442. }
  443. static void parseSoapFault(const char* content, StringBuffer& msg)
  444. {
  445. const char* start = strstr(content, ":Fault");//match any namespace like 'soap' or 'soapenv' etc. before :Fault
  446. if (start)
  447. {
  448. start += 8;
  449. msg.append("SOAP fault:");
  450. int textLen;
  451. const char* elementText;
  452. elementText = getElementText(start, "<faultcode", "</faultcode>", textLen);
  453. if (elementText)
  454. {
  455. msg.append(" code=");
  456. msg.append(textLen, elementText);
  457. msg.append(".");
  458. }
  459. elementText = getElementText(start, "<faultstring", "</faultstring>", textLen);
  460. if (elementText)
  461. {
  462. msg.append(" string=");
  463. msg.append(textLen, elementText);
  464. msg.append(".");
  465. }
  466. elementText = getElementText(start, "<detail", "</detail>", textLen);
  467. if (elementText)
  468. {
  469. msg.append(" detail=");
  470. msg.append(textLen, elementText);
  471. msg.append(".");
  472. }
  473. }
  474. }
  475. int CHttpClient::postRequest(ISoapMessage &req, ISoapMessage& resp)
  476. {
  477. CSoapRequest& request = *(dynamic_cast<CSoapRequest*>(&req));
  478. const char* requeststr = request.get_text();
  479. CSoapResponse& response = *(dynamic_cast<CSoapResponse*>(&resp));
  480. StringBuffer errmsg;
  481. if(connect(errmsg) < 0 || !m_socket)
  482. {
  483. response.set_status(SOAP_CONNECTION_ERROR);
  484. response.set_err(errmsg);
  485. return -1;
  486. }
  487. Owned<CHttpRequest> httprequest(new CHttpRequest(*m_socket));
  488. Owned<CHttpResponse> httpresponse(new CHttpResponse(*m_socket));
  489. httprequest->setMethod("POST");
  490. httprequest->setVersion("HTTP/1.1");
  491. if(m_proxy.length() <= 0)
  492. {
  493. httprequest->setPath(m_path.get());
  494. }
  495. else
  496. {
  497. httprequest->setPath(m_url.get());
  498. }
  499. httprequest->setHost(m_host.get());
  500. httprequest->setPort(m_port);
  501. if(strlen(request.get_content_type()) > 0)
  502. httprequest->setContentType(request.get_content_type());
  503. const char* soapaction = request.get_soapaction();
  504. if(soapaction != NULL && strlen(soapaction) > 0)
  505. {
  506. httprequest->addHeader("SOAPAction", soapaction);
  507. }
  508. if(m_userid.length() > 0)
  509. {
  510. StringBuffer uidpair;
  511. uidpair.append(m_userid.get()).append(":").append(m_password.get());
  512. StringBuffer result;
  513. Utils::base64encode(uidpair.str(), uidpair.length(), result);
  514. StringBuffer authhdr("Basic ");
  515. //Remove the \n from the end of the encoded string.
  516. //Should it even be there??
  517. result.setCharAt(result.length() - 1,0);
  518. authhdr.append(result.str());
  519. httprequest->addHeader("Authorization", authhdr.str());
  520. if(m_proxy.length())
  521. httprequest->addHeader("Proxy-Authorization", authhdr.str());
  522. }
  523. if(m_realm.length() > 0)
  524. {
  525. StringBuffer authheader;
  526. authheader.append("Basic realm=\"").append(m_realm).append("\"");
  527. httprequest->addHeader("WWW-Authenticate", authheader.str());
  528. }
  529. if (m_disableKeepAlive)
  530. httprequest->addHeader("Connection", "close");
  531. httprequest->setContentType(HTTP_TYPE_TEXT_XML);
  532. httprequest->setContent(requeststr);
  533. #ifdef COOKIE_HANDLING
  534. ForEachItemIn(x, m_request_cookies)
  535. {
  536. CEspCookie* cookie = &m_request_cookies.item(x);
  537. if(cookie)
  538. httprequest->addCookie(LINK(cookie));
  539. }
  540. #endif
  541. httprequest->send();
  542. Owned<IMultiException> me = MakeMultiException();
  543. httpresponse->receive(true, me);
  544. #ifdef COOKIE_HANDLING
  545. if(m_context)
  546. {
  547. IArrayOf<CEspCookie>& cookies = httpresponse->queryCookies();
  548. ForEachItemIn(x, cookies)
  549. {
  550. CEspCookie* cookie = &cookies.item(x);
  551. if(!cookie)
  552. continue;
  553. cookie->setHost(m_host.get());
  554. m_context->addCookie(cookie);
  555. }
  556. }
  557. #endif
  558. StringBuffer status;
  559. httpresponse->getStatus(status);
  560. int statusCode = atoi(status.str());
  561. char statusClass = '0';
  562. if(status.length() > 0)
  563. statusClass = status.charAt(0);
  564. errmsg.clear().appendf("HTTP Status %s", status.str());
  565. if(statusClass == '2')
  566. {
  567. response.set_status(SOAP_OK);
  568. }
  569. else if(statusClass == '3')
  570. {
  571. response.set_status(SOAP_SERVER_ERROR);
  572. response.set_err(errmsg.str());
  573. return -1;
  574. }
  575. else if(statusClass == '4')
  576. {
  577. if(statusCode == HTTP_STATUS_UNAUTHORIZED_CODE ||
  578. statusCode == HTTP_STATUS_FORBIDDEN_CODE ||
  579. statusCode == HTTP_STATUS_NOT_ALLOWED_CODE ||
  580. statusCode == HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED_CODE)
  581. response.set_status(SOAP_AUTHENTICATION_ERROR);
  582. else
  583. response.set_status(SOAP_CLIENT_ERROR);
  584. response.set_err(errmsg.str());
  585. DBGLOG("SOAP_CLIENT_ERROR: %s", errmsg.str());
  586. return -1;
  587. }
  588. else if(statusClass == '5')
  589. {
  590. response.set_status(SOAP_SERVER_ERROR);
  591. StringBuffer content;
  592. parseSoapFault(httpresponse->getContent(content),errmsg);
  593. response.set_err(errmsg.str());
  594. DBGLOG("SOAP_SERVER_ERROR: %s", errmsg.str());
  595. return -1;
  596. }
  597. else
  598. {
  599. DBGLOG("%s", errmsg.str());
  600. StringBuffer msg;
  601. if (me->ordinality())
  602. {
  603. aindex_t count = me->ordinality();
  604. for (aindex_t i = 0; i < count; i++)
  605. {
  606. IException& ex = me->item(i);
  607. int errCode = ex.errorCode();
  608. StringBuffer buf;
  609. msg.appendf("errorCode = %d\t message = %s\n", errCode, ex.errorMessage(buf).str());
  610. }
  611. }
  612. DBGLOG("SOAP_RPC_ERROR = %s", msg.str());
  613. response.set_status(SOAP_RPC_ERROR);
  614. response.set_err(msg);
  615. return -1;
  616. }
  617. StringBuffer contenttype;
  618. httpresponse->getContentType(contenttype);
  619. response.set_content_type(contenttype.str());
  620. StringBuffer content;
  621. httpresponse->getContent(content);
  622. if (getEspLogLevel()>LogNormal)
  623. {
  624. if(httpresponse->isTextMessage())
  625. DBGLOG("http response content = %s", content.str());
  626. }
  627. response.set_text(content.str());
  628. // parse soap fault
  629. parseSoapFault(content,errmsg.clear());
  630. if (errmsg.length())
  631. response.set_err(errmsg);
  632. return 0;
  633. }
  634. static Owned<CHttpClientContext> theHttpClientContext;
  635. static CriticalSection httpCrit;
  636. IHttpClientContext* getHttpClientContext()
  637. {
  638. CriticalBlock b(httpCrit);
  639. if(theHttpClientContext.get() == NULL)
  640. {
  641. theHttpClientContext.setown(new CHttpClientContext());
  642. }
  643. return theHttpClientContext.getLink();
  644. }
  645. IHttpClientContext* createHttpClientContext(IPropertyTree* config)
  646. {
  647. return new CHttpClientContext(config);
  648. }