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

404 lines
12 KiB

23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2004 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.0 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_0.txt. |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Brad Lafountain <rodif_bl@yahoo.com> |
  16. | Shane Caraveo <shane@caraveo.com> |
  17. | Dmitry Stogov <dmitry@zend.com> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id$ */
  21. #include "php_soap.h"
  22. /* SOAP client calls this function to parse response from SOAP server */
  23. int parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctionPtr fn, char *fn_name, zval *return_value, zval *soap_headers TSRMLS_DC)
  24. {
  25. char* envelope_ns = NULL;
  26. xmlDocPtr response;
  27. xmlNodePtr trav, env, head, body, resp, cur, fault;
  28. xmlAttrPtr attr;
  29. int param_count = 0;
  30. int soap_version = SOAP_1_1;
  31. HashTable *hdrs = NULL;
  32. ZVAL_NULL(return_value);
  33. /* Response for one-way opearation */
  34. if (buffer_size == 0) {
  35. return TRUE;
  36. }
  37. /* Parse XML packet */
  38. response = soap_xmlParseMemory(buffer, buffer_size);
  39. if (!response) {
  40. add_soap_fault(this_ptr, "Client", "looks like we got no XML document", NULL, NULL TSRMLS_CC);
  41. return FALSE;
  42. }
  43. if (xmlGetIntSubset(response) != NULL) {
  44. add_soap_fault(this_ptr, "Client", "DTD are not supported by SOAP", NULL, NULL TSRMLS_CC);
  45. xmlFreeDoc(response);
  46. return FALSE;
  47. }
  48. /* Get <Envelope> element */
  49. env = NULL;
  50. trav = response->children;
  51. while (trav != NULL) {
  52. if (trav->type == XML_ELEMENT_NODE) {
  53. if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) {
  54. env = trav;
  55. envelope_ns = SOAP_1_1_ENV_NAMESPACE;
  56. soap_version = SOAP_1_1;
  57. } else if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) {
  58. env = trav;
  59. envelope_ns = SOAP_1_2_ENV_NAMESPACE;
  60. soap_version = SOAP_1_2;
  61. } else {
  62. add_soap_fault(this_ptr, "VersionMismatch", "Wrong Version", NULL, NULL TSRMLS_CC);
  63. xmlFreeDoc(response);
  64. return FALSE;
  65. }
  66. }
  67. trav = trav->next;
  68. }
  69. if (env == NULL) {
  70. add_soap_fault(this_ptr, "Client", "looks like we got XML without \"Envelope\" element", NULL, NULL TSRMLS_CC);
  71. xmlFreeDoc(response);
  72. return FALSE;
  73. }
  74. attr = env->properties;
  75. while (attr != NULL) {
  76. if (attr->ns == NULL) {
  77. add_soap_fault(this_ptr, "Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC);
  78. xmlFreeDoc(response);
  79. return FALSE;
  80. } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
  81. if (soap_version == SOAP_1_2) {
  82. add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL TSRMLS_CC);
  83. xmlFreeDoc(response);
  84. return FALSE;
  85. } else if (strcmp(attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
  86. add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC);
  87. xmlFreeDoc(response);
  88. return FALSE;
  89. }
  90. }
  91. attr = attr->next;
  92. }
  93. /* Get <Header> element */
  94. head = NULL;
  95. trav = env->children;
  96. while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
  97. trav = trav->next;
  98. }
  99. if (trav != NULL && node_is_equal_ex(trav,"Header",envelope_ns)) {
  100. head = trav;
  101. trav = trav->next;
  102. }
  103. /* Get <Body> element */
  104. body = NULL;
  105. while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
  106. trav = trav->next;
  107. }
  108. if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) {
  109. body = trav;
  110. trav = trav->next;
  111. }
  112. while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
  113. trav = trav->next;
  114. }
  115. if (body == NULL) {
  116. add_soap_fault(this_ptr, "Client", "Body must be present in a SOAP envelope", NULL, NULL TSRMLS_CC);
  117. xmlFreeDoc(response);
  118. return FALSE;
  119. }
  120. attr = body->properties;
  121. while (attr != NULL) {
  122. if (attr->ns == NULL) {
  123. if (soap_version == SOAP_1_2) {
  124. add_soap_fault(this_ptr, "Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC);
  125. xmlFreeDoc(response);
  126. return FALSE;
  127. }
  128. } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
  129. if (soap_version == SOAP_1_2) {
  130. add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Body", NULL, NULL TSRMLS_CC);
  131. xmlFreeDoc(response);
  132. return FALSE;
  133. } else if (strcmp(attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
  134. add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC);
  135. xmlFreeDoc(response);
  136. return FALSE;
  137. }
  138. }
  139. attr = attr->next;
  140. }
  141. if (trav != NULL && soap_version == SOAP_1_2) {
  142. add_soap_fault(this_ptr, "Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL TSRMLS_CC);
  143. xmlFreeDoc(response);
  144. return FALSE;
  145. }
  146. if (head != NULL) {
  147. attr = head->properties;
  148. while (attr != NULL) {
  149. if (attr->ns == NULL) {
  150. add_soap_fault(this_ptr, "Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC);
  151. xmlFreeDoc(response);
  152. return FALSE;
  153. } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
  154. if (soap_version == SOAP_1_2) {
  155. add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Header", NULL, NULL TSRMLS_CC);
  156. xmlFreeDoc(response);
  157. return FALSE;
  158. } else if (strcmp(attr->children->content,SOAP_1_1_ENC_NAMESPACE) != 0) {
  159. add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC);
  160. xmlFreeDoc(response);
  161. return FALSE;
  162. }
  163. }
  164. attr = attr->next;
  165. }
  166. }
  167. /* Check if <Body> contains <Fault> element */
  168. fault = get_node_ex(body->children,"Fault",envelope_ns);
  169. if (fault != NULL) {
  170. char *faultcode = NULL, *faultstring = NULL, *faultactor = NULL;
  171. zval *details = NULL;
  172. xmlNodePtr tmp;
  173. if (soap_version == SOAP_1_1) {
  174. tmp = get_node(fault->children,"faultcode");
  175. if (tmp != NULL && tmp->children != NULL) {
  176. faultcode = tmp->children->content;
  177. }
  178. tmp = get_node(fault->children,"faultstring");
  179. if (tmp != NULL && tmp->children != NULL) {
  180. faultstring = tmp->children->content;
  181. }
  182. tmp = get_node(fault->children,"faultactor");
  183. if (tmp != NULL && tmp->children != NULL) {
  184. faultactor = tmp->children->content;
  185. }
  186. tmp = get_node(fault->children,"detail");
  187. if (tmp != NULL) {
  188. details = master_to_zval(NULL, tmp);
  189. }
  190. } else {
  191. tmp = get_node(fault->children,"Code");
  192. if (tmp != NULL && tmp->children != NULL) {
  193. tmp = get_node(tmp->children,"Value");
  194. if (tmp != NULL && tmp->children != NULL) {
  195. faultcode = tmp->children->content;
  196. }
  197. }
  198. tmp = get_node(fault->children,"Reason");
  199. if (tmp != NULL && tmp->children != NULL) {
  200. /* TODO: lang attribute */
  201. tmp = get_node(tmp->children,"Text");
  202. if (tmp != NULL && tmp->children != NULL) {
  203. faultstring = tmp->children->content;
  204. }
  205. }
  206. tmp = get_node(fault->children,"Detail");
  207. if (tmp != NULL) {
  208. details = master_to_zval(NULL, tmp);
  209. }
  210. }
  211. add_soap_fault(this_ptr, faultcode, faultstring, faultactor, details TSRMLS_CC);
  212. #ifdef ZEND_ENGINE_2
  213. if (details) {
  214. details->refcount--;
  215. }
  216. #endif
  217. xmlFreeDoc(response);
  218. return FALSE;
  219. }
  220. /* Parse content of <Body> element */
  221. array_init(return_value);
  222. resp = body->children;
  223. while (resp != NULL && resp->type != XML_ELEMENT_NODE) {
  224. resp = resp->next;
  225. }
  226. if (resp != NULL) {
  227. if (fn != NULL && fn->binding && fn->binding->bindingType == BINDING_SOAP) {
  228. /* Function has WSDL description */
  229. sdlParamPtr *h_param, param = NULL;
  230. xmlNodePtr val = NULL;
  231. char *name, *ns = NULL;
  232. zval* tmp;
  233. sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
  234. int res_count;
  235. hdrs = fnb->output.headers;
  236. if (fn->responseParameters) {
  237. res_count = zend_hash_num_elements(fn->responseParameters);
  238. zend_hash_internal_pointer_reset(fn->responseParameters);
  239. while (zend_hash_get_current_data(fn->responseParameters, (void **)&h_param) == SUCCESS) {
  240. param = (*h_param);
  241. if (fnb->style == SOAP_DOCUMENT) {
  242. if (param->element) {
  243. name = param->element->name;
  244. ns = param->element->namens;
  245. /*
  246. name = param->encode->details.type_str;
  247. ns = param->encode->details.ns;
  248. */
  249. } else {
  250. name = param->paramName;
  251. }
  252. } else {
  253. name = fn->responseName;
  254. /* ns = ? */
  255. }
  256. /* Get value of parameter */
  257. cur = get_node_ex(resp, name, ns);
  258. if (!cur) {
  259. cur = get_node(resp, name);
  260. /* TODO: produce warning invalid ns */
  261. }
  262. if (!cur && fnb->style == SOAP_RPC) {
  263. cur = resp;
  264. }
  265. if (cur) {
  266. if (fnb->style == SOAP_DOCUMENT) {
  267. val = cur;
  268. } else {
  269. val = get_node(cur->children, param->paramName);
  270. if (res_count == 1) {
  271. if (val == NULL) {
  272. val = get_node(cur->children, "return");
  273. }
  274. if (val == NULL) {
  275. val = get_node(cur->children, "result");
  276. }
  277. if (val == NULL && cur->children && cur->children->next == NULL) {
  278. val = cur->children;
  279. }
  280. }
  281. }
  282. }
  283. if (!val) {
  284. /* TODO: may be "nil" is not OK? */
  285. MAKE_STD_ZVAL(tmp);
  286. ZVAL_NULL(tmp);
  287. /*
  288. add_soap_fault(this_ptr, "Client", "Can't find response data", NULL, NULL TSRMLS_CC);
  289. xmlFreeDoc(response);
  290. return FALSE;
  291. */
  292. } else {
  293. /* Decoding value of parameter */
  294. if (param != NULL) {
  295. tmp = master_to_zval(param->encode, val);
  296. } else {
  297. tmp = master_to_zval(NULL, val);
  298. }
  299. }
  300. add_assoc_zval(return_value, param->paramName, tmp);
  301. param_count++;
  302. zend_hash_move_forward(fn->responseParameters);
  303. }
  304. }
  305. } else {
  306. /* Function hasn't WSDL description */
  307. xmlNodePtr val;
  308. val = resp->children;
  309. while (val != NULL) {
  310. while (val && val->type != XML_ELEMENT_NODE) {
  311. val = val->next;
  312. }
  313. if (val != NULL) {
  314. if (!node_is_equal_ex(val,"result",RPC_SOAP12_NAMESPACE)) {
  315. zval *tmp;
  316. tmp = master_to_zval(NULL, val);
  317. if (val->name) {
  318. add_assoc_zval(return_value, (char*)val->name, tmp);
  319. } else {
  320. add_next_index_zval(return_value, tmp);
  321. }
  322. ++param_count;
  323. }
  324. val = val->next;
  325. }
  326. }
  327. }
  328. }
  329. if (Z_TYPE_P(return_value) == IS_ARRAY) {
  330. if (param_count == 0) {
  331. zval_dtor(return_value);
  332. ZVAL_NULL(return_value);
  333. } else if (param_count == 1) {
  334. zval *tmp;
  335. zend_hash_internal_pointer_reset(Z_ARRVAL_P(return_value));
  336. zend_hash_get_current_data(Z_ARRVAL_P(return_value), (void**)&tmp);
  337. tmp = *(zval**)tmp;
  338. tmp->refcount++;
  339. zval_dtor(return_value);
  340. *return_value = *tmp;
  341. FREE_ZVAL(tmp);
  342. }
  343. }
  344. if (soap_headers && head) {
  345. trav = head->children;
  346. while (trav != NULL) {
  347. if (trav->type == XML_ELEMENT_NODE) {
  348. encodePtr enc = NULL;
  349. zval* val;
  350. if (hdrs) {
  351. smart_str key = {0};
  352. sdlSoapBindingFunctionHeaderPtr *hdr;
  353. if (trav->ns) {
  354. smart_str_appends(&key,trav->ns->href);
  355. smart_str_appendc(&key,':');
  356. }
  357. smart_str_appends(&key,trav->name);
  358. smart_str_0(&key);
  359. if (zend_hash_find(hdrs, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
  360. enc = (*hdr)->encode;
  361. }
  362. smart_str_free(&key);
  363. }
  364. val = master_to_zval(enc, trav);
  365. add_assoc_zval(soap_headers, (char*)trav->name, val);
  366. }
  367. trav = trav->next;
  368. }
  369. }
  370. xmlFreeDoc(response);
  371. return TRUE;
  372. }