summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/kingate/cgi_gateway.h117
-rw-r--r--include/kingate/exception.h9
-rw-r--r--include/kingate/util.h35
-rw-r--r--src/Makefile.am2
-rw-r--r--src/cgi_gateway.cc175
-rw-r--r--src/util.cc4
6 files changed, 316 insertions, 26 deletions
diff --git a/include/kingate/cgi_gateway.h b/include/kingate/cgi_gateway.h
index f683580..a5c4056 100644
--- a/include/kingate/cgi_gateway.h
+++ b/include/kingate/cgi_gateway.h
@@ -1,164 +1,269 @@
#ifndef __KINGATE_CGI_GATEWAY_H
#define __KINGATE_CGI_GATEWAY_H
#include <map>
#include "kingate/cgi_interface.h"
+#ifndef __deprecated
+#if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3
+#define __deprecated __attribute__((deprecated))
+#else
+#define __deprecated
+#endif
+#endif
+
/**
* @file
* @brief the cgi_gateway -- main interface to CGI.
*/
namespace kingate {
using namespace std;
/**
* The main class interfacing with the CGI environment.
*/
class cgi_gateway {
public:
/**
* The interface to CGI environment (e.g. fastcgi).
*/
cgi_interface& iface;
/**
* The type describing map holding parameters parsed from query string or input.
*/
typedef multimap<string,string> params_t;
/**
* The GET-passed parameters.
*/
params_t get;
/**
* The POST-passed parameters.
*/
params_t post;
/**
* Was the stdin content parsed?
*/
bool b_parsed_content;
/**
* @param ci the interface to use.
*/
cgi_gateway(cgi_interface& ci);
/**
* Check whether there is an 'environment' meta-variable with specific name
* passed to CGI.
* @param n variable name.
* @return true if yes.
* @see cgi_interface::has_meta()
* @see get_meta()
*/
bool has_meta(const string& n) const { return iface.has_meta(n); }
/**
* Retrieve the 'environment' meta-variable value.
* @param n variable name.
* @return variable contents.
* @see exception_notfound
* @see cgi_interface::get_meta()
*/
- string get_meta(const string& n) const { return iface.get_meta(n); }
+ const string& get_meta(const string& n) const { return iface.get_meta(n); }
/**
* fetch reference to the 'stdin' stream.
* @return the reference to the corresponding istream object.
* @see cgi_interface::in()
*/
istream& in() { return iface.in(); }
/**
* fetch reference to the 'stdout' stream.
* @return the reference to the corresponding ostream object.
* @see cgi_interface::out()
*/
ostream& out() { return iface.out(); }
/**
* fetch reference to the 'stderr' stream.
* @return the reference to the corresponding ostream object.
* @see cgi_interface::err()
*/
ostream& err() { return iface.err(); }
/**
* cast to the ostream -- fetches the reference to the 'stdout'
* stream.
* @see out()
*/
operator ostream& (void) { return out(); }
/**
* Check to see whether the parameter was passed via GET.
* @param n the parameter name.
* @return true if yes.
*/
bool has_GET(const string& n) const;
/**
* Retrieve the parameter passed via GET.
* @param n the parameter name.
* @return the parameter contents.
* @see exception_notfound
*/
- string get_GET(const string& n) const;
+ const string& get_GET(const string& n) const;
/**
* Check to see whether the parameter was passed via POST.
* @param n the parameter name.
* @return true if yes.
*/
bool has_POST(const string& n) const;
/**
* Retrieve the POST-parameter.
* @param n the parameter name.
* @return the parameter contents.
* @see exception_notfound
*/
- string get_POST(const string& n) const;
+ const string& get_POST(const string& n) const;
/**
* Check to see whether the parameter was passed either via POST or
* GET.
* @param n the parameter name.
* @return true if yes.
*/
bool has_param(const string& n) const;
/**
* Retrieve the parameter passed either via POST or GET
* (GET-parameter takes precedence).
* @param n the parameter name.
* @return true if yes.
* @see exception_notfound.
*/
- string get_param(const string& n) const;
+ const string& get_param(const string& n) const;
/**
* Retrieve the POST content-type (as passed via CONTENT_TYPE
* environment variable).
* @return the content type.
*/
- const string& get_content_type() const;
+ const string& __deprecated get_content_type() const;
/**
* Retrieve the POST content length (as passed via the
* CONTENT_LENGTH environment variable).
* @return the content length.
*/
- unsigned long get_content_length() const;
+ unsigned long __deprecated get_content_length() const;
/**
* Check to see whether the content from stdin stream was parsed.
* @return true if yes.
*/
bool is_content_parsed() const { return b_parsed_content; }
+
+ /**
+ * Retrieve the HTTP header value from the HTTP_ meta-variable.
+ * (see RFC3875)
+ * @param hn header field name.
+ * @return the HTTP header value.
+ */
+ const string& http_request_header(const string& hn) const;
+
+ /**
+ * Retrieve the AUTH_TYPE meta-variable (see RFC3875)
+ * @return authentication type.
+ */
+ const string& auth_type() const;
+ /**
+ * Retrieve the CONTENT_LENGTH meta-variable (see RFC3875)
+ * @return size of the request message body.
+ */
+ unsigned long cgi_gateway::content_length() const;
+ /**
+ * Retrieve the CONTENT_TYPE meta-variable (see RFC3875)
+ * @return media type of the request message body.
+ */
+ const string& content_type() const;
+ /**
+ * Retrieve the GATEWAY_INTERFACE meta-variable (see RFC3875)
+ * @return the gateway interface dialect.
+ */
+ const string& gateway_interface() const;
+ /**
+ * Retrieve the PATH_INFO meta-variable (see RFC3875)
+ * @return path to be interpreted by the script.
+ */
+ const string& path_info() const;
+ /**
+ * Retrieve the PATH_TRANSLATED meta-variable (see RFC3875)
+ * @return the translated path to the document.
+ */
+ const string& path_translated() const;
+ /**
+ * Retrieve the QUERY_STRING meta-variable (see RFC3875)
+ * @return the query string.
+ */
+ const string& query_string() const;
+ /**
+ * Retrieve the REMOTE_ADDR meta-variable (see RFC3875)
+ * @return the network address of the remote host.
+ */
+ const string& remote_addr() const;
+ /**
+ * Retrieve the REMOTE_HOST meta-variable (see RFC3875)
+ * @return the fully qualified domain name of the client if
+ * available. REMOTE_ADDR otherwise.
+ * @see remote_addr()
+ */
+ const string& remote_host() const;
+ /**
+ * Retrieve the REMOTE_IDENT meta-variable (see RFC3875)
+ * @return remote user identity (see RFC1413).
+ */
+ const string& remote_ident() const;
+ /**
+ * Retrieve the REMOTE_USER meta-variable (see RFC3875)
+ * @return the authenticated user name.
+ */
+ const string& remote_user() const;
+ /**
+ * Retrieve the REQUEST_METHOD meta-variable (see RFC3875)
+ * @return the http request method.
+ */
+ const string& request_method() const;
+ /**
+ * Retrieve the SCRIPT_NAME meta-variable (see RFC3875)
+ * @return the uri path identifying the script.
+ */
+ const string& script_name() const;
+ /**
+ * Retrieve the SERVER_NAME meta-variable (see RFC3875)
+ * @return the server name of the script.
+ */
+ const string& server_name() const;
+ /**
+ * Retrieve the SERVER_PORT meta-variable (see RFC3875)
+ * @return the port on which request was received.
+ */
+ unsigned int server_port() const;
+ /**
+ * Retrieve the SERVER_PROTOCOL meta-variable (see RFC3875)
+ * @return the protocol used for the request.
+ */
+ const string& server_protocol() const;
+ /**
+ * Retrieve the SERVER_SOFTWARE meta-variable (see RFC3875)
+ * @return the name and version of server software.
+ */
+ const string& server_software() const;
+
private:
/**
* Parse the query string, putting the parameters into the map
* specified.
* @param q the query string.
* @param p destination parameters map.
*/
static void parse_query(string& q,params_t& p);
};
}
#endif /* __KINGATE_CGI_GATEWAY_H */
/*
* vim:set ft=cpp:
*/
diff --git a/include/kingate/exception.h b/include/kingate/exception.h
index 6ebb361..85d89ea 100644
--- a/include/kingate/exception.h
+++ b/include/kingate/exception.h
@@ -1,44 +1,53 @@
#ifndef __KINGATE_EXCEPTION_H
#define __KINGATE_EXCEPTION_H
#include <stdexcept>
#include <konforka/exception.h>
/**
* @file
* @brief The kingate-specific exceptions.
*/
/**
* @brief the main kingate namespace.
*/
namespace kingate {
using namespace std;
/**
* The base for kingate-specific exception.
*/
class exception : public konforka::exception {
public:
explicit exception(const string& w)
: konforka::exception(NOCODEPOINT,w) { }
exception(const string& fi,const string& fu,int l,const string &w)
: konforka::exception(fi,fu,l,w) { }
};
/**
* Thrown if the specified variable or parameter wasn't found.
*/
class exception_notfound : public exception {
public:
explicit exception_notfound(const string& w)
: exception(w) { }
exception_notfound(const string& fi,const string& fu,int l,const string& w)
: exception(fi,fu,l,w) { }
};
+
+ /**
+ * Thrown in case of unexpected server behaviour.
+ */
+ class server_error : public exception {
+ public:
+ server_error(const string& fi,const string& fu,int l,const string& w)
+ : exception(fi,fu,l,w) { }
+ };
}
#endif /* __KINGATE_EXCEPTION_H */
/*
* vim:set ft=cpp:
*/
diff --git a/include/kingate/util.h b/include/kingate/util.h
index 4b0dca8..6024ccf 100644
--- a/include/kingate/util.h
+++ b/include/kingate/util.h
@@ -1,26 +1,49 @@
#ifndef __KINGATE_UTIL_H
#define __KINGATE_UTIL_H
#include <string>
+#ifndef __deprecated
+#if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3
+#define __deprecated __attribute__((deprecated))
+#else
+#define __deprecated
+#endif
+#endif
+
namespace kingate {
using namespace std;
/**
- * Escape string for passing via URL.
- * @param str string unescaped.
- * @return the escaped string.
+ * Encode string for passing via URL.
+ * @param str string unencoded.
+ * @return the encoded string.
*/
- string url_escape(const string& str);
+ string url_encode(const string& str);
/**
* Remove URL-encoding from the string.
* @param str the URL-encoded string.
- * @return the unescaped string.
+ * @return the decoded string.
+ */
+ string url_decode(const string& str);
+
+ /**
+ * deprecated alias to url_encode.
+ * @see url_encode
+ */
+ inline string __deprecated url_escape(const string& str) {
+ return url_encode(str);
+ }
+ /**
+ * deprecated alias to url_decode.
+ * @see url_decode
*/
- string url_unescape(const string& str);
+ inline string __deprecated url_unescape(const string& str) {
+ return url_decode(str);
+ }
}
#endif /* __KINGATE_UTIL_H */
/*
* vim:set ft=cpp:
*/
diff --git a/src/Makefile.am b/src/Makefile.am
index d516d37..12bb1f8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,25 +1,25 @@
lib_LTLIBRARIES = libkingate.la libkingate-plaincgi.la
if HAVE_FCGI
lib_LTLIBRARIES += libkingate-fcgi.la
endif
INCLUDES = -I${top_srcdir}/include -I${top_srcdir}
AM_CXXFLAGS = ${KONFORKA_CFLAGS}
LDADD = ${KONFORKA_LIBS}
libkingate_la_SOURCES = \
cgi_gateway.cc \
cgi_interface.cc \
util.cc
-libkingate_la_LDFLAGS = -version-info 1:0:0
+libkingate_la_LDFLAGS = -version-info 2:0:0
libkingate_fcgi_la_SOURCES = \
fastcgi.cc
libkingate_fcgi_la_LDFLAGS = -version-info 1:0:0
libkingate_plaincgi_la_SOURCES = \
plaincgi.cc
libkingate_plaincgi_la_LDFLAGS = -version-info 1:0:0
EXTRA_DIST = ${libkingate_fcgi_la_SOURCES}
diff --git a/src/cgi_gateway.cc b/src/cgi_gateway.cc
index eae7a03..30410f2 100644
--- a/src/cgi_gateway.cc
+++ b/src/cgi_gateway.cc
@@ -1,88 +1,241 @@
+#include <errno.h>
+#include <ctype.h>
#include "kingate/cgi_gateway.h"
#include "kingate/util.h"
#include "kingate/exception.h"
namespace kingate {
+ static string empty_string;
+
cgi_gateway::cgi_gateway(cgi_interface& ci)
: iface(ci), b_parsed_content(false) {
// Fetch GET content
- if(iface.has_meta("QUERY_STRING")) {
- string qs = iface.get_meta("QUERY_STRING");
+ try {
+ string qs = get_meta("QUERY_STRING");
parse_query(qs,get);
- }
+ }catch(exception_notfound& enf) { }
// Fetch POST content
- if(!strcasecmp(get_content_type().c_str(),"application/x-www-form-urlencoded")) {
- unsigned long cl = get_content_length();
+ if(!strcasecmp(content_type().c_str(),"application/x-www-form-urlencoded")) {
+ unsigned long cl = content_length();
if(cl) {
char * tmp = new char[cl];
iface.in().read(tmp,cl);
string qs(tmp,cl);
delete tmp;
parse_query(qs,post);
}
b_parsed_content = true;
}
}
bool cgi_gateway::has_GET(const string& n) const {
return get.find(n) != get.end();
}
- string cgi_gateway::get_GET(const string& n) const {
+ const string& cgi_gateway::get_GET(const string& n) const {
params_t::const_iterator i = get.find(n);
if(i==get.end())
throw exception_notfound(CODEPOINT,"no such parameter");
return i->second;
}
bool cgi_gateway::has_POST(const string& n) const {
return post.find(n) != post.end();
}
- string cgi_gateway::get_POST(const string& n) const {
+ const string& cgi_gateway::get_POST(const string& n) const {
params_t::const_iterator i = post.find(n);
if(i==post.end())
throw exception_notfound(CODEPOINT,"no such parameter");
return i->second;
}
bool cgi_gateway::has_param(const string& n) const {
return has_GET(n) || has_POST(n);
}
- string cgi_gateway::get_param(const string& n) const {
+ const string& cgi_gateway::get_param(const string& n) const {
params_t::const_iterator i = get.find(n);
if(i!=get.end())
return i->second;
i = post.find(n);
if(i!=post.end())
return i->second;
throw exception_notfound(CODEPOINT,"no such parameter");
}
+ /*
+ * deprecated stuff.
+ */
const string& cgi_gateway::get_content_type() const {
if(!has_meta("CONTENT_TYPE"))
- return ""; // XXX:
+ return empty_string;
return get_meta("CONTENT_TYPE");
}
unsigned long cgi_gateway::get_content_length() const {
if(!has_meta("CONTENT_LENGTH"))
return 0;
string cl = get_meta("CONTENT_LENGTH");
return strtol(cl.c_str(),NULL,10);
}
+ /*
+ *
+ */
+
+ const string& cgi_gateway::http_request_header(const string& hn) const {
+ string mvn = "HTTP_";
+ for(const char* p=hn.c_str();*p;p++) {
+ if(*p=='-')
+ mvn += '_';
+ else
+ mvn += toupper(*p);
+ }
+ return get_meta(mvn);
+ }
+
+ const string& cgi_gateway::auth_type() const {
+ try {
+ return get_meta("AUTH_TYPE");
+ }catch(exception_notfound& enf) {
+ return empty_string;
+ }
+ }
+ unsigned long cgi_gateway::content_length() const {
+ try {
+ const string& cl = get_meta("CONTENT_LENGTH");
+ errno = 0;
+ const char *clp = cl.c_str();
+ unsigned long rv = strtol(clp,(char**)&clp,10);
+ if(errno || *clp)
+ throw server_error(CODEPOINT,"Invalid CONTENT_LENGTH value passed from server");
+ return rv;
+ }catch(exception_notfound& enf) {
+ return 0;
+ }
+ }
+ const string& cgi_gateway::content_type() const {
+ try {
+ return get_meta("CONTENT_TYPE");
+ }catch(exception_notfound& enf) {
+ return empty_string;
+ }
+ }
+ const string& cgi_gateway::gateway_interface() const {
+ try {
+ return get_meta("GATEWAY_INTERFACE");
+ }catch(exception_notfound& enf) {
+ return empty_string;
+ }
+ }
+ const string& cgi_gateway::path_info() const {
+ try {
+ return get_meta("PATH_INFO");
+ }catch(exception_notfound& enf) {
+ return empty_string;
+ }
+ }
+ const string& cgi_gateway::path_translated() const {
+ try {
+ return get_meta("PATH_TRANSLATED");
+ }catch(exception_notfound& enf) {
+ return empty_string;
+ }
+ }
+ const string& cgi_gateway::query_string() const {
+ try {
+ return get_meta("QUERY_STRING");
+ }catch(exception_notfound& enf) {
+ return empty_string;
+ }
+ }
+ const string& cgi_gateway::remote_addr() const {
+ try {
+ return get_meta("REMOTE_ADDR");
+ }catch(exception_notfound& enf) {
+ return empty_string;
+ }
+ }
+ const string& cgi_gateway::remote_host() const {
+ try {
+ return get_meta("REMOTE_HOST");
+ }catch(exception_notfound& enf) {
+ return remote_addr();
+ }
+ }
+ const string& cgi_gateway::remote_ident() const {
+ try {
+ return get_meta("REMOTE_IDENT");
+ }catch(exception_notfound& enf) {
+ return empty_string;
+ }
+ }
+ const string& cgi_gateway::remote_user() const {
+ try {
+ return get_meta("REMOTE_USER");
+ }catch(exception_notfound& enf) {
+ return empty_string;
+ }
+ }
+ const string& cgi_gateway::request_method() const {
+ try {
+ return get_meta("REQUEST_METHOD");
+ }catch(exception_notfound& enf) {
+ throw server_error(CODEPOINT,"No REQUEST_METHOD passed from server");
+ }
+ }
+ const string& cgi_gateway::script_name() const {
+ try {
+ return get_meta("SCRIPT_NAME");
+ }catch(exception_notfound& enf) {
+ throw server_error(CODEPOINT,"No SCRIPT_NAME passed from server");
+ }
+ }
+ const string& cgi_gateway::server_name() const {
+ try {
+ return get_meta("SERVER_NAME");
+ }catch(exception_notfound& enf) {
+ throw server_error(CODEPOINT,"No SERVER_NAME passed from server");
+ }
+ }
+ unsigned int cgi_gateway::server_port() const {
+ try {
+ const string& sp = get_meta("SERVER_PORT");
+ errno = 0;
+ const char *spp = sp.c_str();
+ unsigned int rv = strtol(spp,(char**)&spp,10);
+ if(errno || *spp)
+ throw server_error(CODEPOINT,"Invalid SERVER_PORT value passed from server");
+ return rv;
+ }catch(exception_notfound& enf) {
+ throw server_error(CODEPOINT,"No SERVER_PORT passed from server");
+ }
+ }
+ const string& cgi_gateway::server_protocol() const {
+ try {
+ return get_meta("SERVER_PROTOCOL");
+ }catch(exception_notfound& enf) {
+ throw server_error(CODEPOINT,"No SERVER_PROTOCOL passed from server");
+ }
+ }
+ const string& cgi_gateway::server_software() const {
+ try {
+ return get_meta("SERVER_SOFTWARE");
+ }catch(exception_notfound& enf) {
+ throw server_error(CODEPOINT,"No SERVER_SOFTWARE passed from server");
+ }
+ }
void cgi_gateway::parse_query(string& q,params_t& p) {
while(!q.empty()) {
string::size_type amp = q.find('&');
string pp = (amp==string::npos)?q:q.substr(0,amp);
if(amp==string::npos)
q.clear();
else
q.erase(0,amp+1);
string::size_type eq = pp.find('=');
if(eq == string::npos) {
- p.insert(params_t::value_type("",url_unescape(pp)));
+ p.insert(params_t::value_type("",url_decode(pp)));
}else{
- p.insert(params_t::value_type(url_unescape(pp.substr(0,eq)),url_unescape(pp.substr(eq+1))));
+ p.insert(params_t::value_type(url_decode(pp.substr(0,eq)),url_decode(pp.substr(eq+1))));
}
}
}
}
diff --git a/src/util.cc b/src/util.cc
index 2e2d305..3166e62 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -1,53 +1,53 @@
#include "kingate/util.h"
#include "kingate/exception.h"
namespace kingate {
static const char *safeChars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"_-" ;
- string url_escape(const string& str) {
+ string url_encode(const string& str) {
string rv = str;
string::size_type screwed = 0;
for(;;) {
screwed = rv.find_first_not_of(safeChars,screwed);
if(screwed == string::npos)
break;
while(screwed<rv.length() && !strchr(safeChars,rv.at(screwed))) {
char danger = rv.at(screwed);
if(danger==' ') {
rv.replace(screwed++,1,1,'+');
}else{
static char tmp[4] = {'%',0,0,0};
snprintf(&tmp[1],3,"%02X",0xFF&(int)danger);
rv.replace(screwed,1,tmp,3);
screwed+=3;
}
}
}
return rv;
}
- string url_unescape(const string& str) {
+ string url_decode(const string& str) {
string rv = str;
string::size_type unscrewed = 0;
for(;;) {
unscrewed = rv.find_first_of("%+",unscrewed);
if(unscrewed == string::npos)
break;
if(rv.at(unscrewed)=='+') {
rv.replace(unscrewed++,1,1,' ');
}else{
if((rv.length()-unscrewed)<3)
throw exception(CODEPOINT,"incorrectly escaped string");
// XXX: ensure it's hex?
int danger = strtol(rv.substr(unscrewed+1,2).c_str(),NULL,16);
rv.replace(unscrewed,3,1,danger);
unscrewed++;
}
}
return rv;
}
}