|
@@ -350,13 +350,22 @@ void EsdlServiceImpl::addMethodLevelRequestTransform(const char *method, IProper
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void ensureMergeOrderedPTree(Owned<IPropertyTree> &target, IPropertyTree *src)
|
|
|
+static void ensureMergeOrderedEsdlTransform(Owned<IPropertyTree> &dest, IPropertyTree *src)
|
|
|
{
|
|
|
if (!src)
|
|
|
return;
|
|
|
- if (!target)
|
|
|
- target.setown(createPTree(ipt_ordered));
|
|
|
- mergePTree(target, src);
|
|
|
+ if (!dest)
|
|
|
+ dest.setown(createPTree(ipt_ordered));
|
|
|
+ //copy so we can make changes, like adding calculated targets
|
|
|
+ Owned<IPropertyTree> copy = createPTreeFromIPT(src, ipt_ordered);
|
|
|
+ const char *target = copy->queryProp("@target");
|
|
|
+ if (target && *target)
|
|
|
+ {
|
|
|
+ Owned<IPropertyTreeIterator> children = copy->getElements("*");
|
|
|
+ ForEach(*children)
|
|
|
+ children->query().setProp("@_crtTarget", target); //internal use only attribute
|
|
|
+ }
|
|
|
+ mergePTree(dest, copy);
|
|
|
}
|
|
|
|
|
|
void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
|
|
@@ -370,10 +379,10 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
|
|
|
Owned<IPropertyTree> serviceCrt;
|
|
|
try
|
|
|
{
|
|
|
- ensureMergeOrderedPTree(serviceCrt, target_cfg->queryPropTree("xsdl:CustomRequestTransform"));
|
|
|
+ ensureMergeOrderedEsdlTransform(serviceCrt, target_cfg->queryPropTree("xsdl:CustomRequestTransform"));
|
|
|
Owned<IPropertyTreeIterator> transforms = target_cfg->getElements("Transforms/xsdl:CustomRequestTransform");
|
|
|
ForEach(*transforms)
|
|
|
- ensureMergeOrderedPTree(serviceCrt, &transforms->query());
|
|
|
+ ensureMergeOrderedEsdlTransform(serviceCrt, &transforms->query());
|
|
|
}
|
|
|
catch (IPTreeException *e)
|
|
|
{
|
|
@@ -416,10 +425,10 @@ void EsdlServiceImpl::configureTargets(IPropertyTree *cfg, const char *service)
|
|
|
Owned<IPropertyTree> methodCrt;
|
|
|
try
|
|
|
{
|
|
|
- ensureMergeOrderedPTree(methodCrt, methodCfg.queryPropTree("xsdl:CustomRequestTransform"));
|
|
|
+ ensureMergeOrderedEsdlTransform(methodCrt, methodCfg.queryPropTree("xsdl:CustomRequestTransform"));
|
|
|
Owned<IPropertyTreeIterator> transforms = methodCfg.getElements("Transforms/xsdl:CustomRequestTransform");
|
|
|
ForEach(*transforms)
|
|
|
- ensureMergeOrderedPTree(methodCrt, &transforms->query());
|
|
|
+ ensureMergeOrderedEsdlTransform(methodCrt, &transforms->query());
|
|
|
}
|
|
|
catch (IException *e)
|
|
|
{
|
|
@@ -843,7 +852,7 @@ void EsdlServiceImpl::handleFinalRequest(IEspContext &context,
|
|
|
if(isroxie)
|
|
|
{
|
|
|
const char *tgtQueryName = tgtcfg->queryProp("@queryname");
|
|
|
- if (tgtQueryName && *tgtQueryName)
|
|
|
+ if (!isEmptyString(tgtQueryName))
|
|
|
{
|
|
|
soapmsg.append("<soap:Body><").append(tgtQueryName).append(">");
|
|
|
soapmsg.appendf("<_TransactionId>%s</_TransactionId>", context.queryTransactionID());
|
|
@@ -853,6 +862,28 @@ void EsdlServiceImpl::handleFinalRequest(IEspContext &context,
|
|
|
|
|
|
soapmsg.append(req.str());
|
|
|
soapmsg.append("</").append(tgtQueryName).append("></soap:Body>");
|
|
|
+
|
|
|
+ auto cfgGateways = tgtcfg->queryBranch("Gateways");
|
|
|
+ if (cfgGateways)
|
|
|
+ {
|
|
|
+ auto baseXpath = cfgGateways->queryProp("@legacyTransformTarget");
|
|
|
+ if (!isEmptyString(baseXpath))
|
|
|
+ {
|
|
|
+ Owned<IPTree> gws = createPTree("gateways", 0);
|
|
|
+ Owned<IPTree> soapTree = createPTreeFromXMLString(soapmsg.append("</soap:Envelope>"), ipt_ordered);
|
|
|
+ StringBuffer xpath(baseXpath);
|
|
|
+
|
|
|
+ EsdlBindingImpl::transformGatewaysConfig(tgtcfg, gws, "row");
|
|
|
+ xpath.replaceString("{$query}", tgtQueryName);
|
|
|
+ xpath.replaceString("{$method}", mthdef.queryMethodName());
|
|
|
+ xpath.replaceString("{$service}", srvdef.queryName());
|
|
|
+ xpath.replaceString("{$request}", mthdef.queryRequestType());
|
|
|
+ mergePTree(ensurePTree(soapTree, xpath), gws);
|
|
|
+ toXML(soapTree, soapmsg.clear());
|
|
|
+ soapmsg.setLength(strstr(soapmsg, "</soap:Envelope>") - soapmsg.str());
|
|
|
+ soapmsg.trim();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
else
|
|
|
throw makeWsException( ERR_ESDL_BINDING_INTERNERR, WSERR_SERVER, "ESP",
|
|
@@ -871,7 +902,7 @@ void EsdlServiceImpl::handleFinalRequest(IEspContext &context,
|
|
|
soapmsg.append("</soap:Envelope>");
|
|
|
|
|
|
const char *tgtUrl = tgtcfg->queryProp("@url");
|
|
|
- if (tgtUrl && *tgtUrl)
|
|
|
+ if (!isEmptyString(tgtUrl))
|
|
|
{
|
|
|
if (crt)
|
|
|
{
|
|
@@ -889,6 +920,96 @@ void EsdlServiceImpl::handleFinalRequest(IEspContext &context,
|
|
|
"No target URL configured for %s!", mthdef.queryMethodName());
|
|
|
}
|
|
|
|
|
|
+ auto echoInsertionPoint = strstr(out, "</Result></Results>");
|
|
|
+
|
|
|
+ if (echoInsertionPoint)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ auto queryname = (isroxie ? tgtcfg->queryProp("@queryname") : nullptr);
|
|
|
+ auto requestname = mthdef.queryRequestType();
|
|
|
+ const char* qname = nullptr;
|
|
|
+ const char* content = nullptr;
|
|
|
+ StringBuffer encodedContent;
|
|
|
+ StringBuffer echoDataset;
|
|
|
+
|
|
|
+ XmlPullParser xpp(soapmsg.str(), soapmsg.length());
|
|
|
+ StartTag stag;
|
|
|
+ EndTag etag;
|
|
|
+ int type = XmlPullParser::END_DOCUMENT;
|
|
|
+
|
|
|
+ echoDataset.ensureCapacity(soapmsg.length());
|
|
|
+ xpp.setSupportNamespaces(false); // parser throws exceptions when it encounters undefined namespace prefixes, such as CRT's 'xsdl'
|
|
|
+ while ((type = xpp.next()) != XmlPullParser::END_DOCUMENT)
|
|
|
+ {
|
|
|
+ switch (type)
|
|
|
+ {
|
|
|
+ case XmlPullParser::START_TAG:
|
|
|
+ xpp.readStartTag(stag);
|
|
|
+ qname = stag.getQName();
|
|
|
+ if (streq(qname, "soap:Envelope"))
|
|
|
+ echoDataset << "<Dataset name=\"DesdlSoapRequestEcho\">";
|
|
|
+ else if (streq(qname, "soap:Body"))
|
|
|
+ echoDataset << "<Row>";
|
|
|
+ else if (queryname && streq(qname, queryname))
|
|
|
+ echoDataset << "<roxierequest name=\"" << queryname << "\">";
|
|
|
+ else if (streq(qname, requestname))
|
|
|
+ echoDataset << "<esprequest name=\"" << requestname << "\">";
|
|
|
+ else
|
|
|
+ {
|
|
|
+ echoDataset << '<';
|
|
|
+ if (strncmp(qname, "xsdl:", 5) == 0)
|
|
|
+ echoDataset << "xsdl_" << qname + 5; // eliminate problematic namespace prefix
|
|
|
+ else
|
|
|
+ echoDataset << qname;
|
|
|
+ for (int idx = 0; idx < stag.getLength(); idx++)
|
|
|
+ {
|
|
|
+ encodeXML(stag.getValue(idx), encodedContent.clear());
|
|
|
+ echoDataset << ' ' << stag.getRawName(idx) << "=\"" << encodedContent << '"';
|
|
|
+ }
|
|
|
+ echoDataset << '>';
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case XmlPullParser::END_TAG:
|
|
|
+ xpp.readEndTag(etag);
|
|
|
+ qname = etag.getQName();
|
|
|
+ if (streq(qname, "soap:Envelope"))
|
|
|
+ echoDataset << "</Dataset>";
|
|
|
+ else if (streq(qname, "soap:Body"))
|
|
|
+ echoDataset << "</Row>";
|
|
|
+ else if (queryname && streq(qname, queryname))
|
|
|
+ echoDataset << "</roxierequest>";
|
|
|
+ else if (streq(qname, requestname))
|
|
|
+ echoDataset << "</esprequest>";
|
|
|
+ else if (strncmp(qname, "xsdl:", 5) == 0)
|
|
|
+ echoDataset << "</xsdl_" << qname + 5 << '>'; // eliminate problematic namespace prefix
|
|
|
+ else
|
|
|
+ echoDataset << "</" << qname << '>';
|
|
|
+ break;
|
|
|
+
|
|
|
+ case XmlPullParser::CONTENT:
|
|
|
+ content = xpp.readContent();
|
|
|
+ if (!isEmptyString(content))
|
|
|
+ {
|
|
|
+ encodeXML(content, encodedContent.clear());
|
|
|
+ echoDataset << encodedContent;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ out.insert(echoInsertionPoint - out.str(), echoDataset);
|
|
|
+ }
|
|
|
+ catch (XmlPullParserException& xppe)
|
|
|
+ {
|
|
|
+ ERRLOG("Unable to echo transformed request to response: %s", xppe.what());
|
|
|
+ }
|
|
|
+ catch (...)
|
|
|
+ {
|
|
|
+ ERRLOG("Unable to echo transformed request to response");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
processResponse(context,srvdef,mthdef,ns,out);
|
|
|
}
|
|
|
|
|
@@ -1580,6 +1701,7 @@ int EsdlBindingImpl::onGetInstantQuery(IEspContext &context,
|
|
|
generateNamespace(context, request, srvdef->queryName(), mthdef->queryName(), ns);
|
|
|
|
|
|
getSchemaLocation(context, request, schemaLocation);
|
|
|
+ context.setESDLBindingID(m_bindingId.get());
|
|
|
m_pESDLService->handleServiceRequest(context, *srvdef, *mthdef, tgtcfg, tgtctx, ns.str(), schemaLocation.str(), req_pt.get(), out, logdata, 0);
|
|
|
|
|
|
response->setContent(out.str());
|
|
@@ -1881,8 +2003,8 @@ int EsdlBindingImpl::HandleSoapRequest(CHttpRequest* request,
|
|
|
generateNamespace(*ctx, request, srvdef->queryName(), mthdef->queryName(), ns);
|
|
|
getSchemaLocation(*ctx, request, schemaLocation);
|
|
|
|
|
|
- m_pESDLService->handleServiceRequest(*ctx, *srvdef, *mthdef, tgtcfg, tgtctx, ns.str(),
|
|
|
- schemaLocation.str(), pt, baseout, logdata, 0);
|
|
|
+ ctx->setESDLBindingID(m_bindingId.get());
|
|
|
+ m_pESDLService->handleServiceRequest(*ctx, *srvdef, *mthdef, tgtcfg, tgtctx, ns.str(), schemaLocation.str(), pt, baseout, logdata, 0);
|
|
|
|
|
|
StringBuffer out;
|
|
|
out.append(
|
|
@@ -2602,6 +2724,7 @@ void EsdlBindingImpl::handleJSONPost(CHttpRequest *request, CHttpResponse *respo
|
|
|
generateNamespace(*ctx, request, serviceName, methodName, ns);
|
|
|
getSchemaLocation(*ctx, request, schemaLocation);
|
|
|
|
|
|
+ ctx->setESDLBindingID(m_bindingId.get());
|
|
|
m_pESDLService->handleServiceRequest(*ctx, *srvdef, *mthdef, tgtcfg, tgtctx, ns.str(), schemaLocation.str(), reqTree.get(), jsonresp, logdata, ESDL_BINDING_RESPONSE_JSON);
|
|
|
|
|
|
jsonresp.append("}");
|
|
@@ -3119,7 +3242,7 @@ int EsdlBindingImpl::onGetSampleXml(bool isRequest, IEspContext &ctx, CHttpReque
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-void EsdlBindingImpl::transformGatewaysConfig( IPropertyTree* srvcfg, IPropertyTree* forRoxie )
|
|
|
+void EsdlBindingImpl::transformGatewaysConfig( IPropertyTree* srvcfg, IPropertyTree* forRoxie, const char* altElementName )
|
|
|
{
|
|
|
// Do we need to handle 'local FQDN'? It doesn't appear to be in the
|
|
|
// Gateway element. Not sure where it's set but the RemoteNSClient
|
|
@@ -3131,6 +3254,8 @@ void EsdlBindingImpl::transformGatewaysConfig( IPropertyTree* srvcfg, IPropertyT
|
|
|
cfgIter->first();
|
|
|
if( cfgIter->isValid() )
|
|
|
{
|
|
|
+ const char* treeName = (!isEmptyString(altElementName) ? altElementName : "Gateway");
|
|
|
+
|
|
|
while( cfgIter->isValid() )
|
|
|
{
|
|
|
IPropertyTree& cfgGateway = cfgIter->query();
|
|
@@ -3141,11 +3266,11 @@ void EsdlBindingImpl::transformGatewaysConfig( IPropertyTree* srvcfg, IPropertyT
|
|
|
cfgGateway.getProp("@name", service);
|
|
|
service.toLowerCase();
|
|
|
|
|
|
- Owned<IPropertyTree> gw = createPTree("Gateway", false);
|
|
|
+ Owned<IPropertyTree> gw = createPTree(treeName, false);
|
|
|
gw->addProp("ServiceName", service.str());
|
|
|
gw->addProp("URL", url.str());
|
|
|
|
|
|
- forRoxie->addPropTree("Gateway", gw.getLink());
|
|
|
+ forRoxie->addPropTree(treeName, gw.getLink());
|
|
|
}
|
|
|
else
|
|
|
{
|