2 * Copyright 2001-2007 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * AbstractSPRequest.cpp
20 * Abstract base for SPRequest implementations
24 #include "AbstractSPRequest.h"
25 #include "Application.h"
26 #include "ServiceProvider.h"
27 #include "SessionCache.h"
28 #include "util/CGIParser.h"
30 #include <log4cpp/Category.hh>
32 using namespace shibsp;
33 using namespace xmltooling;
34 using namespace log4cpp;
37 AbstractSPRequest::AbstractSPRequest()
38 : m_sp(NULL), m_mapper(NULL), m_app(NULL), m_session(NULL), m_log(&Category::getInstance(SHIBSP_LOGCAT)), m_parser(NULL)
40 m_sp=SPConfig::getConfig().getServiceProvider();
44 AbstractSPRequest::~AbstractSPRequest()
55 RequestMapper::Settings AbstractSPRequest::getRequestSettings() const
60 // Map request to application and content settings.
61 m_mapper=m_sp->getRequestMapper();
63 return m_settings = m_mapper->getSettings(*this);
67 const Application& AbstractSPRequest::getApplication() const
70 // Now find the application from the URL settings
71 m_app=m_sp->getApplication(getRequestSettings().first->getString("applicationId").second);
73 throw ConfigurationException("Unable to map request to application settings, check configuration.");
78 const char* AbstractSPRequest::getRequestURL() const {
80 // Compute the full target URL
82 const char* scheme = getScheme();
83 m_url = string(scheme) + "://" + getHostname();
84 if ((!strcmp(scheme,"http") && port!=80) || (!strcmp(scheme,"https") && port!=443)) {
85 ostringstream portstr;
87 m_url += ":" + portstr.str();
89 scheme = getRequestURI();
96 const char* AbstractSPRequest::getParameter(const char* name) const
99 m_parser=new CGIParser(*this);
101 pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
102 return (bounds.first==bounds.second) ? NULL : bounds.first->second;
105 vector<const char*>::size_type AbstractSPRequest::getParameters(const char* name, vector<const char*>& values) const
108 m_parser=new CGIParser(*this);
110 pair<CGIParser::walker,CGIParser::walker> bounds=m_parser->getParameters(name);
111 while (bounds.first!=bounds.second) {
112 values.push_back(bounds.first->second);
115 return values.size();
118 const char* AbstractSPRequest::getCookie(const char* name) const
120 if (m_cookieMap.empty()) {
121 string cookies=getHeader("Cookie");
123 string::size_type pos=0,cname,namelen,val,vallen;
124 while (pos !=string::npos && pos < cookies.length()) {
125 while (isspace(cookies[pos])) pos++;
127 pos=cookies.find_first_of("=",pos);
128 if (pos == string::npos)
132 if (pos==cookies.length())
135 pos=cookies.find_first_of(";",pos);
136 if (pos != string::npos) {
139 m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val,vallen)));
142 m_cookieMap.insert(make_pair(cookies.substr(cname,namelen),cookies.substr(val)));
145 map<string,string>::const_iterator lookup=m_cookieMap.find(name);
146 return (lookup==m_cookieMap.end()) ? NULL : lookup->second.c_str();
149 const char* AbstractSPRequest::getHandlerURL(const char* resource) const
151 if (!m_handlerURL.empty() && resource && !strcmp(getRequestURL(),resource))
152 return m_handlerURL.c_str();
154 #ifdef HAVE_STRCASECMP
155 if (!resource || (strncasecmp(resource,"http://",7) && strncasecmp(resource,"https://",8)))
157 if (!resource || (strnicmp(resource,"http://",7) && strnicmp(resource,"https://",8)))
159 throw ConfigurationException("Target resource was not an absolute URL.");
162 const char* handler=NULL;
163 const PropertySet* props=m_app->getPropertySet("Sessions");
165 pair<bool,bool> p=props->getBool("handlerSSL");
168 pair<bool,const char*> p2=props->getString("handlerURL");
173 // Should never happen...
174 if (!handler || (*handler!='/' && strncmp(handler,"http:",5) && strncmp(handler,"https:",6)))
175 throw ConfigurationException(
176 "Invalid handlerURL property ($1) in Application ($2)",
177 params(2, handler ? handler : "null", m_app->getId())
180 // The "handlerURL" property can be in one of three formats:
182 // 1) a full URI: http://host/foo/bar
183 // 2) a hostless URI: http:///foo/bar
184 // 3) a relative path: /foo/bar
186 // # Protocol Host Path
187 // 1 handler handler handler
188 // 2 handler resource handler
189 // 3 resource resource handler
191 // note: if ssl_only is true, make sure the protocol is https
193 const char* path = NULL;
195 // Decide whether to use the handler or the resource for the "protocol"
197 if (*handler != '/') {
205 // break apart the "protocol" string into protocol, host, and "the rest"
206 const char* colon=strchr(prot,':');
208 const char* slash=strchr(colon,'/');
212 // Compute the actual protocol and store in member.
214 m_handlerURL.assign("https://");
216 m_handlerURL.assign(prot, colon-prot);
218 // create the "host" from either the colon/slash or from the target string
219 // If prot == handler then we're in either #1 or #2, else #3.
220 // If slash == colon then we're in #2.
221 if (prot != handler || slash == colon) {
222 colon = strchr(resource, ':');
223 colon += 3; // Get past the ://
224 slash = strchr(colon, '/');
226 string host(colon, (slash ? slash-colon : strlen(colon)));
228 // Build the handler URL
229 m_handlerURL += host + path;
230 return m_handlerURL.c_str();
233 void AbstractSPRequest::log(SPLogLevel level, const std::string& msg) const
235 reinterpret_cast<Category*>(m_log)->log(
236 (level == SPDebug ? log4cpp::Priority::DEBUG :
237 (level == SPInfo ? log4cpp::Priority::INFO :
238 (level == SPWarn ? log4cpp::Priority::WARN :
239 (level == SPError ? log4cpp::Priority::ERROR : log4cpp::Priority::CRIT)))),
244 bool AbstractSPRequest::isPriorityEnabled(SPLogLevel level) const
246 return reinterpret_cast<Category*>(m_log)->isPriorityEnabled(
247 (level == SPDebug ? log4cpp::Priority::DEBUG :
248 (level == SPInfo ? log4cpp::Priority::INFO :
249 (level == SPWarn ? log4cpp::Priority::WARN :
250 (level == SPError ? log4cpp::Priority::ERROR : log4cpp::Priority::CRIT))))