1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
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 272374 2008-12-31 11:17:49Z sebastian $ */
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 69 : {
27 69 : char* envelope_ns = NULL;
28 : xmlDocPtr response;
29 : xmlNodePtr trav, env, head, body, resp, cur, fault;
30 : xmlAttrPtr attr;
31 69 : int param_count = 0;
32 69 : int soap_version = SOAP_1_1;
33 69 : HashTable *hdrs = NULL;
34 :
35 69 : ZVAL_NULL(return_value);
36 :
37 : /* Response for one-way opearation */
38 69 : if (buffer_size == 0) {
39 1 : return TRUE;
40 : }
41 :
42 : /* Parse XML packet */
43 68 : response = soap_xmlParseMemory(buffer, buffer_size);
44 :
45 68 : if (!response) {
46 0 : add_soap_fault(this_ptr, "Client", "looks like we got no XML document", NULL, NULL TSRMLS_CC);
47 0 : return FALSE;
48 : }
49 68 : 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 68 : env = NULL;
57 68 : trav = response->children;
58 204 : while (trav != NULL) {
59 68 : if (trav->type == XML_ELEMENT_NODE) {
60 135 : if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_1_ENV_NAMESPACE)) {
61 67 : env = trav;
62 67 : envelope_ns = SOAP_1_1_ENV_NAMESPACE;
63 67 : soap_version = SOAP_1_1;
64 2 : } else if (env == NULL && node_is_equal_ex(trav,"Envelope",SOAP_1_2_ENV_NAMESPACE)) {
65 1 : env = trav;
66 1 : envelope_ns = SOAP_1_2_ENV_NAMESPACE;
67 1 : 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 68 : trav = trav->next;
75 : }
76 68 : 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 68 : attr = env->properties;
83 180 : while (attr != NULL) {
84 44 : 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 44 : } 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 44 : attr = attr->next;
100 : }
101 :
102 : /* Get <Header> element */
103 68 : head = NULL;
104 68 : trav = env->children;
105 136 : while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
106 0 : trav = trav->next;
107 : }
108 68 : 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 68 : body = NULL;
115 136 : while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
116 0 : trav = trav->next;
117 : }
118 68 : if (trav != NULL && node_is_equal_ex(trav,"Body",envelope_ns)) {
119 68 : body = trav;
120 68 : trav = trav->next;
121 : }
122 136 : while (trav != NULL && trav->type != XML_ELEMENT_NODE) {
123 0 : trav = trav->next;
124 : }
125 68 : 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 68 : attr = body->properties;
131 139 : 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 68 : 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 68 : 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 68 : fault = get_node_ex(body->children,"Fault",envelope_ns);
181 68 : if (fault != NULL) {
182 3 : char *faultcode = NULL, *faultstring = NULL, *faultactor = NULL;
183 3 : zval *details = NULL;
184 : xmlNodePtr tmp;
185 :
186 3 : 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 : zval *zv = master_to_zval(get_conversion(IS_STRING), tmp);
195 2 : faultstring = Z_STRVAL_P(zv);
196 2 : FREE_ZVAL(zv);
197 : }
198 :
199 2 : tmp = get_node(fault->children, "faultactor");
200 2 : if (tmp != NULL && tmp->children != NULL) {
201 0 : zval *zv = master_to_zval(get_conversion(IS_STRING), tmp);
202 0 : faultactor = Z_STRVAL_P(zv);
203 0 : FREE_ZVAL(zv);
204 : }
205 :
206 2 : tmp = get_node(fault->children, "detail");
207 2 : if (tmp != NULL) {
208 2 : details = master_to_zval(NULL, tmp);
209 : }
210 : } else {
211 1 : tmp = get_node(fault->children, "Code");
212 1 : if (tmp != NULL && tmp->children != NULL) {
213 1 : tmp = get_node(tmp->children, "Value");
214 1 : if (tmp != NULL && tmp->children != NULL) {
215 1 : faultcode = (char*)tmp->children->content;
216 : }
217 : }
218 :
219 1 : tmp = get_node(fault->children,"Reason");
220 1 : if (tmp != NULL && tmp->children != NULL) {
221 : /* TODO: lang attribute */
222 1 : tmp = get_node(tmp->children,"Text");
223 1 : if (tmp != NULL && tmp->children != NULL) {
224 1 : zval *zv = master_to_zval(get_conversion(IS_STRING), tmp);
225 1 : faultstring = Z_STRVAL_P(zv);
226 1 : FREE_ZVAL(zv);
227 : }
228 : }
229 :
230 1 : tmp = get_node(fault->children,"Detail");
231 1 : if (tmp != NULL) {
232 0 : details = master_to_zval(NULL, tmp);
233 : }
234 : }
235 3 : add_soap_fault(this_ptr, faultcode, faultstring, faultactor, details TSRMLS_CC);
236 3 : if (faultstring) {
237 3 : efree(faultstring);
238 : }
239 3 : if (faultactor) {
240 0 : efree(faultactor);
241 : }
242 : #ifdef ZEND_ENGINE_2
243 3 : if (details) {
244 2 : details->refcount--;
245 : }
246 : #endif
247 3 : xmlFreeDoc(response);
248 3 : return FALSE;
249 : }
250 :
251 : /* Parse content of <Body> element */
252 65 : array_init(return_value);
253 65 : resp = body->children;
254 130 : while (resp != NULL && resp->type != XML_ELEMENT_NODE) {
255 0 : resp = resp->next;
256 : }
257 65 : if (resp != NULL) {
258 109 : if (fn != NULL && fn->binding && fn->binding->bindingType == BINDING_SOAP) {
259 : /* Function has WSDL description */
260 44 : sdlParamPtr *h_param, param = NULL;
261 44 : xmlNodePtr val = NULL;
262 44 : char *name, *ns = NULL;
263 : zval* tmp;
264 44 : sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes;
265 : int res_count;
266 :
267 44 : hdrs = fnb->output.headers;
268 :
269 44 : if (fn->responseParameters) {
270 44 : res_count = zend_hash_num_elements(fn->responseParameters);
271 44 : zend_hash_internal_pointer_reset(fn->responseParameters);
272 134 : while (zend_hash_get_current_data(fn->responseParameters, (void **)&h_param) == SUCCESS) {
273 46 : param = (*h_param);
274 46 : if (fnb->style == SOAP_DOCUMENT) {
275 12 : if (param->element) {
276 6 : name = param->element->name;
277 6 : ns = param->element->namens;
278 : /*
279 : name = param->encode->details.type_str;
280 : ns = param->encode->details.ns;
281 : */
282 : } else {
283 6 : name = param->paramName;
284 : }
285 : } else {
286 34 : name = fn->responseName;
287 : /* ns = ? */
288 : }
289 :
290 : /* Get value of parameter */
291 46 : cur = get_node_ex(resp, name, ns);
292 46 : if (!cur) {
293 4 : cur = get_node(resp, name);
294 : /* TODO: produce warning invalid ns */
295 : }
296 46 : if (!cur && fnb->style == SOAP_RPC) {
297 4 : cur = resp;
298 : }
299 46 : if (cur) {
300 46 : if (fnb->style == SOAP_DOCUMENT) {
301 12 : val = cur;
302 : } else {
303 34 : val = get_node(cur->children, param->paramName);
304 34 : if (res_count == 1) {
305 31 : if (val == NULL) {
306 1 : val = get_node(cur->children, "return");
307 : }
308 31 : if (val == NULL) {
309 1 : val = get_node(cur->children, "result");
310 : }
311 31 : if (val == NULL && cur->children && cur->children->next == NULL) {
312 1 : val = cur->children;
313 : }
314 : }
315 : }
316 : }
317 :
318 46 : if (!val) {
319 : /* TODO: may be "nil" is not OK? */
320 0 : MAKE_STD_ZVAL(tmp);
321 0 : ZVAL_NULL(tmp);
322 : /*
323 : add_soap_fault(this_ptr, "Client", "Can't find response data", NULL, NULL TSRMLS_CC);
324 : xmlFreeDoc(response);
325 : return FALSE;
326 : */
327 : } else {
328 : /* Decoding value of parameter */
329 46 : if (param != NULL) {
330 46 : tmp = master_to_zval(param->encode, val);
331 : } else {
332 0 : tmp = master_to_zval(NULL, val);
333 : }
334 : }
335 46 : add_assoc_zval(return_value, param->paramName, tmp);
336 :
337 46 : param_count++;
338 :
339 46 : zend_hash_move_forward(fn->responseParameters);
340 : }
341 : }
342 : } else {
343 : /* Function hasn't WSDL description */
344 : xmlNodePtr val;
345 21 : val = resp->children;
346 66 : while (val != NULL) {
347 48 : while (val && val->type != XML_ELEMENT_NODE) {
348 0 : val = val->next;
349 : }
350 24 : if (val != NULL) {
351 24 : if (!node_is_equal_ex(val,"result",RPC_SOAP12_NAMESPACE)) {
352 : zval *tmp;
353 : zval **arr;
354 :
355 24 : tmp = master_to_zval(NULL, val);
356 24 : if (val->name) {
357 24 : if (zend_hash_find(Z_ARRVAL_P(return_value), (char*)val->name, strlen((char*)val->name)+1, (void**)&arr) == SUCCESS) {
358 3 : add_next_index_zval(*arr, tmp);
359 22 : } else if (val->next && get_node(val->next, (char*)val->name)) {
360 : zval *arr;
361 :
362 1 : MAKE_STD_ZVAL(arr);
363 1 : array_init(arr);
364 1 : add_next_index_zval(arr, tmp);
365 1 : add_assoc_zval(return_value, (char*)val->name, arr);
366 : } else {
367 20 : add_assoc_zval(return_value, (char*)val->name, tmp);
368 : }
369 : } else {
370 0 : add_next_index_zval(return_value, tmp);
371 : }
372 24 : ++param_count;
373 : }
374 24 : val = val->next;
375 : }
376 : }
377 : }
378 : }
379 :
380 65 : if (Z_TYPE_P(return_value) == IS_ARRAY) {
381 65 : if (param_count == 0) {
382 0 : zval_dtor(return_value);
383 0 : ZVAL_NULL(return_value);
384 65 : } else if (param_count == 1) {
385 : zval *tmp;
386 :
387 63 : zend_hash_internal_pointer_reset(Z_ARRVAL_P(return_value));
388 63 : zend_hash_get_current_data(Z_ARRVAL_P(return_value), (void**)&tmp);
389 63 : tmp = *(zval**)tmp;
390 63 : tmp->refcount++;
391 63 : zval_dtor(return_value);
392 63 : *return_value = *tmp;
393 63 : FREE_ZVAL(tmp);
394 : }
395 : }
396 :
397 65 : if (soap_headers && head) {
398 0 : trav = head->children;
399 0 : while (trav != NULL) {
400 0 : if (trav->type == XML_ELEMENT_NODE) {
401 0 : encodePtr enc = NULL;
402 : zval* val;
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 : add_assoc_zval(soap_headers, (char*)trav->name, val);
421 : }
422 0 : trav = trav->next;
423 : }
424 : }
425 :
426 65 : xmlFreeDoc(response);
427 65 : return TRUE;
428 : }
|