PageRenderTime 57ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/hphp/runtime/ext/soap/packet.cpp

https://gitlab.com/iranjith4/hhvm
C++ | 432 lines | 360 code | 29 blank | 43 comment | 179 complexity | 23ffb01e317ac556c0e5c3fa314c2ad4 MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2016 Facebook, Inc. (http://www.facebook.com) |
  6. | Copyright (c) 1997-2010 The PHP Group |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 3.01 of the PHP license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.php.net/license/3_01.txt |
  12. | If you did not receive a copy of the PHP license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@php.net so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "hphp/runtime/ext/soap/packet.h"
  18. #include <memory>
  19. #include "hphp/runtime/ext/soap/ext_soap.h"
  20. #include "hphp/util/hash-map-typedefs.h"
  21. #include "hphp/system/systemlib.h"
  22. namespace HPHP {
  23. ///////////////////////////////////////////////////////////////////////////////
  24. static void add_soap_fault(SoapClient *client, const String& code,
  25. const String& fault) {
  26. client->m_soap_fault =
  27. SystemLib::AllocSoapFaultObject(String(code, CopyString), fault);
  28. }
  29. /* SOAP client calls this function to parse response from SOAP server */
  30. bool parse_packet_soap(SoapClient *obj, const char *buffer,
  31. int buffer_size,
  32. std::shared_ptr<sdlFunction> fn, const char *fn_name,
  33. Variant &return_value, Array& soap_headers) {
  34. char* envelope_ns = nullptr;
  35. xmlNodePtr trav, env, head, body, resp, cur, fault;
  36. xmlAttrPtr attr;
  37. int param_count = 0;
  38. int soap_version = SOAP_1_1;
  39. sdlSoapBindingFunctionHeaderMap *hdrs = nullptr;
  40. assert(return_value.asTypedValue()->m_type == KindOfUninit);
  41. return_value.asTypedValue()->m_type = KindOfNull;
  42. /* Response for one-way opearation */
  43. if (buffer_size == 0) {
  44. return true;
  45. }
  46. /* Parse XML packet */
  47. xmlDocPtr response = soap_xmlParseMemory(buffer, buffer_size);
  48. if (!response) {
  49. add_soap_fault(obj, "Client", "looks like we got no XML document");
  50. return false;
  51. }
  52. if (xmlGetIntSubset(response) != nullptr) {
  53. add_soap_fault(obj, "Client", "DTD are not supported by SOAP");
  54. xmlFreeDoc(response);
  55. return false;
  56. }
  57. /* Get <Envelope> element */
  58. env = nullptr;
  59. trav = response->children;
  60. while (trav != nullptr) {
  61. if (trav->type == XML_ELEMENT_NODE) {
  62. if (!env && node_is_equal_ex(trav,"Envelope", SOAP_1_1_ENV_NAMESPACE)) {
  63. env = trav;
  64. envelope_ns = SOAP_1_1_ENV_NAMESPACE;
  65. soap_version = SOAP_1_1;
  66. } else if (!env &&
  67. node_is_equal_ex(trav, "Envelope", SOAP_1_2_ENV_NAMESPACE)) {
  68. env = trav;
  69. envelope_ns = SOAP_1_2_ENV_NAMESPACE;
  70. soap_version = SOAP_1_2;
  71. } else {
  72. add_soap_fault(obj, "VersionMismatch", "Wrong Version");
  73. xmlFreeDoc(response);
  74. return false;
  75. }
  76. }
  77. trav = trav->next;
  78. }
  79. if (env == nullptr) {
  80. add_soap_fault(obj, "Client",
  81. "looks like we got XML without \"Envelope\" element");
  82. xmlFreeDoc(response);
  83. return false;
  84. }
  85. attr = env->properties;
  86. while (attr != nullptr) {
  87. if (attr->ns == nullptr) {
  88. add_soap_fault(obj, "Client",
  89. "A SOAP Envelope element cannot have non Namespace "
  90. "qualified attributes");
  91. xmlFreeDoc(response);
  92. return false;
  93. }
  94. if (attr_is_equal_ex(attr, "encodingStyle", SOAP_1_2_ENV_NAMESPACE)) {
  95. if (soap_version == SOAP_1_2) {
  96. add_soap_fault(obj, "Client",
  97. "encodingStyle cannot be specified on the Envelope");
  98. xmlFreeDoc(response);
  99. return false;
  100. }
  101. if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE)) {
  102. add_soap_fault(obj, "Client", "Unknown data encoding style");
  103. xmlFreeDoc(response);
  104. return false;
  105. }
  106. }
  107. attr = attr->next;
  108. }
  109. /* Get <Header> element */
  110. head = nullptr;
  111. trav = env->children;
  112. while (trav != nullptr && trav->type != XML_ELEMENT_NODE) {
  113. trav = trav->next;
  114. }
  115. if (trav != nullptr && node_is_equal_ex(trav,"Header",envelope_ns)) {
  116. head = trav;
  117. trav = trav->next;
  118. }
  119. /* Get <Body> element */
  120. body = nullptr;
  121. while (trav != nullptr && trav->type != XML_ELEMENT_NODE) {
  122. trav = trav->next;
  123. }
  124. if (trav != nullptr && node_is_equal_ex(trav,"Body",envelope_ns)) {
  125. body = trav;
  126. trav = trav->next;
  127. }
  128. while (trav != nullptr && trav->type != XML_ELEMENT_NODE) {
  129. trav = trav->next;
  130. }
  131. if (body == nullptr) {
  132. add_soap_fault(obj, "Client", "Body must be present in a SOAP envelope");
  133. xmlFreeDoc(response);
  134. return false;
  135. }
  136. attr = body->properties;
  137. while (attr != nullptr) {
  138. if (attr->ns == nullptr) {
  139. if (soap_version == SOAP_1_2) {
  140. add_soap_fault(obj, "Client",
  141. "A SOAP Body element cannot have non Namespace "
  142. "qualified attributes");
  143. xmlFreeDoc(response);
  144. return false;
  145. }
  146. } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
  147. if (soap_version == SOAP_1_2) {
  148. add_soap_fault(obj, "Client",
  149. "encodingStyle cannot be specified on the Body");
  150. xmlFreeDoc(response);
  151. return false;
  152. }
  153. if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE)) {
  154. add_soap_fault(obj, "Client", "Unknown data encoding style");
  155. xmlFreeDoc(response);
  156. return false;
  157. }
  158. }
  159. attr = attr->next;
  160. }
  161. if (trav != nullptr && soap_version == SOAP_1_2) {
  162. add_soap_fault(obj, "Client",
  163. "A SOAP 1.2 envelope can contain only Header and Body");
  164. xmlFreeDoc(response);
  165. return false;
  166. }
  167. if (head != nullptr) {
  168. attr = head->properties;
  169. while (attr != nullptr) {
  170. if (attr->ns == nullptr) {
  171. add_soap_fault(obj, "Client",
  172. "A SOAP Header element cannot have non Namespace "
  173. "qualified attributes");
  174. xmlFreeDoc(response);
  175. return false;
  176. }
  177. if (attr_is_equal_ex(attr, "encodingStyle", SOAP_1_2_ENV_NAMESPACE)) {
  178. if (soap_version == SOAP_1_2) {
  179. add_soap_fault(obj, "Client",
  180. "encodingStyle cannot be specified on the Header");
  181. xmlFreeDoc(response);
  182. return false;
  183. }
  184. if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE)) {
  185. add_soap_fault(obj, "Client", "Unknown data encoding style");
  186. xmlFreeDoc(response);
  187. return false;
  188. }
  189. }
  190. attr = attr->next;
  191. }
  192. }
  193. /* Check if <Body> contains <Fault> element */
  194. fault = get_node_ex(body->children,"Fault",envelope_ns);
  195. if (fault != nullptr) {
  196. char *faultcode = nullptr;
  197. String faultstring, faultactor;
  198. Variant details;
  199. xmlNodePtr tmp;
  200. if (soap_version == SOAP_1_1) {
  201. tmp = get_node(fault->children, "faultcode");
  202. if (tmp != nullptr && tmp->children != nullptr) {
  203. faultcode = (char*)tmp->children->content;
  204. }
  205. tmp = get_node(fault->children, "faultstring");
  206. if (tmp != nullptr && tmp->children != nullptr) {
  207. Variant zv = master_to_zval(get_conversion(KindOfString), tmp);
  208. faultstring = zv.toString();
  209. }
  210. tmp = get_node(fault->children, "faultactor");
  211. if (tmp != nullptr && tmp->children != nullptr) {
  212. Variant zv = master_to_zval(get_conversion(KindOfString), tmp);
  213. faultactor = zv.toString();
  214. }
  215. tmp = get_node(fault->children, "detail");
  216. if (tmp != nullptr) {
  217. details = master_to_zval(encodePtr(), tmp);
  218. }
  219. } else {
  220. tmp = get_node(fault->children, "Code");
  221. if (tmp != nullptr && tmp->children != nullptr) {
  222. tmp = get_node(tmp->children, "Value");
  223. if (tmp != nullptr && tmp->children != nullptr) {
  224. faultcode = (char*)tmp->children->content;
  225. }
  226. }
  227. tmp = get_node(fault->children,"Reason");
  228. if (tmp != nullptr && tmp->children != nullptr) {
  229. /* TODO: lang attribute */
  230. tmp = get_node(tmp->children,"Text");
  231. if (tmp != nullptr && tmp->children != nullptr) {
  232. Variant zv = master_to_zval(get_conversion(KindOfString), tmp);
  233. faultstring = zv.toString();
  234. }
  235. }
  236. tmp = get_node(fault->children,"Detail");
  237. if (tmp != nullptr) {
  238. details = master_to_zval(encodePtr(), tmp);
  239. }
  240. }
  241. obj->m_soap_fault =
  242. SystemLib::AllocSoapFaultObject(String(faultcode, CopyString),
  243. faultstring,
  244. faultactor,
  245. details);
  246. xmlFreeDoc(response);
  247. return false;
  248. }
  249. /* Parse content of <Body> element */
  250. return_value = Array::Create();
  251. resp = body->children;
  252. while (resp != nullptr && resp->type != XML_ELEMENT_NODE) {
  253. resp = resp->next;
  254. }
  255. if (resp != nullptr) {
  256. if (fn && fn->binding && fn->binding->bindingType == BINDING_SOAP) {
  257. /* Function has WSDL description */
  258. sdlParamPtr h_param, param;
  259. xmlNodePtr val = nullptr;
  260. const char *name, *ns = nullptr;
  261. Variant tmp(Variant::NullInit{});
  262. sdlSoapBindingFunctionPtr fnb =
  263. (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
  264. int res_count;
  265. hdrs = &fnb->output.headers;
  266. if (!fn->responseParameters.empty()) {
  267. res_count = fn->responseParameters.size();
  268. for (unsigned int i = 0; i < fn->responseParameters.size(); i++) {
  269. h_param = fn->responseParameters[i];
  270. param = h_param;
  271. if (fnb->style == SOAP_DOCUMENT) {
  272. if (param->element) {
  273. name = param->element->name.c_str();
  274. ns = param->element->namens.c_str();
  275. /*
  276. name = param->encode->details.type_str;
  277. ns = param->encode->details.ns;
  278. */
  279. } else {
  280. name = param->paramName.c_str();
  281. }
  282. } else {
  283. name = fn->responseName.c_str();
  284. /* ns = ? */
  285. }
  286. /* Get value of parameter */
  287. cur = get_node_ex(resp, (char*)name, (char*)ns);
  288. if (!cur) {
  289. cur = get_node(resp, (char*)name);
  290. /* TODO: produce warning invalid ns */
  291. }
  292. if (!cur && fnb->style == SOAP_RPC) {
  293. cur = resp;
  294. }
  295. if (cur) {
  296. if (fnb->style == SOAP_DOCUMENT) {
  297. val = cur;
  298. } else {
  299. val = get_node(cur->children, (char*)param->paramName.c_str());
  300. if (res_count == 1) {
  301. if (val == nullptr) {
  302. val = get_node(cur->children, "return");
  303. }
  304. if (val == nullptr) {
  305. val = get_node(cur->children, "result");
  306. }
  307. if (val == nullptr && cur->children && !cur->children->next) {
  308. val = cur->children;
  309. }
  310. }
  311. }
  312. }
  313. if (!val) {
  314. /* TODO: may be "nil" is not OK? */
  315. /*
  316. add_soap_fault(obj, "Client", "Can't find response data");
  317. xmlFreeDoc(response);
  318. return false;
  319. */
  320. } else {
  321. /* Decoding value of parameter */
  322. if (param != nullptr) {
  323. tmp = master_to_zval(param->encode, val);
  324. } else {
  325. tmp = master_to_zval(encodePtr(), val);
  326. }
  327. }
  328. return_value.toArrRef().set(String(param->paramName), tmp);
  329. param_count++;
  330. }
  331. }
  332. } else {
  333. /* Function hasn't WSDL description */
  334. xmlNodePtr val;
  335. val = resp->children;
  336. while (val != nullptr) {
  337. while (val && val->type != XML_ELEMENT_NODE) {
  338. val = val->next;
  339. }
  340. if (val != nullptr) {
  341. if (!node_is_equal_ex(val,"result",RPC_SOAP12_NAMESPACE)) {
  342. Variant tmp = master_to_zval(encodePtr(), val);
  343. if (val->name) {
  344. String key((char*)val->name, CopyString);
  345. if (return_value.toCArrRef().exists(key)) {
  346. auto& lval = return_value.toArrRef().lvalAt(key);
  347. if (!lval.isArray()) lval = lval.toArray();
  348. lval.toArrRef().append(tmp);
  349. } else if (val->next && get_node(val->next, (char*)val->name)) {
  350. Array arr = Array::Create();
  351. arr.append(tmp);
  352. return_value.toArrRef().set(key, arr);
  353. } else {
  354. return_value.toArrRef().set(key, tmp);
  355. }
  356. } else {
  357. return_value.toArrRef().append(tmp);
  358. }
  359. ++param_count;
  360. }
  361. val = val->next;
  362. }
  363. }
  364. }
  365. }
  366. if (return_value.isArray()) {
  367. if (param_count == 0) {
  368. return_value = init_null();
  369. } else if (param_count == 1) {
  370. Array arr = return_value.toArray();
  371. ArrayIter iter(arr);
  372. return_value = iter.second();
  373. }
  374. }
  375. if (head) {
  376. trav = head->children;
  377. while (trav) {
  378. if (trav->type == XML_ELEMENT_NODE) {
  379. encodePtr enc;
  380. if (hdrs && !hdrs->empty()) {
  381. std::string key;
  382. if (trav->ns) {
  383. key += (char*)trav->ns->href;
  384. key += ':';
  385. }
  386. key += (char*)trav->name;
  387. sdlSoapBindingFunctionHeaderMap::const_iterator iter =
  388. hdrs->find(key);
  389. if (iter != hdrs->end()) {
  390. enc = iter->second->encode;
  391. }
  392. }
  393. soap_headers.set(String((char*)trav->name, CopyString),
  394. master_to_zval(enc, trav));
  395. }
  396. trav = trav->next;
  397. }
  398. }
  399. xmlFreeDoc(response);
  400. return true;
  401. }
  402. ///////////////////////////////////////////////////////////////////////////////
  403. }