1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 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_01.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: php_packet_soap.c 278112 2009-04-01 09:38:41Z kalle $ */
21 :
22 : #include "php_soap.h"
23 :
24 : /* SOAP client calls this function to parse response from SOAP server */
25 : 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)
26 67 : {
27 67 : char* envelope_ns = NULL;
28 : xmlDocPtr response;
29 : xmlNodePtr trav, env, head, body, resp, cur, fault;
30 : xmlAttrPtr attr;
31 67 : int param_count = 0;
32 67 : int soap_version = SOAP_1_1;
33 67 : HashTable *hdrs = NULL;
34 :
35 67 : ZVAL_NULL(return_value);
36 :
37 : /* Response for one-way opearation */
38 67 : if (buffer_size == 0) {
39 1 : return TRUE;
40 : }
41 :
42 : /* Parse XML packet */
43 66 : response = soap_xmlParseMemory(buffer, buffer_size);
44 :
45 66 : if (!response) {
46 1 : add_soap_fault(this_ptr, "Client", "looks like we got no XML document", NULL, NULL TSRMLS_CC);
47 1 : return FALSE;
48 : }
49 65 : if (xmlGetIntSubset(response) != NULL) {
50 0 : add_soap_fault(this_ptr, "Client", "DTD are not supported by SOAP", NULL, NULL TSRMLS_CC);
51 0 : xmlFreeDoc(response);
52 0 : return FALSE;
53 : }
54 :
55 : /* Get <Envelope> element */
56 65 : env = NULL;
57 65 : trav = response->children;
58 195 : while (trav != NULL) {
59 65 : if (trav->type == XML_ELEMENT_NODE) {
60 130 : if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) {
61 65 : env = trav;
62 65 : envelope_ns = SOAP_1_1_ENV_NAMESPACE;
63 65 : soap_version = SOAP_1_1;
64 0 : } else if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) {
65 0 : env = trav;
66 0 : envelope_ns = SOAP_1_2_ENV_NAMESPACE;
67 0 : soap_version = SOAP_1_2;
68 : } else {
69 0 : add_soap_fault(this_ptr, "VersionMismatch", "Wrong Version", NULL, NULL TSRMLS_CC);
70 0 : xmlFreeDoc(response);
71 0 : return FALSE;
72 : }
73 : }
74 65 : trav = trav->next;
75 : }
76 65 : if (env == NULL) {
77 0 : add_soap_fault(this_ptr, "Client", "looks like we got XML without \"Envelope\" element", NULL, NULL TSRMLS_CC);
78 0 : xmlFreeDoc(response);
79 0 : return FALSE;
80 : }
81 :
82 65 : attr = env->properties;
83 173 : while (attr != NULL) {
84 43 : if (attr->ns == NULL) {
85 0 : add_soap_fault(this_ptr, "Client", "A SOAP Envelope element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC);
86 0 : xmlFreeDoc(response);
87 0 : return FALSE;
88 43 : } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
89 0 : if (soap_version == SOAP_1_2) {
90 0 : add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Envelope", NULL, NULL TSRMLS_CC);
91 0 : xmlFreeDoc(response);
92 0 : return FALSE;
93 0 : } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) {
94 0 : add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC);
95 0 : xmlFreeDoc(response);
96 0 : return FALSE;
97 : }
98 : }
99 43 : attr = attr->next;
100 : }
101 :
102 : /* Get <Header> element */
103 65 : head = NULL;
104 65 : trav = env->children;
105 130 : while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
106 0 : trav = trav->next;
107 : }
108 65 : if (trav != NULL && node_is_equal_ex(trav,"Header",envelope_ns)) {
109 0 : head = trav;
110 0 : trav = trav->next;
111 : }
112 :
113 : /* Get <Body> element */
114 65 : body = NULL;
115 130 : while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
116 0 : trav = trav->next;
117 : }
118 65 : if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) {
119 65 : body = trav;
120 65 : trav = trav->next;
121 : }
122 130 : while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
123 0 : trav = trav->next;
124 : }
125 65 : if (body == NULL) {
126 0 : add_soap_fault(this_ptr, "Client", "Body must be present in a SOAP envelope", NULL, NULL TSRMLS_CC);
127 0 : xmlFreeDoc(response);
128 0 : return FALSE;
129 : }
130 65 : attr = body->properties;
131 133 : while (attr != NULL) {
132 3 : if (attr->ns == NULL) {
133 2 : if (soap_version == SOAP_1_2) {
134 0 : add_soap_fault(this_ptr, "Client", "A SOAP Body element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC);
135 0 : xmlFreeDoc(response);
136 0 : return FALSE;
137 : }
138 1 : } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
139 0 : if (soap_version == SOAP_1_2) {
140 0 : add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Body", NULL, NULL TSRMLS_CC);
141 0 : xmlFreeDoc(response);
142 0 : return FALSE;
143 0 : } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) {
144 0 : add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC);
145 0 : xmlFreeDoc(response);
146 0 : return FALSE;
147 : }
148 : }
149 3 : attr = attr->next;
150 : }
151 65 : if (trav != NULL && soap_version == SOAP_1_2) {
152 0 : add_soap_fault(this_ptr, "Client", "A SOAP 1.2 envelope can contain only Header and Body", NULL, NULL TSRMLS_CC);
153 0 : xmlFreeDoc(response);
154 0 : return FALSE;
155 : }
156 :
157 65 : if (head != NULL) {
158 0 : attr = head->properties;
159 0 : while (attr != NULL) {
160 0 : if (attr->ns == NULL) {
161 0 : add_soap_fault(this_ptr, "Client", "A SOAP Header element cannot have non Namespace qualified attributes", NULL, NULL TSRMLS_CC);
162 0 : xmlFreeDoc(response);
163 0 : return FALSE;
164 0 : } else if (attr_is_equal_ex(attr,"encodingStyle",SOAP_1_2_ENV_NAMESPACE)) {
165 0 : if (soap_version == SOAP_1_2) {
166 0 : add_soap_fault(this_ptr, "Client", "encodingStyle cannot be specified on the Header", NULL, NULL TSRMLS_CC);
167 0 : xmlFreeDoc(response);
168 0 : return FALSE;
169 0 : } else if (strcmp((char*)attr->children->content, SOAP_1_1_ENC_NAMESPACE) != 0) {
170 0 : add_soap_fault(this_ptr, "Client", "Unknown data encoding style", NULL, NULL TSRMLS_CC);
171 0 : xmlFreeDoc(response);
172 0 : return FALSE;
173 : }
174 : }
175 0 : attr = attr->next;
176 : }
177 : }
178 :
179 : /* Check if <Body> contains <Fault> element */
180 65 : fault = get_node_ex(body->children,"Fault",envelope_ns);
181 65 : if (fault != NULL) {
182 2 : char *faultcode = NULL, *faultstring = NULL, *faultactor = NULL;
183 2 : zval *details = NULL;
184 : xmlNodePtr tmp;
185 :
186 2 : if (soap_version == SOAP_1_1) {
187 2 : tmp = get_node(fault->children, "faultcode");
188 2 : if (tmp != NULL && tmp->children != NULL) {
189 2 : faultcode = (char*)tmp->children->content;
190 : }
191 :
192 2 : tmp = get_node(fault->children, "faultstring");
193 2 : if (tmp != NULL && tmp->children != NULL) {
194 2 : faultstring = (char*)tmp->children->content;
195 : }
196 :
197 2 : tmp = get_node(fault->children, "faultactor");
198 2 : if (tmp != NULL && tmp->children != NULL) {
199 0 : faultactor = (char*)tmp->children->content;
200 : }
201 :
202 2 : tmp = get_node(fault->children, "detail");
203 2 : if (tmp != NULL) {
204 2 : details = master_to_zval(NULL, tmp);
205 : }
206 : } else {
207 0 : tmp = get_node(fault->children, "Code");
208 0 : if (tmp != NULL && tmp->children != NULL) {
209 0 : tmp = get_node(tmp->children, "Value");
210 0 : if (tmp != NULL && tmp->children != NULL) {
211 0 : faultcode = (char*)tmp->children->content;
212 : }
213 : }
214 :
215 0 : tmp = get_node(fault->children,"Reason");
216 0 : if (tmp != NULL && tmp->children != NULL) {
217 : /* TODO: lang attribute */
218 0 : tmp = get_node(tmp->children,"Text");
219 0 : if (tmp != NULL && tmp->children != NULL) {
220 0 : faultstring = (char*)tmp->children->content;
221 : }
222 : }
223 :
224 0 : tmp = get_node(fault->children,"Detail");
225 0 : if (tmp != NULL) {
226 0 : details = master_to_zval(NULL, tmp);
227 : }
228 : }
229 2 : add_soap_fault(this_ptr, faultcode, faultstring, faultactor, details TSRMLS_CC);
230 2 : if (details) {
231 2 : Z_DELREF_P(details);
232 : }
233 2 : xmlFreeDoc(response);
234 2 : return FALSE;
235 : }
236 :
237 : /* Parse content of <Body> element */
238 63 : array_init(return_value);
239 63 : resp = body->children;
240 126 : while (resp != NULL && resp->type != XML_ELEMENT_NODE) {
241 0 : resp = resp->next;
242 : }
243 63 : if (resp != NULL) {
244 106 : if (fn != NULL && fn->binding && fn->binding->bindingType == BINDING_SOAP) {
245 : /* Function has WSDL description */
246 43 : sdlParamPtr *h_param, param = NULL;
247 43 : xmlNodePtr val = NULL;
248 43 : char *name, *ns = NULL;
249 : zval* tmp;
250 43 : sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
251 : int res_count;
252 :
253 43 : hdrs = fnb->output.headers;
254 :
255 43 : if (fn->responseParameters) {
256 43 : res_count = zend_hash_num_elements(fn->responseParameters);
257 43 : zend_hash_internal_pointer_reset(fn->responseParameters);
258 131 : while (zend_hash_get_current_data(fn->responseParameters, (void **)&h_param) == SUCCESS) {
259 45 : UErrorCode status = U_ZERO_ERROR;
260 : zstr u_name;
261 : int u_name_len;
262 :
263 45 : param = (*h_param);
264 45 : if (fnb->style == SOAP_DOCUMENT) {
265 11 : if (param->element) {
266 5 : name = param->element->name;
267 5 : ns = param->element->namens;
268 : /*
269 : name = param->encode->details.type_str;
270 : ns = param->encode->details.ns;
271 : */
272 : } else {
273 6 : name = param->paramName;
274 : }
275 : } else {
276 34 : name = fn->responseName;
277 : /* ns = ? */
278 : }
279 :
280 : /* Get value of parameter */
281 45 : cur = get_node_ex(resp, name, ns);
282 45 : if (!cur) {
283 4 : cur = get_node(resp, name);
284 : /* TODO: produce warning invalid ns */
285 : }
286 45 : if (!cur && fnb->style == SOAP_RPC) {
287 4 : cur = resp;
288 : }
289 45 : if (cur) {
290 45 : if (fnb->style == SOAP_DOCUMENT) {
291 11 : val = cur;
292 : } else {
293 34 : val = get_node(cur->children, param->paramName);
294 34 : if (res_count == 1) {
295 31 : if (val == NULL) {
296 1 : val = get_node(cur->children, "return");
297 : }
298 31 : if (val == NULL) {
299 1 : val = get_node(cur->children, "result");
300 : }
301 31 : if (val == NULL && cur->children && cur->children->next == NULL) {
302 1 : val = cur->children;
303 : }
304 : }
305 : }
306 : }
307 :
308 45 : if (!val) {
309 : /* TODO: may be "nil" is not OK? */
310 0 : MAKE_STD_ZVAL(tmp);
311 0 : ZVAL_NULL(tmp);
312 : /*
313 : add_soap_fault(this_ptr, "Client", "Can't find response data", NULL, NULL TSRMLS_CC);
314 : xmlFreeDoc(response);
315 : return FALSE;
316 : */
317 : } else {
318 : /* Decoding value of parameter */
319 45 : if (param != NULL) {
320 45 : tmp = master_to_zval(param->encode, val);
321 : } else {
322 0 : tmp = master_to_zval(NULL, val);
323 : }
324 : }
325 45 : zend_string_to_unicode_ex(UG(utf8_conv), &u_name.u, &u_name_len, param->paramName, strlen(param->paramName), &status);
326 45 : add_u_assoc_zval_ex(return_value, IS_UNICODE, u_name, u_name_len+1, tmp);
327 45 : efree(u_name.u);
328 :
329 45 : param_count++;
330 :
331 45 : zend_hash_move_forward(fn->responseParameters);
332 : }
333 : }
334 : } else {
335 : /* Function hasn't WSDL description */
336 : xmlNodePtr val;
337 20 : val = resp->children;
338 63 : while (val != NULL) {
339 46 : while (val && val->type != XML_ELEMENT_NODE) {
340 0 : val = val->next;
341 : }
342 23 : if (val != NULL) {
343 23 : if (!node_is_equal_ex(val,"result",RPC_SOAP12_NAMESPACE)) {
344 : zval *tmp;
345 : zval **arr;
346 :
347 23 : tmp = master_to_zval(NULL, val);
348 23 : if (val->name) {
349 23 : UErrorCode status = U_ZERO_ERROR;
350 : zstr u_name;
351 : int u_name_len;
352 23 : zend_string_to_unicode_ex(UG(utf8_conv), &u_name.u, &u_name_len, (char*)val->name, strlen((char*)val->name), &status);
353 23 : if (zend_u_hash_find(Z_ARRVAL_P(return_value), IS_UNICODE, u_name, u_name_len+1, (void**)&arr) == SUCCESS) {
354 3 : add_next_index_zval(*arr, tmp);
355 21 : } else if (val->next && get_node(val->next, (char*)val->name)) {
356 : zval *arr;
357 :
358 1 : MAKE_STD_ZVAL(arr);
359 1 : array_init(arr);
360 1 : add_next_index_zval(arr, tmp);
361 1 : add_u_assoc_zval_ex(return_value, IS_UNICODE, u_name, u_name_len+1, arr);
362 : } else {
363 19 : add_u_assoc_zval_ex(return_value, IS_UNICODE, u_name, u_name_len+1, tmp);
364 : }
365 23 : efree(u_name.u);
366 : } else {
367 0 : add_next_index_zval(return_value, tmp);
368 : }
369 23 : ++param_count;
370 : }
371 23 : val = val->next;
372 : }
373 : }
374 : }
375 : }
376 :
377 63 : if (Z_TYPE_P(return_value) == IS_ARRAY) {
378 63 : if (param_count == 0) {
379 0 : zval_dtor(return_value);
380 0 : ZVAL_NULL(return_value);
381 63 : } else if (param_count == 1) {
382 : zval *tmp;
383 :
384 61 : zend_hash_internal_pointer_reset(Z_ARRVAL_P(return_value));
385 61 : zend_hash_get_current_data(Z_ARRVAL_P(return_value), (void**)&tmp);
386 61 : tmp = *(zval**)tmp;
387 61 : Z_ADDREF_P(tmp);
388 61 : zval_dtor(return_value);
389 61 : *return_value = *tmp;
390 61 : FREE_ZVAL(tmp);
391 : }
392 : }
393 :
394 63 : if (soap_headers && head) {
395 0 : trav = head->children;
396 0 : while (trav != NULL) {
397 0 : if (trav->type == XML_ELEMENT_NODE) {
398 0 : encodePtr enc = NULL;
399 : zval* val;
400 0 : UErrorCode status = U_ZERO_ERROR;
401 : zstr u_name;
402 : int u_name_len;
403 :
404 0 : if (hdrs) {
405 0 : smart_str key = {0};
406 : sdlSoapBindingFunctionHeaderPtr *hdr;
407 :
408 0 : if (trav->ns) {
409 0 : smart_str_appends(&key, (char*)trav->ns->href);
410 0 : smart_str_appendc(&key,':');
411 : }
412 0 : smart_str_appends(&key, (char*)trav->name);
413 0 : smart_str_0(&key);
414 0 : if (zend_hash_find(hdrs, key.c, key.len+1, (void**)&hdr) == SUCCESS) {
415 0 : enc = (*hdr)->encode;
416 : }
417 0 : smart_str_free(&key);
418 : }
419 0 : val = master_to_zval(enc, trav);
420 0 : zend_string_to_unicode_ex(UG(utf8_conv), &u_name.u, &u_name_len, (char*)trav->name, strlen((char*)trav->name), &status);
421 0 : add_u_assoc_zval_ex(soap_headers, IS_UNICODE, u_name, u_name_len+1, val);
422 0 : efree(u_name.u);
423 : }
424 0 : trav = trav->next;
425 : }
426 : }
427 :
428 63 : xmlFreeDoc(response);
429 63 : return TRUE;
430 : }
|