xref: /php-src/ext/soap/php_sdl.c (revision 0a39890c)
1 /*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | https://www.php.net/license/3_01.txt                                 |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Authors: Brad Lafountain <rodif_bl@yahoo.com>                        |
14   |          Shane Caraveo <shane@caraveo.com>                           |
15   |          Dmitry Stogov <dmitry@php.net>                              |
16   +----------------------------------------------------------------------+
17 */
18 
19 #include "php_soap.h"
20 #include "ext/libxml/php_libxml.h"
21 #include "libxml/uri.h"
22 
23 #include "ext/standard/md5.h"
24 #include "zend_virtual_cwd.h"
25 #include "main/php_open_temporary_file.h"
26 
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 
31 #ifndef O_BINARY
32 # define O_BINARY 0
33 #endif
34 
35 static void delete_fault(zval *zv);
36 static void delete_fault_persistent(zval *zv);
37 static void delete_binding(zval *zv);
38 static void delete_binding_persistent(zval *zv);
39 static void delete_function(zval *zv);
40 static void delete_function_persistent(zval *zv);
41 static void delete_parameter(zval *zv);
42 static void delete_parameter_persistent(zval *zv);
43 static void delete_header(zval *header);
44 static void delete_header_int(sdlSoapBindingFunctionHeaderPtr hdr);
45 static void delete_header_persistent(zval *zv);
46 static void delete_document(zval *zv);
47 
get_encoder_from_prefix(sdlPtr sdl,xmlNodePtr node,const xmlChar * type)48 encodePtr get_encoder_from_prefix(sdlPtr sdl, xmlNodePtr node, const xmlChar *type)
49 {
50 	encodePtr enc = NULL;
51 	xmlNsPtr nsptr;
52 	char *ns, *cptype;
53 
54 	parse_namespace(type, &cptype, &ns);
55 	nsptr = xmlSearchNs(node->doc, node, BAD_CAST(ns));
56 	if (nsptr != NULL) {
57 		enc = get_encoder(sdl, (char*)nsptr->href, cptype);
58 		if (enc == NULL) {
59 			enc = get_encoder_ex(sdl, cptype, strlen(cptype));
60 		}
61 	} else {
62 		enc = get_encoder_ex(sdl, (char*)type, xmlStrlen(type));
63 	}
64 	efree(cptype);
65 	if (ns) {efree(ns);}
66 	return enc;
67 }
68 
get_element(sdlPtr sdl,xmlNodePtr node,const xmlChar * type)69 static sdlTypePtr get_element(sdlPtr sdl, xmlNodePtr node, const xmlChar *type)
70 {
71 	sdlTypePtr ret = NULL;
72 
73 	if (sdl->elements) {
74 		xmlNsPtr nsptr;
75 		char *ns, *cptype;
76 		sdlTypePtr sdl_type;
77 
78 		parse_namespace(type, &cptype, &ns);
79 		nsptr = xmlSearchNs(node->doc, node, BAD_CAST(ns));
80 		if (nsptr != NULL) {
81 			int ns_len = xmlStrlen(nsptr->href);
82 			int type_len = strlen(cptype);
83 			int len = ns_len + type_len + 1;
84 			char *nscat = emalloc(len + 1);
85 
86 			memcpy(nscat, nsptr->href, ns_len);
87 			nscat[ns_len] = ':';
88 			memcpy(nscat+ns_len+1, cptype, type_len);
89 			nscat[len] = '\0';
90 
91 			if ((sdl_type = zend_hash_str_find_ptr(sdl->elements, nscat, len)) != NULL) {
92 				ret = sdl_type;
93 			} else if ((sdl_type = zend_hash_str_find_ptr(sdl->elements, (char*)type, type_len)) != NULL) {
94 				ret = sdl_type;
95 			}
96 			efree(nscat);
97 		} else {
98 			if ((sdl_type = zend_hash_str_find_ptr(sdl->elements, (char*)type, xmlStrlen(type))) != NULL) {
99 				ret = sdl_type;
100 			}
101 		}
102 
103 		efree(cptype);
104 		if (ns) {efree(ns);}
105 	}
106 	return ret;
107 }
108 
get_encoder(sdlPtr sdl,const char * ns,const char * type)109 encodePtr get_encoder(sdlPtr sdl, const char *ns, const char *type)
110 {
111 	encodePtr enc = NULL;
112 	char *nscat;
113 	int ns_len = ns ? strlen(ns) : 0;
114 	int type_len = strlen(type);
115 	int len = ns_len + type_len + 1;
116 
117 	nscat = emalloc(len + 1);
118 	if (ns) {
119 		memcpy(nscat, ns, ns_len);
120 	}
121 	nscat[ns_len] = ':';
122 	memcpy(nscat+ns_len+1, type, type_len);
123 	nscat[len] = '\0';
124 
125 	enc = get_encoder_ex(sdl, nscat, len);
126 
127 	if (enc == NULL &&
128 	    ((ns_len == sizeof(SOAP_1_1_ENC_NAMESPACE)-1 &&
129 	      memcmp(ns, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)-1) == 0) ||
130 	     (ns_len == sizeof(SOAP_1_2_ENC_NAMESPACE)-1 &&
131 	      memcmp(ns, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)-1) == 0))) {
132 		char *enc_nscat;
133 		int enc_ns_len;
134 		int enc_len;
135 
136 		enc_ns_len = sizeof(XSD_NAMESPACE)-1;
137 		enc_len = enc_ns_len + type_len + 1;
138 		enc_nscat = emalloc(enc_len + 1);
139 		memcpy(enc_nscat, XSD_NAMESPACE, sizeof(XSD_NAMESPACE)-1);
140 		enc_nscat[enc_ns_len] = ':';
141 		memcpy(enc_nscat+enc_ns_len+1, type, type_len);
142 		enc_nscat[enc_len] = '\0';
143 
144 		enc = get_encoder_ex(NULL, enc_nscat, enc_len);
145 		efree(enc_nscat);
146 		if (enc && sdl) {
147 			encodePtr new_enc	= pemalloc(sizeof(encode), sdl->is_persistent);
148 			memcpy(new_enc, enc, sizeof(encode));
149 			if (sdl->is_persistent) {
150 				new_enc->details.ns = zend_strndup(ns, ns_len);
151 				new_enc->details.type_str = strdup(new_enc->details.type_str);
152 			} else {
153 				new_enc->details.ns = estrndup(ns, ns_len);
154 				new_enc->details.type_str = estrdup(new_enc->details.type_str);
155 			}
156 			if (new_enc->details.clark_notation) {
157 				/* If it was persistent or becomes persistent, we must dup. Otherwise we can copy. */
158 				bool was_persistent = GC_FLAGS(new_enc->details.clark_notation) & IS_STR_PERSISTENT;
159 				if (was_persistent || sdl->is_persistent) {
160 					new_enc->details.clark_notation = zend_string_dup(new_enc->details.clark_notation, sdl->is_persistent);
161 				} else {
162 					zend_string_addref(new_enc->details.clark_notation);
163 				}
164 			}
165 			if (sdl->encoders == NULL) {
166 				sdl->encoders = pemalloc(sizeof(HashTable), sdl->is_persistent);
167 				zend_hash_init(sdl->encoders, 0, NULL, sdl->is_persistent ? delete_encoder_persistent : delete_encoder, sdl->is_persistent);
168 			}
169 			zend_hash_str_update_ptr(sdl->encoders, nscat, len, new_enc);
170 			enc = new_enc;
171 		}
172 	}
173 	efree(nscat);
174 	return enc;
175 }
176 
get_encoder_ex(sdlPtr sdl,const char * nscat,int len)177 encodePtr get_encoder_ex(sdlPtr sdl, const char *nscat, int len)
178 {
179 	encodePtr enc;
180 
181 	if ((enc = zend_hash_str_find_ptr(&SOAP_GLOBAL(defEnc), (char*)nscat, len)) != NULL) {
182 		return enc;
183 	} else if (sdl && sdl->encoders && (enc = zend_hash_str_find_ptr(sdl->encoders, (char*)nscat, len)) != NULL) {
184 		return enc;
185 	}
186 	return NULL;
187 }
188 
get_binding_from_type(sdlPtr sdl,sdlBindingType type)189 sdlBindingPtr get_binding_from_type(sdlPtr sdl, sdlBindingType type)
190 {
191 	sdlBindingPtr binding;
192 
193 	if (sdl == NULL) {
194 		return NULL;
195 	}
196 
197 	ZEND_HASH_MAP_FOREACH_PTR(sdl->bindings, binding) {
198 		if (binding->bindingType == type) {
199 			return binding;
200 		}
201 	} ZEND_HASH_FOREACH_END();
202 	return NULL;
203 }
204 
get_binding_from_name(sdlPtr sdl,char * name,char * ns)205 sdlBindingPtr get_binding_from_name(sdlPtr sdl, char *name, char *ns)
206 {
207 	sdlBindingPtr binding;
208 	smart_str key = {0};
209 
210 	smart_str_appends(&key, ns);
211 	smart_str_appendc(&key, ':');
212 	smart_str_appends(&key, name);
213 	smart_str_0(&key);
214 
215 	binding = zend_hash_find_ptr(sdl->bindings, key.s);
216 
217 	smart_str_free(&key);
218 	return binding;
219 }
220 
is_wsdl_element(xmlNodePtr node)221 static int is_wsdl_element(xmlNodePtr node)
222 {
223 	if (node->ns && strcmp((char*)node->ns->href, WSDL_NAMESPACE) != 0) {
224 		xmlAttrPtr attr;
225 		if ((attr = get_attribute_ex(node->properties, "required", WSDL_NAMESPACE)) != NULL &&
226 		     attr->children && attr->children->content &&
227 		     (strcmp((char*)attr->children->content, "1") == 0 ||
228 		      strcmp((char*)attr->children->content, "true") == 0)) {
229 			soap_error1(E_ERROR, "Parsing WSDL: Unknown required WSDL extension '%s'", node->ns->href);
230 		}
231 		return 0;
232 	}
233 	return 1;
234 }
235 
sdl_set_uri_credentials(sdlCtx * ctx,char * uri)236 void sdl_set_uri_credentials(sdlCtx *ctx, char *uri)
237 {
238 	char *s;
239 	size_t l1, l2;
240 	zval context;
241 	zval *header = NULL;
242 
243 	/* check if we load xsd from the same server */
244 	s = strstr(ctx->sdl->source, "://");
245 	if (!s) return;
246 	s = strchr(s+3, '/');
247 	l1 = s ? (size_t)(s - ctx->sdl->source) : strlen(ctx->sdl->source);
248 	s = strstr((char*)uri, "://");
249 	if (!s) return;
250 	s = strchr(s+3, '/');
251 	l2 = s ? (size_t)(s - (char*)uri) : strlen((char*)uri);
252 	if (l1 != l2) {
253 		/* check for http://...:80/ */
254 		if (l1 > 11 &&
255 		    ctx->sdl->source[4] == ':' &&
256 		    ctx->sdl->source[l1-3] == ':' &&
257 		    ctx->sdl->source[l1-2] == '8' &&
258 		    ctx->sdl->source[l1-1] == '0') {
259 			l1 -= 3;
260 		}
261 		if (l2 > 11 &&
262 		    uri[4] == ':' &&
263 		    uri[l2-3] == ':' &&
264 		    uri[l2-2] == '8' &&
265 		    uri[l2-1] == '0') {
266 			l2 -= 3;
267 		}
268 		/* check for https://...:443/ */
269 		if (l1 > 13 &&
270 		    ctx->sdl->source[4] == 's' &&
271 		    ctx->sdl->source[l1-4] == ':' &&
272 		    ctx->sdl->source[l1-3] == '4' &&
273 		    ctx->sdl->source[l1-2] == '4' &&
274 		    ctx->sdl->source[l1-1] == '3') {
275 			l1 -= 4;
276 		}
277 		if (l2 > 13 &&
278 		    uri[4] == 's' &&
279 		    uri[l2-4] == ':' &&
280 		    uri[l2-3] == '4' &&
281 		    uri[l2-2] == '4' &&
282 		    uri[l2-1] == '3') {
283 			l2 -= 4;
284 		}
285 	}
286 	if (l1 != l2 || memcmp(ctx->sdl->source, uri, l1) != 0) {
287 		/* another server. clear authentication credentals */
288 		php_libxml_switch_context(NULL, &context);
289 		php_libxml_switch_context(&context, NULL);
290 		if (Z_TYPE(context) != IS_UNDEF) {
291 			zval *context_ptr = &context;
292 			ctx->context = php_stream_context_from_zval(context_ptr, 1);
293 
294 			if (ctx->context &&
295 			    (header = php_stream_context_get_option(ctx->context, "http", "header")) != NULL) {
296 				s = strstr(Z_STRVAL_P(header), "Authorization: Basic");
297 				if (s && (s == Z_STRVAL_P(header) || *(s-1) == '\n' || *(s-1) == '\r')) {
298 					char *rest = strstr(s, "\r\n");
299 					if (rest) {
300 						zval new_header;
301 
302 						rest += 2;
303 						ZVAL_NEW_STR(&new_header, zend_string_alloc(Z_STRLEN_P(header) - (rest - s), 0));
304 						memcpy(Z_STRVAL(new_header), Z_STRVAL_P(header), s - Z_STRVAL_P(header));
305 						memcpy(Z_STRVAL(new_header) + (s - Z_STRVAL_P(header)), rest, Z_STRLEN_P(header) - (rest - Z_STRVAL_P(header)) + 1);
306 						ZVAL_COPY(&ctx->old_header, header);
307 						php_stream_context_set_option(ctx->context, "http", "header", &new_header);
308 						zval_ptr_dtor(&new_header);
309 					}
310 				}
311 			}
312 		}
313 	}
314 }
315 
sdl_restore_uri_credentials(sdlCtx * ctx)316 void sdl_restore_uri_credentials(sdlCtx *ctx)
317 {
318 	if (Z_TYPE(ctx->old_header) != IS_UNDEF) {
319 	    php_stream_context_set_option(ctx->context, "http", "header", &ctx->old_header);
320 	    zval_ptr_dtor(&ctx->old_header);
321 		ZVAL_UNDEF(&ctx->old_header);
322 	}
323 	ctx->context = NULL;
324 }
325 
326 #define SAFE_STR(a) ((a)?((const char *)a):"")
327 
load_wsdl_ex(zval * this_ptr,char * struri,sdlCtx * ctx,int include)328 static void load_wsdl_ex(zval *this_ptr, char *struri, sdlCtx *ctx, int include)
329 {
330 	sdlPtr tmpsdl = ctx->sdl;
331 	xmlDocPtr wsdl;
332 	xmlNodePtr root, definitions, trav;
333 	xmlAttrPtr targetNamespace;
334 
335 	if (zend_hash_str_exists(&ctx->docs, struri, strlen(struri))) {
336 		return;
337 	}
338 
339 	sdl_set_uri_credentials(ctx, struri);
340 	wsdl = soap_xmlParseFile(struri);
341 	sdl_restore_uri_credentials(ctx);
342 
343 	if (!wsdl) {
344 		const xmlError *xmlErrorPtr = xmlGetLastError();
345 
346 		if (xmlErrorPtr) {
347 			soap_error2(E_ERROR, "Parsing WSDL: Couldn't load from '%s' : %s", struri, xmlErrorPtr->message);
348 		} else {
349 			soap_error1(E_ERROR, "Parsing WSDL: Couldn't load from '%s'", struri);
350 		}
351 	}
352 
353 	zend_hash_str_add_ptr(&ctx->docs, struri, strlen(struri), wsdl);
354 
355 	root = wsdl->children;
356 	definitions = get_node_ex(root, "definitions", WSDL_NAMESPACE);
357 	if (!definitions) {
358 		if (include) {
359 			xmlNodePtr schema = get_node_ex(root, "schema", XSD_NAMESPACE);
360 			if (schema) {
361 				load_schema(ctx, schema);
362 				return;
363 			}
364 		}
365 		soap_error1(E_ERROR, "Parsing WSDL: Couldn't find <definitions> in '%s'", struri);
366 	}
367 
368 	if (!include) {
369 		targetNamespace = get_attribute(definitions->properties, "targetNamespace");
370 		if (targetNamespace) {
371 			tmpsdl->target_ns = estrdup((char*)targetNamespace->children->content);
372 		}
373 	}
374 
375 	trav = definitions->children;
376 	while (trav != NULL) {
377 		if (!is_wsdl_element(trav)) {
378 			trav = trav->next;
379 			continue;
380 		}
381 		if (node_is_equal(trav,"types")) {
382 			/* TODO: Only one "types" is allowed */
383 			xmlNodePtr trav2 = trav->children;
384 
385 			while (trav2 != NULL) {
386 				if (node_is_equal_ex(trav2, "schema", XSD_NAMESPACE)) {
387 					load_schema(ctx, trav2);
388 				} else if (is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) {
389 					soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>", SAFE_STR(trav2->name));
390 				}
391 				trav2 = trav2->next;
392 			}
393 		} else if (node_is_equal(trav,"import")) {
394 			/* TODO: namespace ??? */
395 			xmlAttrPtr tmp = get_attribute(trav->properties, "location");
396 			if (tmp) {
397 				xmlChar *uri;
398 				xmlChar *base = xmlNodeGetBase(trav->doc, trav);
399 
400 				if (base == NULL) {
401 					uri = xmlBuildURI(tmp->children->content, trav->doc->URL);
402 				} else {
403 					uri = xmlBuildURI(tmp->children->content, base);
404 					xmlFree(base);
405 				}
406 				load_wsdl_ex(this_ptr, (char*)uri, ctx, 1);
407 				xmlFree(uri);
408 			}
409 
410 		} else if (node_is_equal(trav,"message")) {
411 			xmlAttrPtr name = get_attribute(trav->properties, "name");
412 			if (name && name->children && name->children->content) {
413 				if (zend_hash_str_add_ptr(&ctx->messages, (char*)name->children->content, xmlStrlen(name->children->content), trav) == NULL) {
414 					soap_error1(E_ERROR, "Parsing WSDL: <message> '%s' already defined", name->children->content);
415 				}
416 			} else {
417 				soap_error0(E_ERROR, "Parsing WSDL: <message> has no name attribute");
418 			}
419 
420 		} else if (node_is_equal(trav,"portType")) {
421 			xmlAttrPtr name = get_attribute(trav->properties, "name");
422 			if (name && name->children && name->children->content) {
423 				if (zend_hash_str_add_ptr(&ctx->portTypes, (char*)name->children->content, xmlStrlen(name->children->content), trav) == NULL) {
424 					soap_error1(E_ERROR, "Parsing WSDL: <portType> '%s' already defined", name->children->content);
425 				}
426 			} else {
427 				soap_error0(E_ERROR, "Parsing WSDL: <portType> has no name attribute");
428 			}
429 
430 		} else if (node_is_equal(trav,"binding")) {
431 			xmlAttrPtr name = get_attribute(trav->properties, "name");
432 			if (name && name->children && name->children->content) {
433 				if (zend_hash_str_add_ptr(&ctx->bindings, (char*)name->children->content, xmlStrlen(name->children->content), trav) == NULL) {
434 					soap_error1(E_ERROR, "Parsing WSDL: <binding> '%s' already defined", name->children->content);
435 				}
436 			} else {
437 				soap_error0(E_ERROR, "Parsing WSDL: <binding> has no name attribute");
438 			}
439 
440 		} else if (node_is_equal(trav,"service")) {
441 			xmlAttrPtr name = get_attribute(trav->properties, "name");
442 			if (name && name->children && name->children->content) {
443 				if (zend_hash_str_add_ptr(&ctx->services, (char*)name->children->content, xmlStrlen(name->children->content), trav) == NULL) {
444 					soap_error1(E_ERROR, "Parsing WSDL: <service> '%s' already defined", name->children->content);
445 				}
446 			} else {
447 				soap_error0(E_ERROR, "Parsing WSDL: <service> has no name attribute");
448 			}
449 		} else if (!node_is_equal(trav,"documentation")) {
450 			soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
451 		}
452 		trav = trav->next;
453 	}
454 }
455 
wsdl_soap_binding_header(sdlCtx * ctx,xmlNodePtr header,char * wsdl_soap_namespace,int fault)456 static sdlSoapBindingFunctionHeaderPtr wsdl_soap_binding_header(sdlCtx* ctx, xmlNodePtr header, char* wsdl_soap_namespace, int fault)
457 {
458 	xmlAttrPtr tmp;
459 	xmlNodePtr message, part;
460 	char *ctype;
461 	sdlSoapBindingFunctionHeaderPtr h;
462 
463 	tmp = get_attribute(header->properties, "message");
464 	if (!tmp) {
465 		soap_error0(E_ERROR, "Parsing WSDL: Missing message attribute for <header>");
466 	}
467 
468 	ctype = strrchr((char*)tmp->children->content,':');
469 	if (ctype == NULL) {
470 		ctype = (char*)tmp->children->content;
471 	} else {
472 		++ctype;
473 	}
474 	if ((message = zend_hash_str_find_ptr(&ctx->messages, ctype, strlen(ctype))) == NULL) {
475 		soap_error1(E_ERROR, "Parsing WSDL: Missing <message> with name '%s'", tmp->children->content);
476 	}
477 
478 	tmp = get_attribute(header->properties, "part");
479 	if (!tmp) {
480 		soap_error0(E_ERROR, "Parsing WSDL: Missing part attribute for <header>");
481 	}
482 	part = get_node_with_attribute_ex(message->children, "part", WSDL_NAMESPACE, "name", (char*)tmp->children->content, NULL);
483 	if (!part) {
484 		soap_error1(E_ERROR, "Parsing WSDL: Missing part '%s' in <message>", tmp->children->content);
485 	}
486 
487 	h = emalloc(sizeof(sdlSoapBindingFunctionHeader));
488 	memset(h, 0, sizeof(sdlSoapBindingFunctionHeader));
489 	h->name = estrdup((char*)tmp->children->content);
490 
491 	tmp = get_attribute(header->properties, "use");
492 	if (tmp && !strncmp((char*)tmp->children->content, "encoded", sizeof("encoded"))) {
493 		h->use = SOAP_ENCODED;
494 	} else {
495 		h->use = SOAP_LITERAL;
496 	}
497 
498 	tmp = get_attribute(header->properties, "namespace");
499 	if (tmp) {
500 		h->ns = estrdup((char*)tmp->children->content);
501 	}
502 
503 	if (h->use == SOAP_ENCODED) {
504 		tmp = get_attribute(header->properties, "encodingStyle");
505 		if (tmp) {
506 			if (strncmp((char*)tmp->children->content, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)) == 0) {
507 				h->encodingStyle = SOAP_ENCODING_1_1;
508 			} else if (strncmp((char*)tmp->children->content, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)) == 0) {
509 				h->encodingStyle = SOAP_ENCODING_1_2;
510 			} else {
511 				soap_error1(E_ERROR, "Parsing WSDL: Unknown encodingStyle '%s'", tmp->children->content);
512 			}
513 		} else {
514 			soap_error0(E_ERROR, "Parsing WSDL: Unspecified encodingStyle");
515 		}
516 	}
517 
518 	tmp = get_attribute(part->properties, "type");
519 	if (tmp != NULL) {
520 		h->encode = get_encoder_from_prefix(ctx->sdl, part, tmp->children->content);
521 	} else {
522 		tmp = get_attribute(part->properties, "element");
523 		if (tmp != NULL) {
524 			h->element = get_element(ctx->sdl, part, tmp->children->content);
525 			if (h->element) {
526 				h->encode = h->element->encode;
527 				if (!h->ns && h->element->namens) {
528 					h->ns = estrdup(h->element->namens);
529 				}
530 				if (h->element->name) {
531 					efree(h->name);
532 					h->name = estrdup(h->element->name);
533 				}
534 			}
535 		}
536 	}
537 	if (!fault) {
538 		xmlNodePtr trav = header->children;
539 		while (trav != NULL) {
540 			if (node_is_equal_ex(trav, "headerfault", wsdl_soap_namespace)) {
541 				sdlSoapBindingFunctionHeaderPtr hf = wsdl_soap_binding_header(ctx, trav, wsdl_soap_namespace, 1);
542 				smart_str key = {0};
543 
544 				if (h->headerfaults == NULL) {
545 					h->headerfaults = emalloc(sizeof(HashTable));
546 					zend_hash_init(h->headerfaults, 0, NULL, delete_header, 0);
547 				}
548 
549 				if (hf->ns) {
550 					smart_str_appends(&key,hf->ns);
551 					smart_str_appendc(&key,':');
552 				}
553 				smart_str_appends(&key,hf->name);
554 				smart_str_0(&key);
555 				if (zend_hash_add_ptr(h->headerfaults, key.s, hf) == NULL) {
556 					delete_header_int(hf);
557 				}
558 				smart_str_free(&key);
559 			} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
560 				soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
561 			}
562 			trav = trav->next;
563 		}
564 	}
565 	return h;
566 }
567 
wsdl_soap_binding_body(sdlCtx * ctx,xmlNodePtr node,char * wsdl_soap_namespace,sdlSoapBindingFunctionBody * binding,HashTable * params)568 static void wsdl_soap_binding_body(sdlCtx* ctx, xmlNodePtr node, char* wsdl_soap_namespace, sdlSoapBindingFunctionBody *binding, HashTable* params)
569 {
570 	xmlNodePtr body, trav;
571 	xmlAttrPtr tmp;
572 
573 	trav = node->children;
574 	while (trav != NULL) {
575 		if (node_is_equal_ex(trav, "body", wsdl_soap_namespace)) {
576 			body = trav;
577 
578 			tmp = get_attribute(body->properties, "use");
579 			if (tmp && !strncmp((char*)tmp->children->content, "literal", sizeof("literal"))) {
580 				binding->use = SOAP_LITERAL;
581 			} else {
582 				binding->use = SOAP_ENCODED;
583 			}
584 
585 			tmp = get_attribute(body->properties, "namespace");
586 			if (tmp) {
587 				binding->ns = estrdup((char*)tmp->children->content);
588 			}
589 
590 			tmp = get_attribute(body->properties, "parts");
591 			if (tmp) {
592 				HashTable    ht;
593 				char *parts = (char*)tmp->children->content;
594 
595 				/* Delete all parts those are not in the "parts" attribute */
596 				zend_hash_init(&ht, 0, NULL, delete_parameter, 0);
597 				while (*parts) {
598 					sdlParamPtr param;
599 					int found = 0;
600 					char *end;
601 
602 					while (*parts == ' ') ++parts;
603 					if (*parts == '\0') break;
604 					end = strchr(parts, ' ');
605 					if (end) *end = '\0';
606 					ZEND_HASH_FOREACH_PTR(params, param) {
607 						if (param->paramName &&
608 						    strcmp(parts, param->paramName) == 0) {
609 					  	sdlParamPtr x_param;
610 					  	x_param = emalloc(sizeof(sdlParam));
611 					  	*x_param = *param;
612 					  	param->paramName = NULL;
613 					  	zend_hash_next_index_insert_ptr(&ht, x_param);
614 					  	found = 1;
615 					  	break;
616 						}
617 					} ZEND_HASH_FOREACH_END();
618 					if (!found) {
619 						soap_error1(E_ERROR, "Parsing WSDL: Missing part '%s' in <message>", parts);
620 					}
621 					parts += strlen(parts);
622 					if (end) *end = ' ';
623 				}
624 				zend_hash_destroy(params);
625 				*params = ht;
626 			}
627 
628 			if (binding->use == SOAP_ENCODED) {
629 				tmp = get_attribute(body->properties, "encodingStyle");
630 				if (tmp) {
631 					if (strncmp((char*)tmp->children->content, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)) == 0) {
632 						binding->encodingStyle = SOAP_ENCODING_1_1;
633 					} else if (strncmp((char*)tmp->children->content, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)) == 0) {
634 						binding->encodingStyle = SOAP_ENCODING_1_2;
635 					} else {
636 						soap_error1(E_ERROR, "Parsing WSDL: Unknown encodingStyle '%s'", tmp->children->content);
637 					}
638 				} else {
639 					soap_error0(E_ERROR, "Parsing WSDL: Unspecified encodingStyle");
640 				}
641 			}
642 		} else if (node_is_equal_ex(trav, "header", wsdl_soap_namespace)) {
643 			sdlSoapBindingFunctionHeaderPtr h = wsdl_soap_binding_header(ctx, trav, wsdl_soap_namespace, 0);
644 			smart_str key = {0};
645 
646 			if (binding->headers == NULL) {
647 				binding->headers = emalloc(sizeof(HashTable));
648 				zend_hash_init(binding->headers, 0, NULL, delete_header, 0);
649 			}
650 
651 			if (h->ns) {
652 				smart_str_appends(&key,h->ns);
653 				smart_str_appendc(&key,':');
654 			}
655 			smart_str_appends(&key,h->name);
656 			smart_str_0(&key);
657 			if (zend_hash_add_ptr(binding->headers, key.s, h) == NULL) {
658 				delete_header_int(h);
659 			}
660 			smart_str_free(&key);
661 		} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
662 			soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
663 		}
664 		trav = trav->next;
665 	}
666 }
667 
wsdl_message(sdlCtx * ctx,xmlChar * message_name)668 static HashTable* wsdl_message(sdlCtx *ctx, xmlChar* message_name)
669 {
670 	xmlNodePtr trav, part, message = NULL, tmp;
671 	HashTable* parameters = NULL;
672 	char *ctype;
673 
674 	ctype = strrchr((char*)message_name,':');
675 	if (ctype == NULL) {
676 		ctype = (char*)message_name;
677 	} else {
678 		++ctype;
679 	}
680 	if ((tmp = zend_hash_str_find_ptr(&ctx->messages, ctype, strlen(ctype))) == NULL) {
681 		soap_error1(E_ERROR, "Parsing WSDL: Missing <message> with name '%s'", message_name);
682 	}
683 	message = tmp;
684 
685 	parameters = emalloc(sizeof(HashTable));
686 	zend_hash_init(parameters, 0, NULL, delete_parameter, 0);
687 
688 	trav = message->children;
689 	while (trav != NULL) {
690 		xmlAttrPtr element, type, name;
691 		sdlParamPtr param;
692 
693 		if (trav->ns != NULL && strcmp((char*)trav->ns->href, WSDL_NAMESPACE) != 0) {
694 			soap_error1(E_ERROR, "Parsing WSDL: Unexpected extensibility element <%s>",  SAFE_STR(trav->name));
695 		}
696 		if (node_is_equal(trav,"documentation")) {
697 			trav = trav->next;
698 			continue;
699 		}
700 		if (!node_is_equal(trav,"part")) {
701 			soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
702 		}
703 		part = trav;
704 		param = emalloc(sizeof(sdlParam));
705 		memset(param,0,sizeof(sdlParam));
706 		param->order = 0;
707 
708 		name = get_attribute(part->properties, "name");
709 		if (name == NULL) {
710 			soap_error1(E_ERROR, "Parsing WSDL: No name associated with <part> '%s'",  SAFE_STR(message->name));
711 		}
712 
713 		param->paramName = estrdup((char*)name->children->content);
714 
715 		type = get_attribute(part->properties, "type");
716 		if (type != NULL) {
717 			param->encode = get_encoder_from_prefix(ctx->sdl, part, type->children->content);
718 		} else {
719 			element = get_attribute(part->properties, "element");
720 			if (element != NULL) {
721 				param->element = get_element(ctx->sdl, part, element->children->content);
722 				if (param->element) {
723 					param->encode = param->element->encode;
724 				}
725 			}
726 		}
727 
728 		zend_hash_next_index_insert_ptr(parameters, param);
729 
730 		trav = trav->next;
731 	}
732 	return parameters;
733 }
734 
load_wsdl(zval * this_ptr,char * struri)735 static sdlPtr load_wsdl(zval *this_ptr, char *struri)
736 {
737 	sdlCtx ctx;
738 	int i,n;
739 
740 	memset(&ctx,0,sizeof(ctx));
741 	ctx.sdl = emalloc(sizeof(sdl));
742 	memset(ctx.sdl, 0, sizeof(sdl));
743 	ctx.sdl->source = estrdup(struri);
744 	zend_hash_init(&ctx.sdl->functions, 0, NULL, delete_function, 0);
745 
746 	zend_hash_init(&ctx.docs, 0, NULL, delete_document, 0);
747 	zend_hash_init(&ctx.messages, 0, NULL, NULL, 0);
748 	zend_hash_init(&ctx.bindings, 0, NULL, NULL, 0);
749 	zend_hash_init(&ctx.portTypes, 0, NULL, NULL, 0);
750 	zend_hash_init(&ctx.services,  0, NULL, NULL, 0);
751 
752 	zend_try {
753 	load_wsdl_ex(this_ptr, struri, &ctx, 0);
754 	schema_pass2(&ctx);
755 
756 	n = zend_hash_num_elements(&ctx.services);
757 	if (n > 0) {
758 		zend_hash_internal_pointer_reset(&ctx.services);
759 		for (i = 0; i < n; i++) {
760 			xmlNodePtr service, tmp;
761 			xmlNodePtr trav, port;
762 			int has_soap_port = 0;
763 
764 			service = tmp = zend_hash_get_current_data_ptr(&ctx.services);
765 
766 			trav = service->children;
767 			while (trav != NULL) {
768 				xmlAttrPtr type, name, bindingAttr, location;
769 				xmlNodePtr portType, operation;
770 				xmlNodePtr address, binding, trav2;
771 				char *ctype;
772 				sdlBindingPtr tmpbinding;
773 				char *wsdl_soap_namespace = NULL;
774 
775 				if (!is_wsdl_element(trav) || node_is_equal(trav,"documentation")) {
776 					trav = trav->next;
777 					continue;
778 				}
779 				if (!node_is_equal(trav,"port")) {
780 					soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
781 				}
782 
783 				port = trav;
784 
785 				tmpbinding = emalloc(sizeof(sdlBinding));
786 				memset(tmpbinding, 0, sizeof(sdlBinding));
787 
788 				bindingAttr = get_attribute(port->properties, "binding");
789 				if (bindingAttr == NULL) {
790 					soap_error0(E_ERROR, "Parsing WSDL: No binding associated with <port>");
791 				}
792 
793 				/* find address and figure out binding type */
794 				address = NULL;
795 				trav2 = port->children;
796 				while (trav2 != NULL) {
797 					if (node_is_equal(trav2,"address") && trav2->ns) {
798 						if (!strncmp((char*)trav2->ns->href, WSDL_SOAP11_NAMESPACE, sizeof(WSDL_SOAP11_NAMESPACE))) {
799 							address = trav2;
800 							wsdl_soap_namespace = WSDL_SOAP11_NAMESPACE;
801 							tmpbinding->bindingType = BINDING_SOAP;
802 						} else if (!strncmp((char*)trav2->ns->href, WSDL_SOAP12_NAMESPACE, sizeof(WSDL_SOAP12_NAMESPACE))) {
803 							address = trav2;
804 							wsdl_soap_namespace = WSDL_SOAP12_NAMESPACE;
805 							tmpbinding->bindingType = BINDING_SOAP;
806 						} else if (!strncmp((char*)trav2->ns->href, RPC_SOAP12_NAMESPACE, sizeof(RPC_SOAP12_NAMESPACE))) {
807 							address = trav2;
808 							wsdl_soap_namespace = RPC_SOAP12_NAMESPACE;
809 							tmpbinding->bindingType = BINDING_SOAP;
810 						} else if (!strncmp((char*)trav2->ns->href, WSDL_HTTP11_NAMESPACE, sizeof(WSDL_HTTP11_NAMESPACE))) {
811 							address = trav2;
812 							tmpbinding->bindingType = BINDING_HTTP;
813 						} else if (!strncmp((char*)trav2->ns->href, WSDL_HTTP12_NAMESPACE, sizeof(WSDL_HTTP12_NAMESPACE))) {
814 							address = trav2;
815 							tmpbinding->bindingType = BINDING_HTTP;
816 						}
817 					}
818 					if (trav2 != address && is_wsdl_element(trav2) && !node_is_equal(trav2,"documentation")) {
819 						soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav2->name));
820 					}
821 				  trav2 = trav2->next;
822 				}
823 				if (!address || tmpbinding->bindingType == BINDING_HTTP) {
824 					if (has_soap_port || trav->next || i < n-1) {
825 						efree(tmpbinding);
826 						trav = trav->next;
827 						continue;
828 					} else if (!address) {
829 						soap_error0(E_ERROR, "Parsing WSDL: No address associated with <port>");
830 					}
831 				}
832 				has_soap_port = 1;
833 
834 				location = get_attribute(address->properties, "location");
835 				if (!location) {
836 					soap_error0(E_ERROR, "Parsing WSDL: No location associated with <port>");
837 				}
838 
839 				tmpbinding->location = estrdup((char*)location->children->content);
840 
841 				ctype = strrchr((char*)bindingAttr->children->content,':');
842 				if (ctype == NULL) {
843 					ctype = (char*)bindingAttr->children->content;
844 				} else {
845 					++ctype;
846 				}
847 				if ((tmp = zend_hash_str_find_ptr(&ctx.bindings, ctype, strlen(ctype))) == NULL) {
848 					soap_error1(E_ERROR, "Parsing WSDL: No <binding> element with name '%s'", ctype);
849 				}
850 				binding = tmp;
851 
852 				if (tmpbinding->bindingType == BINDING_SOAP) {
853 					sdlSoapBindingPtr soapBinding;
854 					xmlNodePtr soapBindingNode;
855 					xmlAttrPtr tmp;
856 
857 					soapBinding = emalloc(sizeof(sdlSoapBinding));
858 					memset(soapBinding, 0, sizeof(sdlSoapBinding));
859 					soapBinding->style = SOAP_DOCUMENT;
860 
861 					soapBindingNode = get_node_ex(binding->children, "binding", wsdl_soap_namespace);
862 					if (soapBindingNode) {
863 						tmp = get_attribute(soapBindingNode->properties, "style");
864 						if (tmp && !strncmp((char*)tmp->children->content, "rpc", sizeof("rpc"))) {
865 							soapBinding->style = SOAP_RPC;
866 						}
867 
868 						tmp = get_attribute(soapBindingNode->properties, "transport");
869 						if (tmp) {
870 							if (strncmp((char*)tmp->children->content, WSDL_HTTP_TRANSPORT, sizeof(WSDL_HTTP_TRANSPORT)) == 0) {
871 								soapBinding->transport = SOAP_TRANSPORT_HTTP;
872 							} else {
873 								/* try the next binding */
874 								efree(soapBinding);
875 								efree(tmpbinding->location);
876 								efree(tmpbinding);
877 								trav = trav->next;
878 								continue;
879 							}
880 						}
881 					}
882 					tmpbinding->bindingAttributes = (void *)soapBinding;
883 				}
884 
885 				name = get_attribute(binding->properties, "name");
886 				if (name == NULL) {
887 					soap_error0(E_ERROR, "Parsing WSDL: Missing 'name' attribute for <binding>");
888 				}
889 				tmpbinding->name = estrdup((char*)name->children->content);
890 
891 				type = get_attribute(binding->properties, "type");
892 				if (type == NULL) {
893 					soap_error0(E_ERROR, "Parsing WSDL: Missing 'type' attribute for <binding>");
894 				}
895 
896 				ctype = strchr((char*)type->children->content,':');
897 				if (ctype == NULL) {
898 					ctype = (char*)type->children->content;
899 				} else {
900 					++ctype;
901 				}
902 				if ((tmp = zend_hash_str_find_ptr(&ctx.portTypes, ctype, strlen(ctype))) == NULL) {
903 					soap_error1(E_ERROR, "Parsing WSDL: Missing <portType> with name '%s'", name->children->content);
904 				}
905 				portType = tmp;
906 
907 				trav2 = binding->children;
908 				while (trav2 != NULL) {
909 					sdlFunctionPtr function;
910 					xmlNodePtr input, output, fault, portTypeOperation, trav3;
911 					xmlAttrPtr op_name, paramOrder;
912 
913 					if ((tmpbinding->bindingType == BINDING_SOAP &&
914 					    node_is_equal_ex(trav2, "binding", wsdl_soap_namespace)) ||
915 					    !is_wsdl_element(trav2) ||
916 					    node_is_equal(trav2,"documentation")) {
917 						trav2 = trav2->next;
918 						continue;
919 					}
920 					if (!node_is_equal(trav2,"operation")) {
921 						soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav2->name));
922 					}
923 
924 					operation = trav2;
925 
926 					op_name = get_attribute(operation->properties, "name");
927 					if (op_name == NULL) {
928 						soap_error0(E_ERROR, "Parsing WSDL: Missing 'name' attribute for <operation>");
929 					}
930 
931 					trav3 = operation->children;
932 					while  (trav3 != NULL) {
933 						if (tmpbinding->bindingType == BINDING_SOAP &&
934 						    node_is_equal_ex(trav3, "operation", wsdl_soap_namespace)) {
935 						} else if (is_wsdl_element(trav3) &&
936 						           !node_is_equal(trav3,"input") &&
937 						           !node_is_equal(trav3,"output") &&
938 						           !node_is_equal(trav3,"fault") &&
939 						           !node_is_equal(trav3,"documentation")) {
940 							soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav3->name));
941 						}
942 						trav3 = trav3->next;
943 					}
944 
945 					portTypeOperation = get_node_with_attribute_ex(portType->children, "operation", WSDL_NAMESPACE, "name", (char*)op_name->children->content, NULL);
946 					if (portTypeOperation == NULL) {
947 						soap_error1(E_ERROR, "Parsing WSDL: Missing <portType>/<operation> with name '%s'", op_name->children->content);
948 					}
949 
950 					function = emalloc(sizeof(sdlFunction));
951 					memset(function, 0, sizeof(sdlFunction));
952 					function->functionName = estrdup((char*)op_name->children->content);
953 
954 					if (tmpbinding->bindingType == BINDING_SOAP) {
955 						sdlSoapBindingFunctionPtr soapFunctionBinding;
956 						sdlSoapBindingPtr soapBinding;
957 						xmlNodePtr soapOperation;
958 						xmlAttrPtr tmp;
959 
960 						soapFunctionBinding = emalloc(sizeof(sdlSoapBindingFunction));
961 						memset(soapFunctionBinding, 0, sizeof(sdlSoapBindingFunction));
962 						soapBinding = (sdlSoapBindingPtr)tmpbinding->bindingAttributes;
963 						soapFunctionBinding->style = soapBinding->style;
964 
965 						soapOperation = get_node_ex(operation->children, "operation", wsdl_soap_namespace);
966 						if (soapOperation) {
967 							tmp = get_attribute(soapOperation->properties, "soapAction");
968 							if (tmp) {
969 								soapFunctionBinding->soapAction = estrdup((char*)tmp->children->content);
970 							}
971 
972 							tmp = get_attribute(soapOperation->properties, "style");
973 							if (tmp) {
974 								if (!strncmp((char*)tmp->children->content, "rpc", sizeof("rpc"))) {
975 									soapFunctionBinding->style = SOAP_RPC;
976 								} else {
977 									soapFunctionBinding->style = SOAP_DOCUMENT;
978 								}
979 							} else {
980 								soapFunctionBinding->style = soapBinding->style;
981 							}
982 						}
983 
984 						function->bindingAttributes = (void *)soapFunctionBinding;
985 					}
986 
987 					input = get_node_ex(portTypeOperation->children, "input", WSDL_NAMESPACE);
988 					if (input != NULL) {
989 						xmlAttrPtr message;
990 
991 						message = get_attribute(input->properties, "message");
992 						if (message == NULL) {
993 							soap_error1(E_ERROR, "Parsing WSDL: Missing name for <input> of '%s'", op_name->children->content);
994 						}
995 						function->requestParameters = wsdl_message(&ctx, message->children->content);
996 
997 /* FIXME
998 						xmlAttrPtr name = get_attribute(input->properties, "name");
999 						if (name != NULL) {
1000 							function->requestName = estrdup(name->children->content);
1001 						} else {
1002 */
1003 						{
1004 							function->requestName = estrdup(function->functionName);
1005 						}
1006 
1007 						if (tmpbinding->bindingType == BINDING_SOAP) {
1008 							input = get_node_ex(operation->children, "input", WSDL_NAMESPACE);
1009 							if (input != NULL) {
1010 								sdlSoapBindingFunctionPtr soapFunctionBinding = function->bindingAttributes;
1011 								wsdl_soap_binding_body(&ctx, input, wsdl_soap_namespace, &soapFunctionBinding->input, function->requestParameters);
1012 							}
1013 						}
1014 					}
1015 
1016 					output = get_node_ex(portTypeOperation->children, "output", WSDL_NAMESPACE);
1017 					if (output != NULL) {
1018 						xmlAttrPtr message;
1019 
1020 						message = get_attribute(output->properties, "message");
1021 						if (message == NULL) {
1022 							soap_error1(E_ERROR, "Parsing WSDL: Missing name for <output> of '%s'", op_name->children->content);
1023 						}
1024 						function->responseParameters = wsdl_message(&ctx, message->children->content);
1025 
1026 /* FIXME
1027 						xmlAttrPtr name = get_attribute(output->properties, "name");
1028 						if (name != NULL) {
1029 							function->responseName = estrdup(name->children->content);
1030 						} else if (input == NULL) {
1031 							function->responseName = estrdup(function->functionName);
1032 						} else {
1033 */
1034 						{
1035 							int len = strlen(function->functionName);
1036 							function->responseName = emalloc(len + sizeof("Response"));
1037 							memcpy(function->responseName, function->functionName, len);
1038 							memcpy(function->responseName+len, "Response", sizeof("Response"));
1039 						}
1040 
1041 						if (tmpbinding->bindingType == BINDING_SOAP) {
1042 							output = get_node_ex(operation->children, "output", WSDL_NAMESPACE);
1043 							if (output != NULL) {
1044 								sdlSoapBindingFunctionPtr soapFunctionBinding = function->bindingAttributes;
1045 								wsdl_soap_binding_body(&ctx, output, wsdl_soap_namespace, &soapFunctionBinding->output, function->responseParameters);
1046 							}
1047 						}
1048 					}
1049 
1050 					paramOrder = get_attribute(portTypeOperation->properties, "parameterOrder");
1051 					if (paramOrder) {
1052 						/* FIXME: */
1053 					}
1054 
1055 					fault = portTypeOperation->children;
1056 					while (fault != NULL) {
1057 						if (node_is_equal_ex(fault, "fault", WSDL_NAMESPACE)) {
1058 							xmlAttrPtr message, name;
1059 							sdlFaultPtr f;
1060 
1061 							name = get_attribute(fault->properties, "name");
1062 							if (name == NULL) {
1063 								soap_error1(E_ERROR, "Parsing WSDL: Missing name for <fault> of '%s'", op_name->children->content);
1064 							}
1065 							message = get_attribute(fault->properties, "message");
1066 							if (message == NULL) {
1067 								soap_error1(E_ERROR, "Parsing WSDL: Missing name for <output> of '%s'", op_name->children->content);
1068 							}
1069 
1070 							f = emalloc(sizeof(sdlFault));
1071 							memset(f, 0, sizeof(sdlFault));
1072 
1073 							f->name = estrdup((char*)name->children->content);
1074 							f->details = wsdl_message(&ctx, message->children->content);
1075 							if (f->details == NULL || zend_hash_num_elements(f->details) > 1) {
1076 								soap_error1(E_ERROR, "Parsing WSDL: The fault message '%s' must have a single part", message->children->content);
1077 							}
1078 
1079 							if (tmpbinding->bindingType == BINDING_SOAP) {
1080 								xmlNodePtr soap_fault = get_node_with_attribute_ex(operation->children, "fault", WSDL_NAMESPACE, "name", f->name, NULL);
1081 								if (soap_fault != NULL) {
1082 									xmlNodePtr trav = soap_fault->children;
1083 									while (trav != NULL) {
1084 										if (node_is_equal_ex(trav, "fault", wsdl_soap_namespace)) {
1085 											xmlAttrPtr tmp;
1086 										  sdlSoapBindingFunctionFaultPtr binding;
1087 
1088 											binding = f->bindingAttributes = emalloc(sizeof(sdlSoapBindingFunctionFault));
1089 											memset(f->bindingAttributes, 0, sizeof(sdlSoapBindingFunctionFault));
1090 
1091 											tmp = get_attribute(trav->properties, "use");
1092 											if (tmp && !strncmp((char*)tmp->children->content, "encoded", sizeof("encoded"))) {
1093 												binding->use = SOAP_ENCODED;
1094 											} else {
1095 												binding->use = SOAP_LITERAL;
1096 											}
1097 
1098 											tmp = get_attribute(trav->properties, "namespace");
1099 											if (tmp) {
1100 												binding->ns = estrdup((char*)tmp->children->content);
1101 											}
1102 
1103 											if (binding->use == SOAP_ENCODED) {
1104 												tmp = get_attribute(trav->properties, "encodingStyle");
1105 												if (tmp) {
1106 													if (strncmp((char*)tmp->children->content, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)) == 0) {
1107 														binding->encodingStyle = SOAP_ENCODING_1_1;
1108 													} else if (strncmp((char*)tmp->children->content, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)) == 0) {
1109 														binding->encodingStyle = SOAP_ENCODING_1_2;
1110 													} else {
1111 														soap_error1(E_ERROR, "Parsing WSDL: Unknown encodingStyle '%s'", tmp->children->content);
1112 													}
1113 												} else {
1114 													soap_error0(E_ERROR, "Parsing WSDL: Unspecified encodingStyle");
1115 												}
1116 											}
1117 										} else if (is_wsdl_element(trav) && !node_is_equal(trav,"documentation")) {
1118 											soap_error1(E_ERROR, "Parsing WSDL: Unexpected WSDL element <%s>",  SAFE_STR(trav->name));
1119 										}
1120 										trav = trav->next;
1121 									}
1122 								}
1123 							}
1124 							if (function->faults == NULL) {
1125 								function->faults = emalloc(sizeof(HashTable));
1126 								zend_hash_init(function->faults, 0, NULL, delete_fault, 0);
1127 							}
1128 							if (zend_hash_str_add_ptr(function->faults, f->name, strlen(f->name), f) == NULL) {
1129 								soap_error2(E_ERROR, "Parsing WSDL: <fault> with name '%s' already defined in '%s'", f->name, op_name->children->content);
1130 							}
1131 						}
1132 						fault = fault->next;
1133 					}
1134 
1135 					function->binding = tmpbinding;
1136 
1137 					{
1138 						char *tmp = estrdup(function->functionName);
1139 						int  len = strlen(tmp);
1140 
1141 						zend_str_tolower(tmp, len);
1142 						if (zend_hash_str_add_ptr(&ctx.sdl->functions, tmp, len, function) == NULL) {
1143 							zend_hash_next_index_insert_ptr(&ctx.sdl->functions, function);
1144 						}
1145 						efree(tmp);
1146 						if (function->requestName != NULL && strcmp(function->requestName,function->functionName) != 0) {
1147 							if (ctx.sdl->requests == NULL) {
1148 								ctx.sdl->requests = emalloc(sizeof(HashTable));
1149 								zend_hash_init(ctx.sdl->requests, 0, NULL, NULL, 0);
1150 							}
1151 							tmp = estrdup(function->requestName);
1152 							len = strlen(tmp);
1153 							zend_str_tolower(tmp, len);
1154 							zend_hash_str_add_ptr(ctx.sdl->requests, tmp, len, function);
1155 							efree(tmp);
1156 						}
1157 					}
1158 					trav2 = trav2->next;
1159 				}
1160 
1161 				if (!ctx.sdl->bindings) {
1162 					ctx.sdl->bindings = emalloc(sizeof(HashTable));
1163 					zend_hash_init(ctx.sdl->bindings, 0, NULL, delete_binding, 0);
1164 				}
1165 
1166 				if (!zend_hash_str_add_ptr(ctx.sdl->bindings, tmpbinding->name, strlen(tmpbinding->name), tmpbinding)) {
1167 					zend_hash_next_index_insert_ptr(ctx.sdl->bindings, tmpbinding);
1168 				}
1169 				trav= trav->next;
1170 			}
1171 
1172 			zend_hash_move_forward(&ctx.services);
1173 		}
1174 	} else {
1175 		soap_error0(E_ERROR, "Parsing WSDL: Couldn't bind to service");
1176 	}
1177 
1178 	if (ctx.sdl->bindings == NULL || ctx.sdl->bindings->nNumOfElements == 0) {
1179 		soap_error0(E_ERROR, "Parsing WSDL: Could not find any usable binding services in WSDL.");
1180 	}
1181 
1182 	} zend_catch {
1183 		/* Avoid persistent memory leak. */
1184 		zend_hash_destroy(&ctx.docs);
1185 		zend_bailout();
1186 	} zend_end_try();
1187 
1188 	zend_hash_destroy(&ctx.messages);
1189 	zend_hash_destroy(&ctx.bindings);
1190 	zend_hash_destroy(&ctx.portTypes);
1191 	zend_hash_destroy(&ctx.services);
1192 	zend_hash_destroy(&ctx.docs);
1193 
1194 	return ctx.sdl;
1195 }
1196 
1197 #define WSDL_CACHE_VERSION 0x10
1198 
1199 #define WSDL_CACHE_GET(ret,type,buf)   memcpy(&ret,*buf,sizeof(type)); *buf += sizeof(type);
1200 #define WSDL_CACHE_GET_INT(ret,buf)    ret = ((unsigned char)(*buf)[0])|((unsigned char)(*buf)[1]<<8)|((unsigned char)(*buf)[2]<<16)|((unsigned)(*buf)[3]<<24); *buf += 4;
1201 #define WSDL_CACHE_GET_1(ret,type,buf) ret = (type)(**buf); (*buf)++;
1202 #define WSDL_CACHE_GET_N(ret,n,buf)    memcpy(ret,*buf,n); *buf += n;
1203 #define WSDL_CACHE_SKIP(n,buf)         *buf += n;
1204 
1205 #define WSDL_CACHE_PUT_INT(val,buf)    smart_str_appendc(buf,(char)(val & 0xff)); \
1206                                        smart_str_appendc(buf,(char)((val >> 8) & 0xff)); \
1207                                        smart_str_appendc(buf,(char)((val >> 16) & 0xff)); \
1208                                        smart_str_appendc(buf,(char)((val >> 24) & 0xff));
1209 #define WSDL_CACHE_PUT_1(val,buf)      smart_str_appendc(buf,val);
1210 #define WSDL_CACHE_PUT_N(val,n,buf)    smart_str_appendl(buf,(char*)val,n);
1211 
1212 #define WSDL_NO_STRING_MARKER 0x7fffffff
1213 
sdl_deserialize_string(char ** in)1214 static char* sdl_deserialize_string(char **in)
1215 {
1216 	char *s;
1217 	int len;
1218 
1219 	WSDL_CACHE_GET_INT(len, in);
1220 	if (len == WSDL_NO_STRING_MARKER) {
1221 		return NULL;
1222 	} else {
1223 		s = emalloc(len+1);
1224 		WSDL_CACHE_GET_N(s, len, in);
1225 		s[len] = '\0';
1226 		return s;
1227 	}
1228 }
1229 
sdl_deserialize_key(HashTable * ht,void * data,char ** in)1230 static void sdl_deserialize_key(HashTable* ht, void* data, char **in)
1231 {
1232 	int len;
1233 
1234 	WSDL_CACHE_GET_INT(len, in);
1235 	if (len == WSDL_NO_STRING_MARKER) {
1236 		zend_hash_next_index_insert_ptr(ht, data);
1237 	} else {
1238 		zend_hash_str_add_ptr(ht, *in, len, data);
1239 		WSDL_CACHE_SKIP(len, in);
1240 	}
1241 }
1242 
sdl_deserialize_attribute(sdlAttributePtr attr,encodePtr * encoders,char ** in)1243 static void sdl_deserialize_attribute(sdlAttributePtr attr, encodePtr *encoders, char **in)
1244 {
1245 	int i;
1246 
1247 	attr->name = sdl_deserialize_string(in);
1248 	attr->namens = sdl_deserialize_string(in);
1249 	attr->ref = sdl_deserialize_string(in);
1250 	attr->def = sdl_deserialize_string(in);
1251 	attr->fixed = sdl_deserialize_string(in);
1252 	WSDL_CACHE_GET_1(attr->form, sdlForm, in);
1253 	WSDL_CACHE_GET_1(attr->use, sdlUse, in);
1254 	WSDL_CACHE_GET_INT(i, in);
1255 	attr->encode = encoders[i];
1256 	WSDL_CACHE_GET_INT(i, in);
1257 	if (i > 0) {
1258 		attr->extraAttributes = emalloc(sizeof(HashTable));
1259 		zend_hash_init(attr->extraAttributes, i, NULL, delete_extra_attribute, 0);
1260 		while (i > 0) {
1261 			sdlExtraAttributePtr x = emalloc(sizeof(sdlExtraAttribute));
1262 			sdl_deserialize_key(attr->extraAttributes, x, in);
1263 			x->ns = sdl_deserialize_string(in);
1264 			x->val = sdl_deserialize_string(in);
1265 			--i;
1266 		}
1267 	}
1268 }
1269 
sdl_deserialize_resriction_int(char ** in)1270 static sdlRestrictionIntPtr sdl_deserialize_resriction_int(char **in)
1271 {
1272 	if (**in == 1) {
1273 		sdlRestrictionIntPtr x = emalloc(sizeof(sdlRestrictionInt));
1274 		WSDL_CACHE_SKIP(1, in);
1275 		WSDL_CACHE_GET_INT(x->value, in);
1276 		WSDL_CACHE_GET_1(x->fixed, char, in);
1277 		return x;
1278 	} else {
1279 		WSDL_CACHE_SKIP(1, in);
1280 		return NULL;
1281 	}
1282 }
1283 
sdl_deserialize_resriction_char(char ** in)1284 static sdlRestrictionCharPtr sdl_deserialize_resriction_char(char **in)
1285 {
1286 	if (**in == 1) {
1287 		sdlRestrictionCharPtr x = emalloc(sizeof(sdlRestrictionChar));
1288 		WSDL_CACHE_SKIP(1, in);
1289 		x->value = sdl_deserialize_string(in);
1290 		WSDL_CACHE_GET_1(x->fixed, char, in);
1291 		return x;
1292 	} else {
1293 		WSDL_CACHE_SKIP(1, in);
1294 		return NULL;
1295 	}
1296 }
1297 
sdl_deserialize_model(sdlTypePtr * types,sdlTypePtr * elements,char ** in)1298 static sdlContentModelPtr sdl_deserialize_model(sdlTypePtr *types, sdlTypePtr *elements, char **in)
1299 {
1300 	int i;
1301 	sdlContentModelPtr model = emalloc(sizeof(sdlContentModel));
1302 
1303 	WSDL_CACHE_GET_1(model->kind, sdlContentKind, in);
1304 	WSDL_CACHE_GET_INT(model->min_occurs, in);
1305 	WSDL_CACHE_GET_INT(model->max_occurs, in);
1306 	switch (model->kind) {
1307 		case XSD_CONTENT_ELEMENT:
1308 			WSDL_CACHE_GET_INT(i, in);
1309 			model->u.element = elements[i];
1310 			break;
1311 		case XSD_CONTENT_SEQUENCE:
1312 		case XSD_CONTENT_ALL:
1313 		case XSD_CONTENT_CHOICE:
1314 			WSDL_CACHE_GET_INT(i, in);
1315 			model->u.content = emalloc(sizeof(HashTable));
1316 			zend_hash_init(model->u.content, i, NULL, delete_model, 0);
1317 			while (i > 0) {
1318 				sdlContentModelPtr x = sdl_deserialize_model(types, elements, in);
1319 				zend_hash_next_index_insert_ptr(model->u.content, x);
1320 				i--;
1321 			}
1322 			break;
1323 		case XSD_CONTENT_GROUP_REF:
1324 			model->u.group_ref = sdl_deserialize_string(in);
1325 			break;
1326 		case XSD_CONTENT_GROUP:
1327 			WSDL_CACHE_GET_INT(i, in);
1328 			model->u.group = types[i];
1329 			break;
1330 		default:
1331 			break;
1332 	}
1333 	return model;
1334 }
1335 
sdl_deserialize_type(sdlTypePtr type,sdlTypePtr * types,encodePtr * encoders,char ** in)1336 static void sdl_deserialize_type(sdlTypePtr type, sdlTypePtr *types, encodePtr *encoders, char **in)
1337 {
1338 	int i;
1339 	sdlTypePtr *elements = NULL;
1340 
1341 	WSDL_CACHE_GET_1(type->kind, sdlTypeKind, in);
1342 	type->name = sdl_deserialize_string(in);
1343 	type->namens = sdl_deserialize_string(in);
1344 	type->def = sdl_deserialize_string(in);
1345 	type->fixed = sdl_deserialize_string(in);
1346 	type->ref = sdl_deserialize_string(in);
1347 	WSDL_CACHE_GET_1(type->nillable, char, in);
1348 	WSDL_CACHE_GET_1(type->form, sdlForm, in);
1349 
1350 	WSDL_CACHE_GET_INT(i, in);
1351 	type->encode = encoders[i];
1352 
1353 	if (**in == 1) {
1354 		WSDL_CACHE_SKIP(1, in);
1355 		type->restrictions = emalloc(sizeof(sdlRestrictions));
1356 		/*memset(type->restrictions, 0, sizeof(sdlRestrictions));*/
1357 		type->restrictions->minExclusive = sdl_deserialize_resriction_int(in);
1358 		type->restrictions->minInclusive = sdl_deserialize_resriction_int(in);
1359 		type->restrictions->maxExclusive = sdl_deserialize_resriction_int(in);
1360 		type->restrictions->maxInclusive = sdl_deserialize_resriction_int(in);
1361 		type->restrictions->totalDigits = sdl_deserialize_resriction_int(in);
1362 		type->restrictions->fractionDigits = sdl_deserialize_resriction_int(in);
1363 		type->restrictions->length = sdl_deserialize_resriction_int(in);
1364 		type->restrictions->minLength = sdl_deserialize_resriction_int(in);
1365 		type->restrictions->maxLength = sdl_deserialize_resriction_int(in);
1366 		type->restrictions->whiteSpace = sdl_deserialize_resriction_char(in);
1367 		type->restrictions->pattern = sdl_deserialize_resriction_char(in);
1368 		WSDL_CACHE_GET_INT(i, in);
1369 		if (i > 0) {
1370 			type->restrictions->enumeration = emalloc(sizeof(HashTable));
1371 			zend_hash_init(type->restrictions->enumeration, i, NULL, delete_restriction_var_char, 0);
1372 			while (i > 0) {
1373 				sdlRestrictionCharPtr x = sdl_deserialize_resriction_char(in);
1374 				sdl_deserialize_key(type->restrictions->enumeration, x, in);
1375 				--i;
1376 			}
1377 		} else {
1378 			type->restrictions->enumeration = NULL;
1379 		}
1380 	} else {
1381 		WSDL_CACHE_SKIP(1, in);
1382 	}
1383 
1384 	WSDL_CACHE_GET_INT(i, in);
1385 	if (i > 0) {
1386 		elements = safe_emalloc((i+1), sizeof(sdlTypePtr), 0);
1387 		elements[0] = NULL;
1388 		type->elements = emalloc(sizeof(HashTable));
1389 		zend_hash_init(type->elements, i, NULL, delete_type, 0);
1390 		while (i > 0) {
1391 			sdlTypePtr t = emalloc(sizeof(sdlType));
1392 			memset(t, 0, sizeof(sdlType));
1393 			sdl_deserialize_key(type->elements, t, in);
1394 			sdl_deserialize_type(t, types, encoders, in);
1395 			elements[i] = t;
1396 			--i;
1397 		}
1398 	}
1399 
1400 	WSDL_CACHE_GET_INT(i, in);
1401 	if (i > 0) {
1402 		type->attributes = emalloc(sizeof(HashTable));
1403 		zend_hash_init(type->attributes, i, NULL, delete_attribute, 0);
1404 		while (i > 0) {
1405 			sdlAttributePtr attr = emalloc(sizeof(sdlAttribute));
1406 			memset(attr, 0, sizeof(sdlAttribute));
1407 			sdl_deserialize_key(type->attributes, attr, in);
1408 			sdl_deserialize_attribute(attr, encoders, in);
1409 			--i;
1410 		}
1411 	}
1412 
1413 	if (**in != 0) {
1414 		WSDL_CACHE_SKIP(1, in);
1415 		type->model = sdl_deserialize_model(types, elements, in);
1416 	} else {
1417 		WSDL_CACHE_SKIP(1, in);
1418 	}
1419 	if (elements != NULL) {
1420 		efree(elements);
1421 	}
1422 }
1423 
sdl_deserialize_encoder(encodePtr enc,sdlTypePtr * types,char ** in)1424 static void sdl_deserialize_encoder(encodePtr enc, sdlTypePtr *types, char **in)
1425 {
1426 	int i;
1427 
1428 	WSDL_CACHE_GET_INT(enc->details.type, in);
1429 	enc->details.type_str = sdl_deserialize_string(in);
1430 	enc->details.ns = sdl_deserialize_string(in);
1431 	if (enc->details.ns) {
1432 		enc->details.clark_notation = zend_strpprintf(0, "{%s}%s", enc->details.ns, enc->details.type_str);
1433 	}
1434 	WSDL_CACHE_GET_INT(i, in);
1435 	enc->details.sdl_type = types[i];
1436 	enc->to_xml = sdl_guess_convert_xml;
1437 	enc->to_zval = sdl_guess_convert_zval;
1438 
1439 	if (enc->details.sdl_type == NULL) {
1440 		int ns_len = strlen(enc->details.ns);
1441 		int type_len = strlen(enc->details.type_str);
1442 
1443 		if (((ns_len == sizeof(SOAP_1_1_ENC_NAMESPACE)-1 &&
1444 		      memcmp(enc->details.ns, SOAP_1_1_ENC_NAMESPACE, sizeof(SOAP_1_1_ENC_NAMESPACE)-1) == 0) ||
1445 		     (ns_len == sizeof(SOAP_1_2_ENC_NAMESPACE)-1 &&
1446 		      memcmp(enc->details.ns, SOAP_1_2_ENC_NAMESPACE, sizeof(SOAP_1_2_ENC_NAMESPACE)-1) == 0))) {
1447 			char *enc_nscat;
1448 			int enc_ns_len;
1449 			int enc_len;
1450 			encodePtr real_enc;
1451 
1452 			enc_ns_len = sizeof(XSD_NAMESPACE)-1;
1453 			enc_len = enc_ns_len + type_len + 1;
1454 			enc_nscat = emalloc(enc_len + 1);
1455 			memcpy(enc_nscat, XSD_NAMESPACE, sizeof(XSD_NAMESPACE)-1);
1456 			enc_nscat[enc_ns_len] = ':';
1457 			memcpy(enc_nscat+enc_ns_len+1, enc->details.type_str, type_len);
1458 			enc_nscat[enc_len] = '\0';
1459 
1460 			real_enc = get_encoder_ex(NULL, enc_nscat, enc_len);
1461 			efree(enc_nscat);
1462 			if (real_enc) {
1463 				enc->to_zval = real_enc->to_zval;
1464 				enc->to_xml = real_enc->to_xml;
1465 			}
1466 		}
1467 	}
1468 }
1469 
sdl_deserialize_soap_body(sdlSoapBindingFunctionBodyPtr body,encodePtr * encoders,sdlTypePtr * types,char ** in)1470 static void sdl_deserialize_soap_body(sdlSoapBindingFunctionBodyPtr body, encodePtr *encoders, sdlTypePtr *types, char **in)
1471 {
1472 	int i, j, n;
1473 
1474 	WSDL_CACHE_GET_1(body->use, sdlEncodingUse, in);
1475 	if (body->use == SOAP_ENCODED) {
1476 		WSDL_CACHE_GET_1(body->encodingStyle, sdlRpcEncodingStyle, in);
1477 	} else {
1478 		body->encodingStyle = SOAP_ENCODING_DEFAULT;
1479 	}
1480 	body->ns = sdl_deserialize_string(in);
1481 	WSDL_CACHE_GET_INT(i, in);
1482 	if (i > 0) {
1483 		body->headers = emalloc(sizeof(HashTable));
1484 		zend_hash_init(body->headers, i, NULL, delete_header, 0);
1485 		while (i > 0) {
1486 			sdlSoapBindingFunctionHeaderPtr tmp = emalloc(sizeof(sdlSoapBindingFunctionHeader));
1487 			memset(tmp, 0, sizeof(sdlSoapBindingFunctionHeader));
1488 			sdl_deserialize_key(body->headers, tmp, in);
1489 			WSDL_CACHE_GET_1(tmp->use, sdlEncodingUse, in);
1490 			if (tmp->use == SOAP_ENCODED) {
1491 				WSDL_CACHE_GET_1(tmp->encodingStyle, sdlRpcEncodingStyle, in);
1492 			} else {
1493 				tmp->encodingStyle = SOAP_ENCODING_DEFAULT;
1494 			}
1495 			tmp->name = sdl_deserialize_string(in);
1496 			tmp->ns = sdl_deserialize_string(in);
1497 			WSDL_CACHE_GET_INT(n, in);
1498 			tmp->encode = encoders[n];
1499 			WSDL_CACHE_GET_INT(n, in);
1500 			tmp->element = types[n];
1501 			--i;
1502 			WSDL_CACHE_GET_INT(j, in);
1503 			if (j > 0) {
1504 				tmp->headerfaults = emalloc(sizeof(HashTable));
1505 				zend_hash_init(tmp->headerfaults, i, NULL, delete_header, 0);
1506 				while (j > 0) {
1507 					sdlSoapBindingFunctionHeaderPtr tmp2 = emalloc(sizeof(sdlSoapBindingFunctionHeader));
1508 					memset(tmp2, 0, sizeof(sdlSoapBindingFunctionHeader));
1509 					sdl_deserialize_key(tmp->headerfaults, tmp2, in);
1510 					WSDL_CACHE_GET_1(tmp2->use, sdlEncodingUse, in);
1511 					if (tmp2->use == SOAP_ENCODED) {
1512 						WSDL_CACHE_GET_1(tmp2->encodingStyle, sdlRpcEncodingStyle, in);
1513 					} else {
1514 						tmp2->encodingStyle = SOAP_ENCODING_DEFAULT;
1515 					}
1516 					tmp2->name = sdl_deserialize_string(in);
1517 					tmp2->ns = sdl_deserialize_string(in);
1518 					WSDL_CACHE_GET_INT(n, in);
1519 					tmp2->encode = encoders[n];
1520 					WSDL_CACHE_GET_INT(n, in);
1521 					tmp2->element = types[n];
1522 					--j;
1523 				}
1524 			}
1525 		}
1526 	}
1527 }
1528 
sdl_deserialize_parameters(encodePtr * encoders,sdlTypePtr * types,char ** in)1529 static HashTable* sdl_deserialize_parameters(encodePtr *encoders, sdlTypePtr *types, char **in)
1530 {
1531 	int i, n;
1532 	HashTable *ht;
1533 
1534 	WSDL_CACHE_GET_INT(i, in);
1535 	if (i == 0) {return NULL;}
1536 	ht = emalloc(sizeof(HashTable));
1537 	zend_hash_init(ht, i, NULL, delete_parameter, 0);
1538 	while (i > 0) {
1539 		sdlParamPtr param = emalloc(sizeof(sdlParam));
1540 		sdl_deserialize_key(ht, param, in);
1541 		param->paramName = sdl_deserialize_string(in);
1542 		WSDL_CACHE_GET_INT(param->order, in);
1543 		WSDL_CACHE_GET_INT(n, in);
1544 		param->encode = encoders[n];
1545 		WSDL_CACHE_GET_INT(n, in);
1546 		param->element = types[n];
1547 		--i;
1548 	}
1549 	return ht;
1550 }
1551 
get_sdl_from_cache(const char * fn,const char * uri,size_t uri_len,time_t t,time_t * cached)1552 static sdlPtr get_sdl_from_cache(const char *fn, const char *uri, size_t uri_len, time_t t, time_t *cached)
1553 {
1554 	sdlPtr sdl;
1555 	time_t old_t;
1556 	int  i, num_groups, num_types, num_elements, num_encoders, num_bindings, num_func;
1557 	sdlFunctionPtr *functions = NULL;
1558 	sdlBindingPtr *bindings;
1559 	sdlTypePtr *types;
1560 	encodePtr *encoders;
1561 	const encode *enc;
1562 
1563 	int f;
1564 	struct stat st;
1565 	char *in, *buf;
1566 
1567 	f = open(fn, O_RDONLY|O_BINARY);
1568 	if (f < 0) {
1569 		return NULL;
1570 	}
1571 	if (fstat(f, &st) != 0) {
1572 		close(f);
1573 		return NULL;
1574 	}
1575 	buf = in = emalloc(st.st_size);
1576 	if (read(f, in, st.st_size) != st.st_size) {
1577 		close(f);
1578 		efree(in);
1579 		return NULL;
1580 	}
1581 	close(f);
1582 
1583 	if (strncmp(in,"wsdl",4) != 0 || in[4] != WSDL_CACHE_VERSION || in[5] != '\0') {
1584 		unlink(fn);
1585 		efree(buf);
1586 		return NULL;
1587 	}
1588 	in += 6;
1589 
1590 	WSDL_CACHE_GET(old_t, time_t, &in);
1591 	if (old_t < t) {
1592 		unlink(fn);
1593 		efree(buf);
1594 		return NULL;
1595 	}
1596 	*cached = old_t;
1597 
1598 	WSDL_CACHE_GET_INT(i, &in);
1599 	if (i != uri_len || strncmp(in, uri, i) != 0) {
1600 		unlink(fn);
1601 		efree(buf);
1602 		return NULL;
1603 	}
1604 	WSDL_CACHE_SKIP(i, &in);
1605 
1606 	sdl = emalloc(sizeof(*sdl));
1607 	memset(sdl, 0, sizeof(*sdl));
1608 
1609 	sdl->source = sdl_deserialize_string(&in);
1610 	sdl->target_ns = sdl_deserialize_string(&in);
1611 
1612 	WSDL_CACHE_GET_INT(num_groups, &in);
1613 	WSDL_CACHE_GET_INT(num_types, &in);
1614 	WSDL_CACHE_GET_INT(num_elements, &in);
1615 	WSDL_CACHE_GET_INT(num_encoders, &in);
1616 
1617 	i = num_groups+num_types+num_elements;
1618 	types = safe_emalloc((i+1), sizeof(sdlTypePtr), 0);
1619 	types[0] = NULL;
1620 	while (i > 0) {
1621 		types[i] = emalloc(sizeof(sdlType));
1622 		memset(types[i], 0, sizeof(sdlType));
1623 		i--;
1624 	}
1625 
1626 	i = num_encoders;
1627 	enc = defaultEncoding;
1628 	while (enc->details.type != END_KNOWN_TYPES) {
1629 		i++; enc++;
1630 	}
1631 	encoders = safe_emalloc((i+1), sizeof(encodePtr), 0);
1632 	i = num_encoders;
1633 	encoders[0] = NULL;
1634 	while (i > 0) {
1635 		encoders[i] = emalloc(sizeof(encode));
1636 		memset(encoders[i], 0, sizeof(encode));
1637 		i--;
1638 	}
1639 	i = num_encoders;
1640 	enc = defaultEncoding;
1641 	while (enc->details.type != END_KNOWN_TYPES) {
1642 		encoders[++i] = (encodePtr)enc++;
1643 	}
1644 
1645 	i = 1;
1646 	if (num_groups > 0) {
1647 		sdl->groups = emalloc(sizeof(HashTable));
1648 		zend_hash_init(sdl->groups, num_groups, NULL, delete_type, 0);
1649 		while (i < num_groups+1) {
1650 			sdl_deserialize_key(sdl->groups, types[i], &in);
1651 			sdl_deserialize_type(types[i], types, encoders, &in);
1652 			i++;
1653 		}
1654 	}
1655 
1656 	if (num_types > 0) {
1657 		sdl->types = emalloc(sizeof(HashTable));
1658 		zend_hash_init(sdl->types, num_types, NULL, delete_type, 0);
1659 		while (i < num_groups+num_types+1) {
1660 			sdl_deserialize_key(sdl->types, types[i], &in);
1661 			sdl_deserialize_type(types[i], types, encoders, &in);
1662 			i++;
1663 		}
1664 	}
1665 
1666 	if (num_elements > 0) {
1667 		sdl->elements = emalloc(sizeof(HashTable));
1668 		zend_hash_init(sdl->elements, num_elements, NULL, delete_type, 0);
1669 		while (i < num_groups+num_types+num_elements+1) {
1670 			sdl_deserialize_key(sdl->elements, types[i], &in);
1671 			sdl_deserialize_type(types[i], types, encoders, &in);
1672 			i++;
1673 		}
1674 	}
1675 
1676 	i = 1;
1677 	if (num_encoders > 0) {
1678 		sdl->encoders = emalloc(sizeof(HashTable));
1679 		zend_hash_init(sdl->encoders, num_encoders, NULL, delete_encoder, 0);
1680 		while (i < num_encoders+1) {
1681 			sdl_deserialize_key(sdl->encoders, encoders[i], &in);
1682 			sdl_deserialize_encoder(encoders[i], types, &in);
1683 			i++;
1684 		}
1685 	}
1686 
1687 	/* deserialize bindings */
1688 	WSDL_CACHE_GET_INT(num_bindings, &in);
1689 	bindings = safe_emalloc(num_bindings, sizeof(sdlBindingPtr), 0);
1690 	if (num_bindings > 0) {
1691 		sdl->bindings = emalloc(sizeof(HashTable));
1692 		zend_hash_init(sdl->bindings, num_bindings, NULL, delete_binding, 0);
1693 		for (i = 0; i < num_bindings; i++) {
1694 			sdlBindingPtr binding = emalloc(sizeof(sdlBinding));
1695 			memset(binding, 0, sizeof(sdlBinding));
1696 			sdl_deserialize_key(sdl->bindings, binding, &in);
1697 			binding->name = sdl_deserialize_string(&in);
1698 			binding->location = sdl_deserialize_string(&in);
1699 			WSDL_CACHE_GET_1(binding->bindingType,sdlBindingType,&in);
1700 			if (binding->bindingType == BINDING_SOAP && *in != 0) {
1701 			  sdlSoapBindingPtr soap_binding = binding->bindingAttributes = emalloc(sizeof(sdlSoapBinding));
1702 				WSDL_CACHE_GET_1(soap_binding->style,sdlEncodingStyle,&in);
1703 				WSDL_CACHE_GET_1(soap_binding->transport,sdlTransport,&in);
1704 			} else {
1705 				WSDL_CACHE_SKIP(1,&in);
1706 			}
1707 			bindings[i] = binding;
1708 		}
1709 	}
1710 
1711 	/* deserialize functions */
1712 	WSDL_CACHE_GET_INT(num_func, &in);
1713 	zend_hash_init(&sdl->functions, num_func, NULL, delete_function, 0);
1714 	if (num_func > 0) {
1715 		functions = safe_emalloc(num_func, sizeof(sdlFunctionPtr), 0);
1716 		for (i = 0; i < num_func; i++) {
1717 			int binding_num, num_faults;
1718 			sdlFunctionPtr func = emalloc(sizeof(sdlFunction));
1719 			sdl_deserialize_key(&sdl->functions, func, &in);
1720 			func->functionName = sdl_deserialize_string(&in);
1721 			func->requestName = sdl_deserialize_string(&in);
1722 			func->responseName = sdl_deserialize_string(&in);
1723 
1724 			WSDL_CACHE_GET_INT(binding_num, &in);
1725 			if (binding_num == 0) {
1726 				func->binding = NULL;
1727 			} else {
1728 				func->binding = bindings[binding_num-1];
1729 			}
1730 			if (func->binding && func->binding->bindingType == BINDING_SOAP && *in != 0) {
1731 				sdlSoapBindingFunctionPtr binding = func->bindingAttributes = emalloc(sizeof(sdlSoapBindingFunction));
1732 				memset(binding, 0, sizeof(sdlSoapBindingFunction));
1733 				WSDL_CACHE_GET_1(binding->style,sdlEncodingStyle,&in);
1734 				binding->soapAction = sdl_deserialize_string(&in);
1735 				sdl_deserialize_soap_body(&binding->input, encoders, types, &in);
1736 				sdl_deserialize_soap_body(&binding->output, encoders, types, &in);
1737 			} else {
1738 				WSDL_CACHE_SKIP(1, &in);
1739 				func->bindingAttributes = NULL;
1740 			}
1741 
1742 			func->requestParameters = sdl_deserialize_parameters(encoders, types, &in);
1743 			func->responseParameters = sdl_deserialize_parameters(encoders, types, &in);
1744 
1745 			WSDL_CACHE_GET_INT(num_faults, &in);
1746 			if (num_faults > 0) {
1747 			  int j;
1748 
1749 				func->faults = emalloc(sizeof(HashTable));
1750 				zend_hash_init(func->faults, num_faults, NULL, delete_fault, 0);
1751 
1752 				for (j = 0; j < num_faults; j++) {
1753 					sdlFaultPtr fault = emalloc(sizeof(sdlFault));
1754 
1755 					sdl_deserialize_key(func->faults, fault, &in);
1756 					fault->name =sdl_deserialize_string(&in);
1757 					fault->details =sdl_deserialize_parameters(encoders, types, &in);
1758 					if (*in != 0) {
1759 						sdlSoapBindingFunctionFaultPtr binding = fault->bindingAttributes = emalloc(sizeof(sdlSoapBindingFunctionFault));
1760 						memset(binding, 0, sizeof(sdlSoapBindingFunctionFault));
1761 						WSDL_CACHE_GET_1(binding->use,sdlEncodingUse,&in);
1762 						if (binding->use == SOAP_ENCODED) {
1763 							WSDL_CACHE_GET_1(binding->encodingStyle, sdlRpcEncodingStyle, &in);
1764 						} else {
1765 							binding->encodingStyle = SOAP_ENCODING_DEFAULT;
1766 						}
1767 						binding->ns = sdl_deserialize_string(&in);
1768 					} else {
1769 						WSDL_CACHE_SKIP(1, &in);
1770 						fault->bindingAttributes = NULL;
1771 					}
1772 				}
1773 			} else {
1774 				func->faults = NULL;
1775 			}
1776 			functions[i] = func;
1777 		}
1778 	}
1779 
1780 	/* deserialize requests */
1781 	WSDL_CACHE_GET_INT(i, &in);
1782 	if (i > 0) {
1783 		sdl->requests = emalloc(sizeof(HashTable));
1784 		zend_hash_init(sdl->requests, i, NULL, NULL, 0);
1785 		while (i > 0) {
1786 			int function_num;
1787 
1788 			WSDL_CACHE_GET_INT(function_num, &in);
1789 			sdl_deserialize_key(sdl->requests, functions[function_num-1], &in);
1790 			i--;
1791 		}
1792 	}
1793 
1794 	if (functions) {
1795 		efree(functions);
1796 	}
1797 	efree(bindings);
1798 	efree(encoders);
1799 	efree(types);
1800 	efree(buf);
1801 	return sdl;
1802 }
1803 
sdl_serialize_string(const char * str,smart_str * out)1804 static void sdl_serialize_string(const char *str, smart_str *out)
1805 {
1806 	if (str) {
1807 		int i = strlen(str);
1808 		WSDL_CACHE_PUT_INT(i, out);
1809 		if (i > 0) {
1810 			WSDL_CACHE_PUT_N(str, i, out);
1811 		}
1812 	} else {
1813 		WSDL_CACHE_PUT_INT(WSDL_NO_STRING_MARKER, out);
1814 	}
1815 }
1816 
1817 // TODO: refactor it
sdl_serialize_key(zend_string * key,smart_str * out)1818 static void sdl_serialize_key(zend_string *key, smart_str *out)
1819 {
1820 	if (key) {
1821 		WSDL_CACHE_PUT_INT(ZSTR_LEN(key), out);
1822 		WSDL_CACHE_PUT_N(ZSTR_VAL(key), ZSTR_LEN(key), out);
1823 	} else {
1824 		WSDL_CACHE_PUT_INT(WSDL_NO_STRING_MARKER, out);
1825 	}
1826 }
1827 
sdl_serialize_encoder_ref(encodePtr enc,HashTable * tmp_encoders,smart_str * out)1828 static void sdl_serialize_encoder_ref(encodePtr enc, HashTable *tmp_encoders, smart_str *out) {
1829 	if (enc) {
1830 		zval *encoder_num;
1831 		if ((encoder_num = zend_hash_str_find(tmp_encoders, (char*)&enc, sizeof(enc))) != 0) {
1832 			WSDL_CACHE_PUT_INT(Z_LVAL_P(encoder_num), out);
1833 		} else {
1834 			WSDL_CACHE_PUT_INT(0, out);
1835 		}
1836 	} else {
1837 		WSDL_CACHE_PUT_INT(0, out);
1838 	}
1839 }
1840 
sdl_serialize_type_ref(sdlTypePtr type,HashTable * tmp_types,smart_str * out)1841 static void sdl_serialize_type_ref(sdlTypePtr type, HashTable *tmp_types, smart_str *out) {
1842 	if (type) {
1843 		zval *type_num;
1844 		if ((type_num = zend_hash_str_find(tmp_types, (char*)&type, sizeof(type))) != NULL) {
1845 			WSDL_CACHE_PUT_INT(Z_LVAL_P(type_num), out);
1846 		} else {
1847 			WSDL_CACHE_PUT_INT(0, out);
1848 		}
1849 	} else {
1850 		WSDL_CACHE_PUT_INT(0,out);
1851 	}
1852 }
1853 
sdl_serialize_attribute(sdlAttributePtr attr,HashTable * tmp_encoders,smart_str * out)1854 static void sdl_serialize_attribute(sdlAttributePtr attr, HashTable *tmp_encoders, smart_str *out)
1855 {
1856 	int i;
1857 
1858 	sdl_serialize_string(attr->name, out);
1859 	sdl_serialize_string(attr->namens, out);
1860 	sdl_serialize_string(attr->ref, out);
1861 	sdl_serialize_string(attr->def, out);
1862 	sdl_serialize_string(attr->fixed, out);
1863 	WSDL_CACHE_PUT_1(attr->form, out);
1864 	WSDL_CACHE_PUT_1(attr->use, out);
1865 	sdl_serialize_encoder_ref(attr->encode, tmp_encoders, out);
1866 	if (attr->extraAttributes) {
1867 		i = zend_hash_num_elements(attr->extraAttributes);
1868 	} else {
1869 		i = 0;
1870 	}
1871 	WSDL_CACHE_PUT_INT(i, out);
1872 	if (i > 0) {
1873 		sdlExtraAttributePtr tmp;
1874 		zend_string *key;
1875 
1876 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(attr->extraAttributes, key, tmp) {
1877 			sdl_serialize_key(key, out);
1878 			sdl_serialize_string(tmp->ns, out);
1879 			sdl_serialize_string(tmp->val, out);
1880 		} ZEND_HASH_FOREACH_END();
1881 	}
1882 }
1883 
sdl_serialize_model(sdlContentModelPtr model,HashTable * tmp_types,HashTable * tmp_elements,smart_str * out)1884 static void sdl_serialize_model(sdlContentModelPtr model, HashTable *tmp_types, HashTable *tmp_elements, smart_str *out)
1885 {
1886 	WSDL_CACHE_PUT_1(model->kind, out);
1887 	WSDL_CACHE_PUT_INT(model->min_occurs, out);
1888 	WSDL_CACHE_PUT_INT(model->max_occurs, out);
1889 	switch (model->kind) {
1890 		case XSD_CONTENT_ELEMENT:
1891 			sdl_serialize_type_ref(model->u.element, tmp_elements, out);
1892 			break;
1893 		case XSD_CONTENT_SEQUENCE:
1894 		case XSD_CONTENT_ALL:
1895 		case XSD_CONTENT_CHOICE: {
1896 				sdlContentModelPtr tmp;
1897 				int i = zend_hash_num_elements(model->u.content);
1898 
1899 				WSDL_CACHE_PUT_INT(i, out);
1900 				ZEND_HASH_FOREACH_PTR(model->u.content, tmp) {
1901 					sdl_serialize_model(tmp, tmp_types, tmp_elements, out);
1902 				} ZEND_HASH_FOREACH_END();
1903 			}
1904 			break;
1905 		case XSD_CONTENT_GROUP_REF:
1906 			sdl_serialize_string(model->u.group_ref,out);
1907 			break;
1908 		case XSD_CONTENT_GROUP:
1909 			sdl_serialize_type_ref(model->u.group, tmp_types, out);
1910 			break;
1911 		default:
1912 			break;
1913 	}
1914 }
1915 
sdl_serialize_resriction_int(sdlRestrictionIntPtr x,smart_str * out)1916 static void sdl_serialize_resriction_int(sdlRestrictionIntPtr x, smart_str *out)
1917 {
1918 	if (x) {
1919 		WSDL_CACHE_PUT_1(1, out);
1920 		WSDL_CACHE_PUT_INT(x->value, out);
1921 		WSDL_CACHE_PUT_1(x->fixed, out);
1922 	} else {
1923 		WSDL_CACHE_PUT_1(0, out);
1924 	}
1925 }
1926 
sdl_serialize_resriction_char(sdlRestrictionCharPtr x,smart_str * out)1927 static void sdl_serialize_resriction_char(sdlRestrictionCharPtr x, smart_str *out)
1928 {
1929 	if (x) {
1930 		WSDL_CACHE_PUT_1(1, out);
1931 		sdl_serialize_string(x->value, out);
1932 		WSDL_CACHE_PUT_1(x->fixed, out);
1933 	} else {
1934 		WSDL_CACHE_PUT_1(0, out);
1935 	}
1936 }
1937 
sdl_serialize_type(sdlTypePtr type,HashTable * tmp_encoders,HashTable * tmp_types,smart_str * out)1938 static void sdl_serialize_type(sdlTypePtr type, HashTable *tmp_encoders, HashTable *tmp_types, smart_str *out)
1939 {
1940 	int i;
1941 	HashTable *tmp_elements = NULL;
1942 
1943 	WSDL_CACHE_PUT_1(type->kind, out);
1944 	sdl_serialize_string(type->name, out);
1945 	sdl_serialize_string(type->namens, out);
1946 	sdl_serialize_string(type->def, out);
1947 	sdl_serialize_string(type->fixed, out);
1948 	sdl_serialize_string(type->ref, out);
1949 	WSDL_CACHE_PUT_1(type->nillable, out);
1950 	WSDL_CACHE_PUT_1(type->form, out);
1951 	sdl_serialize_encoder_ref(type->encode, tmp_encoders, out);
1952 
1953 	if (type->restrictions) {
1954 		WSDL_CACHE_PUT_1(1, out);
1955 		sdl_serialize_resriction_int(type->restrictions->minExclusive,out);
1956 		sdl_serialize_resriction_int(type->restrictions->minInclusive,out);
1957 		sdl_serialize_resriction_int(type->restrictions->maxExclusive,out);
1958 		sdl_serialize_resriction_int(type->restrictions->maxInclusive,out);
1959 		sdl_serialize_resriction_int(type->restrictions->totalDigits,out);
1960 		sdl_serialize_resriction_int(type->restrictions->fractionDigits,out);
1961 		sdl_serialize_resriction_int(type->restrictions->length,out);
1962 		sdl_serialize_resriction_int(type->restrictions->minLength,out);
1963 		sdl_serialize_resriction_int(type->restrictions->maxLength,out);
1964 		sdl_serialize_resriction_char(type->restrictions->whiteSpace,out);
1965 		sdl_serialize_resriction_char(type->restrictions->pattern,out);
1966 		if (type->restrictions->enumeration) {
1967 			i = zend_hash_num_elements(type->restrictions->enumeration);
1968 		} else {
1969 			i = 0;
1970 		}
1971 		WSDL_CACHE_PUT_INT(i, out);
1972 		if (i > 0) {
1973 			sdlRestrictionCharPtr tmp;
1974 			zend_string *key;
1975 
1976 			ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(type->restrictions->enumeration, key, tmp) {
1977 				sdl_serialize_resriction_char(tmp, out);
1978 				sdl_serialize_key(key, out);
1979 			} ZEND_HASH_FOREACH_END();
1980 		}
1981 	} else {
1982 		WSDL_CACHE_PUT_1(0, out);
1983 	}
1984 	if (type->elements) {
1985 		i = zend_hash_num_elements(type->elements);
1986 	} else {
1987 		i = 0;
1988 	}
1989 	WSDL_CACHE_PUT_INT(i, out);
1990 	if (i > 0) {
1991 		sdlTypePtr tmp;
1992 		zend_string *key;
1993 		zval zv;
1994 
1995 		tmp_elements = emalloc(sizeof(HashTable));
1996 		zend_hash_init(tmp_elements, i, NULL, NULL, 0);
1997 
1998 		ZEND_HASH_FOREACH_STR_KEY_PTR(type->elements, key, tmp) {
1999 			sdl_serialize_key(key, out);
2000 			sdl_serialize_type(tmp, tmp_encoders, tmp_types, out);
2001 			ZVAL_LONG(&zv, i);
2002 			zend_hash_str_add(tmp_elements, (char*)&tmp, sizeof(tmp), &zv);
2003 			i--;
2004 		} ZEND_HASH_FOREACH_END();
2005 	}
2006 
2007 	if (type->attributes) {
2008 		i = zend_hash_num_elements(type->attributes);
2009 	} else {
2010 		i = 0;
2011 	}
2012 	WSDL_CACHE_PUT_INT(i, out);
2013 	if (i > 0) {
2014 		sdlAttributePtr tmp;
2015 		zend_string *key;
2016 
2017 		ZEND_HASH_FOREACH_STR_KEY_PTR(type->attributes, key, tmp) {
2018 			sdl_serialize_key(key, out);
2019 			sdl_serialize_attribute(tmp, tmp_encoders, out);
2020 		} ZEND_HASH_FOREACH_END();
2021 	}
2022 	if (type->model) {
2023 		WSDL_CACHE_PUT_1(1, out);
2024 		sdl_serialize_model(type->model, tmp_types, tmp_elements, out);
2025 	} else {
2026 		WSDL_CACHE_PUT_1(0, out);
2027 	}
2028 	if (tmp_elements != NULL) {
2029 		zend_hash_destroy(tmp_elements);
2030 		efree(tmp_elements);
2031 	}
2032 }
2033 
sdl_serialize_encoder(encodePtr enc,HashTable * tmp_types,smart_str * out)2034 static void sdl_serialize_encoder(encodePtr enc, HashTable *tmp_types, smart_str *out)
2035 {
2036 	WSDL_CACHE_PUT_INT(enc->details.type, out);
2037 	sdl_serialize_string(enc->details.type_str, out);
2038 	sdl_serialize_string(enc->details.ns, out);
2039 	sdl_serialize_type_ref(enc->details.sdl_type, tmp_types, out);
2040 }
2041 
sdl_serialize_parameters(HashTable * ht,HashTable * tmp_encoders,HashTable * tmp_types,smart_str * out)2042 static void sdl_serialize_parameters(HashTable *ht, HashTable *tmp_encoders, HashTable *tmp_types, smart_str *out)
2043 {
2044 	int i;
2045 
2046 	if (ht) {
2047 		i = zend_hash_num_elements(ht);
2048 	} else {
2049 		i = 0;
2050 	}
2051 	WSDL_CACHE_PUT_INT(i, out);
2052 	if (i > 0) {
2053 		sdlParamPtr tmp;
2054 		zend_string *key;
2055 
2056 		ZEND_HASH_FOREACH_STR_KEY_PTR(ht, key, tmp) {
2057 			sdl_serialize_key(key, out);
2058 			sdl_serialize_string(tmp->paramName, out);
2059 			WSDL_CACHE_PUT_INT(tmp->order, out);
2060 			sdl_serialize_encoder_ref(tmp->encode, tmp_encoders, out);
2061 			sdl_serialize_type_ref(tmp->element, tmp_types, out);
2062 		} ZEND_HASH_FOREACH_END();
2063 	}
2064 }
2065 
sdl_serialize_soap_body(sdlSoapBindingFunctionBodyPtr body,HashTable * tmp_encoders,HashTable * tmp_types,smart_str * out)2066 static void sdl_serialize_soap_body(sdlSoapBindingFunctionBodyPtr body, HashTable *tmp_encoders, HashTable *tmp_types, smart_str *out)
2067 {
2068 	int i, j;
2069 
2070 	WSDL_CACHE_PUT_1(body->use, out);
2071 	if (body->use == SOAP_ENCODED) {
2072 		WSDL_CACHE_PUT_1(body->encodingStyle, out);
2073 	}
2074 	sdl_serialize_string(body->ns, out);
2075 	if (body->headers) {
2076 		i = zend_hash_num_elements(body->headers);
2077 	} else {
2078 		i = 0;
2079 	}
2080 	WSDL_CACHE_PUT_INT(i, out);
2081 	if (i > 0) {
2082 		sdlSoapBindingFunctionHeaderPtr tmp;
2083 		zend_string *key;
2084 
2085 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(body->headers, key, tmp) {
2086 			sdl_serialize_key(key, out);
2087 			WSDL_CACHE_PUT_1(tmp->use, out);
2088 			if (tmp->use == SOAP_ENCODED) {
2089 				WSDL_CACHE_PUT_1(tmp->encodingStyle, out);
2090 			}
2091 			sdl_serialize_string(tmp->name, out);
2092 			sdl_serialize_string(tmp->ns, out);
2093 			sdl_serialize_encoder_ref(tmp->encode, tmp_encoders, out);
2094 			sdl_serialize_type_ref(tmp->element, tmp_types, out);
2095 			if (tmp->headerfaults) {
2096 				j = zend_hash_num_elements(tmp->headerfaults);
2097 			} else {
2098 				j = 0;
2099 			}
2100 			WSDL_CACHE_PUT_INT(j, out);
2101 			if (j > 0) {
2102 				sdlSoapBindingFunctionHeaderPtr tmp2;
2103 				zend_string *key;
2104 
2105 				ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(body->headers, key, tmp2) {
2106 					sdl_serialize_key(key, out);
2107 					WSDL_CACHE_PUT_1(tmp2->use, out);
2108 					if (tmp2->use == SOAP_ENCODED) {
2109 						WSDL_CACHE_PUT_1(tmp2->encodingStyle, out);
2110 					}
2111 					sdl_serialize_string(tmp2->name, out);
2112 					sdl_serialize_string(tmp2->ns, out);
2113 					sdl_serialize_encoder_ref(tmp2->encode, tmp_encoders, out);
2114 					sdl_serialize_type_ref(tmp2->element, tmp_types, out);
2115 				} ZEND_HASH_FOREACH_END();
2116 			}
2117 		} ZEND_HASH_FOREACH_END();
2118 	}
2119 }
2120 
add_sdl_to_cache(const char * fn,const char * uri,time_t t,sdlPtr sdl)2121 static void add_sdl_to_cache(const char *fn, const char *uri, time_t t, sdlPtr sdl)
2122 {
2123 	smart_str buf = {0};
2124 	smart_str *out = &buf;
2125 	int i;
2126 	int type_num = 1;
2127 	int encoder_num = 1;
2128 	int f;
2129 	const encode *enc;
2130 	HashTable tmp_types;
2131 	HashTable tmp_encoders;
2132 	HashTable tmp_bindings;
2133 	HashTable tmp_functions;
2134 
2135 	/* To avoid race conditions, we first create a temporary file and then rename it atomically
2136 	 * at the end of the function. (see bug #66150) */
2137 	zend_string *temp_file_path;
2138 	f = php_open_temporary_fd_ex(SOAP_GLOBAL(cache_dir), "tmp.wsdl.", &temp_file_path, PHP_TMP_FILE_SILENT);
2139 
2140 	if (f < 0) {return;}
2141 
2142 	zend_hash_init(&tmp_types, 0, NULL, NULL, 0);
2143 	zend_hash_init(&tmp_encoders, 0, NULL, NULL, 0);
2144 	zend_hash_init(&tmp_bindings, 0, NULL, NULL, 0);
2145 	zend_hash_init(&tmp_functions, 0, NULL, NULL, 0);
2146 
2147 	WSDL_CACHE_PUT_N("wsdl", 4, out);
2148 	WSDL_CACHE_PUT_1(WSDL_CACHE_VERSION,out);
2149 	WSDL_CACHE_PUT_1(0,out);
2150 	WSDL_CACHE_PUT_N(&t, sizeof(t), out);
2151 
2152 	sdl_serialize_string(uri, out);
2153 	sdl_serialize_string(sdl->source, out);
2154 	sdl_serialize_string(sdl->target_ns, out);
2155 
2156 	if (sdl->groups) {
2157 		i = zend_hash_num_elements(sdl->groups);
2158 	} else {
2159 		i = 0;
2160 	}
2161 	WSDL_CACHE_PUT_INT(i, out);
2162 	if (i > 0) {
2163 		sdlTypePtr tmp;
2164 		zval zv;
2165 
2166 		ZEND_HASH_MAP_FOREACH_PTR(sdl->groups, tmp) {
2167 			ZVAL_LONG(&zv, type_num);
2168 			zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
2169 			++type_num;
2170 		} ZEND_HASH_FOREACH_END();
2171 	}
2172 
2173 	if (sdl->types) {
2174 		i = zend_hash_num_elements(sdl->types);
2175 	} else {
2176 		i = 0;
2177 	}
2178 	WSDL_CACHE_PUT_INT(i, out);
2179 	if (i > 0) {
2180 		sdlTypePtr tmp;
2181 		zval zv;
2182 
2183 		ZEND_HASH_FOREACH_PTR(sdl->types, tmp) {
2184 			ZVAL_LONG(&zv,  type_num);
2185 			zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
2186 			++type_num;
2187 		} ZEND_HASH_FOREACH_END();
2188 	}
2189 
2190 	if (sdl->elements) {
2191 		i = zend_hash_num_elements(sdl->elements);
2192 	} else {
2193 		i = 0;
2194 	}
2195 	WSDL_CACHE_PUT_INT(i, out);
2196 	if (i > 0) {
2197 		sdlTypePtr tmp;
2198 		zval zv;
2199 
2200 		ZEND_HASH_MAP_FOREACH_PTR(sdl->elements, tmp) {
2201 			ZVAL_LONG(&zv, type_num);
2202 			zend_hash_str_add(&tmp_types, (char*)&tmp, sizeof(tmp), &zv);
2203 			++type_num;
2204 		} ZEND_HASH_FOREACH_END();
2205 	}
2206 
2207 	if (sdl->encoders) {
2208 		i = zend_hash_num_elements(sdl->encoders);
2209 	} else {
2210 		i = 0;
2211 	}
2212 	WSDL_CACHE_PUT_INT(i, out);
2213 	if (i > 0) {
2214 		encodePtr tmp;
2215 		zval zv;
2216 
2217 		ZEND_HASH_FOREACH_PTR(sdl->encoders, tmp) {
2218 			ZVAL_LONG(&zv, encoder_num);
2219 			zend_hash_str_add(&tmp_encoders, (char*)&tmp, sizeof(tmp), &zv);
2220 			++encoder_num;
2221 		} ZEND_HASH_FOREACH_END();
2222 	}
2223 	enc = defaultEncoding;
2224 	while (enc->details.type != END_KNOWN_TYPES) {
2225 		zval zv;
2226 
2227 		ZVAL_LONG(&zv, encoder_num);
2228 		zend_hash_str_add(&tmp_encoders, (char*)&enc, sizeof(encodePtr), &zv);
2229 		enc++;
2230 		++encoder_num;
2231 	}
2232 
2233 	if (sdl->groups) {
2234 		sdlTypePtr tmp;
2235 		zend_string *key;
2236 
2237 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
2238 			sdl_serialize_key(key, out);
2239 			sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
2240 		} ZEND_HASH_FOREACH_END();
2241 	}
2242 
2243 	if (sdl->types) {
2244 		sdlTypePtr tmp;
2245 		zend_string *key;
2246 
2247 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->types, key, tmp) {
2248 			sdl_serialize_key(key, out);
2249 			sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
2250 		} ZEND_HASH_FOREACH_END();
2251 	}
2252 
2253 	if (sdl->elements) {
2254 		sdlTypePtr tmp;
2255 		zend_string *key;
2256 
2257 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
2258 			sdl_serialize_key(key, out);
2259 			sdl_serialize_type(tmp, &tmp_encoders, &tmp_types, out);
2260 		} ZEND_HASH_FOREACH_END();
2261 	}
2262 
2263 	if (sdl->encoders) {
2264 		encodePtr tmp;
2265 		zend_string *key;
2266 
2267 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->encoders, key, tmp) {
2268 			sdl_serialize_key(key, out);
2269 			sdl_serialize_encoder(tmp, &tmp_types, out);
2270 		} ZEND_HASH_FOREACH_END();
2271 	}
2272 
2273 	/* serialize bindings */
2274 	if (sdl->bindings) {
2275 		i = zend_hash_num_elements(sdl->bindings);
2276 	} else {
2277 		i = 0;
2278 	}
2279 	WSDL_CACHE_PUT_INT(i, out);
2280 	if (i > 0) {
2281 		sdlBindingPtr tmp;
2282 		int binding_num = 1;
2283 		zval zv;
2284 		zend_string *key;
2285 
2286 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
2287 			sdl_serialize_key(key, out);
2288 			sdl_serialize_string(tmp->name, out);
2289 			sdl_serialize_string(tmp->location, out);
2290 			WSDL_CACHE_PUT_1(tmp->bindingType,out);
2291 			if (tmp->bindingType == BINDING_SOAP && tmp->bindingAttributes != NULL) {
2292 				sdlSoapBindingPtr binding = (sdlSoapBindingPtr)tmp->bindingAttributes;
2293 				WSDL_CACHE_PUT_1(binding->style, out);
2294 				WSDL_CACHE_PUT_1(binding->transport, out);
2295 			} else {
2296 				WSDL_CACHE_PUT_1(0,out);
2297 			}
2298 
2299 			ZVAL_LONG(&zv, binding_num);
2300 			zend_hash_str_add(&tmp_bindings, (char*)&tmp, sizeof(tmp), &zv);
2301 			binding_num++;
2302 		} ZEND_HASH_FOREACH_END();
2303 	}
2304 
2305 	/* serialize functions */
2306 	i = zend_hash_num_elements(&sdl->functions);
2307 	WSDL_CACHE_PUT_INT(i, out);
2308 	if (i > 0) {
2309 		sdlFunctionPtr tmp;
2310 		zval *binding_num, zv;
2311 		int function_num = 1;
2312 		zend_string *key;
2313 
2314 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
2315 			sdl_serialize_key(key, out);
2316 			sdl_serialize_string(tmp->functionName, out);
2317 			sdl_serialize_string(tmp->requestName, out);
2318 			sdl_serialize_string(tmp->responseName, out);
2319 
2320 			if (tmp->binding) {
2321 				binding_num = zend_hash_str_find(&tmp_bindings,(char*)&tmp->binding, sizeof(tmp->binding));
2322 				if (binding_num) {
2323 					WSDL_CACHE_PUT_INT(Z_LVAL_P(binding_num), out);
2324 					if (Z_LVAL_P(binding_num) >= 0) {
2325 						if (tmp->binding->bindingType == BINDING_SOAP && tmp->bindingAttributes != NULL) {
2326 							sdlSoapBindingFunctionPtr binding = (sdlSoapBindingFunctionPtr)tmp->bindingAttributes;
2327 							WSDL_CACHE_PUT_1(binding->style, out);
2328 							sdl_serialize_string(binding->soapAction, out);
2329 							sdl_serialize_soap_body(&binding->input, &tmp_encoders, &tmp_types, out);
2330 							sdl_serialize_soap_body(&binding->output, &tmp_encoders, &tmp_types, out);
2331 						} else {
2332 							WSDL_CACHE_PUT_1(0,out);
2333 						}
2334 					}
2335 				}
2336 			}
2337 			sdl_serialize_parameters(tmp->requestParameters, &tmp_encoders, &tmp_types, out);
2338 			sdl_serialize_parameters(tmp->responseParameters, &tmp_encoders, &tmp_types, out);
2339 
2340 			if (tmp->faults) {
2341 				sdlFaultPtr fault;
2342 				zend_string *key;
2343 
2344 				WSDL_CACHE_PUT_INT(zend_hash_num_elements(tmp->faults), out);
2345 
2346 				ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(tmp->faults, key, fault) {
2347 					sdl_serialize_key(key, out);
2348 					sdl_serialize_string(fault->name, out);
2349 					sdl_serialize_parameters(fault->details, &tmp_encoders, &tmp_types, out);
2350 					if (tmp->binding->bindingType == BINDING_SOAP && fault->bindingAttributes != NULL) {
2351 						sdlSoapBindingFunctionFaultPtr binding = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
2352 						WSDL_CACHE_PUT_1(binding->use, out);
2353 						if (binding->use == SOAP_ENCODED) {
2354 							WSDL_CACHE_PUT_1(binding->encodingStyle, out);
2355 						}
2356 						sdl_serialize_string(binding->ns, out);
2357 					} else {
2358 						WSDL_CACHE_PUT_1(0, out);
2359 					}
2360 				} ZEND_HASH_FOREACH_END();
2361 			} else {
2362 				WSDL_CACHE_PUT_INT(0, out);
2363 			}
2364 
2365 			ZVAL_LONG(&zv, function_num);
2366 			zend_hash_str_add(&tmp_functions, (char*)&tmp, sizeof(tmp), &zv);
2367 			function_num++;
2368 		} ZEND_HASH_FOREACH_END();
2369 	}
2370 
2371 	/* serialize requests */
2372 	if (sdl->requests) {
2373 		i = zend_hash_num_elements(sdl->requests);
2374 	} else {
2375 		i = 0;
2376 	}
2377 	WSDL_CACHE_PUT_INT(i, out);
2378 	if (i > 0) {
2379 		sdlFunctionPtr tmp;
2380 		zval *function_num;
2381 		zend_string *key;
2382 
2383 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->requests, key, tmp) {
2384 			function_num = zend_hash_str_find(&tmp_functions, (char*)&tmp, sizeof(tmp));
2385 			WSDL_CACHE_PUT_INT(Z_LVAL_P(function_num), out);
2386 			sdl_serialize_key(key, out);
2387 		} ZEND_HASH_FOREACH_END();
2388 	}
2389 
2390 	bool valid_file = write(f, ZSTR_VAL(buf.s), ZSTR_LEN(buf.s)) == ZSTR_LEN(buf.s);
2391 	close(f);
2392 
2393 	/* Make sure that incomplete files (e.g. due to disk space issues, see bug #66150) are not utilised. */
2394 	if (valid_file) {
2395 		/* This is allowed to fail, this means that another process was raced to create the file. */
2396 		if (VCWD_RENAME(ZSTR_VAL(temp_file_path), fn) < 0) {
2397 			VCWD_UNLINK(ZSTR_VAL(temp_file_path));
2398 		}
2399 	}
2400 
2401 	smart_str_free(&buf);
2402 	zend_hash_destroy(&tmp_functions);
2403 	zend_hash_destroy(&tmp_bindings);
2404 	zend_hash_destroy(&tmp_encoders);
2405 	zend_hash_destroy(&tmp_types);
2406 	zend_string_release_ex(temp_file_path, false);
2407 }
2408 
2409 
make_persistent_restriction_int(void * data)2410 static void make_persistent_restriction_int(void *data)
2411 {
2412 	sdlRestrictionIntPtr *rest = (sdlRestrictionIntPtr *)data;
2413 	sdlRestrictionIntPtr prest = NULL;
2414 
2415 	prest = malloc(sizeof(sdlRestrictionInt));
2416 	*prest = **rest;
2417 	*rest = prest;
2418 }
2419 
2420 
make_persistent_restriction_char_int(sdlRestrictionCharPtr * rest)2421 static void make_persistent_restriction_char_int(sdlRestrictionCharPtr *rest)
2422 {
2423 	sdlRestrictionCharPtr prest = NULL;
2424 
2425 	prest = malloc(sizeof(sdlRestrictionChar));
2426 	memset(prest, 0, sizeof(sdlRestrictionChar));
2427 	prest->value = strdup((*rest)->value);
2428 	prest->fixed = (*rest)->fixed;
2429 	*rest = prest;
2430 }
2431 
2432 
make_persistent_sdl_type_ref(sdlTypePtr * type,HashTable * ptr_map,HashTable * bp_types)2433 static void make_persistent_sdl_type_ref(sdlTypePtr *type, HashTable *ptr_map, HashTable *bp_types)
2434 {
2435 	sdlTypePtr tmp;
2436 
2437 	if ((tmp = zend_hash_str_find_ptr(ptr_map, (char *)type, sizeof(sdlTypePtr))) != NULL) {
2438 		*type = tmp;
2439 	} else {
2440 		zend_hash_next_index_insert_ptr(bp_types, *type);
2441 	}
2442 }
2443 
2444 
make_persistent_sdl_encoder_ref(encodePtr * enc,HashTable * ptr_map,HashTable * bp_encoders)2445 static void make_persistent_sdl_encoder_ref(encodePtr *enc, HashTable *ptr_map, HashTable *bp_encoders)
2446 {
2447 	encodePtr tmp;
2448 
2449 	/* do not process defaultEncoding's here */
2450 	if ((*enc) >= defaultEncoding && (*enc) < defaultEncoding + numDefaultEncodings) {
2451 		return;
2452 	}
2453 
2454 	if ((tmp = zend_hash_str_find_ptr(ptr_map, (char *)enc, sizeof(encodePtr))) != NULL) {
2455 		*enc = tmp;
2456 	} else {
2457 		zend_hash_next_index_insert_ptr(bp_encoders, enc);
2458 	}
2459 }
2460 
2461 
make_persistent_sdl_function_headers(HashTable * headers,HashTable * ptr_map)2462 static HashTable* make_persistent_sdl_function_headers(HashTable *headers, HashTable *ptr_map)
2463 {
2464 	HashTable *pheaders;
2465 	sdlSoapBindingFunctionHeaderPtr tmp, pheader;
2466 	encodePtr penc;
2467 	sdlTypePtr ptype;
2468 	zend_string *key;
2469 
2470 	pheaders = malloc(sizeof(HashTable));
2471 	zend_hash_init(pheaders, zend_hash_num_elements(headers), NULL, delete_header_persistent, 1);
2472 
2473 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(headers, key, tmp) {
2474 		pheader = malloc(sizeof(sdlSoapBindingFunctionHeader));
2475 		memset(pheader, 0, sizeof(sdlSoapBindingFunctionHeader));
2476 		*pheader = *tmp;
2477 
2478 		if (pheader->name) {
2479 			pheader->name = strdup(pheader->name);
2480 		}
2481 		if (pheader->ns) {
2482 			pheader->ns = strdup(pheader->ns);
2483 		}
2484 
2485 		if (pheader->encode && pheader->encode->details.sdl_type) {
2486 			if ((penc = zend_hash_str_find_ptr(ptr_map, (char*)&pheader->encode, sizeof(encodePtr))) == NULL) {
2487 				assert(0);
2488 			}
2489 			pheader->encode = penc;
2490 		}
2491 		if (pheader->element) {
2492 			if ((ptype = zend_hash_str_find_ptr(ptr_map, (char*)&pheader->element, sizeof(sdlTypePtr))) == NULL) {
2493 				assert(0);
2494 			}
2495 			pheader->element = ptype;
2496 		}
2497 
2498 		if (pheader->headerfaults) {
2499 			pheader->headerfaults = make_persistent_sdl_function_headers(pheader->headerfaults, ptr_map);
2500 		}
2501 
2502 		if (key) {
2503 			/* We have to duplicate key emalloc->malloc */
2504 			zend_hash_str_add_ptr(pheaders, ZSTR_VAL(key), ZSTR_LEN(key), pheader);
2505 		} else {
2506 			zend_hash_next_index_insert_ptr(pheaders, pheader);
2507 		}
2508 	} ZEND_HASH_FOREACH_END();
2509 
2510 	return pheaders;
2511 }
2512 
2513 
make_persistent_sdl_soap_body(sdlSoapBindingFunctionBodyPtr body,HashTable * ptr_map)2514 static void make_persistent_sdl_soap_body(sdlSoapBindingFunctionBodyPtr body, HashTable *ptr_map)
2515 {
2516 	if (body->ns) {
2517 		body->ns = strdup(body->ns);
2518 	}
2519 
2520 	if (body->headers) {
2521 		body->headers = make_persistent_sdl_function_headers(body->headers, ptr_map);
2522 	}
2523 }
2524 
2525 
make_persistent_sdl_parameters(HashTable * params,HashTable * ptr_map)2526 static HashTable* make_persistent_sdl_parameters(HashTable *params, HashTable *ptr_map)
2527 {
2528 	HashTable *pparams;
2529 	sdlParamPtr tmp, pparam;
2530 	sdlTypePtr ptype;
2531 	encodePtr penc;
2532 	zend_string *key;
2533 
2534 	pparams = malloc(sizeof(HashTable));
2535 	zend_hash_init(pparams, zend_hash_num_elements(params), NULL, delete_parameter_persistent, 1);
2536 
2537 	ZEND_HASH_FOREACH_STR_KEY_PTR(params, key, tmp) {
2538 		pparam = malloc(sizeof(sdlParam));
2539 		memset(pparam, 0, sizeof(sdlParam));
2540 		*pparam = *tmp;
2541 
2542 		if (pparam->paramName) {
2543 			pparam->paramName = strdup(pparam->paramName);
2544 		}
2545 
2546 		if (pparam->encode && pparam->encode->details.sdl_type) {
2547 			if ((penc = zend_hash_str_find_ptr(ptr_map, (char*)&pparam->encode, sizeof(encodePtr))) == NULL) {
2548 				assert(0);
2549 			}
2550 			pparam->encode = penc;
2551 		}
2552 		if (pparam->element) {
2553 			if ((ptype = zend_hash_str_find_ptr(ptr_map, (char*)&pparam->element, sizeof(sdlTypePtr))) == NULL) {
2554 				assert(0);
2555 			}
2556 			pparam->element = ptype;
2557 		}
2558 
2559 		if (key) {
2560 			/* We have to duplicate key emalloc->malloc */
2561 			zend_hash_str_add_ptr(pparams, ZSTR_VAL(key), ZSTR_LEN(key), pparam);
2562 		} else {
2563 			zend_hash_next_index_insert_ptr(pparams, pparam);
2564 		}
2565 	} ZEND_HASH_FOREACH_END();
2566 
2567 	return pparams;
2568 }
2569 
make_persistent_sdl_function_faults(sdlFunctionPtr func,HashTable * faults,HashTable * ptr_map)2570 static HashTable* make_persistent_sdl_function_faults(sdlFunctionPtr func, HashTable *faults, HashTable *ptr_map)
2571 {
2572 	HashTable *pfaults;
2573 	sdlFaultPtr tmp, pfault;
2574 	zend_string *key;
2575 
2576 	pfaults = malloc(sizeof(HashTable));
2577 	zend_hash_init(pfaults, zend_hash_num_elements(faults), NULL, delete_fault_persistent, 1);
2578 
2579 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(faults, key, tmp) {
2580 		pfault = malloc(sizeof(sdlFault));
2581 		memset(pfault, 0, sizeof(sdlFault));
2582 		*pfault = *tmp;
2583 
2584 		if (pfault->name) {
2585 			pfault->name = strdup(pfault->name);
2586 		}
2587 		if (pfault->details) {
2588 			pfault->details = make_persistent_sdl_parameters(pfault->details, ptr_map);
2589 		}
2590 
2591 		if (func->binding->bindingType == BINDING_SOAP && pfault->bindingAttributes) {
2592 			sdlSoapBindingFunctionFaultPtr soap_binding;
2593 
2594 		   	soap_binding = malloc(sizeof(sdlSoapBindingFunctionFault));
2595 			memset(soap_binding, 0, sizeof(sdlSoapBindingFunctionFault));
2596 			*soap_binding = *(sdlSoapBindingFunctionFaultPtr)pfault->bindingAttributes;
2597 			if (soap_binding->ns) {
2598 				soap_binding->ns = strdup(soap_binding->ns);
2599 			}
2600 			pfault->bindingAttributes = soap_binding;
2601 		}
2602 
2603 		if (key) {
2604 			/* We have to duplicate key emalloc->malloc */
2605 			zend_hash_str_add_ptr(pfaults, ZSTR_VAL(key), ZSTR_LEN(key), pfault);
2606 		} else {
2607 			zend_hash_next_index_insert_ptr(pfaults, pfault);
2608 		}
2609 
2610 	} ZEND_HASH_FOREACH_END();
2611 
2612 	return pfaults;
2613 }
2614 
2615 
make_persistent_sdl_attribute(sdlAttributePtr attr,HashTable * ptr_map,HashTable * bp_types,HashTable * bp_encoders)2616 static sdlAttributePtr make_persistent_sdl_attribute(sdlAttributePtr attr, HashTable *ptr_map, HashTable *bp_types, HashTable *bp_encoders)
2617 {
2618 	sdlAttributePtr pattr;
2619 	zend_string *key;
2620 
2621 	pattr = malloc(sizeof(sdlAttribute));
2622 	memset(pattr, 0, sizeof(sdlAttribute));
2623 
2624 	*pattr = *attr;
2625 
2626 	if (pattr->name) {
2627 		pattr->name = strdup(pattr->name);
2628 	}
2629 	if (pattr->namens) {
2630 		pattr->namens = strdup(pattr->namens);
2631 	}
2632 	if (pattr->ref) {
2633 		pattr->ref = strdup(pattr->ref);
2634 	}
2635 	if (pattr->def) {
2636 		pattr->def = strdup(pattr->def);
2637 	}
2638 	if (pattr->fixed) {
2639 		pattr->fixed = strdup(pattr->fixed);
2640 	}
2641 
2642 	/* we do not want to process defaultEncoding's here */
2643 	if (pattr->encode) {
2644 		make_persistent_sdl_encoder_ref(&pattr->encode, ptr_map, bp_encoders);
2645 	}
2646 
2647 	if (pattr->extraAttributes) {
2648 		sdlExtraAttributePtr tmp, pextra;
2649 
2650 		pattr->extraAttributes = malloc(sizeof(HashTable));
2651 		zend_hash_init(pattr->extraAttributes, zend_hash_num_elements(attr->extraAttributes), NULL, delete_extra_attribute_persistent, 1);
2652 
2653 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(attr->extraAttributes, key, tmp) {
2654 			if (key) {
2655 				pextra = malloc(sizeof(sdlExtraAttribute));
2656 				memset(pextra, 0, sizeof(sdlExtraAttribute));
2657 
2658 				if (tmp->ns) {
2659 					pextra->ns = strdup(tmp->ns);
2660 				}
2661 				if (tmp->val) {
2662 					pextra->val = strdup(tmp->val);
2663 				}
2664 
2665 				/* We have to duplicate key emalloc->malloc */
2666 				zend_hash_str_add_ptr(pattr->extraAttributes, ZSTR_VAL(key), ZSTR_LEN(key), pextra);
2667 			}
2668 		} ZEND_HASH_FOREACH_END();
2669 	}
2670 
2671 	return pattr;
2672 }
2673 
2674 
make_persistent_sdl_model(sdlContentModelPtr model,HashTable * ptr_map,HashTable * bp_types,HashTable * bp_encoders)2675 static sdlContentModelPtr make_persistent_sdl_model(sdlContentModelPtr model, HashTable *ptr_map, HashTable *bp_types, HashTable *bp_encoders)
2676 {
2677 	sdlContentModelPtr pmodel;
2678 	sdlContentModelPtr tmp, pcontent;
2679 
2680 	pmodel = malloc(sizeof(sdlContentModel));
2681 	memset(pmodel, 0, sizeof(sdlContentModel));
2682 	*pmodel = *model;
2683 
2684 	switch (pmodel->kind) {
2685 		case XSD_CONTENT_ELEMENT:
2686 			if (pmodel->u.element) {
2687 				make_persistent_sdl_type_ref(&pmodel->u.element, ptr_map, bp_types);
2688 			}
2689 			break;
2690 
2691 		case XSD_CONTENT_SEQUENCE:
2692 		case XSD_CONTENT_ALL:
2693 		case XSD_CONTENT_CHOICE:
2694 			pmodel->u.content = malloc(sizeof(HashTable));
2695 			zend_hash_init(pmodel->u.content, zend_hash_num_elements(model->u.content), NULL, delete_model_persistent, 1);
2696 
2697 			ZEND_HASH_FOREACH_PTR(model->u.content, tmp) {
2698 				pcontent = make_persistent_sdl_model(tmp, ptr_map, bp_types, bp_encoders);
2699 				zend_hash_next_index_insert_ptr(pmodel->u.content, pcontent);
2700 			} ZEND_HASH_FOREACH_END();
2701 			break;
2702 
2703 		case XSD_CONTENT_GROUP_REF:
2704 			if (pmodel->u.group_ref) {
2705 				pmodel->u.group_ref = strdup(pmodel->u.group_ref);
2706 			}
2707 			break;
2708 
2709 		case XSD_CONTENT_GROUP:
2710 			if (pmodel->u.group) {
2711 				make_persistent_sdl_type_ref(&pmodel->u.group, ptr_map, bp_types);
2712 			}
2713 			break;
2714 
2715 		default:
2716 			break;
2717 	}
2718 
2719 	return pmodel;
2720 }
2721 
2722 
make_persistent_sdl_type(sdlTypePtr type,HashTable * ptr_map,HashTable * bp_types,HashTable * bp_encoders)2723 static sdlTypePtr make_persistent_sdl_type(sdlTypePtr type, HashTable *ptr_map, HashTable *bp_types, HashTable *bp_encoders)
2724 {
2725 	zend_string *key;
2726 	sdlTypePtr ptype = NULL;
2727 
2728 	ptype = malloc(sizeof(sdlType));
2729 	memset(ptype, 0, sizeof(sdlType));
2730 
2731 	*ptype = *type;
2732 
2733 	if (ptype->name) {
2734 		ptype->name = strdup(ptype->name);
2735 	}
2736 	if (ptype->namens) {
2737 		ptype->namens = strdup(ptype->namens);
2738 	}
2739 	if (ptype->def) {
2740 		ptype->def = strdup(ptype->def);
2741 	}
2742 	if (ptype->fixed) {
2743 		ptype->fixed = strdup(ptype->fixed);
2744 	}
2745 	if (ptype->ref) {
2746 		ptype->ref = strdup(ptype->ref);
2747 	}
2748 
2749 	/* we do not want to process defaultEncoding's here */
2750 	if (ptype->encode) {
2751 		make_persistent_sdl_encoder_ref(&ptype->encode, ptr_map, bp_encoders);
2752 	}
2753 
2754 	if (ptype->restrictions) {
2755 		ptype->restrictions = malloc(sizeof(sdlRestrictions));
2756 		memset(ptype->restrictions, 0, sizeof(sdlRestrictions));
2757 		*ptype->restrictions = *type->restrictions;
2758 
2759 		if (ptype->restrictions->minExclusive) {
2760 			make_persistent_restriction_int(&ptype->restrictions->minExclusive);
2761 		}
2762 		if (ptype->restrictions->maxExclusive) {
2763 			make_persistent_restriction_int(&ptype->restrictions->maxExclusive);
2764 		}
2765 		if (ptype->restrictions->minInclusive) {
2766 			make_persistent_restriction_int(&ptype->restrictions->minInclusive);
2767 		}
2768 		if (ptype->restrictions->maxInclusive) {
2769 			make_persistent_restriction_int(&ptype->restrictions->maxInclusive);
2770 		}
2771 		if (ptype->restrictions->totalDigits) {
2772 			make_persistent_restriction_int(&ptype->restrictions->totalDigits);
2773 		}
2774 		if (ptype->restrictions->fractionDigits) {
2775 			make_persistent_restriction_int(&ptype->restrictions->fractionDigits);
2776 		}
2777 		if (ptype->restrictions->length) {
2778 			make_persistent_restriction_int(&ptype->restrictions->length);
2779 		}
2780 		if (ptype->restrictions->minLength) {
2781 			make_persistent_restriction_int(&ptype->restrictions->minLength);
2782 		}
2783 		if (ptype->restrictions->maxLength) {
2784 			make_persistent_restriction_int(&ptype->restrictions->maxLength);
2785 		}
2786 		if (ptype->restrictions->whiteSpace) {
2787 			make_persistent_restriction_char_int(&ptype->restrictions->whiteSpace);
2788 		}
2789 		if (ptype->restrictions->pattern) {
2790 			make_persistent_restriction_char_int(&ptype->restrictions->pattern);
2791 		}
2792 
2793 		if (type->restrictions->enumeration) {
2794 			sdlRestrictionCharPtr tmp, penum;
2795 			ptype->restrictions->enumeration = malloc(sizeof(HashTable));
2796 			zend_hash_init(ptype->restrictions->enumeration, zend_hash_num_elements(type->restrictions->enumeration), NULL, delete_restriction_var_char_persistent, 1);
2797 			ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(type->restrictions->enumeration, key, tmp) {
2798 				penum = tmp;
2799 				make_persistent_restriction_char_int(&penum);
2800 				/* We have to duplicate key emalloc->malloc */
2801 				zend_hash_str_add_ptr(ptype->restrictions->enumeration, ZSTR_VAL(key), ZSTR_LEN(key), penum);
2802 			} ZEND_HASH_FOREACH_END();
2803 		}
2804 	}
2805 
2806 	if (ptype->elements) {
2807 		sdlTypePtr tmp, pelem;
2808 
2809 		ptype->elements = malloc(sizeof(HashTable));
2810 		zend_hash_init(ptype->elements, zend_hash_num_elements(type->elements), NULL, delete_type_persistent, 1);
2811 
2812 		ZEND_HASH_FOREACH_STR_KEY_PTR(type->elements, key, tmp) {
2813 			pelem = make_persistent_sdl_type(tmp, ptr_map, bp_types, bp_encoders);
2814 			if (key) {
2815 				/* We have to duplicate key emalloc->malloc */
2816 				zend_hash_str_add_ptr(ptype->elements, ZSTR_VAL(key), ZSTR_LEN(key), pelem);
2817 			} else {
2818 				zend_hash_next_index_insert_ptr(ptype->elements, pelem);
2819 			}
2820 			zend_hash_str_add_ptr(ptr_map, (char*)&tmp, sizeof(tmp), pelem);
2821 		} ZEND_HASH_FOREACH_END();
2822 	}
2823 
2824 	if (ptype->attributes) {
2825 		sdlAttributePtr tmp, pattr;
2826 
2827 		ptype->attributes = malloc(sizeof(HashTable));
2828 		zend_hash_init(ptype->attributes, zend_hash_num_elements(type->attributes), NULL, delete_attribute_persistent, 1);
2829 
2830 		ZEND_HASH_FOREACH_STR_KEY_PTR(type->attributes, key, tmp) {
2831 			pattr = make_persistent_sdl_attribute(tmp, ptr_map, bp_types, bp_encoders);
2832 			if (key) {
2833 				/* We have to duplicate key emalloc->malloc */
2834 				zend_hash_str_add_ptr(ptype->attributes, ZSTR_VAL(key), ZSTR_LEN(key), pattr);
2835 			} else {
2836 				zend_hash_next_index_insert_ptr(ptype->attributes, pattr);
2837 			}
2838 		} ZEND_HASH_FOREACH_END();
2839 	}
2840 
2841 	if (type->model) {
2842 		ptype->model = make_persistent_sdl_model(ptype->model, ptr_map, bp_types, bp_encoders);
2843 	}
2844 
2845 	return ptype;
2846 }
2847 
make_persistent_sdl_encoder(encodePtr enc,HashTable * ptr_map,HashTable * bp_types,HashTable * bp_encoders)2848 static encodePtr make_persistent_sdl_encoder(encodePtr enc, HashTable *ptr_map, HashTable *bp_types, HashTable *bp_encoders)
2849 {
2850 	encodePtr penc = NULL;
2851 
2852 	penc = malloc(sizeof(encode));
2853 	memset(penc, 0, sizeof(encode));
2854 
2855 	*penc = *enc;
2856 
2857 	if (penc->details.type_str) {
2858 		penc->details.type_str = strdup(penc->details.type_str);
2859 	}
2860 	if (penc->details.ns) {
2861 		penc->details.ns = strdup(penc->details.ns);
2862 		penc->details.clark_notation = zend_string_dup(penc->details.clark_notation, 1);
2863 	}
2864 
2865 	if (penc->details.sdl_type) {
2866 		make_persistent_sdl_type_ref(&penc->details.sdl_type, ptr_map, bp_types);
2867 	}
2868 
2869 	return penc;
2870 }
2871 
make_persistent_sdl_binding(sdlBindingPtr bind,HashTable * ptr_map)2872 static sdlBindingPtr make_persistent_sdl_binding(sdlBindingPtr bind, HashTable *ptr_map)
2873 {
2874 	sdlBindingPtr pbind = NULL;
2875 
2876 	pbind = malloc(sizeof(sdlBinding));
2877 	memset(pbind, 0, sizeof(sdlBinding));
2878 
2879 	*pbind = *bind;
2880 
2881 	if (pbind->name) {
2882 		pbind->name = strdup(pbind->name);
2883 	}
2884 	if (pbind->location) {
2885 		pbind->location = strdup(pbind->location);
2886 	}
2887 
2888 	if (pbind->bindingType == BINDING_SOAP && pbind->bindingAttributes) {
2889 		sdlSoapBindingPtr soap_binding;
2890 
2891 		soap_binding = malloc(sizeof(sdlSoapBinding));
2892 		memset(soap_binding, 0, sizeof(sdlSoapBinding));
2893 		*soap_binding = *(sdlSoapBindingPtr)pbind->bindingAttributes;
2894 		pbind->bindingAttributes = soap_binding;
2895 	}
2896 
2897 	return pbind;
2898 }
2899 
make_persistent_sdl_function(sdlFunctionPtr func,HashTable * ptr_map)2900 static sdlFunctionPtr make_persistent_sdl_function(sdlFunctionPtr func, HashTable *ptr_map)
2901 {
2902 	sdlFunctionPtr pfunc = NULL;
2903 
2904 	pfunc = malloc(sizeof(sdlFunction));
2905 	memset(pfunc, 0, sizeof(sdlFunction));
2906 
2907 	*pfunc = *func;
2908 
2909 	if (pfunc->functionName) {
2910 		pfunc->functionName = strdup(pfunc->functionName);
2911 	}
2912 	if (pfunc->requestName) {
2913 		pfunc->requestName = strdup(pfunc->requestName);
2914 	}
2915 	if (pfunc->responseName) {
2916 		pfunc->responseName = strdup(pfunc->responseName);
2917 	}
2918 
2919 	if (pfunc->binding) {
2920 		sdlBindingPtr tmp;
2921 
2922 		if ((tmp = zend_hash_str_find_ptr(ptr_map, (char*)&pfunc->binding, sizeof(pfunc->binding))) == NULL) {
2923 			assert(0);
2924 		}
2925 		pfunc->binding = tmp;
2926 
2927 		if (pfunc->binding->bindingType == BINDING_SOAP && pfunc->bindingAttributes) {
2928 			sdlSoapBindingFunctionPtr soap_binding;
2929 
2930 		   	soap_binding = malloc(sizeof(sdlSoapBindingFunction));
2931 			memset(soap_binding, 0, sizeof(sdlSoapBindingFunction));
2932 			*soap_binding = *(sdlSoapBindingFunctionPtr)pfunc->bindingAttributes;
2933 			if (soap_binding->soapAction) {
2934 				soap_binding->soapAction = strdup(soap_binding->soapAction);
2935 			}
2936 			make_persistent_sdl_soap_body(&soap_binding->input, ptr_map);
2937 			make_persistent_sdl_soap_body(&soap_binding->output, ptr_map);
2938 			pfunc->bindingAttributes = soap_binding;
2939 		}
2940 
2941 		if (pfunc->requestParameters) {
2942 			pfunc->requestParameters = make_persistent_sdl_parameters(pfunc->requestParameters, ptr_map);
2943 		}
2944 		if (pfunc->responseParameters) {
2945 			pfunc->responseParameters = make_persistent_sdl_parameters(pfunc->responseParameters, ptr_map);
2946 		}
2947 		if (pfunc->faults) {
2948 			pfunc->faults = make_persistent_sdl_function_faults(pfunc, pfunc->faults, ptr_map);
2949 		}
2950 	}
2951 
2952 	return pfunc;
2953 }
2954 
make_persistent_sdl(sdlPtr sdl)2955 static sdlPtr make_persistent_sdl(sdlPtr sdl)
2956 {
2957 	sdlPtr psdl = NULL;
2958 	HashTable ptr_map;
2959 	HashTable bp_types, bp_encoders;
2960 	zend_string *key;
2961 
2962 	zend_hash_init(&bp_types, 0, NULL, NULL, 0);
2963 	zend_hash_init(&bp_encoders, 0, NULL, NULL, 0);
2964 	zend_hash_init(&ptr_map, 0, NULL, NULL, 0);
2965 
2966 	psdl = malloc(sizeof(*sdl));
2967 	memset(psdl, 0, sizeof(*sdl));
2968 
2969 	if (sdl->source) {
2970 		psdl->source = strdup(sdl->source);
2971 	}
2972 	if (sdl->target_ns) {
2973 		psdl->target_ns = strdup(sdl->target_ns);
2974 	}
2975 
2976 	if (sdl->groups) {
2977 		sdlTypePtr tmp;
2978 		sdlTypePtr ptype;
2979 
2980 		psdl->groups = malloc(sizeof(HashTable));
2981 		zend_hash_init(psdl->groups, zend_hash_num_elements(sdl->groups), NULL, delete_type_persistent, 1);
2982 
2983 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
2984 			ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
2985 			if (key) {
2986 				/* We have to duplicate key emalloc->malloc */
2987 				zend_hash_str_add_ptr(psdl->groups, ZSTR_VAL(key), ZSTR_LEN(key), ptype);
2988 			} else {
2989 				zend_hash_next_index_insert_ptr(psdl->groups, ptype);
2990 			}
2991 			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), ptype);
2992 		} ZEND_HASH_FOREACH_END();
2993 	}
2994 
2995 	if (sdl->types) {
2996 		sdlTypePtr tmp;
2997 		sdlTypePtr ptype;
2998 
2999 		psdl->types = malloc(sizeof(HashTable));
3000 		zend_hash_init(psdl->types, zend_hash_num_elements(sdl->types), NULL, delete_type_persistent, 1);
3001 
3002 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->types, key, tmp) {
3003 			ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
3004 			if (key) {
3005 				/* We have to duplicate key emalloc->malloc */
3006 				zend_hash_str_add_ptr(psdl->types, ZSTR_VAL(key), ZSTR_LEN(key), ptype);
3007 			} else {
3008 				zend_hash_next_index_insert_ptr(psdl->types, ptype);
3009 			}
3010 			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), ptype);
3011 		} ZEND_HASH_FOREACH_END();
3012 	}
3013 
3014 	if (sdl->elements) {
3015 		sdlTypePtr tmp;
3016 		sdlTypePtr ptype;
3017 
3018 		psdl->elements = malloc(sizeof(HashTable));
3019 		zend_hash_init(psdl->elements, zend_hash_num_elements(sdl->elements), NULL, delete_type_persistent, 1);
3020 
3021 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
3022 			ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
3023 			if (key) {
3024 				/* We have to duplicate key emalloc->malloc */
3025 				zend_hash_str_add_ptr(psdl->elements, ZSTR_VAL(key), ZSTR_LEN(key), ptype);
3026 			} else {
3027 				zend_hash_next_index_insert_ptr(psdl->elements, ptype);
3028 			}
3029 			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), ptype);
3030 		} ZEND_HASH_FOREACH_END();
3031 	}
3032 
3033 	if (sdl->encoders) {
3034 		encodePtr tmp;
3035 		encodePtr penc;
3036 
3037 		psdl->encoders = malloc(sizeof(HashTable));
3038 		zend_hash_init(psdl->encoders, zend_hash_num_elements(sdl->encoders), NULL, delete_encoder_persistent, 1);
3039 
3040 		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->encoders, key, tmp) {
3041 			penc = make_persistent_sdl_encoder(tmp, &ptr_map, &bp_types, &bp_encoders);
3042 			if (key) {
3043 				/* We have to duplicate key emalloc->malloc */
3044 				zend_hash_str_add_ptr(psdl->encoders, ZSTR_VAL(key), ZSTR_LEN(key), penc);
3045 			} else {
3046 				zend_hash_next_index_insert_ptr(psdl->encoders, penc);
3047 			}
3048 			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), penc);
3049 		} ZEND_HASH_FOREACH_END();
3050 	}
3051 
3052 	/* do backpatching here */
3053 	if (zend_hash_num_elements(&bp_types)) {
3054 		sdlTypePtr *tmp, ptype = NULL;
3055 
3056 		ZEND_HASH_FOREACH_PTR(&bp_types, tmp) {
3057 			if ((ptype = zend_hash_str_find_ptr(&ptr_map, (char*)tmp, sizeof(*tmp))) == NULL) {
3058 				assert(0);
3059 			}
3060 			*tmp = ptype;
3061 		} ZEND_HASH_FOREACH_END();
3062 	}
3063 	if (zend_hash_num_elements(&bp_encoders)) {
3064 		encodePtr *tmp, penc = NULL;
3065 
3066 		ZEND_HASH_FOREACH_PTR(&bp_encoders, tmp) {
3067 			if ((penc = zend_hash_str_find_ptr(&ptr_map, (char*)tmp, sizeof(*tmp))) == NULL) {
3068 				assert(0);
3069 			}
3070 			*tmp = penc;
3071 		} ZEND_HASH_FOREACH_END();
3072 	}
3073 
3074 
3075 	if (sdl->bindings) {
3076 		sdlBindingPtr tmp;
3077 		sdlBindingPtr pbind;
3078 
3079 		psdl->bindings = malloc(sizeof(HashTable));
3080 		zend_hash_init(psdl->bindings, zend_hash_num_elements(sdl->bindings), NULL, delete_binding_persistent, 1);
3081 
3082 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
3083 			pbind = make_persistent_sdl_binding(tmp, &ptr_map);
3084 			if (key) {
3085 				/* We have to duplicate key emalloc->malloc */
3086 				zend_hash_str_add_ptr(psdl->bindings, ZSTR_VAL(key), ZSTR_LEN(key), pbind);
3087 			} else {
3088 				zend_hash_next_index_insert_ptr(psdl->bindings, pbind);
3089 			}
3090 			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), pbind);
3091 		} ZEND_HASH_FOREACH_END();
3092 	}
3093 
3094 	zend_hash_init(&psdl->functions, zend_hash_num_elements(&sdl->functions), NULL, delete_function_persistent, 1);
3095 	if (zend_hash_num_elements(&sdl->functions)) {
3096 		sdlFunctionPtr tmp;
3097 		sdlFunctionPtr pfunc;
3098 
3099 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
3100 			pfunc = make_persistent_sdl_function(tmp, &ptr_map);
3101 			if (key) {
3102 				/* We have to duplicate key emalloc->malloc */
3103 				zend_hash_str_add_ptr(&psdl->functions, ZSTR_VAL(key), ZSTR_LEN(key), pfunc);
3104 			} else {
3105 				zend_hash_next_index_insert_ptr(&psdl->functions, pfunc);
3106 			}
3107 			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), pfunc);
3108 		} ZEND_HASH_FOREACH_END();
3109 	}
3110 
3111 	if (sdl->requests) {
3112 		zval *zv;
3113 		sdlFunctionPtr tmp;
3114 		sdlFunctionPtr preq;
3115 
3116 		psdl->requests = malloc(sizeof(HashTable));
3117 		zend_hash_init(psdl->requests, zend_hash_num_elements(sdl->requests), NULL, NULL, 1);
3118 
3119 		ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(sdl->requests, key, zv) {
3120 			tmp = Z_PTR_P(zv);
3121 			if ((preq = zend_hash_str_find_ptr(&ptr_map, (char*)&tmp, sizeof(tmp))) == NULL) {
3122 				assert(0);
3123 			}
3124 			Z_PTR_P(zv) = preq;
3125 			if (key) {
3126 				/* We have to duplicate key emalloc->malloc */
3127 				zend_hash_str_add_ptr(psdl->requests, ZSTR_VAL(key), ZSTR_LEN(key), preq);
3128 			}
3129 		} ZEND_HASH_FOREACH_END();
3130 	}
3131 
3132 	zend_hash_destroy(&ptr_map);
3133 	zend_hash_destroy(&bp_encoders);
3134 	zend_hash_destroy(&bp_types);
3135 
3136 	return psdl;
3137 }
3138 
3139 typedef struct _sdl_cache_bucket {
3140 	sdlPtr sdl;
3141 	time_t time;
3142 } sdl_cache_bucket;
3143 
delete_psdl_int(sdl_cache_bucket * p)3144 static void delete_psdl_int(sdl_cache_bucket *p)
3145 {
3146 	sdlPtr tmp = p->sdl;
3147 
3148 	zend_hash_destroy(&tmp->functions);
3149 	if (tmp->source) {
3150 		free(tmp->source);
3151 	}
3152 	if (tmp->target_ns) {
3153 		free(tmp->target_ns);
3154 	}
3155 	if (tmp->elements) {
3156 		zend_hash_destroy(tmp->elements);
3157 		free(tmp->elements);
3158 	}
3159 	if (tmp->encoders) {
3160 		zend_hash_destroy(tmp->encoders);
3161 		free(tmp->encoders);
3162 	}
3163 	if (tmp->types) {
3164 		zend_hash_destroy(tmp->types);
3165 		free(tmp->types);
3166 	}
3167 	if (tmp->groups) {
3168 		zend_hash_destroy(tmp->groups);
3169 		free(tmp->groups);
3170 	}
3171 	if (tmp->bindings) {
3172 		zend_hash_destroy(tmp->bindings);
3173 		free(tmp->bindings);
3174 	}
3175 	if (tmp->requests) {
3176 		zend_hash_destroy(tmp->requests);
3177 		free(tmp->requests);
3178 	}
3179 	free(tmp);
3180 }
3181 
delete_psdl(zval * zv)3182 static void delete_psdl(zval *zv)
3183 {
3184 	delete_psdl_int(Z_PTR_P(zv));
3185 	free(Z_PTR_P(zv));
3186 }
3187 
get_sdl(zval * this_ptr,char * uri,zend_long cache_wsdl)3188 sdlPtr get_sdl(zval *this_ptr, char *uri, zend_long cache_wsdl)
3189 {
3190 	char  fn[MAXPATHLEN];
3191 	sdlPtr sdl = NULL;
3192 	char* old_error_code = SOAP_GLOBAL(error_code);
3193 	size_t uri_len = 0;
3194 	php_stream_context *context=NULL;
3195 	zval *tmp, orig_context, new_context;
3196 	smart_str headers = {0};
3197 	char* key = NULL;
3198 	time_t t = time(0);
3199 	bool has_proxy_authorization = 0;
3200 	bool has_authorization = 0;
3201 
3202 	ZVAL_UNDEF(&orig_context);
3203 	ZVAL_UNDEF(&new_context);
3204 	if (strchr(uri,':') != NULL || IS_ABSOLUTE_PATH(uri, uri_len)) {
3205 		uri_len = strlen(uri);
3206 	} else if (VCWD_REALPATH(uri, fn) == NULL) {
3207 		cache_wsdl = WSDL_CACHE_NONE;
3208 	} else {
3209 		uri = fn;
3210 		uri_len = strlen(uri);
3211 	}
3212 
3213 	if ((cache_wsdl & WSDL_CACHE_MEMORY) && SOAP_GLOBAL(mem_cache)) {
3214 		sdl_cache_bucket *p;
3215 
3216 		if (NULL != (p = zend_hash_str_find_ptr(SOAP_GLOBAL(mem_cache), uri, uri_len))) {
3217 			if (p->time < t - SOAP_GLOBAL(cache_ttl)) {
3218 				/* in-memory cache entry is expired */
3219 				zend_hash_str_del(&EG(persistent_list), uri, uri_len);
3220 			} else {
3221 				return p->sdl;
3222 			}
3223 		}
3224 	}
3225 
3226 	if ((cache_wsdl & WSDL_CACHE_DISK) && (uri_len < MAXPATHLEN)) {
3227 		time_t t = time(0);
3228 		char md5str[33];
3229 		PHP_MD5_CTX context;
3230 		unsigned char digest[16];
3231 		int len = strlen(SOAP_GLOBAL(cache_dir));
3232 		time_t cached;
3233 		char *user = php_get_current_user();
3234 		int user_len = user ? strlen(user) + 1 : 0;
3235 
3236 		md5str[0] = '\0';
3237 		PHP_MD5Init(&context);
3238 		PHP_MD5Update(&context, (unsigned char*)uri, uri_len);
3239 		PHP_MD5Final(digest, &context);
3240 		make_digest(md5str, digest);
3241 		key = emalloc(len+sizeof("/wsdl-")-1+user_len+2+sizeof(md5str));
3242 		memcpy(key,SOAP_GLOBAL(cache_dir),len);
3243 		memcpy(key+len,"/wsdl-",sizeof("/wsdl-")-1);
3244 		len += sizeof("/wsdl-")-1;
3245 		if (user_len) {
3246 			memcpy(key+len, user, user_len-1);
3247 			len += user_len-1;
3248 			key[len++] = '-';
3249 		}
3250 		if (WSDL_CACHE_VERSION <= 0x9f) {
3251 			key[len++] = (WSDL_CACHE_VERSION >> 8) + '0';
3252 		} else {
3253 			key[len++] = (WSDL_CACHE_VERSION >> 8) - 10 + 'a';
3254 		}
3255 		if ((WSDL_CACHE_VERSION & 0xf) <= 0x9) {
3256 			key[len++] = (WSDL_CACHE_VERSION & 0xf) + '0';
3257 		} else {
3258 			key[len++] = (WSDL_CACHE_VERSION & 0xf) - 10 + 'a';
3259 		}
3260 		memcpy(key+len,md5str,sizeof(md5str));
3261 
3262 		if ((sdl = get_sdl_from_cache(key, uri, uri_len, t-SOAP_GLOBAL(cache_ttl), &cached)) != NULL) {
3263 			t = cached;
3264 			efree(key);
3265 			goto cache_in_memory;
3266 		}
3267 	}
3268 
3269 	if (instanceof_function(Z_OBJCE_P(this_ptr), soap_class_entry)) {
3270 		tmp = Z_CLIENT_STREAM_CONTEXT_P(this_ptr);
3271 		if (Z_TYPE_P(tmp) == IS_RESOURCE) {
3272 			context = php_stream_context_from_zval(tmp, 0);
3273 			/* Share a reference with new_context down below.
3274 			 * For new contexts, the reference is only in new_context so that doesn't need extra refcounting. */
3275 			GC_ADDREF(context->res);
3276 		}
3277 
3278 		tmp = Z_CLIENT_USER_AGENT_P(this_ptr);
3279 		if (Z_TYPE_P(tmp) == IS_STRING && Z_STRLEN_P(tmp) > 0) {
3280 			smart_str_appends(&headers, "User-Agent: ");
3281 			smart_str_appends(&headers, Z_STRVAL_P(tmp));
3282 			smart_str_appends(&headers, "\r\n");
3283 		}
3284 
3285 		zval *proxy_host = Z_CLIENT_PROXY_HOST_P(this_ptr);
3286 		zval *proxy_port = Z_CLIENT_PROXY_PORT_P(this_ptr);
3287 		if (Z_TYPE_P(proxy_host) == IS_STRING && Z_TYPE_P(proxy_port) == IS_LONG) {
3288 			zval str_proxy;
3289 			smart_str proxy = {0};
3290 			smart_str_appends(&proxy,"tcp://");
3291 			smart_str_appends(&proxy,Z_STRVAL_P(proxy_host));
3292 			smart_str_appends(&proxy,":");
3293 			smart_str_append_long(&proxy,Z_LVAL_P(proxy_port));
3294 			ZVAL_STR(&str_proxy, smart_str_extract(&proxy));
3295 
3296 			if (!context) {
3297 				context = php_stream_context_alloc();
3298 			}
3299 			php_stream_context_set_option(context, "http", "proxy", &str_proxy);
3300 			zval_ptr_dtor(&str_proxy);
3301 
3302 			if (uri_len < sizeof("https://")-1 ||
3303 				strncasecmp(uri, "https://", sizeof("https://")-1) != 0) {
3304 				ZVAL_TRUE(&str_proxy);
3305 				php_stream_context_set_option(context, "http", "request_fulluri", &str_proxy);
3306 			}
3307 
3308 			has_proxy_authorization = proxy_authentication(this_ptr, &headers);
3309 		}
3310 
3311 		has_authorization = basic_authentication(this_ptr, &headers);
3312 	}
3313 
3314 	if (!context) {
3315 		context = php_stream_context_alloc();
3316 	}
3317 
3318 	/* Use HTTP/1.1 with "Connection: close" by default */
3319 	if ((tmp = php_stream_context_get_option(context, "http", "protocol_version")) == NULL) {
3320 		zval http_version;
3321 
3322 		ZVAL_DOUBLE(&http_version, 1.1);
3323 		php_stream_context_set_option(context, "http", "protocol_version", &http_version);
3324 		smart_str_appendl(&headers, "Connection: close\r\n", sizeof("Connection: close\r\n")-1);
3325 	}
3326 
3327 	if (headers.s && ZSTR_LEN(headers.s) > 0) {
3328 		zval str_headers;
3329 
3330 		if (!context) {
3331 			context = php_stream_context_alloc();
3332 		} else {
3333 			http_context_headers(context, has_authorization, has_proxy_authorization, 0, &headers);
3334 		}
3335 
3336 		ZVAL_STR(&str_headers, smart_str_extract(&headers));
3337 		php_stream_context_set_option(context, "http", "header", &str_headers);
3338 		zval_ptr_dtor(&str_headers);
3339 	}
3340 
3341 	if (context) {
3342 		ZVAL_RES(&new_context, context->res);
3343 		php_libxml_switch_context(&new_context, &orig_context);
3344 	}
3345 
3346 	SOAP_GLOBAL(error_code) = "WSDL";
3347 
3348 	sdl = load_wsdl(this_ptr, uri);
3349 	if (sdl) {
3350 		sdl->is_persistent = 0;
3351 	}
3352 
3353 	SOAP_GLOBAL(error_code) = old_error_code;
3354 
3355 	if (context) {
3356 		php_libxml_switch_context(&orig_context, NULL);
3357 		zval_ptr_dtor(&new_context);
3358 	}
3359 
3360 	if ((cache_wsdl & WSDL_CACHE_DISK) && key) {
3361 		if (sdl) {
3362 			add_sdl_to_cache(key, uri, t, sdl);
3363 		}
3364 		efree(key);
3365 	}
3366 
3367 cache_in_memory:
3368 	if (cache_wsdl & WSDL_CACHE_MEMORY) {
3369 		if (sdl) {
3370 			sdlPtr psdl;
3371 			sdl_cache_bucket p;
3372 
3373 			if (SOAP_GLOBAL(mem_cache) == NULL) {
3374 				SOAP_GLOBAL(mem_cache) = malloc(sizeof(HashTable));
3375 				zend_hash_init(SOAP_GLOBAL(mem_cache), 0, NULL, delete_psdl, 1);
3376 			} else if (SOAP_GLOBAL(cache_limit) > 0 &&
3377 			           SOAP_GLOBAL(cache_limit) <= (zend_long)zend_hash_num_elements(SOAP_GLOBAL(mem_cache))) {
3378 				/* in-memory cache overflow */
3379 				sdl_cache_bucket *q;
3380 				time_t latest = t;
3381 				zend_string *latest_key = NULL, *key;
3382 
3383 				ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(SOAP_GLOBAL(mem_cache), key, q) {
3384 					if (q->time < latest) {
3385 						latest = q->time;
3386 						latest_key = key;
3387 					}
3388 				} ZEND_HASH_FOREACH_END();
3389 				if (latest_key) {
3390 					zend_hash_del(SOAP_GLOBAL(mem_cache), latest_key);
3391 				} else {
3392 					return sdl;
3393 				}
3394 			}
3395 
3396 			psdl = make_persistent_sdl(sdl);
3397 			psdl->is_persistent = 1;
3398 			p.time = t;
3399 			p.sdl = psdl;
3400 
3401 			zend_hash_str_update_mem(SOAP_GLOBAL(mem_cache), uri,
3402 											uri_len, &p, sizeof(sdl_cache_bucket));
3403 			/* remove non-persitent sdl structure */
3404 			delete_sdl_impl(sdl);
3405 			/* and replace it with persistent one */
3406 			sdl = psdl;
3407 		}
3408 	}
3409 
3410 	return sdl;
3411 }
3412 
3413 /* Deletes */
delete_sdl_impl(void * handle)3414 void delete_sdl_impl(void *handle)
3415 {
3416 	sdlPtr tmp = (sdlPtr)handle;
3417 
3418 	zend_hash_destroy(&tmp->functions);
3419 	if (tmp->source) {
3420 		efree(tmp->source);
3421 	}
3422 	if (tmp->target_ns) {
3423 		efree(tmp->target_ns);
3424 	}
3425 	if (tmp->elements) {
3426 		zend_hash_destroy(tmp->elements);
3427 		efree(tmp->elements);
3428 	}
3429 	if (tmp->encoders) {
3430 		zend_hash_destroy(tmp->encoders);
3431 		efree(tmp->encoders);
3432 	}
3433 	if (tmp->types) {
3434 		zend_hash_destroy(tmp->types);
3435 		efree(tmp->types);
3436 	}
3437 	if (tmp->groups) {
3438 		zend_hash_destroy(tmp->groups);
3439 		efree(tmp->groups);
3440 	}
3441 	if (tmp->bindings) {
3442 		zend_hash_destroy(tmp->bindings);
3443 		efree(tmp->bindings);
3444 	}
3445 	if (tmp->requests) {
3446 		zend_hash_destroy(tmp->requests);
3447 		efree(tmp->requests);
3448 	}
3449 	efree(tmp);
3450 }
3451 
delete_sdl(void * handle)3452 void delete_sdl(void *handle)
3453 {
3454 	sdlPtr tmp = (sdlPtr)handle;
3455 
3456 	if (!tmp->is_persistent) {
3457 		delete_sdl_impl(tmp);
3458 	}
3459 }
3460 
delete_binding(zval * zv)3461 static void delete_binding(zval *zv)
3462 {
3463 	sdlBindingPtr binding = Z_PTR_P(zv);
3464 
3465 	if (binding->location) {
3466 		efree(binding->location);
3467 	}
3468 	if (binding->name) {
3469 		efree(binding->name);
3470 	}
3471 
3472 	if (binding->bindingType == BINDING_SOAP) {
3473 		sdlSoapBindingPtr soapBind = binding->bindingAttributes;
3474 		if (soapBind) {
3475 			efree(soapBind);
3476 		}
3477 	}
3478 	efree(binding);
3479 }
3480 
delete_binding_persistent(zval * zv)3481 static void delete_binding_persistent(zval *zv)
3482 {
3483 	sdlBindingPtr binding = Z_PTR_P(zv);
3484 
3485 	if (binding->location) {
3486 		free(binding->location);
3487 	}
3488 	if (binding->name) {
3489 		free(binding->name);
3490 	}
3491 
3492 	if (binding->bindingType == BINDING_SOAP) {
3493 		sdlSoapBindingPtr soapBind = binding->bindingAttributes;
3494 		if (soapBind) {
3495 			free(soapBind);
3496 		}
3497 	}
3498 	free(binding);
3499 }
3500 
delete_sdl_soap_binding_function_body(sdlSoapBindingFunctionBody body)3501 static void delete_sdl_soap_binding_function_body(sdlSoapBindingFunctionBody body)
3502 {
3503 	if (body.ns) {
3504 		efree(body.ns);
3505 	}
3506 	if (body.headers) {
3507 		zend_hash_destroy(body.headers);
3508 		efree(body.headers);
3509 	}
3510 }
3511 
delete_sdl_soap_binding_function_body_persistent(sdlSoapBindingFunctionBody body)3512 static void delete_sdl_soap_binding_function_body_persistent(sdlSoapBindingFunctionBody body)
3513 {
3514 	if (body.ns) {
3515 		free(body.ns);
3516 	}
3517 	if (body.headers) {
3518 		zend_hash_destroy(body.headers);
3519 		free(body.headers);
3520 	}
3521 }
3522 
delete_function(zval * zv)3523 static void delete_function(zval *zv)
3524 {
3525 	sdlFunctionPtr function = Z_PTR_P(zv);
3526 
3527 	if (function->functionName) {
3528 		efree(function->functionName);
3529 	}
3530 	if (function->requestName) {
3531 		efree(function->requestName);
3532 	}
3533 	if (function->responseName) {
3534 		efree(function->responseName);
3535 	}
3536 	if (function->requestParameters) {
3537 		zend_hash_destroy(function->requestParameters);
3538 		efree(function->requestParameters);
3539 	}
3540 	if (function->responseParameters) {
3541 		zend_hash_destroy(function->responseParameters);
3542 		efree(function->responseParameters);
3543 	}
3544 	if (function->faults) {
3545 		zend_hash_destroy(function->faults);
3546 		efree(function->faults);
3547 	}
3548 
3549 	if (function->bindingAttributes &&
3550 	    function->binding && function->binding->bindingType == BINDING_SOAP) {
3551 		sdlSoapBindingFunctionPtr soapFunction = function->bindingAttributes;
3552 		if (soapFunction->soapAction) {
3553 			efree(soapFunction->soapAction);
3554 		}
3555 		delete_sdl_soap_binding_function_body(soapFunction->input);
3556 		delete_sdl_soap_binding_function_body(soapFunction->output);
3557 		efree(soapFunction);
3558 	}
3559 	efree(function);
3560 }
3561 
delete_function_persistent(zval * zv)3562 static void delete_function_persistent(zval *zv)
3563 {
3564 	sdlFunctionPtr function = Z_PTR_P(zv);
3565 
3566 	if (function->functionName) {
3567 		free(function->functionName);
3568 	}
3569 	if (function->requestName) {
3570 		free(function->requestName);
3571 	}
3572 	if (function->responseName) {
3573 		free(function->responseName);
3574 	}
3575 	if (function->requestParameters) {
3576 		zend_hash_destroy(function->requestParameters);
3577 		free(function->requestParameters);
3578 	}
3579 	if (function->responseParameters) {
3580 		zend_hash_destroy(function->responseParameters);
3581 		free(function->responseParameters);
3582 	}
3583 	if (function->faults) {
3584 		zend_hash_destroy(function->faults);
3585 		free(function->faults);
3586 	}
3587 
3588 	if (function->bindingAttributes &&
3589 	    function->binding && function->binding->bindingType == BINDING_SOAP) {
3590 		sdlSoapBindingFunctionPtr soapFunction = function->bindingAttributes;
3591 		if (soapFunction->soapAction) {
3592 			free(soapFunction->soapAction);
3593 		}
3594 		delete_sdl_soap_binding_function_body_persistent(soapFunction->input);
3595 		delete_sdl_soap_binding_function_body_persistent(soapFunction->output);
3596 		free(soapFunction);
3597 	}
3598 	free(function);
3599 }
3600 
delete_parameter(zval * zv)3601 static void delete_parameter(zval *zv)
3602 {
3603 	sdlParamPtr param = Z_PTR_P(zv);
3604 	if (param->paramName) {
3605 		efree(param->paramName);
3606 	}
3607 	efree(param);
3608 }
3609 
delete_parameter_persistent(zval * zv)3610 static void delete_parameter_persistent(zval *zv)
3611 {
3612 	sdlParamPtr param = Z_PTR_P(zv);
3613 	if (param->paramName) {
3614 		free(param->paramName);
3615 	}
3616 	free(param);
3617 }
3618 
delete_header_int(sdlSoapBindingFunctionHeaderPtr hdr)3619 static void delete_header_int(sdlSoapBindingFunctionHeaderPtr hdr)
3620 {
3621 	if (hdr->name) {
3622 		efree(hdr->name);
3623 	}
3624 	if (hdr->ns) {
3625 		efree(hdr->ns);
3626 	}
3627 	if (hdr->headerfaults) {
3628 		zend_hash_destroy(hdr->headerfaults);
3629 		efree(hdr->headerfaults);
3630 	}
3631 	efree(hdr);
3632 }
3633 
delete_header(zval * zv)3634 static void delete_header(zval *zv)
3635 {
3636 	delete_header_int(Z_PTR_P(zv));
3637 }
3638 
delete_header_persistent(zval * zv)3639 static void delete_header_persistent(zval *zv)
3640 {
3641 	sdlSoapBindingFunctionHeaderPtr hdr = Z_PTR_P(zv);
3642 	if (hdr->name) {
3643 		free(hdr->name);
3644 	}
3645 	if (hdr->ns) {
3646 		free(hdr->ns);
3647 	}
3648 	if (hdr->headerfaults) {
3649 		zend_hash_destroy(hdr->headerfaults);
3650 		free(hdr->headerfaults);
3651 	}
3652 	free(hdr);
3653 }
3654 
delete_fault(zval * zv)3655 static void delete_fault(zval *zv)
3656 {
3657 	sdlFaultPtr fault = Z_PTR_P(zv);
3658 	if (fault->name) {
3659 		efree(fault->name);
3660 	}
3661 	if (fault->details) {
3662 		zend_hash_destroy(fault->details);
3663 		efree(fault->details);
3664 	}
3665 	if (fault->bindingAttributes) {
3666 		sdlSoapBindingFunctionFaultPtr binding = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
3667 
3668 		if (binding->ns) {
3669 			efree(binding->ns);
3670 		}
3671 		efree(fault->bindingAttributes);
3672 	}
3673 	efree(fault);
3674 }
3675 
delete_fault_persistent(zval * zv)3676 static void delete_fault_persistent(zval *zv)
3677 {
3678 	sdlFaultPtr fault = Z_PTR_P(zv);
3679 	if (fault->name) {
3680 		free(fault->name);
3681 	}
3682 	if (fault->details) {
3683 		zend_hash_destroy(fault->details);
3684 		free(fault->details);
3685 	}
3686 	if (fault->bindingAttributes) {
3687 		sdlSoapBindingFunctionFaultPtr binding = (sdlSoapBindingFunctionFaultPtr)fault->bindingAttributes;
3688 
3689 		if (binding->ns) {
3690 			free(binding->ns);
3691 		}
3692 		free(fault->bindingAttributes);
3693 	}
3694 	free(fault);
3695 }
3696 
delete_document(zval * zv)3697 static void delete_document(zval *zv)
3698 {
3699 	xmlDocPtr doc = Z_PTR_P(zv);
3700 	xmlFreeDoc(doc);
3701 }
3702