version 0.3.0
[fms.git] / src / http / ipagehandler.cpp
index 4874365..b8bef90 100644 (file)
@@ -1,6 +1,8 @@
 #include "../../include/http/ipagehandler.h"\r
-#include "../../include/http/httpdefs.h"\r
 #include "../../include/stringfunctions.h"\r
+#include "../../include/http/multipartparser.h"\r
+\r
+#include <Poco/Net/HTMLForm.h>\r
 \r
 #include <cstring>\r
 \r
@@ -55,232 +57,44 @@ const std::string IPageHandler::CreateTrueFalseDropDown(const std::string &name,
        return rval;\r
 }\r
 \r
-const bool IPageHandler::Handle(shttpd_arg *arg)\r
+void IPageHandler::CreateQueryVarMap(Poco::Net::HTTPServerRequest &request, std::map<std::string,std::string> &vars)\r
 {\r
-       const char *uri=shttpd_get_env(arg,"REQUEST_URI");\r
-       const char *method=shttpd_get_env(arg,"REQUEST_METHOD");\r
-       std::string methodstr="";\r
-       if(method)\r
+       for(Poco::Net::HTTPServerRequest::ConstIterator i=request.begin(); i!=request.end(); i++)\r
        {\r
-               methodstr=method;\r
+               vars[(*i).first]=(*i).second;\r
        }\r
 \r
-       if(uri && WillHandleURI(std::string(uri)))\r
+       // handle HTMLForm and multiparts\r
+       MultiPartParser mpp;\r
+       Poco::Net::HTMLForm form(request,request.stream(),mpp);\r
+       for(Poco::Net::HTMLForm::ConstIterator i=form.begin(); i!=form.end(); i++)\r
        {\r
-               httpstate *mystate=(httpstate *)arg->state;\r
-\r
-               // first check if there was a connection error - if so delete the input/output and state buffers and return immediately\r
-               if((arg->flags & SHTTPD_CONNECTION_ERROR)==SHTTPD_CONNECTION_ERROR)\r
-               {\r
-                       if(mystate && mystate->m_indata)\r
-                       {\r
-                               delete mystate->m_indata;\r
-                               mystate->m_indata=NULL;\r
-                       }\r
-                       if(mystate && mystate->m_outdata)\r
-                       {\r
-                               delete mystate->m_outdata;\r
-                               mystate->m_outdata=NULL;\r
-                       }\r
-                       if(mystate)\r
-                       {\r
-                               delete mystate;\r
-                               mystate=NULL;\r
-                       }\r
-                       return true;\r
-               }\r
-\r
-               // this is a new request - create a new arg object\r
-               if(arg->state==NULL)\r
-               {\r
-                       arg->state=new httpstate;\r
-                       memset(arg->state,0,sizeof(httpstate));\r
-                       mystate=(httpstate *)arg->state;\r
-\r
-                       // if post then create input buffer\r
-                       if(methodstr=="POST")\r
-                       {\r
-                               const char *lenstr=shttpd_get_header(arg,"Content-Length");\r
-                               if(lenstr)\r
-                               {\r
-                                       long len=0;\r
-                                       StringFunctions::Convert(std::string(lenstr),len);\r
-                                       mystate->m_indata=new char[len+1];\r
-                                       mystate->m_indata[len]='\0';\r
-                                       mystate->m_indatalen=len;\r
-                                       mystate->m_indatapos=0;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               // we have more POST data to get\r
-               if(arg->in.len>0)\r
-               {\r
-                       int pos=0;\r
-                       while(pos<arg->in.len)\r
-                       {\r
-                               mystate->m_indata[mystate->m_indatapos++]=arg->in.buf[pos++];\r
-                       }\r
-                       arg->in.num_bytes=arg->in.len;\r
-               }\r
-\r
-               // we have all POST data (or it was 0 to begin with) - generate the page\r
-               if(mystate->m_indatalen==mystate->m_indatapos && mystate->m_outdata==NULL)\r
-               {\r
-                       //parse POST data and any QUERY_STRING before generating page\r
-                       std::map<std::string,std::string> args;\r
-                       std::vector<std::string> argparts;\r
-                       std::string contenttype="";\r
-                       \r
-                       if(shttpd_get_header(arg,"Content-Type"))\r
-                       {\r
-                               contenttype=shttpd_get_header(arg,"Content-Type");\r
-                       }\r
-                       \r
-                       if(contenttype.find("multipart/form-data")!=std::string::npos)\r
-                       {\r
-                               HandleMultiPartData(contenttype,mystate->m_indata,mystate->m_indatalen,args);\r
-                       }\r
-                       else\r
-                       {\r
-                               // split apart non-multipart POST\r
-                               if(mystate->m_indata)\r
-                               {\r
-                                       StringFunctions::Split(mystate->m_indata,"&",argparts);\r
-                               }\r
-                               // split apart query string\r
-                               if(shttpd_get_env(arg,"QUERY_STRING"))\r
-                               {\r
-                                       StringFunctions::Split(shttpd_get_env(arg,"QUERY_STRING"),"&",argparts);\r
-                               }\r
-\r
-                               for(std::vector<std::string>::iterator argi=argparts.begin(); argi!=argparts.end(); argi++)\r
-                               {\r
-                                       std::vector<std::string> parts;\r
-                                       StringFunctions::Split((*argi),"=",parts);\r
-                                       if(parts.size()>0)\r
-                                       {\r
-                                               // replace + with space before UriDecoding\r
-                                               parts[0]=StringFunctions::Replace(parts[0],"+"," ");\r
-                                               args[StringFunctions::UriDecode(parts[0])];\r
-                                               if(parts.size()>1)\r
-                                               {\r
-                                                       // replace + with space before UriDecoding\r
-                                                       parts[1]=StringFunctions::Replace(parts[1],"+"," ");\r
-                                                       args[StringFunctions::UriDecode(parts[0])]=StringFunctions::UriDecode(parts[1]);\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-\r
-                       std::string page=GeneratePage(methodstr,args);\r
-                       mystate->m_outdata=new char[page.size()];\r
-                       memcpy(mystate->m_outdata,page.c_str(),page.size());\r
-                       mystate->m_outdatalen=page.size();\r
-                       mystate->m_outdatapos=0;\r
-               }\r
-\r
-               // if we have output data, push next block of data onto out buffer\r
-               if(mystate->m_outdata && mystate->m_outdatapos<mystate->m_outdatalen)\r
-               {\r
-                       int pos=0;\r
-                       while(mystate->m_outdatapos<mystate->m_outdatalen && pos<arg->out.len)\r
-                       {\r
-                               arg->out.buf[pos++]=mystate->m_outdata[mystate->m_outdatapos++];\r
-                       }\r
-                       arg->out.num_bytes=pos;\r
-               }\r
-\r
-               // if we have no more output data to send - delete the data pointers and set end of output flag\r
-               if(mystate->m_outdata && mystate->m_outdatapos==mystate->m_outdatalen)\r
-               {\r
-                       if(mystate->m_indata)\r
-                       {\r
-                               delete [] mystate->m_indata;\r
-                       }\r
-                       if(mystate->m_outdata)\r
-                       {\r
-                               delete [] mystate->m_outdata;\r
-                       }\r
-                       delete mystate;\r
-                       arg->state=NULL;\r
-\r
-                       arg->flags|=SHTTPD_END_OF_OUTPUT;\r
-               }\r
-\r
-               return true;\r
+               vars[(*i).first]=(*i).second;\r
        }\r
-       else\r
+\r
+       // get any multiparts\r
+       std::map<std::string,std::string> mpvars=mpp.GetVars();\r
+       for(std::map<std::string,std::string>::iterator i=mpvars.begin(); i!=mpvars.end(); i++)\r
        {\r
-               return false;\r
+               vars[(*i).first]=(*i).second;\r
        }\r
+\r
 }\r
 \r
-void IPageHandler::HandleMultiPartData(const std::string &contenttypeheader, char *data, const long datalen, std::map<std::string,std::string> &args)\r
+void IPageHandler::handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response)\r
 {\r
-       if(data)\r
-       {\r
-               std::string datastr(data,data+datalen);\r
-               std::vector<std::string> parts;\r
-               std::string boundary="";\r
-               std::string::size_type pos=contenttypeheader.find("boundary=");\r
+       m_log->trace("IPageHandler::handleRequest from "+request.clientAddress().toString());\r
 \r
-               // find boundary\r
-               if(pos!=std::string::npos)\r
-               {\r
-                       boundary=contenttypeheader.substr(pos+9);\r
-                       // strip off any " and ;\r
-                       boundary=StringFunctions::Replace(boundary,"\"","");\r
-                       boundary=StringFunctions::Replace(boundary,";","");\r
-               }\r
+       std::map<std::string,std::string> vars;\r
 \r
-               // split into parts separated by boundary\r
-               StringFunctions::Split(datastr,"--"+boundary+"\r\n",parts);\r
+       CreateQueryVarMap(request,vars);\r
 \r
-               // go through each part and get name=value\r
-               for(std::vector<std::string>::iterator i=parts.begin(); i!=parts.end(); i++)\r
-               {\r
-                       std::string data="";\r
-                       std::string name="";\r
+       response.setChunkedTransferEncoding(true);\r
+       response.setContentType("text/html");\r
 \r
-                       // find name\r
-                       pos=(*i).find("name=");\r
-                       if(pos!=std::string::npos)\r
-                       {\r
-                               std::string::size_type pos2=(*i).find(";",pos);\r
-                               if(pos2!=std::string::npos)\r
-                               {\r
-                                       name=(*i).substr(pos+5,pos2-(pos+5));\r
-                               }\r
-                               else\r
-                               {\r
-                                       pos2=(*i).find("\r\n",pos);\r
-                                       if(pos2!=std::string::npos)\r
-                                       {\r
-                                               name=(*i).substr(pos+5,pos2-(pos+5));\r
-                                       }\r
-                               }\r
+       std::ostream &ostr = response.send();\r
+       ostr << GeneratePage(request.getMethod(),vars);\r
 \r
-                               name=StringFunctions::Replace(name,"\"","");\r
-                       }\r
-\r
-                       // find header boundary\r
-                       pos=(*i).find("\r\n\r\n");\r
-                       if(pos!=std::string::npos)\r
-                       {\r
-                               data=(*i).substr(pos+4);\r
-                               // strip off final \r\n from data\r
-                               if(data.size()>2 && data.rfind("\r\n")==data.size()-2)\r
-                               {\r
-                                       data.erase(data.size()-2);\r
-                               }\r
-                       }\r
-                       if(name!="" && data!="")\r
-                       {\r
-                               args[name]=data;\r
-                       }\r
-               }\r
-       }\r
 }\r
 \r
 const std::string IPageHandler::SanitizeOutput(const std::string &input)\r