summaryrefslogtreecommitdiffabout
path: root/src
Side-by-side diff
Diffstat (limited to 'src') (more/less context) (show whitespace changes)
-rw-r--r--src/.gitignore7
-rw-r--r--src/Makefile.am15
-rw-r--r--src/cgi_gateway.cc88
-rw-r--r--src/cgi_interface.cc16
-rw-r--r--src/fastcgi.cc67
-rw-r--r--src/util.cc53
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;
+ }
+}