SSPCPP-616 - clean up concatenated string literals
[shibboleth/cpp-sp.git] / shibsp / binding / impl / XMLProtocolProvider.cpp
index 327a18f..3084076 100644 (file)
-/*\r
- *  Copyright 2010 Internet2\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *     http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/**\r
- * XMLProtocolProvider.cpp\r
- *\r
- * XML-based protocol provider.\r
- */\r
-\r
-#include "internal.h"\r
-#include "exceptions.h"\r
-#include "binding/ProtocolProvider.h"\r
-#include "util/DOMPropertySet.h"\r
-#include "util/SPConstants.h"\r
-\r
-#include <map>\r
-#include <xmltooling/io/HTTPResponse.h>\r
-#include <xmltooling/util/NDC.h>\r
-#include <xmltooling/util/ReloadableXMLFile.h>\r
-#include <xmltooling/util/Threads.h>\r
-#include <xmltooling/util/XMLHelper.h>\r
-#include <xercesc/util/XMLUniDefs.hpp>\r
-\r
-using shibspconstants::SHIB2SPPROTOCOLS_NS;\r
-using namespace shibsp;\r
-using namespace xmltooling;\r
-using namespace std;\r
-\r
-namespace shibsp {\r
-\r
-    static const XMLCh _id[] =                  UNICODE_LITERAL_2(i,d);\r
-    static const XMLCh Binding[] =              UNICODE_LITERAL_7(B,i,n,d,i,n,g);\r
-    static const XMLCh Protocol[] =             UNICODE_LITERAL_8(P,r,o,t,o,c,o,l);\r
-    static const XMLCh Protocols[] =            UNICODE_LITERAL_9(P,r,o,t,o,c,o,l,s);\r
-    static const XMLCh Service[] =              UNICODE_LITERAL_7(S,e,r,v,i,c,e);\r
-\r
-#if defined (_MSC_VER)\r
-    #pragma warning( push )\r
-    #pragma warning( disable : 4250 )\r
-#endif\r
-\r
-    class SHIBSP_DLLLOCAL XMLProtocolProviderImpl : public DOMNodeFilter, DOMPropertySet\r
-    {\r
-    public:\r
-        XMLProtocolProviderImpl(const DOMElement* e, Category& log);\r
-        ~XMLProtocolProviderImpl() {\r
-            for (protmap_t::iterator i = m_map.begin(); i != m_map.end(); ++i) {\r
-                delete i->second.first;\r
-                for_each(i->second.second.begin(), i->second.second.end(), xmltooling::cleanup<PropertySet>());\r
-            }\r
-            if (m_document)\r
-                m_document->release();\r
-        }\r
-\r
-        void setDocument(DOMDocument* doc) {\r
-            m_document = doc;\r
-        }\r
-\r
-#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE\r
-        short\r
-#else\r
-        FilterAction\r
-#endif\r
-        acceptNode(const DOMNode* node) const {\r
-            return FILTER_REJECT;\r
-        }\r
-\r
-    private:\r
-        DOMDocument* m_document;\r
-        // Map of protocol/service pair to a service propset plus an array of Binding propsets.\r
-        typedef map< pair<string,string>, pair< PropertySet*,vector<const PropertySet*> > > protmap_t;\r
-        protmap_t m_map;\r
-\r
-        friend class SHIBSP_DLLLOCAL XMLProtocolProvider;\r
-    };\r
-\r
-    class XMLProtocolProvider : public ProtocolProvider, public ReloadableXMLFile\r
-    {\r
-    public:\r
-        XMLProtocolProvider(const DOMElement* e)\r
-                : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".ProtocolProvider.XML")), m_impl(nullptr) {\r
-            background_load(); // guarantees an exception or the policy is loaded\r
-        }\r
-\r
-        ~XMLProtocolProvider() {\r
-            shutdown();\r
-            delete m_impl;\r
-        }\r
-\r
-        const PropertySet* getService(const char* protocol, const char* service) const {\r
-            XMLProtocolProviderImpl::protmap_t::const_iterator i = m_impl->m_map.find(pair<string,string>(protocol,service));\r
-            return (i != m_impl->m_map.end()) ? i->second.first : nullptr;\r
-        }\r
-\r
-        const vector<const PropertySet*>& getBindings(const char* protocol, const char* service) const {\r
-            XMLProtocolProviderImpl::protmap_t::const_iterator i = m_impl->m_map.find(pair<string,string>(protocol,service));\r
-            if (i != m_impl->m_map.end())\r
-                return i->second.second;\r
-            throw ConfigurationException("ProtocolProvider can't return bindings for undefined protocol and service.");\r
-        }\r
-\r
-    protected:\r
-        pair<bool,DOMElement*> load(bool backup);\r
-        pair<bool,DOMElement*> background_load();\r
-\r
-    private:\r
-        XMLProtocolProviderImpl* m_impl;\r
-    };\r
-\r
-#if defined (_MSC_VER)\r
-    #pragma warning( pop )\r
-#endif\r
-\r
-    ProtocolProvider* SHIBSP_DLLLOCAL XMLProtocolProviderFactory(const DOMElement* const & e)\r
-    {\r
-        return new XMLProtocolProvider(e);\r
-    }\r
-}\r
-\r
-void SHIBSP_API shibsp::registerProtocolProviders()\r
-{\r
-    SPConfig::getConfig().ProtocolProviderManager.registerFactory(XML_PROTOCOL_PROVIDER, XMLProtocolProviderFactory);\r
-}\r
-\r
-ProtocolProvider::ProtocolProvider()\r
-{\r
-}\r
-\r
-ProtocolProvider::~ProtocolProvider()\r
-{\r
-}\r
-\r
-XMLProtocolProviderImpl::XMLProtocolProviderImpl(const DOMElement* e, Category& log) : m_document(nullptr)\r
-{\r
-#ifdef _DEBUG\r
-    xmltooling::NDC ndc("XMLProtocolProviderImpl");\r
-#endif\r
-    //typedef map< pair<string,string>, pair< PropertySet*,vector<const PropertySet*> > > protmap_t;\r
-\r
-    if (!XMLHelper::isNodeNamed(e, SHIB2SPPROTOCOLS_NS, Protocols))\r
-        throw ConfigurationException("XML ProtocolProvider requires prot:Protocols at root of configuration.");\r
-\r
-    e = XMLHelper::getFirstChildElement(e, SHIB2SPPROTOCOLS_NS, Protocol);\r
-    while (e) {\r
-        string id = XMLHelper::getAttrString(e, nullptr, _id);\r
-        if (!id.empty()) {\r
-            const DOMElement* svc = XMLHelper::getFirstChildElement(e, SHIB2SPPROTOCOLS_NS, Service);\r
-            while (svc) {\r
-                string svcid = XMLHelper::getAttrString(svc, nullptr, _id);\r
-                if (!svcid.empty()) {\r
-                    pair< PropertySet*,vector<const PropertySet*> >& entry = m_map[make_pair(id,svcid)];\r
-                    if (!entry.first) {\r
-                        // Wrap the Service in a propset.\r
-                        DOMPropertySet* svcprop = new DOMPropertySet();\r
-                        entry.first = svcprop;\r
-                        svcprop->load(svc, &log, this);\r
-\r
-                        // Walk the Bindings.\r
-                        const DOMElement* bind = XMLHelper::getFirstChildElement(svc, SHIB2SPPROTOCOLS_NS, Binding);\r
-                        while (bind) {\r
-                            DOMPropertySet* bindprop = new DOMPropertySet();\r
-                            entry.second.push_back(bindprop);\r
-                            bindprop->load(bind, &log, this);\r
-                            bind = XMLHelper::getNextSiblingElement(bind, SHIB2SPPROTOCOLS_NS, Binding);\r
-                        }\r
-                    }\r
-                }\r
-                svc = XMLHelper::getNextSiblingElement(svc, SHIB2SPPROTOCOLS_NS, Service);\r
-            }\r
-        }\r
-        e = XMLHelper::getNextSiblingElement(e, SHIB2SPPROTOCOLS_NS, Protocol);\r
-    }\r
-}\r
-\r
-\r
-pair<bool,DOMElement*> XMLProtocolProvider::load(bool backup)\r
-{\r
-    // Load from source using base class.\r
-    pair<bool,DOMElement*> raw = ReloadableXMLFile::load(backup);\r
-\r
-    // If we own it, wrap it.\r
-    XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : nullptr);\r
-\r
-    XMLProtocolProviderImpl* impl = new XMLProtocolProviderImpl(raw.second, m_log);\r
-\r
-    // If we held the document, transfer it to the impl. If we didn't, it's a no-op.\r
-    impl->setDocument(docjanitor.release());\r
-\r
-    // Perform the swap inside a lock.\r
-    if (m_lock)\r
-        m_lock->wrlock();\r
-    SharedLock locker(m_lock, false);\r
-    delete m_impl;\r
-    m_impl = impl;\r
-\r
-\r
-    return make_pair(false,(DOMElement*)nullptr);\r
-}\r
-\r
-pair<bool,DOMElement*> XMLProtocolProvider::background_load()\r
-{\r
-    try {\r
-        return load(false);\r
-    }\r
-    catch (long& ex) {\r
-        if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED)\r
-            m_log.info("remote resource (%s) unchanged", m_source.c_str());\r
-        if (!m_loaded && !m_backing.empty())\r
-            return load(true);\r
-        throw;\r
-    }\r
-    catch (exception&) {\r
-        if (!m_loaded && !m_backing.empty())\r
-            return load(true);\r
-        throw;\r
-    }\r
-}\r
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you 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.
+ */
+
+/**
+ * XMLProtocolProvider.cpp
+ *
+ * XML-based protocol provider.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "binding/ProtocolProvider.h"
+#include "util/DOMPropertySet.h"
+#include "util/SPConstants.h"
+
+#include <map>
+#include <boost/shared_ptr.hpp>
+#include <xmltooling/io/HTTPResponse.h>
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/ReloadableXMLFile.h>
+#include <xmltooling/util/Threads.h>
+#include <xmltooling/util/XMLHelper.h>
+#include <xercesc/util/XMLUniDefs.hpp>
+
+using shibspconstants::SHIB2SPPROTOCOLS_NS;
+using namespace shibsp;
+using namespace xmltooling;
+using namespace boost;
+using namespace std;
+
+namespace shibsp {
+    static const XMLCh _id[] =          UNICODE_LITERAL_2(i,d);
+    static const XMLCh Binding[] =      UNICODE_LITERAL_7(B,i,n,d,i,n,g);
+    static const XMLCh Initiator[] =    UNICODE_LITERAL_9(I,n,i,t,i,a,t,o,r);
+    static const XMLCh Protocol[] =     UNICODE_LITERAL_8(P,r,o,t,o,c,o,l);
+    static const XMLCh Protocols[] =    UNICODE_LITERAL_9(P,r,o,t,o,c,o,l,s);
+    static const XMLCh Service[] =      UNICODE_LITERAL_7(S,e,r,v,i,c,e);
+
+#if defined (_MSC_VER)
+    #pragma warning( push )
+    #pragma warning( disable : 4250 )
+#endif
+
+    class SHIBSP_DLLLOCAL XMLProtocolProviderImpl : public DOMNodeFilter, DOMPropertySet
+    {
+    public:
+        XMLProtocolProviderImpl(const DOMElement* e, Category& log);
+        ~XMLProtocolProviderImpl() {
+            if (m_document)
+                m_document->release();
+        }
+
+        void setDocument(DOMDocument* doc) {
+            m_document = doc;
+        }
+
+#ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
+        short
+#else
+        FilterAction
+#endif
+        acceptNode(const DOMNode* node) const {
+            return FILTER_REJECT;
+        }
+
+    private:
+        DOMDocument* m_document;
+        // Map of protocol/service pair to an Initiator propset plus an array of Binding propsets.
+        typedef map< pair<string,string>, pair< const PropertySet*,vector<const PropertySet*> > > protmap_t;
+        protmap_t m_map;
+        vector< boost::shared_ptr<PropertySet> > m_propsetJanitor;  // needed to maintain vector API
+
+        friend class SHIBSP_DLLLOCAL XMLProtocolProvider;
+    };
+
+    class XMLProtocolProvider : public ProtocolProvider, public ReloadableXMLFile
+    {
+    public:
+        XMLProtocolProvider(const DOMElement* e)
+                : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT ".ProtocolProvider.XML")) {
+            background_load(); // guarantees an exception or the policy is loaded
+        }
+
+        ~XMLProtocolProvider() {
+            shutdown();
+        }
+
+        const PropertySet* getInitiator(const char* protocol, const char* service) const {
+            XMLProtocolProviderImpl::protmap_t::const_iterator i = m_impl->m_map.find(pair<string,string>(protocol,service));
+            return (i != m_impl->m_map.end()) ? i->second.first : nullptr;
+        }
+
+        const vector<const PropertySet*>& getBindings(const char* protocol, const char* service) const {
+            XMLProtocolProviderImpl::protmap_t::const_iterator i = m_impl->m_map.find(pair<string,string>(protocol,service));
+            return (i != m_impl->m_map.end()) ? i->second.second : m_noBindings;
+        }
+
+    protected:
+        pair<bool,DOMElement*> load(bool backup);
+        pair<bool,DOMElement*> background_load();
+
+    private:
+        static vector<const PropertySet*> m_noBindings;
+        scoped_ptr<XMLProtocolProviderImpl> m_impl;
+    };
+
+#if defined (_MSC_VER)
+    #pragma warning( pop )
+#endif
+
+    ProtocolProvider* SHIBSP_DLLLOCAL XMLProtocolProviderFactory(const DOMElement* const & e)
+    {
+        return new XMLProtocolProvider(e);
+    }
+}
+
+void SHIBSP_API shibsp::registerProtocolProviders()
+{
+    SPConfig::getConfig().ProtocolProviderManager.registerFactory(XML_PROTOCOL_PROVIDER, XMLProtocolProviderFactory);
+}
+
+ProtocolProvider::ProtocolProvider()
+{
+}
+
+ProtocolProvider::~ProtocolProvider()
+{
+}
+
+vector<const PropertySet*> XMLProtocolProvider::m_noBindings;
+
+XMLProtocolProviderImpl::XMLProtocolProviderImpl(const DOMElement* e, Category& log) : m_document(nullptr)
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("XMLProtocolProviderImpl");
+#endif
+    if (!XMLHelper::isNodeNamed(e, SHIB2SPPROTOCOLS_NS, Protocols))
+        throw ConfigurationException("XML ProtocolProvider requires prot:Protocols at root of configuration.");
+
+    e = XMLHelper::getFirstChildElement(e, SHIB2SPPROTOCOLS_NS, Protocol);
+    while (e) {
+        string id = XMLHelper::getAttrString(e, nullptr, _id);
+        if (!id.empty()) {
+            const DOMElement* svc = XMLHelper::getFirstChildElement(e, SHIB2SPPROTOCOLS_NS, Service);
+            while (svc) {
+                string svcid = XMLHelper::getAttrString(svc, nullptr, _id);
+                if (!svcid.empty() && m_map.count(make_pair(id,svcid)) == 0) {
+                    pair< const PropertySet*,vector<const PropertySet*> >& entry = m_map[make_pair(id,svcid)];
+                    // Wrap the Initiator in a propset, if any.
+                    const DOMElement* child = XMLHelper::getFirstChildElement(svc, SHIB2SPPROTOCOLS_NS, Initiator);
+                    if (child) {
+                        boost::shared_ptr<DOMPropertySet> initprop(new DOMPropertySet());
+                        initprop->load(child, nullptr, this);
+                        m_propsetJanitor.push_back(initprop);
+                        entry.first = initprop.get();
+                    }
+                    else {
+                        entry.first = nullptr;
+                    }
+
+                    // Walk the Bindings.
+                    child = XMLHelper::getFirstChildElement(svc, SHIB2SPPROTOCOLS_NS, Binding);
+                    while (child) {
+                        boost::shared_ptr<DOMPropertySet> bindprop(new DOMPropertySet());
+                        bindprop->load(child, nullptr, this);
+                        m_propsetJanitor.push_back(bindprop);
+                        entry.second.push_back(bindprop.get());
+                        child = XMLHelper::getNextSiblingElement(child, SHIB2SPPROTOCOLS_NS, Binding);
+                    }
+                }
+                svc = XMLHelper::getNextSiblingElement(svc, SHIB2SPPROTOCOLS_NS, Service);
+            }
+        }
+        e = XMLHelper::getNextSiblingElement(e, SHIB2SPPROTOCOLS_NS, Protocol);
+    }
+}
+
+
+pair<bool,DOMElement*> XMLProtocolProvider::load(bool backup)
+{
+    // Load from source using base class.
+    pair<bool,DOMElement*> raw = ReloadableXMLFile::load(backup);
+
+    // If we own it, wrap it.
+    XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : nullptr);
+
+    scoped_ptr<XMLProtocolProviderImpl> impl(new XMLProtocolProviderImpl(raw.second, m_log));
+
+    // If we held the document, transfer it to the impl. If we didn't, it's a no-op.
+    impl->setDocument(docjanitor.release());
+
+    // Perform the swap inside a lock.
+    if (m_lock)
+        m_lock->wrlock();
+    SharedLock locker(m_lock, false);
+    m_impl.swap(impl);
+
+
+    return make_pair(false,(DOMElement*)nullptr);
+}
+
+pair<bool,DOMElement*> XMLProtocolProvider::background_load()
+{
+    try {
+        return load(false);
+    }
+    catch (long& ex) {
+        if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED)
+            m_log.info("remote resource (%s) unchanged", m_source.c_str());
+        if (!m_loaded && !m_backing.empty())
+            return load(true);
+        throw;
+    }
+    catch (std::exception&) {
+        if (!m_loaded && !m_backing.empty())
+            return load(true);
+        throw;
+    }
+}