#include #include #include #include #include "kingate/cgi_gateway.h" #include "kingate/util.h" #include "kingate/exception.h" #include "config.h" #ifdef HAVE_MIMETIC # include # include #endif /* HAVE_MIMETIC */ namespace kingate { #ifdef HAVE_MIMETIC using mimetic::MimeEntity; struct TornMimeEntity : public MimeEntity { typedef istreambuf_iterator it_type; typedef it_type::iterator_category it_cat; struct IParser : public mimetic::IteratorParser { typedef mimetic::IteratorParser BT; IParser(MimeEntity& me) : BT::IteratorParser(me) { } void loadHeader(it_type bit,it_type eit) { m_bit = bit; m_eit = eit; BT::loadHeader(); } void loadBody(it_type bit,it_type eit) { m_bit = bit; m_eit = eit; BT::loadBody(); } }; void load(istream& hs,istream& bs,int mask=0) { IParser prs(*this); prs.iMask(mask); prs.loadHeader(it_type(hs),it_type()); prs.loadBody(it_type(bs),it_type()); } }; #endif /* HAVE_MIMETIC */ static string empty_string; cgi_gateway::basic_file_t::~basic_file_t() { } class string_file_t : public cgi_gateway::basic_file_t { public: string _file_name; string _content_type; stringstream _content; string_file_t(const string& fn,const string& ct,const string& s) : _file_name(fn), _content_type(ct), _content(s,ios::in) { } const string& filename() const { return _file_name; } const string& content_type() const { return _content_type; } istream& content() { return _content; } }; cgi_gateway::cgi_gateway(cgi_interface& ci,bool parsebody) : iface(ci), b_parsed_content(false) { // Fetch GET content try { string qs = get_meta("QUERY_STRING"); parse_query(qs,get); }catch(exception_notfound& enf) { } if(parsebody) parse_request_body(); // Parse cookies try { cookies.parse_cookies(get_meta("HTTP_COOKIE")); }catch(exception_notfound& enf) { } } cgi_gateway::~cgi_gateway() throw() { for(files_t::iterator i=files.begin();i!=files.end();++i) delete i->second; files.clear(); } void cgi_gateway::parse_request_body() { if(b_parsed_content) throw konforka::exception(CODEPOINT,"request body is already parsed"); // Fetch POST content if(!strncasecmp( content_type().c_str(), "application/x-www-form-urlencoded", sizeof("application/x-www-form-urlencoded")-1) ) { 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; } #ifdef HAVE_MIMETIC else if(!strncasecmp( content_type().c_str(), "multipart/form-data", sizeof("multipart/form-data")-1) ) { stringstream h; h << "Content-Type: " << content_type() << "\r\n" << "Content-Length: " << content_length() << "\r\n\n"; TornMimeEntity me; me.load(h,iface.in(),0); mimetic::MimeEntityList& parts = me.body().parts(); for(mimetic::MimeEntityList::iterator i=parts.begin();i!=parts.end();++i) { MimeEntity *p = *i; const mimetic::ContentDisposition& cd = p->header().contentDisposition(); string n = cd.param("name"); string fn = cd.param("filename"); if(fn.empty()) { post.insert(params_t::value_type(n,p->body())); }else{ const mimetic::ContentType& ct = p->header().contentType(); files.insert(files_t::value_type(n,new string_file_t(fn,ct.str(),p->body()))); } } b_parsed_content = true; } #endif /* HAVE_MIMETIC */ } bool cgi_gateway::has_GET(const string& n) const { return get.find(n) != get.end(); } 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(); } 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); } 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"); } bool cgi_gateway::has_file(const string& n) const { return files.find(n) != files.end(); } const cgi_gateway::file_t cgi_gateway::get_file(const string& n) const { files_t::const_iterator i = files.find(n); if(i==files.end()) throw exception_notfound(CODEPOINT,"no such parameter"); return i->second; } cgi_gateway::file_t cgi_gateway::get_file(const string& n) { files_t::const_iterator i = files.find(n); if(i==files.end()) throw exception_notfound(CODEPOINT,"no such parameter"); return i->second; } /* * deprecated stuff. */ const string& cgi_gateway::get_content_type() const { if(!has_meta("CONTENT_TYPE")) 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_decode(pp))); }else{ p.insert(params_t::value_type(url_decode(pp.substr(0,eq)),url_decode(pp.substr(eq+1)))); } } } }