author | Michael Krelin <hacker@klever.net> | 2005-01-29 20:14:37 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2005-01-29 20:14:37 (UTC) |
commit | ff4b919683537625f693eedf53006364d0f8444d (patch) (side-by-side diff) | |
tree | 4c19e38c0832b16b4ca98ae5af6542d932373eb1 /src | |
parent | f9a64a67c89a7566e63ed66c3a69c359abea4dfd (diff) | |
download | kingate-0.0.zip kingate-0.0.tar.gz kingate-0.0.tar.bz2 |
initial commit into repository0.0
-rw-r--r-- | src/.gitignore | 7 | ||||
-rw-r--r-- | src/Makefile.am | 15 | ||||
-rw-r--r-- | src/cgi_gateway.cc | 88 | ||||
-rw-r--r-- | src/cgi_interface.cc | 16 | ||||
-rw-r--r-- | src/fastcgi.cc | 67 | ||||
-rw-r--r-- | src/util.cc | 53 |
6 files changed, 246 insertions, 0 deletions
diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..af4f4dd --- a/dev/null +++ b/src/.gitignore @@ -0,0 +1,7 @@ +Makefile.in +.deps +Makefile +.libs +*.o +*.lo +*.la diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..8a5447b --- a/dev/null +++ b/src/Makefile.am @@ -0,0 +1,15 @@ +lib_LTLIBRARIES = libkingate.la libkingate-fcgi.la + +INCLUDES = -I${top_srcdir}/include +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_fcgi_la_SOURCES = \ + fastcgi.cc +libkingate_fcgi_la_LDFLAGS = -version-info 1:0:0 diff --git a/src/cgi_gateway.cc b/src/cgi_gateway.cc new file mode 100644 index 0000000..eae7a03 --- a/dev/null +++ b/src/cgi_gateway.cc @@ -0,0 +1,88 @@ +#include "kingate/cgi_gateway.h" +#include "kingate/util.h" +#include "kingate/exception.h" + +namespace kingate { + + 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"); + parse_query(qs,get); + } + // Fetch POST content + if(!strcasecmp(get_content_type().c_str(),"application/x-www-form-urlencoded")) { + unsigned long cl = get_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 { + 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 { + 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 { + 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"); + } + + const string& cgi_gateway::get_content_type() const { + if(!has_meta("CONTENT_TYPE")) + return ""; // XXX: + 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); + } + + 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))); + }else{ + p.insert(params_t::value_type(url_unescape(pp.substr(0,eq)),url_unescape(pp.substr(eq+1)))); + } + } + } + +} diff --git a/src/cgi_interface.cc b/src/cgi_interface.cc new file mode 100644 index 0000000..ffbd2bf --- a/dev/null +++ b/src/cgi_interface.cc @@ -0,0 +1,16 @@ +#include "kingate/cgi_interface.h" +#include "kingate/exception.h" + +namespace kingate { + + bool cgi_interface::has_meta(const string& n) const { + return metavars.find(n) != metavars.end(); + } + const string& cgi_interface::get_meta(const string& n) const { + metavars_t::const_iterator rv = metavars.find(n); + if(rv == metavars.end()) + throw exception_notfound(CODEPOINT,"no such meta-variable"); + return rv->second; + } + +} diff --git a/src/fastcgi.cc b/src/fastcgi.cc new file mode 100644 index 0000000..7484449 --- a/dev/null +++ b/src/fastcgi.cc @@ -0,0 +1,67 @@ +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "kingate/fastcgi.h" +#include "kingate/exception.h" + +namespace kingate { + + bool fcgi_socket::_initialized = false; + + fcgi_socket::fcgi_socket(const char *s,int bl) + : sock(-1) { + if(!_initialized) { + if( FCGX_Init() ) + throw exception(CODEPOINT,"failed to FCGX_Init()"); + _initialized = true; + } + sock = FCGX_OpenSocket(s,bl); + if(sock<0) + throw exception(CODEPOINT,"failed to FCGX_OpenSocket("); + // TODO: check if there is a ':', not if it starts with ':' + if(*s != ':') + if(chmod(s,0777)) // XXX: configurable. + throw exception(CODEPOINT,"failed to chmod()"); + } + fcgi_socket::fcgi_socket(int s) + : sock(0) { + if(!_initialized) { + if( FCGX_Init() ) + throw exception(CODEPOINT,"failed to FCGX_Init()"); + _initialized = true; + } + } + fcgi_socket::~fcgi_socket() { + if(sock>=0) + close(sock); + } + + fcgi_interface::fcgi_interface(fcgi_socket& s,int f) + : sin(&sbin), sout(&sbout), serr(&sberr) { + if( FCGX_InitRequest(&request,s.sock,f) ) + throw exception(CODEPOINT,"failed to FCGX_InitRequest()"); + if( FCGX_Accept_r(&request) ) + throw exception(CODEPOINT,"failed to FCGX_Accept_r()"); + sbin.attach(request.in); + sbout.attach(request.out); + sberr.attach(request.err); + metavars.clear(); // XXX: redundant. + for(char **p = request.envp; *p; p++) { + const char *e = strchr(*p,'='); + if(!e){ + // XXX: check if we have it already? + metavars[*p] = string(0); + }else{ + int l = e-*p; e++; + // XXX: check if we have it already? + metavars[string(*p,l)]=e; + } + } + } + fcgi_interface::~fcgi_interface() { + sout.flush(); + serr.flush(); + FCGX_Finish_r(&request); + } + +} diff --git a/src/util.cc b/src/util.cc new file mode 100644 index 0000000..2e2d305 --- a/dev/null +++ b/src/util.cc @@ -0,0 +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 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 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; + } +} |