in hphp/runtime/ext/soap/ext_soap.cpp [1213:1557]
static xmlDocPtr serialize_response_call(
std::shared_ptr<sdlFunction> function,
const char *function_name,
const char *uri, Variant &ret,
const Array& headers, int version) {
xmlNodePtr envelope = nullptr, body, param;
xmlNsPtr ns = nullptr;
int use = SOAP_LITERAL;
xmlNodePtr head = nullptr;
encode_reset_ns();
xmlDocPtr doc = xmlNewDoc(BAD_CAST("1.0"));
doc->charset = XML_CHAR_ENCODING_UTF8;
doc->encoding = xmlCharStrdup("UTF-8");
if (version == SOAP_1_1) {
envelope = xmlNewDocNode(doc, nullptr, BAD_CAST("Envelope"), nullptr);
ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENV_NAMESPACE),
BAD_CAST(SOAP_1_1_ENV_NS_PREFIX));
xmlSetNs(envelope,ns);
} else if (version == SOAP_1_2) {
envelope = xmlNewDocNode(doc, nullptr, BAD_CAST("Envelope"), nullptr);
ns = xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENV_NAMESPACE),
BAD_CAST(SOAP_1_2_ENV_NS_PREFIX));
xmlSetNs(envelope,ns);
} else {
throw_soap_server_fault("Server", "Unknown SOAP version");
}
xmlDocSetRootElement(doc, envelope);
if (ret.isObject() &&
ret.toObject()->instanceof(SystemLib::s_SoapFaultClass)) {
ObjectData* obj = ret.getObjectData();
char *detail_name;
std::shared_ptr<sdlFault> fault;
string fault_ns;
if (!headers.empty()) {
encodePtr hdr_enc;
int hdr_use = SOAP_LITERAL;
Variant hdr_ret = obj->o_get("headerfault");
auto h = cast<soapHeader>(headers[0]);
const char *hdr_ns = h->hdr ? h->hdr->ns.c_str() : nullptr;
const char *hdr_name = h->function_name.data();
head = xmlNewChild(envelope, ns, BAD_CAST("Header"), nullptr);
if (hdr_ret.isObject() &&
hdr_ret.toObject().instanceof(SoapHeader::getClass())) {
const SoapHeader *ht = Native::data<SoapHeader>(hdr_ret.toObject());
string key;
if (!ht->m_namespace.empty()) {
key += ht->m_namespace.data();
key += ':';
hdr_ns = ht->m_namespace.data();
}
if (!ht->m_name.empty()) {
key += ht->m_name.data();
hdr_name = ht->m_name.data();
}
if (h->hdr) {
sdlSoapBindingFunctionHeaderMap::iterator iter =
h->hdr->headerfaults.find(key);
if (iter != h->hdr->headerfaults.end()) {
auto hdr = iter->second;
hdr_enc = hdr->encode;
hdr_use = hdr->use;
}
}
hdr_ret = ht->m_data;
obj->setProp(nullptr, s_headerfault.get(), *hdr_ret.asTypedValue());
}
if (h->function) {
if (serialize_response_call2(head, h->function,
h->function_name.data(), uri,
hdr_ret, version, 0) == SOAP_ENCODED) {
obj->setProp(nullptr, s_headerfault.get(), *hdr_ret.asTypedValue());
use = SOAP_ENCODED;
}
} else {
xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head);
if (hdr_name) {
xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
}
if (hdr_ns) {
xmlNsPtr nsptr = encode_add_ns(xmlHdr, hdr_ns);
xmlSetNs(xmlHdr, nsptr);
}
}
}
body = xmlNewChild(envelope, ns, BAD_CAST("Body"), nullptr);
param = xmlNewChild(body, ns, BAD_CAST("Fault"), nullptr);
fault_ns = obj->o_get("faultcodens").toString().data();
use = SOAP_LITERAL;
if (!obj->o_get("_name").toString().empty()) {
if (function) {
sdlFaultMap::iterator iter =
function->faults.find(obj->o_get("_name").toString().data());
if (iter != function->faults.end()) {
fault = iter->second;
if (function->binding &&
function->binding->bindingType == BINDING_SOAP &&
fault->bindingAttributes) {
sdlSoapBindingFunctionFaultPtr fb = fault->bindingAttributes;
use = fb->use;
if (fault_ns.empty()) {
fault_ns = fb->ns;
}
}
}
}
} else if (function && function->faults.size() == 1) {
fault = function->faults[0];
if (function->binding &&
function->binding->bindingType == BINDING_SOAP &&
fault->bindingAttributes) {
sdlSoapBindingFunctionFaultPtr fb = fault->bindingAttributes;
use = fb->use;
if (fault_ns.empty()) {
fault_ns = fb->ns;
}
}
}
if (fault_ns.empty() && fault && fault->details.size() == 1) {
sdlParamPtr sparam = fault->details[0];
if (sparam->element) {
fault_ns = sparam->element->namens;
}
}
if (version == SOAP_1_1) {
if (!obj->o_get("faultcode").toString().empty()) {
xmlNodePtr node = xmlNewNode(nullptr, BAD_CAST("faultcode"));
String str = StringUtil::HtmlEncode(obj->o_get("faultcode").toString(),
StringUtil::QuoteStyle::Double,
"UTF-8", true, true);
xmlAddChild(param, node);
if (!fault_ns.empty()) {
xmlNsPtr nsptr = encode_add_ns(node, fault_ns.c_str());
xmlChar *code = xmlBuildQName(BAD_CAST(str.data()), nsptr->prefix,
nullptr, 0);
xmlNodeSetContent(node, code);
xmlFree(code);
} else {
xmlNodeSetContentLen(node, BAD_CAST(str.data()), str.size());
}
}
if (!obj->o_get("faultstring").toString().empty()) {
xmlNodePtr node = master_to_xml(
get_conversion(dataTypeToSoap(KindOfString)),
obj->o_get("faultstring"), SOAP_LITERAL,
param
);
xmlNodeSetName(node, BAD_CAST("faultstring"));
}
if (!obj->o_get("faultactor").toString().empty()) {
xmlNodePtr node = master_to_xml(
get_conversion(dataTypeToSoap(KindOfString)),
obj->o_get("faultactor"), SOAP_LITERAL,
param
);
xmlNodeSetName(node, BAD_CAST("faultactor"));
}
detail_name = "detail";
} else {
if (!obj->o_get("faultcode").toString().empty()) {
xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Code"), nullptr);
String str = StringUtil::HtmlEncode(obj->o_get("faultcode").toString(),
StringUtil::QuoteStyle::Double,
"UTF-8", true, true);
node = xmlNewChild(node, ns, BAD_CAST("Value"), nullptr);
if (!fault_ns.empty()) {
xmlNsPtr nsptr = encode_add_ns(node, fault_ns.c_str());
xmlChar *code = xmlBuildQName(BAD_CAST(str.data()), nsptr->prefix,
nullptr, 0);
xmlNodeSetContent(node, code);
xmlFree(code);
} else {
xmlNodeSetContentLen(node, BAD_CAST(str.data()), str.size());
}
}
if (!obj->o_get("faultstring").toString().empty()) {
xmlNodePtr node = xmlNewChild(param, ns, BAD_CAST("Reason"), nullptr);
node = master_to_xml(
get_conversion(dataTypeToSoap(KindOfString)),
obj->o_get("faultstring"),
SOAP_LITERAL, node
);
xmlNodeSetName(node, BAD_CAST("Text"));
xmlSetNs(node, ns);
}
detail_name = SOAP_1_2_ENV_NS_PREFIX":Detail";
}
if (fault && fault->details.size() == 1) {
xmlNodePtr node;
Variant detail;
sdlParamPtr sparam;
xmlNodePtr x;
if (!obj->o_get("detail").isNull()) {
detail = obj->o_get("detail");
}
node = xmlNewNode(nullptr, BAD_CAST(detail_name));
xmlAddChild(param, node);
sparam = fault->details[0];
if (detail.isObject() && sparam->element) {
Variant prop = detail.toObject()->o_get(sparam->element->name.c_str());
if (!prop.isNull()) {
detail = prop;
}
}
x = serialize_parameter(sparam, detail, 1, nullptr, use, node);
if (function &&
function->binding &&
function->binding->bindingType == BINDING_SOAP &&
function->bindingAttributes) {
sdlSoapBindingFunctionPtr fnb = function->bindingAttributes;
if (fnb->style == SOAP_RPC && !sparam->element) {
if (fault->bindingAttributes) {
sdlSoapBindingFunctionFaultPtr fb = fault->bindingAttributes;
if (!fb->ns.empty()) {
xmlNsPtr ns2 = encode_add_ns(x, fb->ns.c_str());
xmlSetNs(x, ns2);
}
}
} else {
if (sparam->element) {
xmlNsPtr ns2 = encode_add_ns(x, sparam->element->namens.c_str());
xmlNodeSetName(x, BAD_CAST(sparam->element->name.c_str()));
xmlSetNs(x, ns2);
}
}
}
if (use == SOAP_ENCODED && version == SOAP_1_2) {
xmlSetNsProp(x, envelope->ns, BAD_CAST("encodingStyle"),
BAD_CAST(SOAP_1_2_ENC_NAMESPACE));
}
} else if (!obj->o_get("detail").isNull()) {
serialize_zval(obj->o_get("detail"), sdlParamPtr(), detail_name, use, param);
}
} else {
if (!headers.empty()) {
head = xmlNewChild(envelope, ns, BAD_CAST("Header"), nullptr);
for (ArrayIter iter(headers); iter; ++iter) {
auto h = cast<soapHeader>(iter.second());
if (!h->retval.isNull()) {
encodePtr hdr_enc;
int hdr_use = SOAP_LITERAL;
Variant &hdr_ret = h->retval;
const char *hdr_ns = h->hdr ? h->hdr->ns.c_str() : nullptr;
const char *hdr_name = h->function_name.data();
if (h->retval.isObject() &&
h->retval.toObject().instanceof(SoapHeader::getClass())) {
const SoapHeader *ht = Native::data<SoapHeader>(
h->retval.toObject());
string key;
if (!ht->m_namespace.empty()) {
key += ht->m_namespace.data();
key += ':';
hdr_ns = ht->m_namespace.data();
}
if (!ht->m_name.empty()) {
key += ht->m_name.data();
hdr_name = ht->m_name.data();
}
if (function && function->binding &&
function->binding->bindingType == BINDING_SOAP) {
sdlSoapBindingFunctionPtr fnb = function->bindingAttributes;
sdlSoapBindingFunctionHeaderMap::iterator iter =
fnb->output.headers.find(key);
if (iter != fnb->output.headers.end()) {
hdr_enc = iter->second->encode;
hdr_use = iter->second->use;
}
}
hdr_ret = ht->m_data;
}
if (h->function) {
if (serialize_response_call2(head, h->function,
h->function_name.data(), uri, hdr_ret,
version, 0) == SOAP_ENCODED) {
use = SOAP_ENCODED;
}
} else {
xmlNodePtr xmlHdr = master_to_xml(hdr_enc, hdr_ret, hdr_use, head);
if (hdr_name) {
xmlNodeSetName(xmlHdr, BAD_CAST(hdr_name));
}
if (hdr_ns) {
xmlNsPtr nsptr = encode_add_ns(xmlHdr,hdr_ns);
xmlSetNs(xmlHdr, nsptr);
}
}
}
}
if (head->children == nullptr) {
xmlUnlinkNode(head);
xmlFreeNode(head);
}
}
body = xmlNewChild(envelope, ns, BAD_CAST("Body"), nullptr);
if (serialize_response_call2(body, function.get(), function_name, uri, ret,
version, 1) == SOAP_ENCODED) {
use = SOAP_ENCODED;
}
}
if (use == SOAP_ENCODED) {
xmlNewNs(envelope, BAD_CAST(XSD_NAMESPACE), BAD_CAST(XSD_NS_PREFIX));
if (version == SOAP_1_1) {
xmlNewNs(envelope, BAD_CAST(SOAP_1_1_ENC_NAMESPACE),
BAD_CAST(SOAP_1_1_ENC_NS_PREFIX));
xmlSetNsProp(envelope, envelope->ns, BAD_CAST("encodingStyle"),
BAD_CAST(SOAP_1_1_ENC_NAMESPACE));
} else if (version == SOAP_1_2) {
xmlNewNs(envelope, BAD_CAST(SOAP_1_2_ENC_NAMESPACE),
BAD_CAST(SOAP_1_2_ENC_NS_PREFIX));
}
}
encode_finish();
if (function && function->responseName.empty() &&
body->children == nullptr && head == nullptr) {
xmlFreeDoc(doc);
return nullptr;
}
return doc;
}