//%LICENSE//////////////////////////////////////////////////////////////// // // Licensed to The Open Group (TOG) under one or more contributor license // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with // this work for additional information regarding copyright ownership. // Each contributor licenses this file to you under the OpenPegasus Open // Source License; you may not use this file except in compliance with the // License. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ////////////////////////////////////////////////////////////////////////// // //%//////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include "WsmConstants.h" #include "WsmUtils.h" #include "WsmWriter.h" #include "WsmSelectorSet.h" PEGASUS_NAMESPACE_BEGIN inline void _writeNewlineForReadability(Buffer& out) { // Uncomment this statement for XML response readability. // out << '\n'; } // Append something like this to buffer: ""); _writeNewlineForReadability(out); appendSoapHeader(out, action, messageId, relatesTo); } void WsmWriter::appendSoapFaultBody( Buffer& out, const SoapNotUnderstoodFault& fault) { ContentLanguageList msgLang = fault.getMessageLanguage(); appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Fault")); appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Code")); String codeValue = String(WsmNamespaces::supportedNamespaces[ WsmNamespaces::SOAP_ENVELOPE].localName) + String(":MustUnderstand"); appendTagValue( out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Value"), codeValue); appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Code")); String msg = fault.getMessage(); if (msg.size() != 0) { String lang; if (msgLang.size() == 0) lang = "en-US"; else lang = msgLang.getLanguageTag(0).toString(); appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Reason")); appendTagValue(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Text"), msg, "xml:lang", lang); appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Reason")); } appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Fault")); } void WsmWriter::appendWsmFaultBody( Buffer& out, const WsmFault& fault) { ContentLanguageList reasonLang = fault.getReasonLanguage(); appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Fault")); appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Code")); appendTagValue(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Value"), fault.getCode()); appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Subcode")); appendTagValue(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Value"), fault.getSubcode()); appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Subcode")); appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Code")); String reason = fault.getReason(); if (reason.size() != 0) { String lang; if (reasonLang.size() == 0) lang = "en-US"; else lang = reasonLang.getLanguageTag(0).toString(); appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Reason")); appendTagValue(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Text"), reason, "xml:lang", lang); appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Reason")); } String detail = fault.getFaultDetail(); if (detail.size() != 0) { appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Detail")); appendTagValue( out, WsmNamespaces::WS_MAN, STRLIT("FaultDetail"), detail); appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Detail")); } appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Fault")); } void WsmWriter::appendInstanceElement( Buffer& out, const String& resourceUri, WsmInstance& instance, const char* ns, Boolean isEmbedded) { size_t nsLength = strlen(ns); // Class opening element: _appendStartPrefix(out, ns); out << instance.getClassName(); out << STRLIT(" xmlns:"); out.append(ns, nsLength); out << STRLIT("=\""); out << WsmUtils::getRootResourceUri(resourceUri); out << STRLIT("/") << instance.getClassName(); out << STRLIT("\""); // DSP0230, section 7.2.5.2. The property element MUST contain an // xsi:type attribute with the XSD type of the class of the instance // (see section 7.3.1). if (isEmbedded) { out << STRLIT(" "); out << WsmNamespaces::supportedNamespaces[ WsmNamespaces::XML_SCHEMA_INSTANCE].localName; out << STRLIT(":type=\""); out << instance.getClassName(); out << STRLIT("_Type\""); } out << STRLIT(">"); _writeNewlineForReadability(out); // Sort properties before writing them out instance.sortProperties(); // Properties: for (Uint32 i = 0, n = instance.getPropertyCount(); i < n; i++) appendPropertyElement(out, resourceUri, instance.getProperty(i), ns); // Class closing element: _appendEndPrefix(out, ns); out << instance.getClassName() << STRLIT(">"); _writeNewlineForReadability(out); } void WsmWriter::appendPropertyElement( Buffer& out, const String& resourceUri, WsmProperty& property, const char* ns) { WsmValue val = property.getValue(); String propName = property.getName(); // Form start element prefix. For example: ""); return; } if (val.isArray()) { switch (val.getType()) { case WSMTYPE_REFERENCE: { Array eprs; val.get(eprs); for (Uint32 i = 0, n = eprs.size(); i < n; i++) { out << start << propName << STRLIT(">"); _writeNewlineForReadability(out); appendEPRElement(out, eprs[i]); out << end << propName << STRLIT(">"); _writeNewlineForReadability(out); } break; } case WSMTYPE_INSTANCE: { Array instances; val.get(instances); for (Uint32 i = 0, n = instances.size(); i < n; i++) { out << start << propName << STRLIT(">"); _writeNewlineForReadability(out); appendInstanceElement(out, resourceUri, instances[i], PEGASUS_INSTANCE_NS, true); out << end << propName << STRLIT(">"); _writeNewlineForReadability(out); } break; } case WSMTYPE_OTHER: { Array strs; val.get(strs); for (Uint32 i = 0, n = strs.size(); i < n; i++) { out << start << propName << STRLIT(">"); _writeNewlineForReadability(out); appendStringElement(out, strs[i]); out << end << propName << STRLIT(">"); _writeNewlineForReadability(out); } break; } default: { PEGASUS_ASSERT(0); } } } else { switch (val.getType()) { case WSMTYPE_REFERENCE: { WsmEndpointReference epr; val.get(epr); out << start << propName << STRLIT(">"); _writeNewlineForReadability(out); appendEPRElement(out, epr); out << end << propName << STRLIT(">"); _writeNewlineForReadability(out); break; } case WSMTYPE_INSTANCE: { WsmInstance instance; val.get(instance); out << start << propName << STRLIT(">"); _writeNewlineForReadability(out); appendInstanceElement(out, resourceUri, instance, PEGASUS_INSTANCE_NS, true); out << end << propName << STRLIT(">"); _writeNewlineForReadability(out); break; } case WSMTYPE_OTHER: { String str; val.get(str); out << start << propName << STRLIT(">"); _writeNewlineForReadability(out); appendStringElement(out, str); out << end << propName << STRLIT(">"); _writeNewlineForReadability(out); break; } default: { PEGASUS_ASSERT(0); } } } } void WsmWriter::appendEPRElement( Buffer& out, const WsmEndpointReference& epr) { appendTagValue( out, WsmNamespaces::WS_ADDRESSING, STRLIT("Address"), epr.address); appendStartTag( out, WsmNamespaces::WS_ADDRESSING, STRLIT("ReferenceParameters")); appendTagValue( out, WsmNamespaces::WS_MAN, STRLIT("ResourceURI"), epr.resourceUri); if (epr.selectorSet && epr.selectorSet->selectors.size() > 0) { appendStartTag(out, WsmNamespaces::WS_MAN, STRLIT("SelectorSet")); for (Uint32 i = 0, n = epr.selectorSet->selectors.size(); i < n; i++) { WsmSelector selector = epr.selectorSet->selectors[i]; appendStartTag(out, WsmNamespaces::WS_MAN, STRLIT("Selector"), "Name", selector.name); if (selector.type == WsmSelector::EPR) { appendStartTag(out, WsmNamespaces::WS_ADDRESSING, STRLIT("EndpointReference")); appendEPRElement(out, selector.epr); appendEndTag(out, WsmNamespaces::WS_ADDRESSING, STRLIT("EndpointReference")); } else { XmlGenerator::appendSpecial(out, selector.value); _writeNewlineForReadability(out); } appendEndTag(out, WsmNamespaces::WS_MAN, STRLIT("Selector")); } appendEndTag(out, WsmNamespaces::WS_MAN, STRLIT("SelectorSet")); } appendEndTag( out, WsmNamespaces::WS_ADDRESSING, STRLIT("ReferenceParameters")); } void WsmWriter::appendStringElement( Buffer& out, const String& str) { XmlGenerator::appendSpecial(out, str); _writeNewlineForReadability(out); } void WsmWriter::appendStartTag( Buffer& out, WsmNamespaces::Type nsType, const StrLit& tagName, const char* attrName, const String& attrValue) { out << STRLIT("<"); out << WsmNamespaces::supportedNamespaces[nsType].localName; out << STRLIT(":") << tagName; if (attrName) { out << STRLIT(" ") << attrName << STRLIT("="); out << STRLIT("\"") << attrValue << STRLIT("\""); } out << STRLIT(">"); _writeNewlineForReadability(out); } void WsmWriter::appendEndTag( Buffer& out, WsmNamespaces::Type nsType, const StrLit& tagName) { out << STRLIT(""); _writeNewlineForReadability(out); } void WsmWriter::appendEmptyTag( Buffer& out, WsmNamespaces::Type nsType, const StrLit& tagName) { out << STRLIT("<"); out << WsmNamespaces::supportedNamespaces[nsType].localName; out << STRLIT(":") << tagName << STRLIT("/>"); _writeNewlineForReadability(out); } void WsmWriter::appendTagValue( Buffer& out, WsmNamespaces::Type nsType, const StrLit& tagName, const String& value, const char* attrName, const String& attrValue) { appendStartTag(out, nsType, tagName, attrName, attrValue); out << value; _writeNewlineForReadability(out); appendEndTag(out, nsType, tagName); } void WsmWriter::appendHTTPResponseHeader( Buffer& out, const String& action, HttpMethod httpMethod, Boolean omitXMLProcessingInstruction, const ContentLanguageList& contentLanguages, Boolean isFault, Uint32 contentLength) { if (isFault) { out << STRLIT("HTTP/1.1 " HTTP_STATUS_INTERNALSERVERERROR "\r\n"); } else { out << STRLIT("HTTP/1.1 " HTTP_STATUS_OK "\r\n"); } out << STRLIT("Content-Type: application/soap+xml;charset=UTF-8\r\n"); OUTPUT_CONTENTLENGTH(out, contentLength); if (contentLanguages.size() > 0) { out << STRLIT("Content-Language: ") << contentLanguages << STRLIT("\r\n"); } if (httpMethod == HTTP_METHOD_M_POST) { char nn[] = { '0' + (rand() % 10), '0' + (rand() % 10), '\0' }; out << STRLIT("Ext:\r\n"); out << STRLIT("Cache-Control: no-cache\r\n"); out << STRLIT("Man: urn:schemas-xmlsoap-org:soap.v1; ns=") << nn << STRLIT("\r\n"); out << nn << STRLIT("-SOAPAction: ") << action << STRLIT("\r\n"); } else { out << STRLIT("SOAPAction: "); out << action << STRLIT("\r\n"); } out << STRLIT("\r\n"); if (!omitXMLProcessingInstruction) { out << STRLIT(""); } _writeNewlineForReadability(out); } void WsmWriter::appendSoapEnvelopeStart( Buffer& out, const ContentLanguageList& contentLanguages) { out << STRLIT("<"); out << WsmNamespaces::supportedNamespaces[ WsmNamespaces::SOAP_ENVELOPE].localName; out << STRLIT(":Envelope"); // DSP0226 R6.3-4: In any response, event, or singleton message, the // service should include the xml:lang attribute in the s:Envelope (or // other elements) to signal to the receiver that localized content // appears in the body of the message. This attribute may be omitted // if no descriptive content appears in the body. Including the // xml:lang attribute is not an error, even if no descriptive content // occurs. if (contentLanguages.size() > 0) { out << STRLIT(" xml:lang=\""); out << contentLanguages.getLanguageTag(0).toString() << STRLIT("\""); } for (Uint32 i = 0; i < WsmNamespaces::LAST; i++) { _writeNewlineForReadability(out); out << STRLIT(" xmlns:"); out << WsmNamespaces::supportedNamespaces[i].localName; out << STRLIT("=\""); out << WsmNamespaces::supportedNamespaces[i].extendedName; out << STRLIT("\""); } out << STRLIT(">"); _writeNewlineForReadability(out); } void WsmWriter::appendSoapEnvelopeEnd(Buffer& out) { appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Envelope")); } void WsmWriter::appendSoapHeaderStart(Buffer& out) { appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Header")); } void WsmWriter::appendSoapHeaderEnd(Buffer& out) { appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Header")); } void WsmWriter::appendSoapBodyStart(Buffer& out) { appendStartTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Body")); } void WsmWriter::appendSoapBodyEnd(Buffer& out) { appendEndTag(out, WsmNamespaces::SOAP_ENVELOPE, STRLIT("Body")); } void WsmWriter::appendSoapHeader( Buffer& out, const String& action, const String& messageId, const String& relatesTo) { // Add entry appendStartTag(out, WsmNamespaces::WS_ADDRESSING, STRLIT("To")); // Note: The reply is always written on the requestor's connection. // The WsmRequestDecoder checks that the wsa:ReplyTo header is anonymous. out << STRLIT(WSM_ADDRESS_ANONYMOUS); _writeNewlineForReadability(out); appendEndTag(out, WsmNamespaces::WS_ADDRESSING, STRLIT("To")); // Add entry appendTagValue(out, WsmNamespaces::WS_ADDRESSING, STRLIT("Action"), action); // Add entry appendTagValue( out, WsmNamespaces::WS_ADDRESSING, STRLIT("MessageID"), messageId); // Add entry only if necessary. An empty relates to tag // breaks some WS-Management clients (such as WinRM). if (relatesTo.size()) { appendTagValue( out, WsmNamespaces::WS_ADDRESSING, STRLIT("RelatesTo"), relatesTo); } } void WsmWriter::appendInvokeOutputElement( Buffer& out, const String& resourceUri, const String& className, const String& methodName, WsmInstance& instance, const char* ns) { CString mn(methodName.getCString()); // Form tagname. Buffer tagBuffer; tagBuffer.append(ns, strlen(ns)); tagBuffer.append(':'); tagBuffer.append(mn, strlen(mn)); tagBuffer.append("_OUTPUT", 7); const char* tag = tagBuffer.getData(); size_t tagSize = tagBuffer.size(); // Write start tag. out.append('<'); out.append(tag, tagSize); out << STRLIT(" xmlns:"); out.append(ns, strlen(ns)); out << STRLIT("=\""); out << WsmUtils::getRootResourceUri(resourceUri); out << STRLIT("/"); out << className; out << STRLIT("\">"); _writeNewlineForReadability(out); // Write properties: for (Uint32 i = 0, n = instance.getPropertyCount(); i < n; i++) appendPropertyElement(out, resourceUri, instance.getProperty(i), ns); // Write end tag. out << STRLIT("'); _writeNewlineForReadability(out); } PEGASUS_NAMESPACE_END