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