Work around Solaris issue
[shibboleth/cpp-sp.git] / shibsp / util / TemplateParameters.cpp
1 /**
2  * Licensed to the University Corporation for Advanced Internet
3  * Development, Inc. (UCAID) under one or more contributor license
4  * agreements. See the NOTICE file distributed with this work for
5  * additional information regarding copyright ownership.
6  *
7  * UCAID licenses this file to you under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the
10  * License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17  * either express or implied. See the License for the specific
18  * language governing permissions and limitations under the License.
19  */
20
21 /**
22  * TemplateParameters.cpp
23  * 
24  * Supplies xmltooling TemplateEngine with additional parameters from a PropertySet. 
25  */
26
27 #include "internal.h"
28 #include "SessionCache.h"
29 #include "attribute/Attribute.h"
30 #include "util/PropertySet.h"
31 #include "util/TemplateParameters.h"
32
33 #include <ctime>
34 #include <xmltooling/XMLToolingConfig.h>
35 #include <xmltooling/util/URLEncoder.h>
36
37 using namespace shibsp;
38 using namespace xmltooling;
39 using namespace std;
40
41 TemplateParameters::TemplateParameters(const exception* e, const PropertySet* props, const Session* session)
42     : m_exception(e), m_toolingException(dynamic_cast<const XMLToolingException*>(e)), m_session(session)
43 {
44     setPropertySet(props);
45 }
46
47 TemplateParameters::~TemplateParameters()
48 {
49 }
50
51 void TemplateParameters::setPropertySet(const PropertySet* props)
52 {
53     m_props = props;
54
55     // Create a timestamp.
56     time_t now = time(nullptr);
57 #if defined(HAVE_CTIME_R_2)
58     char timebuf[32];
59     m_map["now"] = ctime_r(&now,timebuf);
60 #elif defined(HAVE_CTIME_R_3)
61     char timebuf[32];
62     m_map["now"] = ctime_r(&now,timebuf,sizeof(timebuf));
63 #else
64     m_map["now"] = ctime(&now);
65 #endif
66     string& s = m_map["now"];
67     s.erase(s.begin() + s.size() - 1);
68 }
69
70 const XMLToolingException* TemplateParameters::getRichException() const
71 {
72     return m_toolingException;
73 }
74
75 const char* TemplateParameters::getParameter(const char* name) const
76 {
77     if (m_exception) {
78         if (!strcmp(name, "errorType"))
79             return m_toolingException ? m_toolingException->getClassName() : "std::exception";
80         else if (!strcmp(name, "errorText"))
81             return m_exception->what();
82     }
83
84     const char* pch = TemplateEngine::TemplateParameters::getParameter(name);
85     if (pch)
86         return pch;
87
88     if (m_session) {
89         if (!strcmp(name, "entityID"))
90             return m_session->getEntityID();
91
92         const multimap<string,const Attribute*>& attrs = m_session->getIndexedAttributes();
93         pair<multimap<string,const Attribute*>::const_iterator, multimap<string,const Attribute*>::const_iterator> walker;
94         for (walker = attrs.equal_range(name); walker.first != walker.second; ++walker.first) {
95             if (walker.first->second->valueCount() > 0)
96                 return walker.first->second->getSerializedValues().front().c_str();
97         }
98     }
99
100     if (m_props) {
101         pair<bool,const char*> p = m_props->getString(name);
102         if (p.first)
103             return p.second;
104     }
105
106     return nullptr;
107 }
108
109 string TemplateParameters::toQueryString() const
110 {
111     // Capture local stuff.
112     string q;
113
114     const URLEncoder* enc = XMLToolingConfig::getConfig().getURLEncoder();
115     for (map<string,string>::const_iterator i = m_map.begin(); i != m_map.end(); ++i)
116         q = q + '&' + i->first + '=' + enc->encode(i->second.c_str());
117
118     // Add in the exception content.
119     if (m_exception) {
120         q = q + "&errorType=" + enc->encode(getParameter("errorType")) + "&errorText=" + enc->encode(getParameter("errorText"));
121         if (m_toolingException)
122             q = q + '&' + m_toolingException->toQueryString();
123     }
124
125     q.erase(0,1);
126     return q;
127 }