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