/* * Copyright 2004-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * XSEC * * XSECSOAPRequestorSimple := (Very) Basic implementation of a SOAP * HTTP wrapper for testing the client code. * * * $Id: XSECSOAPRequestorSimple.cpp 450286 2006-09-27 01:47:51Z blautenb $ * */ #include "XSECSOAPRequestorSimple.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include XERCES_CPP_NAMESPACE_USE // -------------------------------------------------------------------------------- // Strings for constructing SOAP envelopes // -------------------------------------------------------------------------------- static XMLCh s_prefix[] = { chLatin_e, chLatin_n, chLatin_v, chNull }; static XMLCh s_Envelope[] = { chLatin_E, chLatin_n, chLatin_v, chLatin_e, chLatin_l, chLatin_o, chLatin_p, chLatin_e, chNull }; static XMLCh s_Body[] = { chLatin_B, chLatin_o, chLatin_d, chLatin_y, chNull }; // -------------------------------------------------------------------------------- // Constructors and Destructors // -------------------------------------------------------------------------------- /* NOTE: This is initialised via the platform specific code */ XSECSOAPRequestorSimple::~XSECSOAPRequestorSimple() { } // -------------------------------------------------------------------------------- // Wrap and serialise the request message // -------------------------------------------------------------------------------- char * XSECSOAPRequestorSimple::wrapAndSerialise(DOMDocument * request) { // Prepare the serialiser XMLCh tempStr[100]; XMLString::transcode("Core", tempStr, 99); DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr); #if defined (XSEC_XERCES_DOMLSSERIALIZER) // DOM L3 version as per Xerces 3.0 API DOMLSSerializer *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer(); Janitor j_theSerializer(theSerializer); // Get the config so we can set up pretty printing DOMConfiguration *dc = theSerializer->getDomConfig(); dc->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, false); // Now create an output object to format to UTF-8 DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput(); Janitor j_theOutput(theOutput); MemBufFormatTarget *formatTarget = new MemBufFormatTarget; Janitor j_formatTarget(formatTarget); theOutput->setEncoding(MAKE_UNICODE_STRING("UTF-8")); theOutput->setByteStream(formatTarget); #else DOMWriter *theSerializer = ((DOMImplementationLS*)impl)->createDOMWriter(); Janitor j_theSerializer(theSerializer); theSerializer->setEncoding(MAKE_UNICODE_STRING("UTF-8")); if (theSerializer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, false)) theSerializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, false); MemBufFormatTarget *formatTarget = new MemBufFormatTarget; Janitor j_formatTarget(formatTarget); #endif if (m_envelopeType != ENVELOPE_NONE) { // Create a new document to wrap the request in safeBuffer str; makeQName(str, s_prefix, s_Envelope); DOMDocument *doc; if (m_envelopeType == ENVELOPE_SOAP11) { doc = impl->createDocument( XKMSConstants::s_unicodeStrURISOAP11, str.rawXMLChBuffer(), NULL); DOMElement *rootElem = doc->getDocumentElement(); makeQName(str, s_prefix, s_Body); DOMElement *body = doc->createElementNS( XKMSConstants::s_unicodeStrURISOAP11, str.rawXMLChBuffer()); rootElem->appendChild(body); // Now replicate the request into the document DOMElement * reqElement = (DOMElement *) doc->importNode(request->getDocumentElement(), true); body->appendChild(reqElement); } else { doc = impl->createDocument( XKMSConstants::s_unicodeStrURISOAP12, str.rawXMLChBuffer(), NULL); DOMElement *rootElem = doc->getDocumentElement(); makeQName(str, s_prefix, s_Body); DOMElement *body = doc->createElementNS( XKMSConstants::s_unicodeStrURISOAP12, str.rawXMLChBuffer()); rootElem->appendChild(body); // Now replicate the request into the document DOMElement * reqElement = (DOMElement *) doc->importNode(request->getDocumentElement(), true); body->appendChild(reqElement); } // OK - Now we have the SOAP request as a document, we serialise to a string buffer // and return #if defined (XSEC_XERCES_DOMLSSERIALIZER) theSerializer->write(doc, theOutput); #else theSerializer->writeNode(formatTarget, *doc); #endif doc->release(); } else { #if defined (XSEC_XERCES_DOMLSSERIALIZER) theSerializer->write(request, theOutput); #else theSerializer->writeNode(formatTarget, *request); #endif } // Now replicate the buffer return XMLString::replicate((const char *) formatTarget->getRawBuffer()); } // -------------------------------------------------------------------------------- // UnWrap and de-serialise the response message // -------------------------------------------------------------------------------- DOMDocument * XSECSOAPRequestorSimple::parseAndUnwrap(const char * buf, unsigned int len) { XercesDOMParser * parser = new XercesDOMParser; Janitor j_parser(parser); parser->setDoNamespaces(true); parser->setCreateEntityReferenceNodes(true); parser->setDoSchema(true); // Create an input source MemBufInputSource* memIS = new MemBufInputSource ((const XMLByte*) buf, len, "XSECMem"); Janitor j_memIS(memIS); int errorCount = 0; parser->parse(*memIS); errorCount = parser->getErrorCount(); if (errorCount > 0) throw XSECException(XSECException::HTTPURIInputStreamError, "Error parsing response message"); if (m_envelopeType == ENVELOPE_NONE) { return parser->adoptDocument(); } DOMDocument * responseDoc = parser->getDocument(); // Must be a SOAP message of some kind - so lets remove the wrapper. // First create a new document for the Response message XMLCh tempStr[100]; XMLString::transcode("Core", tempStr, 99); DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr); DOMDocument * retDoc = impl->createDocument(); // Find the base of the response DOMNode * e = responseDoc->getDocumentElement(); e = e->getFirstChild(); while (e != NULL && (e->getNodeType() != DOMNode::ELEMENT_NODE || !strEquals(e->getLocalName(), "Body"))) e = e->getNextSibling(); if (e == NULL) throw XSECException(XSECException::HTTPURIInputStreamError, "Could not find SOAP body"); e = findFirstChildOfType(e, DOMNode::ELEMENT_NODE); if (e == NULL) throw XSECException(XSECException::HTTPURIInputStreamError, "Could not find message within SOAP body"); /* See if this is a soap fault */ if (strEquals(e->getLocalName(), "Fault")) { // Something has gone wrong somewhere! safeBuffer sb; sb.sbTranscodeIn("SOAP Fault : "); // Find the fault code e = findFirstElementChild(e); while (e != NULL && !strEquals(e->getLocalName(), "Code")) e = findNextElementChild(e); if (e != NULL) { DOMNode * c = findFirstElementChild(e); while (c != NULL && !strEquals(c->getLocalName(), "Value")) c = findNextElementChild(c); if (c != NULL) { DOMNode * t = findFirstChildOfType(c, DOMNode::TEXT_NODE); if (t != NULL) { sb.sbXMLChCat(t->getNodeValue()); sb.sbXMLChCat(" : "); } } } // Find the reason while (e != NULL && !strEquals(e->getLocalName(), "Reason")) e = findNextElementChild(e); if (e != NULL) { DOMNode * t = findFirstChildOfType(e, DOMNode::TEXT_NODE); if (t != NULL) { sb.sbXMLChCat(t->getNodeValue()); } } retDoc->release(); char * msg = XMLString::transcode(sb.rawXMLChBuffer()); ArrayJanitor j_msg(msg); throw XSECException(XSECException::HTTPURIInputStreamError, msg); } retDoc->appendChild(retDoc->importNode(e, true)); return retDoc; } // -------------------------------------------------------------------------------- // Envelope Type handling // -------------------------------------------------------------------------------- void XSECSOAPRequestorSimple::setEnvelopeType(envelopeType et) { m_envelopeType = et; }