/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.wsdl.support.soap;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.mock.DispatchException;
import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
import com.eviware.soapui.model.iface.Attachment;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.types.StringToStringsMap;
import com.eviware.soapui.support.xml.XmlUtils;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.wsdl.BindingOperation;
import javax.wsdl.Message;
import javax.wsdl.Part;
import javax.xml.namespace.QName;
import java.util.List;
/**
* SOAP-related utility-methods..
*
* @author ole.matzura
*/
public class SoapUtils {
public static boolean isSoapFault(String responseContent, SoapVersion soapVersion) throws XmlException {
if (StringUtils.isNullOrEmpty(responseContent)) {
return false;
}
// check manually before resource intensive xpath
if (responseContent.indexOf(":Fault") > 0 || responseContent.indexOf("<Fault") > 0) {
// XmlObject xml = XmlObject.Factory.parse( responseContent );
XmlObject xml = XmlUtils.createXmlObject(responseContent);
XmlObject[] paths = xml.selectPath("declare namespace env='" + soapVersion.getEnvelopeNamespace() + "';"
+ "//env:Fault");
if (paths.length > 0) {
return true;
}
}
return false;
}
public static boolean isSoapFault(String responseContent) throws XmlException {
return isSoapFault(responseContent, SoapVersion.Soap12) || isSoapFault(responseContent, SoapVersion.Soap11);
}
/**
* Init soapversion from content-type header.. should envelope be checked
* and/or override?
*
* @param xmlObject
*/
public static SoapVersion deduceSoapVersion(String contentType, XmlObject xmlObject) {
if (xmlObject != null) {
Element elm = ((Document) (xmlObject.getDomNode())).getDocumentElement();
if (elm.getLocalName().equals("Envelope")) {
if (elm.getNamespaceURI().equals(SoapVersion.Soap11.getEnvelopeNamespace())) {
return SoapVersion.Soap11;
} else if (elm.getNamespaceURI().equals(SoapVersion.Soap12.getEnvelopeNamespace())) {
return SoapVersion.Soap12;
}
}
}
SoapVersion soapVersion = null;
if (StringUtils.isNullOrEmpty(contentType)) {
return null;
}
soapVersion = contentType.startsWith(SoapVersion.Soap11.getContentType()) ? SoapVersion.Soap11 : null;
soapVersion = soapVersion == null && contentType.startsWith(SoapVersion.Soap12.getContentType()) ? SoapVersion.Soap12
: soapVersion;
if (soapVersion == null && contentType.startsWith("application/xop+xml")) {
if (contentType.indexOf("type=\"" + SoapVersion.Soap11.getContentType() + "\"") > 0) {
soapVersion = SoapVersion.Soap11;
} else if (contentType.indexOf("type=\"" + SoapVersion.Soap12.getContentType() + "\"") > 0) {
soapVersion = SoapVersion.Soap12;
}
}
return soapVersion;
}
public static String getSoapAction(SoapVersion soapVersion, StringToStringsMap headers) {
String soapAction = null;
String contentType = headers.get("Content-Type", "");
if (soapVersion == SoapVersion.Soap11) {
soapAction = headers.get("SOAPAction", "");
} else if (soapVersion == SoapVersion.Soap12) {
int ix = contentType.indexOf("action=");
if (ix > 0) {
int endIx = contentType.indexOf(';', ix);
soapAction = endIx == -1 ? contentType.substring(ix + 7) : contentType.substring(ix + 7, endIx);
}
}
soapAction = StringUtils.unquote(soapAction);
return soapAction;
}
public static XmlObject getBodyElement(XmlObject messageObject, SoapVersion soapVersion) throws XmlException {
XmlObject[] envelope = messageObject.selectChildren(soapVersion.getEnvelopeQName());
if (envelope.length != 1) {
throw new XmlException("Missing/Invalid SOAP Envelope, expecting [" + soapVersion.getEnvelopeQName() + "]");
}
XmlObject[] body = envelope[0].selectChildren(soapVersion.getBodyQName());
if (body.length != 1) {
throw new XmlException("Missing/Invalid SOAP Body, expecting [" + soapVersion.getBodyQName() + "]");
}
return body[0];
}
public static XmlObject getHeaderElement(XmlObject messageObject, SoapVersion soapVersion, boolean create)
throws XmlException {
XmlObject[] envelope = messageObject.selectChildren(soapVersion.getEnvelopeQName());
if (envelope.length != 1) {
throw new XmlException("Missing/Invalid SOAP Envelope, expecting [" + soapVersion.getEnvelopeQName() + "]");
}
QName headerQName = soapVersion.getHeaderQName();
XmlObject[] header = envelope[0].selectChildren(headerQName);
if (header.length == 0 && create) {
Element elm = (Element) envelope[0].getDomNode();
Element headerElement = elm.getOwnerDocument().createElementNS(headerQName.getNamespaceURI(),
headerQName.getLocalPart());
elm.insertBefore(headerElement, elm.getFirstChild());
header = envelope[0].selectChildren(headerQName);
}
return header.length == 0 ? null : header[0];
}
public static XmlObject getContentElement(XmlObject messageObject, SoapVersion soapVersion) throws XmlException {
if (messageObject == null) {
return null;
}
XmlObject bodyElement = SoapUtils.getBodyElement(messageObject, soapVersion);
if (bodyElement != null) {
XmlCursor cursor = bodyElement.newCursor();
try {
if (cursor.toFirstChild()) {
while (!cursor.isContainer()) {
cursor.toNextSibling();
}
if (cursor.isContainer()) {
return cursor.getObject();
}
}
} catch (Exception e) {
SoapUI.logError(e);
} finally {
cursor.dispose();
}
}
return null;
}
@SuppressWarnings("unchecked")
public static WsdlOperation findOperationForRequest(SoapVersion soapVersion, String soapAction,
XmlObject requestContent, List<WsdlOperation> operations, boolean requireSoapVersionMatch,
boolean requireSoapActionMatch, Attachment[] attachments) throws Exception {
XmlObject contentElm = getContentElement(requestContent, soapVersion);
if (contentElm == null) {
for (WsdlOperation operation : operations) {
if (operation.getAction().equals(soapAction)
&& operation.getBindingOperation().getOperation().getInput().getMessage().getParts().size() == 0) {
return operation;
}
}
return null;
}
QName contentQName = XmlUtils.getQName(contentElm.getDomNode());
NodeList contentChildNodes = null;
for (int c = 0; c < operations.size(); c++) {
WsdlOperation wsdlOperation = operations.get(c);
String action = wsdlOperation.getAction();
// matches soapAction?
if (!requireSoapActionMatch
|| ((soapAction == null && wsdlOperation.getAction() == null) || (action != null && action
.equals(soapAction)))) {
QName qname = wsdlOperation.getRequestBodyElementQName();
if (!contentQName.equals(qname)) {
continue;
}
SoapVersion ifaceSoapVersion = wsdlOperation.getInterface().getSoapVersion();
if (requireSoapVersionMatch && ifaceSoapVersion != soapVersion) {
continue;
}
// check content
if (wsdlOperation.getStyle().equals(WsdlOperation.STYLE_DOCUMENT)) {
// check that all attachments match
BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
Message message = bindingOperation.getOperation().getInput().getMessage();
List<Part> parts = message.getOrderedParts(null);
for (int x = 0; x < parts.size(); x++) {
// check for attachment part
if (WsdlUtils.isAttachmentInputPart(parts.get(x), bindingOperation)) {
for (Attachment attachment : attachments) {
if (attachment.getPart().equals(parts.get(x).getName())) {
parts.remove(x);
x--;
}
}
} else {
parts.remove(x);
x--;
}
}
// matches!
if (parts.isEmpty()) {
return wsdlOperation;
}
} else if (wsdlOperation.getStyle().equals(WsdlOperation.STYLE_RPC)) {
BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
Message message = bindingOperation.getOperation().getInput().getMessage();
List<Part> parts = message.getOrderedParts(null);
if (contentChildNodes == null) {
contentChildNodes = XmlUtils.getChildElements((Element) contentElm.getDomNode());
}
int i = 0;
if (parts.size() > 0) {
for (int x = 0; x < parts.size(); x++) {
if (WsdlUtils.isAttachmentInputPart(parts.get(x), bindingOperation)) {
for (Attachment attachment : attachments) {
if (attachment.getPart().equals(parts.get(x).getName())) {
parts.remove(x);
x--;
}
}
}
// ignore header parts for now..
if (x >= 0 && WsdlUtils.isHeaderInputPart(parts.get(x), message, bindingOperation)) {
parts.remove(x);
x--;
}
}
for (; i < contentChildNodes.getLength() && !parts.isEmpty(); i++) {
Node item = contentChildNodes.item(i);
if (item.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
int j = 0;
while ((j < parts.size()) && (!item.getNodeName().equals(parts.get(j).getName()))) {
Part part = parts.get(j);
if (part.getElementName() != null) {
QName qn = part.getElementName();
if (item.getLocalName().equals(qn.getLocalPart())
&& item.getNamespaceURI().equals(qn.getNamespaceURI())) {
break;
}
} else {
if (item.getNodeName().equals(parts.get(j).getName())) {
break;
}
}
j++;
}
if (j == parts.size()) {
break;
}
parts.remove(j);
}
}
// match?
if (i == contentChildNodes.getLength() && parts.isEmpty()) {
return wsdlOperation;
}
}
}
}
throw new DispatchException("Missing operation for soapAction [" + soapAction + "] and body element ["
+ contentQName + "] with SOAP Version [" + soapVersion + "]");
}
@SuppressWarnings("unchecked")
public static WsdlOperation findOperationForResponse(SoapVersion soapVersion, String soapAction,
XmlObject responseContent, List<WsdlOperation> operations, boolean requireSoapVersionMatch,
boolean requireSoapActionMatch) throws Exception {
XmlObject contentElm = getContentElement(responseContent, soapVersion);
if (contentElm == null) {
return null;
}
QName contentQName = XmlUtils.getQName(contentElm.getDomNode());
NodeList contentChildNodes = null;
for (int c = 0; c < operations.size(); c++) {
WsdlOperation wsdlOperation = operations.get(c);
String action = wsdlOperation.getAction();
// matches soapAction?
if (!requireSoapActionMatch
|| ((soapAction == null && wsdlOperation.getAction() == null) || (action != null && action
.equals(soapAction)))) {
QName qname = wsdlOperation.getResponseBodyElementQName();
if (!contentQName.equals(qname)) {
continue;
}
SoapVersion ifaceSoapVersion = wsdlOperation.getInterface().getSoapVersion();
if (requireSoapVersionMatch && ifaceSoapVersion != soapVersion) {
continue;
}
// check content
if (wsdlOperation.getStyle().equals(WsdlOperation.STYLE_DOCUMENT)) {
// matches!
return wsdlOperation;
} else if (wsdlOperation.getStyle().equals(WsdlOperation.STYLE_RPC)) {
BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
Message message = bindingOperation.getOperation().getOutput().getMessage();
List<Part> parts = message.getOrderedParts(null);
if (contentChildNodes == null) {
contentChildNodes = XmlUtils.getChildElements((Element) contentElm.getDomNode());
}
int i = 0;
if (parts.size() > 0) {
for (int x = 0; x < parts.size(); x++) {
if (WsdlUtils.isAttachmentOutputPart(parts.get(x), bindingOperation)
|| WsdlUtils.isHeaderOutputPart(parts.get(x), message, bindingOperation)) {
parts.remove(x);
x--;
}
}
for (; i < contentChildNodes.getLength() && !parts.isEmpty(); i++) {
Node item = contentChildNodes.item(i);
if (item.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
int j = 0;
while ((j < parts.size()) && (!item.getNodeName().equals(parts.get(j).getName()))) {
Part part = parts.get(j);
if (part.getElementName() != null) {
QName qn = part.getElementName();
if (item.getLocalName().equals(qn.getLocalPart())
&& item.getNamespaceURI().equals(qn.getNamespaceURI())) {
break;
}
} else {
if (item.getNodeName().equals(parts.get(j).getName())) {
break;
}
}
j++;
}
if (j == parts.size()) {
break;
}
parts.remove(j);
}
}
// match?
if (i == contentChildNodes.getLength() && parts.isEmpty()) {
return wsdlOperation;
}
}
}
}
throw new DispatchException("Missing response operation for soapAction [" + soapAction + "] and body element ["
+ contentQName + "] with SOAP Version [" + soapVersion + "]");
}
public static String removeEmptySoapHeaders(String content, SoapVersion soapVersion) throws XmlException {
// XmlObject xmlObject = XmlObject.Factory.parse( content );
XmlObject xmlObject = XmlUtils.createXmlObject(content);
XmlObject[] selectPath = xmlObject.selectPath("declare namespace soap='" + soapVersion.getEnvelopeNamespace()
+ "';/soap:Envelope/soap:Header");
if (selectPath.length > 0) {
Node domNode = selectPath[0].getDomNode();
if (!domNode.hasChildNodes() && !domNode.hasAttributes()) {
domNode.getParentNode().removeChild(domNode);
return xmlObject.xmlText();
}
}
return content;
}
public static SoapVersion deduceSoapVersion(String requestContentType, String requestContent) {
try {
// return deduceSoapVersion( requestContentType,
// XmlObject.Factory.parse( requestContent ) );
return deduceSoapVersion(requestContentType, XmlUtils.createXmlObject(requestContent));
} catch (XmlException e) {
return deduceSoapVersion(requestContentType, (XmlObject) null);
}
}
public static String transferSoapHeaders(String requestContent, String newRequest, SoapVersion soapVersion) {
try {
// XmlObject source = XmlObject.Factory.parse( requestContent );
XmlObject source = XmlUtils.createXmlObject(requestContent);
String headerXPath = "declare namespace ns='" + soapVersion.getEnvelopeNamespace() + "'; //ns:Header";
XmlObject[] header = source.selectPath(headerXPath);
if (header.length == 1) {
Element headerElm = (Element) header[0].getDomNode();
NodeList childNodes = headerElm.getChildNodes();
if (childNodes.getLength() > 0) {
// XmlObject dest = XmlObject.Factory.parse( newRequest );
XmlObject dest = XmlUtils.createXmlObject(newRequest);
header = dest.selectPath(headerXPath);
Element destElm = null;
if (header.length == 0) {
Element docElm = ((Document) dest.getDomNode()).getDocumentElement();
destElm = (Element) docElm.insertBefore(
docElm.getOwnerDocument().createElementNS(soapVersion.getEnvelopeNamespace(),
docElm.getPrefix() + ":Header"),
XmlUtils.getFirstChildElementNS(docElm, soapVersion.getBodyQName()));
} else {
destElm = (Element) header[0].getDomNode();
}
for (int c = 0; c < childNodes.getLength(); c++) {
Node childNode = childNodes.item(c);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
if (XmlUtils.getFirstChildElementNS(destElm, childNode.getNamespaceURI(),
childNode.getLocalName()) != null) {
continue;
}
destElm.appendChild(destElm.getOwnerDocument().importNode(childNode, true));
}
}
return dest.xmlText();
}
}
} catch (XmlException e) {
SoapUI.logError(e);
}
return newRequest;
}
}