in hphp/runtime/ext/soap/sdl.cpp [573:1005]
sdlPtr load_wsdl(char *struri, HttpClient *http) {
sdlCtx ctx;
ctx.sdl = std::make_shared<sdl>();
ctx.sdl->source = struri;
load_wsdl_ex(struri, &ctx, false, http);
schema_pass2(&ctx);
int i = 0;
for (auto servicesIter = ctx.services.begin();
servicesIter != ctx.services.end(); ++servicesIter, ++i) {
xmlNodePtr service = servicesIter->second;
xmlNodePtr port;
bool has_soap_port = false;
xmlNodePtr trav = service->children;
while (trav) {
if (!is_wsdl_element(trav) || node_is_equal(trav,"documentation")) {
trav = trav->next;
continue;
}
if (!node_is_equal(trav,"port")) {
throw SoapException("Parsing WSDL: Unexpected WSDL element <%s>",
trav->name);
}
port = trav;
auto tmpbinding = std::make_shared<sdlBinding>();
xmlAttrPtr bindingAttr = get_attribute(port->properties, "binding");
if (bindingAttr == nullptr) {
throw SoapException("Parsing WSDL: No binding associated with <port>");
}
char *wsdl_soap_namespace = nullptr;
/* find address and figure out binding type */
xmlNodePtr address = nullptr;
xmlNodePtr trav2 = port->children;
while (trav2) {
if (node_is_equal(trav2,"address") && trav2->ns) {
if (!strncmp((char*)trav2->ns->href, WSDL_SOAP11_NAMESPACE,
sizeof(WSDL_SOAP11_NAMESPACE))) {
address = trav2;
wsdl_soap_namespace = WSDL_SOAP11_NAMESPACE;
tmpbinding->bindingType = BINDING_SOAP;
} else if (!strncmp((char*)trav2->ns->href, WSDL_SOAP12_NAMESPACE,
sizeof(WSDL_SOAP12_NAMESPACE))) {
address = trav2;
wsdl_soap_namespace = WSDL_SOAP12_NAMESPACE;
tmpbinding->bindingType = BINDING_SOAP;
} else if (!strncmp((char*)trav2->ns->href, RPC_SOAP12_NAMESPACE,
sizeof(RPC_SOAP12_NAMESPACE))) {
address = trav2;
wsdl_soap_namespace = RPC_SOAP12_NAMESPACE;
tmpbinding->bindingType = BINDING_SOAP;
} else if (!strncmp((char*)trav2->ns->href, WSDL_HTTP11_NAMESPACE,
sizeof(WSDL_HTTP11_NAMESPACE))) {
address = trav2;
tmpbinding->bindingType = BINDING_HTTP;
} else if (!strncmp((char*)trav2->ns->href, WSDL_HTTP12_NAMESPACE,
sizeof(WSDL_HTTP12_NAMESPACE))) {
address = trav2;
tmpbinding->bindingType = BINDING_HTTP;
}
}
if (trav2 != address && is_wsdl_element(trav2) &&
!node_is_equal(trav2,"documentation")) {
throw SoapException("Parsing WSDL: Unexpected WSDL element <%s>",
trav2->name);
}
trav2 = trav2->next;
}
if (!address || tmpbinding->bindingType == BINDING_HTTP) {
if (has_soap_port || trav->next || i < (int)ctx.services.size() - 1) {
trav = trav->next;
continue;
} else if (!address) {
throw SoapException("Parsing WSDL: No address associated "
"with <port>");
}
}
has_soap_port = true;
xmlAttrPtr location = get_attribute(address->properties, "location");
if (!location) {
throw SoapException("Parsing WSDL: No location associated "
"with <port>");
}
tmpbinding->location = (char*)location->children->content;
char *ctype = strrchr((char*)bindingAttr->children->content,':');
if (ctype == nullptr) {
ctype = (char*)bindingAttr->children->content;
} else {
++ctype;
}
xmlNodeMap::iterator iterBinding = ctx.bindings.find(ctype);
if (iterBinding == ctx.bindings.end()) {
throw SoapException("Parsing WSDL: No <binding> element "
"with name '%s'", ctype);
}
xmlNodePtr binding = iterBinding->second;
if (tmpbinding->bindingType == BINDING_SOAP) {
xmlAttrPtr tmp;
auto soapBinding = std::make_shared<sdlSoapBinding>();
soapBinding->style = SOAP_DOCUMENT;
xmlNodePtr soapBindingNode = get_node_ex(binding->children, "binding",
wsdl_soap_namespace);
if (soapBindingNode) {
tmp = get_attribute(soapBindingNode->properties, "style");
if (tmp &&
!strncmp((char*)tmp->children->content, "rpc", sizeof("rpc"))) {
soapBinding->style = SOAP_RPC;
}
tmp = get_attribute(soapBindingNode->properties, "transport");
if (tmp) {
if (strncmp((char*)tmp->children->content, WSDL_HTTP_TRANSPORT,
sizeof(WSDL_HTTP_TRANSPORT)) == 0) {
soapBinding->transport = SOAP_TRANSPORT_HTTP;
} else {
throw SoapException("Parsing WSDL: PHP-SOAP doesn't support "
"transport '%s'", tmp->children->content);
}
}
}
tmpbinding->bindingAttributes = soapBinding;
}
xmlAttrPtr name = get_attribute(binding->properties, "name");
if (name == nullptr) {
throw SoapException("Parsing WSDL: Missing 'name' attribute "
"for <binding>");
}
tmpbinding->name = (char*)name->children->content;
xmlAttrPtr type = get_attribute(binding->properties, "type");
if (type == nullptr) {
throw SoapException("Parsing WSDL: Missing 'type' attribute "
"for <binding>");
}
xmlNodePtr portType, operation;
ctype = strrchr((char*)type->children->content,':');
if (ctype == nullptr) {
ctype = (char*)type->children->content;
} else {
++ctype;
}
xmlNodeMap::iterator iter = ctx.portTypes.find(ctype);
if (iter == ctx.portTypes.end()) {
throw SoapException("Parsing WSDL: Missing <portType> with name '%s'",
name->children->content);
}
portType = iter->second;
trav2 = binding->children;
while (trav2) {
if ((tmpbinding->bindingType == BINDING_SOAP &&
node_is_equal_ex(trav2, "binding", wsdl_soap_namespace)) ||
!is_wsdl_element(trav2) ||
node_is_equal(trav2,"documentation")) {
trav2 = trav2->next;
continue;
}
if (!node_is_equal(trav2,"operation")) {
throw SoapException("Parsing WSDL: Unexpected WSDL element <%s>",
trav2->name);
}
operation = trav2;
xmlAttrPtr op_name = get_attribute(operation->properties, "name");
if (op_name == nullptr) {
throw SoapException("Parsing WSDL: Missing 'name' attribute "
"for <operation>");
}
xmlNodePtr trav3 = operation->children;
while (trav3) {
if (tmpbinding->bindingType == BINDING_SOAP &&
node_is_equal_ex(trav3, "operation", wsdl_soap_namespace)) {
} else if (is_wsdl_element(trav3) &&
!node_is_equal(trav3,"input") &&
!node_is_equal(trav3,"output") &&
!node_is_equal(trav3,"fault") &&
!node_is_equal(trav3,"documentation")) {
throw SoapException("Parsing WSDL: Unexpected WSDL element <%s>",
trav3->name);
}
trav3 = trav3->next;
}
xmlNodePtr portTypeOperation =
get_node_with_attribute_ex(portType->children, "operation",
WSDL_NAMESPACE, "name",
(char*)op_name->children->content, nullptr);
if (portTypeOperation == nullptr) {
throw SoapException("Parsing WSDL: Missing <portType>/<operation> "
"with name '%s'", op_name->children->content);
}
xmlNodePtr input, output, fault;
xmlAttrPtr paramOrder;
auto function = std::make_shared<sdlFunction>();
function->functionName = (char*)op_name->children->content;
if (tmpbinding->bindingType == BINDING_SOAP) {
auto soapFunctionBinding = std::make_shared<sdlSoapBindingFunction>();
sdlSoapBindingPtr soapBinding = tmpbinding->bindingAttributes;
soapFunctionBinding->style = soapBinding->style;
xmlNodePtr soapOperation = get_node_ex
(operation->children, "operation", wsdl_soap_namespace);
xmlAttrPtr tmp;
if (soapOperation) {
tmp = get_attribute(soapOperation->properties, "soapAction");
if (tmp) {
soapFunctionBinding->soapAction = (char*)tmp->children->content;
}
tmp = get_attribute(soapOperation->properties, "style");
if (tmp) {
if (!strncmp((char*)tmp->children->content, "rpc",
sizeof("rpc"))) {
soapFunctionBinding->style = SOAP_RPC;
} else {
soapFunctionBinding->style = SOAP_DOCUMENT;
}
} else {
soapFunctionBinding->style = soapBinding->style;
}
}
function->bindingAttributes = soapFunctionBinding;
}
input = get_node_ex(portTypeOperation->children, "input",
WSDL_NAMESPACE);
if (input) {
xmlAttrPtr message = get_attribute(input->properties, "message");
if (message == nullptr) {
throw SoapException("Parsing WSDL: Missing name for <input> "
"of '%s'", op_name->children->content);
}
wsdl_message(&ctx, function->requestParameters,
message->children->content);
/* FIXME
xmlAttrPtr name = get_attribute(input->properties, "name");
if (name) {
function->requestName = estrdup(name->children->content);
} else {
*/
{
function->requestName = function->functionName;
}
if (tmpbinding->bindingType == BINDING_SOAP) {
input = get_node_ex(operation->children, "input", WSDL_NAMESPACE);
if (input) {
sdlSoapBindingFunctionPtr soapFunctionBinding =
function->bindingAttributes;
wsdl_soap_binding_body(&ctx, input, wsdl_soap_namespace,
&soapFunctionBinding->input,
function->requestParameters);
}
}
}
output = get_node_ex(portTypeOperation->children, "output",
WSDL_NAMESPACE);
if (output) {
xmlAttrPtr message = get_attribute(output->properties, "message");
if (message == nullptr) {
throw SoapException("Parsing WSDL: Missing name for <output> "
"of '%s'", op_name->children->content);
}
wsdl_message(&ctx, function->responseParameters,
message->children->content);
/* FIXME
xmlAttrPtr name = get_attribute(output->properties, "name");
if (name) {
function->responseName = estrdup(name->children->content);
} else if (input == nullptr) {
function->responseName = estrdup(function->functionName);
} else {
*/
{
function->responseName = function->functionName + "Response";
}
if (tmpbinding->bindingType == BINDING_SOAP) {
output = get_node_ex(operation->children, "output",
WSDL_NAMESPACE);
if (output) {
sdlSoapBindingFunctionPtr soapFunctionBinding =
function->bindingAttributes;
wsdl_soap_binding_body(&ctx, output, wsdl_soap_namespace,
&soapFunctionBinding->output,
function->responseParameters);
}
}
}
paramOrder = get_attribute(portTypeOperation->properties,
"parameterOrder");
if (paramOrder) {
/* FIXME: */
}
fault = portTypeOperation->children;
while (fault) {
if (node_is_equal_ex(fault, "fault", WSDL_NAMESPACE)) {
xmlAttrPtr propName = get_attribute(fault->properties, "name");
if (propName == nullptr) {
throw SoapException("Parsing WSDL: Missing name for <fault> "
"of '%s'", op_name->children->content);
}
xmlAttrPtr message = get_attribute(fault->properties, "message");
if (message == nullptr) {
throw SoapException("Parsing WSDL: Missing name for <output> "
"of '%s'", op_name->children->content);
}
auto f = std::make_shared<sdlFault>();
f->name = (char*)propName->children->content;
wsdl_message(&ctx, f->details, message->children->content);
if (f->details.size() != 1) {
throw SoapException("Parsing WSDL: The fault message '%s' must "
"have a single part",
message->children->content);
}
if (tmpbinding->bindingType == BINDING_SOAP) {
xmlNodePtr soap_fault =
get_node_with_attribute_ex(operation->children, "fault",
WSDL_NAMESPACE, "name",
(char*)f->name.c_str(), nullptr);
if (soap_fault) {
xmlNodePtr childTrav = soap_fault->children;
while (childTrav) {
if (node_is_equal_ex(
childTrav, "fault", wsdl_soap_namespace)) {
auto binding = f->bindingAttributes =
std::make_shared<sdlSoapBindingFunctionFault>();
xmlAttrPtr tmp = get_attribute(childTrav->properties, "use");
if (tmp && !strncmp((char*)tmp->children->content,
"encoded", sizeof("encoded"))) {
binding->use = SOAP_ENCODED;
} else {
binding->use = SOAP_LITERAL;
}
tmp = get_attribute(childTrav->properties, "namespace");
if (tmp) {
binding->ns = (char*)tmp->children->content;
}
if (binding->use == SOAP_ENCODED) {
tmp = get_attribute(childTrav->properties,
"encodingStyle");
if (tmp) {
if (strncmp((char*)tmp->children->content,
SOAP_1_1_ENC_NAMESPACE,
sizeof(SOAP_1_1_ENC_NAMESPACE)) == 0) {
binding->encodingStyle = SOAP_ENCODING_1_1;
} else if (strncmp((char*)tmp->children->content,
SOAP_1_2_ENC_NAMESPACE,
sizeof(SOAP_1_2_ENC_NAMESPACE))
== 0) {
binding->encodingStyle = SOAP_ENCODING_1_2;
} else {
throw SoapException("Parsing WSDL: Unknown "
"encodingStyle '%s'",
tmp->children->content);
}
} else {
throw SoapException("Parsing WSDL: Unspecified "
"encodingStyle");
}
}
} else if (is_wsdl_element(childTrav) &&
!node_is_equal(childTrav,"documentation")) {
throw SoapException("Parsing WSDL: Unexpected WSDL "
"element <%s>", childTrav->name);
}
childTrav = childTrav->next;
}
}
}
sdlFaultMap::iterator iter = function->faults.find(f->name);
if (iter != function->faults.end()) {
throw SoapException("Parsing WSDL: <fault> with name '%s' "
"already defined in '%s'", f->name.c_str(),
op_name->children->content);
}
function->faults[f->name] = f;
}
fault = fault->next;
}
function->binding = tmpbinding;
{
std::string tmp = toLower(function->functionName);
sdlFunctionMap::iterator iter = ctx.sdl->functions.find(tmp);
if (iter != ctx.sdl->functions.end()) {
ctx.sdl->functions[folly::to<std::string>
(ctx.sdl->functions.size())] = function;
} else {
ctx.sdl->functions[tmp] = function;
}
ctx.sdl->functionsOrder.push_back(tmp);
if (function->requestName != function->functionName) {
ctx.sdl->requests[toLower(function->requestName)] = function;
}
}
trav2 = trav2->next;
}
ctx.sdl->bindings[tmpbinding->name] = tmpbinding;
trav= trav->next;
}
}
if (i == 0) {
throw SoapException("Parsing WSDL: Couldn't bind to service");
}
return ctx.sdl;
}