author | Michael Krelin <hacker@klever.net> | 2005-07-04 22:54:09 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2005-07-04 22:54:09 (UTC) |
commit | c5d7daf77e265b53951e1e2b09c51e2fba5e93dc (patch) (side-by-side diff) | |
tree | 2337ff96d85d8de6d25fbaed75eb9c0d71a1625d /src | |
parent | c8bcbfb951eec5fe14dac0b14f4faaf4a9f9f229 (diff) | |
download | kingate-c5d7daf77e265b53951e1e2b09c51e2fba5e93dc.zip kingate-c5d7daf77e265b53951e1e2b09c51e2fba5e93dc.tar.gz kingate-c5d7daf77e265b53951e1e2b09c51e2fba5e93dc.tar.bz2 |
1. awkward yet working support for POST file upload (requires mimetic)
2. support for NOT handling/parsing POSTed data (including application/x-www-form-urlencoded)
-rw-r--r-- | src/cgi_gateway.cc | 132 |
1 files changed, 119 insertions, 13 deletions
diff --git a/src/cgi_gateway.cc b/src/cgi_gateway.cc index ab48f78..1706679 100644 --- a/src/cgi_gateway.cc +++ b/src/cgi_gateway.cc @@ -1,161 +1,267 @@ #include <errno.h> #include <ctype.h> +#include <sstream> #include "kingate/cgi_gateway.h" #include "kingate/util.h" #include "kingate/exception.h" +#include "config.h" +#ifdef HAVE_MIMETIC +# include <mimetic/mimeentity.h> +# include <mimetic/parser/itparser.h> +#endif /* HAVE_MIMETIC */ namespace kingate { + using mimetic::MimeEntity; + +#ifdef HAVE_MIMETIC + struct TornMimeEntity : public MimeEntity { + typedef istreambuf_iterator<char> it_type; + typedef it_type::iterator_category it_cat; + struct IParser : public mimetic::IteratorParser<it_type,it_cat> { + typedef mimetic::IteratorParser<it_type,it_cat> BT; + IParser(MimeEntity& me) + : BT::IteratorParser<it_type,it_cat>(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::cgi_gateway(cgi_interface& ci) + 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) { } - // Fetch POST content - 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; - } + 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) { |