[cpp-sp] branch main updated: Remove Generic request/response interfaces
Codeberg
noreply at shibboleth.net
Thu Jun 4 18:45:50 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository cpp-sp.
View the commit online:
https://codeberg.org/Shibboleth/cpp-sp/commit/e4cced44f76d8f4226a3c30aef52adf2389d821d
The following commit(s) were added to refs/heads/main by this push:
new e4cced44 Remove Generic request/response interfaces
e4cced44 is described below
commit e4cced44f76d8f4226a3c30aef52adf2389d821d
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Thu Jun 4 14:45:33 2026 -0400
Remove Generic request/response interfaces
---
Projects/vc22/shibsp.vcxproj | 2 -
Projects/vc22/shibsp.vcxproj.filters | 6 -
apache/mod_shib4.cpp | 2 +-
fastcgi/shibauthorizer.cpp | 3 +-
fastcgi/shibresponder.cpp | 3 +-
iis/IIS7Request.cpp | 2 +-
shibsp/AbstractSPRequest.cpp | 48 +++++++
shibsp/AbstractSPRequest.h | 26 +++-
shibsp/Agent.cpp | 22 +++-
shibsp/Makefile.am | 2 -
shibsp/handler/impl/AbstractHandler.cpp | 6 +-
shibsp/handler/impl/AttributeCheckerHandler.cpp | 4 +-
shibsp/handler/impl/LogoutConsumer.cpp | 11 +-
shibsp/handler/impl/LogoutInitiator.cpp | 11 +-
shibsp/handler/impl/TokenConsumer.cpp | 1 -
shibsp/impl/DefaultAgent.cpp | 5 +-
shibsp/io/GenericRequest.h | 168 ------------------------
shibsp/io/GenericResponse.h | 78 -----------
shibsp/io/HTTPRequest.h | 117 ++++++++++++++++-
shibsp/io/HTTPResponse.h | 66 +++++-----
shibsp/io/impl/HTTPRequest.cpp | 27 ----
shibsp/io/impl/HTTPResponse.cpp | 48 -------
tests/DummyRequest.h | 1 +
23 files changed, 249 insertions(+), 410 deletions(-)
diff --git a/Projects/vc22/shibsp.vcxproj b/Projects/vc22/shibsp.vcxproj
index 6eac1914..4de41ef0 100644
--- a/Projects/vc22/shibsp.vcxproj
+++ b/Projects/vc22/shibsp.vcxproj
@@ -47,8 +47,6 @@
<ClInclude Include="..\..\shibsp\handler\SecuredHandler.h" />
<ClInclude Include="..\..\shibsp\internal.h" />
<ClInclude Include="..\..\shibsp\io\CookieManager.h" />
- <ClInclude Include="..\..\shibsp\io\GenericRequest.h" />
- <ClInclude Include="..\..\shibsp\io\GenericResponse.h" />
<ClInclude Include="..\..\shibsp\io\HTTPRequest.h" />
<ClInclude Include="..\..\shibsp\io\HTTPResponse.h" />
<ClInclude Include="..\..\shibsp\logging\Category.h" />
diff --git a/Projects/vc22/shibsp.vcxproj.filters b/Projects/vc22/shibsp.vcxproj.filters
index d866eac3..1227abb5 100644
--- a/Projects/vc22/shibsp.vcxproj.filters
+++ b/Projects/vc22/shibsp.vcxproj.filters
@@ -129,12 +129,6 @@
<ClInclude Include="..\..\shibsp\io\CookieManager.h">
<Filter>Header Files\IO</Filter>
</ClInclude>
- <ClInclude Include="..\..\shibsp\io\GenericRequest.h">
- <Filter>Header Files\IO</Filter>
- </ClInclude>
- <ClInclude Include="..\..\shibsp\io\GenericResponse.h">
- <Filter>Header Files\IO</Filter>
- </ClInclude>
<ClInclude Include="..\..\shibsp\io\HTTPRequest.h">
<Filter>Header Files\IO</Filter>
</ClInclude>
diff --git a/apache/mod_shib4.cpp b/apache/mod_shib4.cpp
index 90817d8e..6797c670 100644
--- a/apache/mod_shib4.cpp
+++ b/apache/mod_shib4.cpp
@@ -499,7 +499,7 @@ public:
return DONE;
}
long sendRedirect(const char* url) {
- HTTPResponse::sendRedirect(url);
+ url = sanitizeURL(url);
apr_table_set(m_req->headers_out, "Location", url);
if (getRequestSettings().first->getBool(
diff --git a/fastcgi/shibauthorizer.cpp b/fastcgi/shibauthorizer.cpp
index 2bad8b68..3db6b4bc 100644
--- a/fastcgi/shibauthorizer.cpp
+++ b/fastcgi/shibauthorizer.cpp
@@ -229,7 +229,8 @@ public:
}
long sendRedirect(const char* url) {
- HTTPResponse::sendRedirect(url);
+ url = sanitizeURL(url);
+
string hdr=string("Status: 302 Please Wait\r\nLocation: ") + url + "\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 40\r\n";
diff --git a/fastcgi/shibresponder.cpp b/fastcgi/shibresponder.cpp
index 81306421..0276e87f 100644
--- a/fastcgi/shibresponder.cpp
+++ b/fastcgi/shibresponder.cpp
@@ -190,7 +190,8 @@ public:
}
long sendRedirect(const char* url) {
- HTTPResponse::sendRedirect(url);
+ url = sanitizeURL(url);
+
string hdr=string("Status: 302 Please Wait\r\nLocation: ") + url + "\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 40\r\n";
diff --git a/iis/IIS7Request.cpp b/iis/IIS7Request.cpp
index f753c089..a9c5c530 100644
--- a/iis/IIS7Request.cpp
+++ b/iis/IIS7Request.cpp
@@ -466,7 +466,7 @@ void IIS7Request::setResponseHeader(const char* name, const char* value, bool re
long IIS7Request::sendRedirect(const char* url)
{
- HTTPResponse::sendRedirect(url);
+ url = sanitizeURL(url);
if (getRequestSettings().first->getBool(
RequestMapper::EXPIRE_REDIRECTS_PROP_NAME, RequestMapper::EXPIRE_REDIRECTS_PROP_DEFAULT)) {
diff --git a/shibsp/AbstractSPRequest.cpp b/shibsp/AbstractSPRequest.cpp
index 4a564ab0..39d4235f 100644
--- a/shibsp/AbstractSPRequest.cpp
+++ b/shibsp/AbstractSPRequest.cpp
@@ -64,6 +64,13 @@ AbstractSPRequest::~AbstractSPRequest()
m_mapper->unlock_shared();
}
+vector<string> AbstractSPRequest::m_allowedSchemes;
+
+vector<string>& AbstractSPRequest::getAllowedSchemes()
+{
+ return m_allowedSchemes;
+}
+
const Agent& AbstractSPRequest::getAgent() const
{
return m_agent;
@@ -531,6 +538,47 @@ bool AbstractSPRequest::isPriorityEnabled(Priority::Value level) const
return m_log.isPriorityEnabled(level);
}
+const char* AbstractSPRequest::sanitizeURL(const char* url)
+{
+ if (!url) {
+ throw domain_error("URL was null");
+ }
+
+ const char* ch;
+ for (ch=url; *ch; ++ch) {
+ if (iscntrl((unsigned char)(*ch))) { // convert to unsigned to allow full range from 00-FF
+ throw domain_error("URL contained a control character.");
+ }
+ }
+
+ ch = strchr(url, ':');
+ if (!ch) {
+ throw domain_error("URL is missing a colon where expected; improper URL encoding?");
+ }
+ string s(url, ch - url);
+
+ for (const string& scheme : getAllowedSchemes()) {
+ if (strcasecmp(s.c_str(), scheme.c_str()) == 0) {
+ // Checks out, but absolutize if necessary.
+ if (*url == '/') {
+ // Compute a URL to the root of the site.
+ const char* scheme = getScheme();
+ m_absoluteHolder = string(scheme) + "://" + getHostname();
+ if (!isDefaultPort()) {
+ m_absoluteHolder += ":" + boost::lexical_cast<string>(getPort());
+ }
+ m_absoluteHolder += url;
+ return m_absoluteHolder.c_str();
+ }
+ else {
+ return url;
+ }
+ }
+ }
+
+ throw domain_error("URL contains invalid scheme.");
+}
+
void SPRequest::debug(const string& msg) const
{
log(Priority::SHIB_DEBUG, msg);
diff --git a/shibsp/AbstractSPRequest.h b/shibsp/AbstractSPRequest.h
index cd67b2af..85bf5d97 100644
--- a/shibsp/AbstractSPRequest.h
+++ b/shibsp/AbstractSPRequest.h
@@ -59,6 +59,16 @@ namespace shibsp {
public:
virtual ~AbstractSPRequest();
+ /**
+ * Returns a modifiable array of schemes to permit in sanitized URLs.
+ *
+ * <p>Updates to this array must be externally synchronized with any use
+ * of this class or its subclasses.
+ *
+ * @return a mutable array of strings containing the schemes to permit
+ */
+ static std::vector<std::string>& getAllowedSchemes();
+
// Virtual function overrides.
const Agent& getAgent() const;
RequestMapper::Settings getRequestSettings() const;
@@ -84,6 +94,16 @@ namespace shibsp {
bool isPriorityEnabled(Priority::Value level) const;
protected:
+ /**
+ * Check for unsafe URLs vulnerable to injection attacks and promote
+ * relative URLs to absolute based on current request.
+ *
+ * @param url location to check/promote
+ *
+ * @return sanitized and possibly altered URL
+ */
+ const char* sanitizeURL(const char* url);
+
/**
* Gets the transformed header name constructed from a raw input name by transforming
* punctuation into underscores and prefixing with "HTTP_".
@@ -99,15 +119,19 @@ namespace shibsp {
virtual const char* getLogContext() const;
private:
+ static std::vector<std::string> m_allowedSchemes;
+
Category& m_log;
Agent& m_agent;
mutable RequestMapper* m_mapper;
mutable RequestMapper::Settings m_settings;
std::string m_uri;
- mutable std::string m_url;
+ mutable std::string m_url;
mutable std::string m_handlerURL;
mutable std::unique_ptr<CGIParser> m_parser;
mutable std::map<std::string,std::string> m_cookieMap;
+ // Holds URL when promoted to absolute.
+ std::string m_absoluteHolder;
};
#if defined (_MSC_VER)
diff --git a/shibsp/Agent.cpp b/shibsp/Agent.cpp
index 91ce3f51..6b888167 100644
--- a/shibsp/Agent.cpp
+++ b/shibsp/Agent.cpp
@@ -95,9 +95,14 @@ long Agent::handleError(SPRequest& request, exception* ex, bool mayRedirect) con
if (mayRedirect && redirectErrors) {
string loc(redirectErrors);
- request.absolutize(loc);
if (richEx) {
- loc = loc + '?' + richEx->toQueryString();
+ if (loc.find('?') != string::npos) {
+ loc += '&';
+ }
+ else {
+ loc += '?';
+ }
+ loc += richEx->toQueryString();
}
return request.sendRedirect(loc.c_str());
}
@@ -220,17 +225,20 @@ pair<bool,long> Agent::doAuthentication(SPRequest& request, bool handler) const
if (!qstr || !strstr(qstr, "shiblogoutdone=1")) {
// First leg of circuit, so we redirect to the logout endpoint specified with this URL as a return location.
string selfurl = request.getRequestURL();
- if (qstr)
+ if (qstr) {
selfurl += '&';
- else
+ }
+ else {
selfurl += '?';
+ }
selfurl += "shiblogoutdone=1";
string loc(requireLogoutWith);
- request.absolutize(loc);
- if (loc.find('?') != string::npos)
+ if (loc.find('?') != string::npos) {
loc += '&';
- else
+ }
+ else {
loc += '?';
+ }
loc += "return=" + AgentConfig::getConfig().getURLEncoder().encode(selfurl.c_str());
return make_pair(true, request.sendRedirect(loc.c_str()));
}
diff --git a/shibsp/Makefile.am b/shibsp/Makefile.am
index bf667822..f59dd5a5 100644
--- a/shibsp/Makefile.am
+++ b/shibsp/Makefile.am
@@ -49,8 +49,6 @@ handinclude_HEADERS = \
ioinclude_HEADERS = \
io/CookieManager.h \
- io/GenericRequest.h \
- io/GenericResponse.h \
io/HTTPRequest.h \
io/HTTPResponse.h
diff --git a/shibsp/handler/impl/AbstractHandler.cpp b/shibsp/handler/impl/AbstractHandler.cpp
index 1d47e233..61b82979 100644
--- a/shibsp/handler/impl/AbstractHandler.cpp
+++ b/shibsp/handler/impl/AbstractHandler.cpp
@@ -174,12 +174,10 @@ pair<bool,long> AbstractHandler::unwrapResponse(SPRequest& request, DDF& wrapped
h = http["redirect"];
if (h.isstring()) {
- string dest(h.string());
- request.absolutize(dest);
if (limitRedirect) {
- request.limitRedirect(dest.c_str());
+ request.limitRedirect(h.string());
}
- return make_pair(true, request.sendRedirect(dest.c_str()));
+ return make_pair(true, request.sendRedirect(h.string()));
}
h = http["response"];
diff --git a/shibsp/handler/impl/AttributeCheckerHandler.cpp b/shibsp/handler/impl/AttributeCheckerHandler.cpp
index 8aab8dfc..a8a9acc8 100644
--- a/shibsp/handler/impl/AttributeCheckerHandler.cpp
+++ b/shibsp/handler/impl/AttributeCheckerHandler.cpp
@@ -154,9 +154,7 @@ pair<bool,long> AttributeCheckerHandler::run(SPRequest& request, bool isHandler)
}
if (checked) {
- string loc(returnURL);
- request.absolutize(loc);
- return make_pair(true, request.sendRedirect(loc.c_str()));
+ return make_pair(true, request.sendRedirect(returnURL));
}
if (m_flushSession && session) {
diff --git a/shibsp/handler/impl/LogoutConsumer.cpp b/shibsp/handler/impl/LogoutConsumer.cpp
index a0d4b7be..86756b01 100644
--- a/shibsp/handler/impl/LogoutConsumer.cpp
+++ b/shibsp/handler/impl/LogoutConsumer.cpp
@@ -236,15 +236,8 @@ pair <bool,long> LogoutConsumer::completeLogout(SPRequest& request, bool removeS
dest = getHomeURL(request);
}
- // Relative URLs get promoted, absolutes get validated.
- if (*dest == '/') {
- string d(dest);
- request.absolutize(d);
- return make_pair(true, request.sendRedirect(d.c_str()));
- } else {
- request.limitRedirect(dest);
- return make_pair(true, request.sendRedirect(dest));
- }
+ request.limitRedirect(dest);
+ return make_pair(true, request.sendRedirect(dest));
}
const char* LogoutConsumer::getHomeURL(SPRequest& request) const
diff --git a/shibsp/handler/impl/LogoutInitiator.cpp b/shibsp/handler/impl/LogoutInitiator.cpp
index f9e37275..a5824f3b 100644
--- a/shibsp/handler/impl/LogoutInitiator.cpp
+++ b/shibsp/handler/impl/LogoutInitiator.cpp
@@ -132,13 +132,6 @@ pair<bool,long> LogoutInitiator::run(SPRequest& request, bool isHandler) const
}
}
- // Relative URLs get promoted, absolutes get validated.
- if (*dest == '/') {
- string d(dest);
- request.absolutize(d);
- return make_pair(true, request.sendRedirect(d.c_str()));
- } else {
- request.limitRedirect(dest);
- return make_pair(true, request.sendRedirect(dest));
- }
+ request.limitRedirect(dest);
+ return make_pair(true, request.sendRedirect(dest));
}
diff --git a/shibsp/handler/impl/TokenConsumer.cpp b/shibsp/handler/impl/TokenConsumer.cpp
index 809c63cb..2418e599 100644
--- a/shibsp/handler/impl/TokenConsumer.cpp
+++ b/shibsp/handler/impl/TokenConsumer.cpp
@@ -174,7 +174,6 @@ pair<bool,long> TokenConsumer::run(SPRequest& request, bool isHandler) const
if (sessionHook) {
string hook(sessionHook);
- request.absolutize(hook);
// Compute the return URL. We use a self-referential link plus a hook indicator to break the cycle.
// The target also must be included.
diff --git a/shibsp/impl/DefaultAgent.cpp b/shibsp/impl/DefaultAgent.cpp
index 53f7a52c..98bc3f50 100644
--- a/shibsp/impl/DefaultAgent.cpp
+++ b/shibsp/impl/DefaultAgent.cpp
@@ -22,6 +22,7 @@
#include "exceptions.h"
#include "version.h"
+#include "AbstractSPRequest.h"
#include "Agent.h"
#include "AgentConfig.h"
#include "RequestMapper.h"
@@ -151,8 +152,8 @@ void DefaultAgent::init()
}
const char* prop = getString(ALLOWED_SCHEMES_PROP_NAME, ALLOWED_SCHEMES_PROP_DEFAULT);
- HTTPResponse::getAllowedSchemes().clear();
- split_to_container(HTTPResponse::getAllowedSchemes(), prop);
+ AbstractSPRequest::getAllowedSchemes().clear();
+ split_to_container(AbstractSPRequest::getAllowedSchemes(), prop);
prop = getString(EXTRA_AUTH_TYPES_PROP_NAME);
if (prop) {
diff --git a/shibsp/io/GenericRequest.h b/shibsp/io/GenericRequest.h
deleted file mode 100644
index b1a58b96..00000000
--- a/shibsp/io/GenericRequest.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * 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.
- */
-
-/**
- * @file shibsp/io/GenericRequest.h
- *
- * Interface to generic protocol requests handled by agents.
- */
-
-#ifndef __shibsp_genreq_h__
-#define __shibsp_genreq_h__
-
-#include <shibsp/base.h>
-
-#include <string>
-#include <vector>
-
-namespace shibsp {
-
-#if defined (_MSC_VER)
- #pragma warning( push )
- #pragma warning( disable : 4251 )
-#endif
-
- /**
- * Interface to generic protocol requests handled by agents.
- *
- * <p>This interface need not be threadsafe.</p>
- */
- class SHIBSP_API GenericRequest {
- MAKE_NONCOPYABLE(GenericRequest);
- protected:
- GenericRequest();
- public:
- virtual ~GenericRequest();
-
- /**
- * Returns the URL scheme of the request (http, https, ftp, ldap, etc.)
- *
- * @return the URL scheme
- */
- virtual const char* getScheme() const=0;
-
- /**
- * Returns true iff the request is over a confidential channel.
- *
- * @return confidential channel indicator
- */
- virtual bool isSecure() const=0;
-
- /**
- * Returns hostname of service that received request.
- *
- * @return hostname of service
- */
- virtual const char* getHostname() const=0;
-
- /**
- * Returns incoming port.
- *
- * @return incoming port
- */
- virtual int getPort() const=0;
-
- /**
- * Returns true iff the request port is the default port for the request protocol.
- *
- * @return default port indicator
- */
- virtual bool isDefaultPort() const;
-
- /**
- * Returns the MIME type of the request, if known.
- *
- * @return the MIME type, or an empty string
- */
- virtual std::string getContentType() const=0;
-
- /**
- * Returns the length of the request body, if known.
- *
- * @return the content length, or -1 if unknown
- */
- virtual long getContentLength() const=0;
-
- /**
- * Returns the raw request body.
- *
- * @return the request body, or nullptr
- */
- virtual const char* getRequestBody() const=0;
-
- /**
- * Returns a decoded named parameter value from the request.
- * If a parameter has multiple values, only one will be returned.
- *
- * @param name the name of the parameter to return
- * @return a single parameter value or nullptr
- */
- virtual const char* getParameter(const char* name) const=0;
-
- /**
- * Returns all of the decoded values of a named parameter from the request.
- * All values found will be returned.
- *
- * @param name the name of the parameter to return
- * @param values a vector in which to return pointers to the decoded values
- * @return the number of values returned
- */
- virtual std::vector<const char*>::size_type getParameters(
- const char* name, std::vector<const char*>& values
- ) const=0;
-
- /**
- * Returns the transport-authenticated identity associated with the request,
- * if authentication is solely handled by the transport.
- *
- * @return the authenticated username or an empty string
- */
- virtual std::string getRemoteUser() const=0;
-
- /**
- * Gets the authentication type associated with the request.
- *
- * @return the authentication type or nullptr
- */
- virtual std::string getAuthType() const=0;
-
- /**
- * Returns the IP address of the client.
- *
- * @return the client's IP address
- */
- virtual std::string getRemoteAddr() const=0;
-
- /**
- * Returns the IP address of the server.
- *
- * @return the server's IP address
- */
- virtual std::string getLocalAddr() const=0;
-
- /**
- * Converts a relative URL into an absolute one based on the properties of the request.
- *
- * @param url input URL to convert, will be modified in place
- */
- virtual void absolutize(std::string& url) const;
- };
-
-#if defined (_MSC_VER)
- #pragma warning( pop )
-#endif
-
-};
-
-#endif /* __shibsp_genreq_h__ */
diff --git a/shibsp/io/GenericResponse.h b/shibsp/io/GenericResponse.h
deleted file mode 100644
index 94cadf2b..00000000
--- a/shibsp/io/GenericResponse.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * 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.
- */
-
-/**
- * @file shibsp/io/GenericResponse.h
- *
- * Interface to generic protocol responses issued by agents.
- */
-
-#ifndef __shibsp_genres_h__
-#define __shibsp_genres_h__
-
-#include <shibsp/base.h>
-
-#include <iostream>
-
-namespace shibsp {
-
- /**
- * Interface to generic protocol responses issued by agents.
- *
- * <p>This interface need not be threadsafe.</p>
- */
- class SHIBSP_API GenericResponse {
- MAKE_NONCOPYABLE(GenericResponse);
- protected:
- GenericResponse();
- public:
- virtual ~GenericResponse();
-
- /**
- * Sets or clears the MIME type of the response.
- *
- * @param type the MIME type, or nullptr to clear
- */
- virtual void setContentType(const char* type=nullptr)=0;
-
- /**
- * Sends a completed response to the client along with a
- * transport-specific "OK" indication. Used for "normal" responses.
- *
- * @param inputStream reference to source of response data
- * @return a result code to return from the calling MessageEncoder
- */
- virtual long sendResponse(std::istream& inputStream)=0;
-
- /**
- * Sends an "error" response to the client along with a
- * transport-specific error indication.
- *
- * @param inputStream reference to source of response data
- * @return a result code to return from the calling MessageEncoder
- */
- virtual long sendError(std::istream& inputStream)=0;
-
- /**
- * Sends a completed response to the client.
- *
- * @param inputStream reference to source of response data
- * @param status transport-specific status to return
- * @return a result code to return from the calling MessageEncoder
- */
- virtual long sendResponse(std::istream& inputStream, long status)=0;
- };
-};
-
-#endif /* __shibsp_genres_h__ */
diff --git a/shibsp/io/HTTPRequest.h b/shibsp/io/HTTPRequest.h
index 3492a742..643cb7d0 100644
--- a/shibsp/io/HTTPRequest.h
+++ b/shibsp/io/HTTPRequest.h
@@ -21,7 +21,7 @@
#ifndef __shibsp_httpreq_h__
#define __shibsp_httpreq_h__
-#include <shibsp/io/GenericRequest.h>
+#include <shibsp/base.h>
#include <map>
@@ -37,19 +37,124 @@ namespace shibsp {
*
* <p>To supply information from the surrounding web server environment,
* a shim must be supplied in the form of this interface to adapt the
- * library to different proprietary server APIs.</p>
+ * library to different proprietary server APIs. Typically this
+ * is done via implementation of SPRequest.</p>
*
* <p>This interface need not be threadsafe.</p>
*/
- class SHIBSP_API HTTPRequest : public GenericRequest {
+ class SHIBSP_API HTTPRequest {
+ MAKE_NONCOPYABLE(HTTPRequest);
protected:
HTTPRequest();
public:
virtual ~HTTPRequest();
- bool isSecure() const;
- bool isDefaultPort() const;
-
+ /**
+ * Returns the URL scheme of the request (http, https, ftp, ldap, etc.)
+ *
+ * @return the URL scheme
+ */
+ virtual const char* getScheme() const=0;
+
+ /**
+ * Returns true iff the request is over a confidential channel.
+ *
+ * @return confidential channel indicator
+ */
+ virtual bool isSecure() const;
+
+ /**
+ * Returns hostname of service that received request.
+ *
+ * @return hostname of service
+ */
+ virtual const char* getHostname() const=0;
+
+ /**
+ * Returns incoming port.
+ *
+ * @return incoming port
+ */
+ virtual int getPort() const=0;
+
+ /**
+ * Returns true iff the request port is the default port for the request protocol.
+ *
+ * @return default port indicator
+ */
+ virtual bool isDefaultPort() const;
+
+ /**
+ * Returns the MIME type of the request, if known.
+ *
+ * @return the MIME type, or an empty string
+ */
+ virtual std::string getContentType() const=0;
+
+ /**
+ * Returns the length of the request body, if known.
+ *
+ * @return the content length, or -1 if unknown
+ */
+ virtual long getContentLength() const=0;
+
+ /**
+ * Returns the raw request body.
+ *
+ * @return the request body, or nullptr
+ */
+ virtual const char* getRequestBody() const=0;
+
+ /**
+ * Returns a decoded named parameter value from the request.
+ * If a parameter has multiple values, only one will be returned.
+ *
+ * @param name the name of the parameter to return
+ * @return a single parameter value or nullptr
+ */
+ virtual const char* getParameter(const char* name) const=0;
+
+ /**
+ * Returns all of the decoded values of a named parameter from the request.
+ * All values found will be returned.
+ *
+ * @param name the name of the parameter to return
+ * @param values a vector in which to return pointers to the decoded values
+ * @return the number of values returned
+ */
+ virtual std::vector<const char*>::size_type getParameters(
+ const char* name, std::vector<const char*>& values
+ ) const=0;
+
+ /**
+ * Returns the transport-authenticated identity associated with the request,
+ * if authentication is solely handled by the transport.
+ *
+ * @return the authenticated username or an empty string
+ */
+ virtual std::string getRemoteUser() const=0;
+
+ /**
+ * Gets the authentication type associated with the request.
+ *
+ * @return the authentication type or nullptr
+ */
+ virtual std::string getAuthType() const=0;
+
+ /**
+ * Returns the IP address of the client.
+ *
+ * @return the client's IP address
+ */
+ virtual std::string getRemoteAddr() const=0;
+
+ /**
+ * Returns the IP address of the server.
+ *
+ * @return the server's IP address
+ */
+ virtual std::string getLocalAddr() const=0;
+
/**
* Returns the HTTP method of the request (GET, POST, etc.)
*
diff --git a/shibsp/io/HTTPResponse.h b/shibsp/io/HTTPResponse.h
index e215f860..af664dc3 100644
--- a/shibsp/io/HTTPResponse.h
+++ b/shibsp/io/HTTPResponse.h
@@ -21,7 +21,7 @@
#ifndef __shibsp_httpres_h__
#define __shibsp_httpres_h__
-#include <shibsp/io/GenericResponse.h>
+#include <shibsp/base.h>
#include <string>
#include <vector>
@@ -38,38 +38,63 @@ namespace shibsp {
*
* <p>To supply information to the surrounding web server environment,
* a shim must be supplied in the form of this interface to adapt the
- * library to different proprietary server APIs.</p>
+ * library to different proprietary server APIs. Typically this
+ * is done via implementation of SPRequest.</p>
*
* <p>This interface need not be threadsafe.</p>
*/
- class SHIBSP_API HTTPResponse : public GenericResponse {
+ class SHIBSP_API HTTPResponse {
+ MAKE_NONCOPYABLE(HTTPResponse);
protected:
HTTPResponse();
public:
virtual ~HTTPResponse();
- void setContentType(const char* type);
-
/**
* Sets, adds, or clears a response header.
*
+ * <p>The default implementation polices name and value for control characters.</p>
+ *
* @param name header name
* @param value value to set, or nullptr to clear
* @param replace true iff this should replace existing header(s)
*/
virtual void setResponseHeader(const char* name, const char* value, bool replace = false);
+ /**
+ * Sets or clears the MIME type of the response.
+ *
+ * @param type the MIME type, or nullptr to clear
+ */
+ virtual void setContentType(const char* type=nullptr);
+
+ /**
+ * Sends a completed response to the client.
+ *
+ * @param inputStream reference to source of response data
+ * @param status transport-specific status to return
+ * @return a result code to return from the calling MessageEncoder
+ */
+ virtual long sendResponse(std::istream& inputStream, long status=SHIBSP_HTTP_STATUS_OK)=0;
+
+ /**
+ * Sends an "error" response to the client along with a
+ * transport-specific error indication.
+ *
+ * @param inputStream reference to source of response data
+ * @return a result code to return from the calling MessageEncoder
+ */
+ virtual long sendError(std::istream& inputStream);
+
/**
* Redirect the client to the specified URL and complete the response.
*
* <p>Any headers previously set will be sent ahead of the redirect.
*
- * <p>The URL will be validated with the sanitizeURL method below.
- *
* @param url location to redirect client
* @return a result code to return
*/
- virtual long sendRedirect(const char* url);
+ virtual long sendRedirect(const char* url)=0;
/** Some common HTTP status codes. */
enum status_t {
@@ -82,31 +107,6 @@ namespace shibsp {
SHIBSP_HTTP_STATUS_NOTFOUND = 404,
SHIBSP_HTTP_STATUS_ERROR = 500
};
-
- long sendError(std::istream& inputStream);
-
- using GenericResponse::sendResponse;
- long sendResponse(std::istream& inputStream);
-
- /**
- * Returns a modifiable array of schemes to permit in sanitized URLs.
- *
- * <p>Updates to this array must be externally synchronized with any use
- * of this class or its subclasses.
- *
- * @return a mutable array of strings containing the schemes to permit
- */
- static std::vector<std::string>& getAllowedSchemes();
-
- /**
- * Manually check for unsafe URLs vulnerable to injection attacks.
- *
- * @param url location to check
- */
- static void sanitizeURL(const char* url);
-
- private:
- static std::vector<std::string> m_allowedSchemes;
};
#if defined (_MSC_VER)
diff --git a/shibsp/io/impl/HTTPRequest.cpp b/shibsp/io/impl/HTTPRequest.cpp
index 10a09a6f..cdf78739 100644
--- a/shibsp/io/impl/HTTPRequest.cpp
+++ b/shibsp/io/impl/HTTPRequest.cpp
@@ -29,33 +29,6 @@
using namespace shibsp;
using namespace std;
-GenericRequest::GenericRequest()
-{
-}
-
-GenericRequest::~GenericRequest()
-{
-}
-
-bool GenericRequest::isDefaultPort() const
-{
- return false;
-}
-
-void GenericRequest::absolutize(string& url) const
-{
- if (url.empty())
- url = '/';
- if (url[0] == '/') {
- // Compute a URL to the root of the site.
- const char* scheme = getScheme();
- string root = string(scheme) + "://" + getHostname();
- if (!isDefaultPort())
- root += ":" + boost::lexical_cast<string>(getPort());
- url = root + url;
- }
-}
-
HTTPRequest::HTTPRequest()
{
}
diff --git a/shibsp/io/impl/HTTPResponse.cpp b/shibsp/io/impl/HTTPResponse.cpp
index 1db1c566..f2986e9e 100644
--- a/shibsp/io/impl/HTTPResponse.cpp
+++ b/shibsp/io/impl/HTTPResponse.cpp
@@ -32,43 +32,6 @@
using namespace shibsp;
using namespace std;
-GenericResponse::GenericResponse()
-{
-}
-
-GenericResponse::~GenericResponse()
-{
-}
-
-vector<string> HTTPResponse::m_allowedSchemes;
-
-vector<string>& HTTPResponse::getAllowedSchemes()
-{
- return m_allowedSchemes;
-}
-
-void HTTPResponse::sanitizeURL(const char* url)
-{
- const char* ch;
- for (ch=url; *ch; ++ch) {
- if (iscntrl((unsigned char)(*ch))) // convert to unsigned to allow full range from 00-FF
- throw domain_error("URL contained a control character.");
- }
-
- ch = strchr(url, ':');
- if (!ch)
- throw domain_error("URL is missing a colon where expected; improper URL encoding?");
- string s(url, ch - url);
-
- for (const string& scheme : m_allowedSchemes) {
- if (strcasecmp(s.c_str(), scheme.c_str()) == 0) {
- return;
- }
- }
-
- throw domain_error("URL contains invalid scheme.");
-}
-
HTTPResponse::HTTPResponse()
{
}
@@ -99,18 +62,7 @@ void HTTPResponse::setResponseHeader(const char* name, const char* value, bool)
}
}
-long HTTPResponse::sendRedirect(const char* url)
-{
- sanitizeURL(url);
- return SHIBSP_HTTP_STATUS_MOVED;
-}
-
long HTTPResponse::sendError(istream& inputStream)
{
return sendResponse(inputStream, SHIBSP_HTTP_STATUS_ERROR);
}
-
-long HTTPResponse::sendResponse(istream& inputStream)
-{
- return sendResponse(inputStream, SHIBSP_HTTP_STATUS_OK);
-}
diff --git a/tests/DummyRequest.h b/tests/DummyRequest.h
index bc0773c7..c0b1dad8 100644
--- a/tests/DummyRequest.h
+++ b/tests/DummyRequest.h
@@ -46,6 +46,7 @@ namespace shibsp {
std::string getRemoteAddr() const { return m_addr; }
std::string getLocalAddr() const { return ""; }
std::string getAuthType() const { return ""; }
+ long sendRedirect(const char* url) { return SHIBSP_HTTP_STATUS_MOVED; }
long sendResponse(std::istream&, long status) { return status; }
void clearHeader(const char* name) {}
void setHeader(const char* name, const char* value) {}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list