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