version 0.2.14
[fms.git] / src / http / ipagehandler.cpp
index d90a927..6edd8ac 100644 (file)
@@ -2,6 +2,8 @@
 #include "../../include/http/httpdefs.h"\r
 #include "../../include/stringfunctions.h"\r
 \r
+#include <cstring>\r
+\r
 #ifdef XMEM\r
        #include <xmem.h>\r
 #endif\r
@@ -12,7 +14,7 @@ void IPageHandler::CreateArgArray(const std::map<std::string,std::string> &vars,
        {\r
                if((*i).first.find(basename)==0 && (*i).first.find("[")!=std::string::npos && (*i).first.find("]")!=std::string::npos)\r
                {\r
-                       int index;\r
+                       int index=0;\r
                        std::string indexstr;\r
                        std::string::size_type startpos;\r
                        std::string::size_type endpos;\r
@@ -31,6 +33,28 @@ void IPageHandler::CreateArgArray(const std::map<std::string,std::string> &vars,
        }\r
 }\r
 \r
+const std::string IPageHandler::CreateTrueFalseDropDown(const std::string &name, const std::string &selected)\r
+{\r
+       std::string rval="";\r
+\r
+       rval+="<select name=\""+name+"\">";\r
+       rval+="<option value=\"true\"";\r
+       if(selected=="true")\r
+       {\r
+               rval+=" SELECTED";\r
+       }\r
+       rval+=">true</option>";\r
+       rval+="<option value=\"false\"";\r
+       if(selected=="false")\r
+       {\r
+               rval+=" SELECTED";\r
+       }\r
+       rval+=">false</option>";\r
+       rval+="</select>";\r
+\r
+       return rval;\r
+}\r
+\r
 const bool IPageHandler::Handle(shttpd_arg *arg)\r
 {\r
        const char *uri=shttpd_get_env(arg,"REQUEST_URI");\r
@@ -44,6 +68,28 @@ const bool IPageHandler::Handle(shttpd_arg *arg)
        if(uri && WillHandleURI(std::string(uri)))\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
@@ -60,7 +106,7 @@ const bool IPageHandler::Handle(shttpd_arg *arg)
                                        long len;\r
                                        StringFunctions::Convert(std::string(lenstr),len);\r
                                        mystate->m_indata=new char[len+1];\r
-                                       mystate->m_indata[len]=NULL;\r
+                                       mystate->m_indata[len]='\0';\r
                                        mystate->m_indatalen=len;\r
                                        mystate->m_indatapos=0;\r
                                }\r
@@ -81,32 +127,48 @@ const bool IPageHandler::Handle(shttpd_arg *arg)
                // 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
-                       //TODO parse POST data and any QUERY_STRING before generating page\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(mystate->m_indata)\r
+                       if(shttpd_get_header(arg,"Content-Type"))\r
                        {\r
-                               StringFunctions::Split(mystate->m_indata,"&",argparts);\r
+                               contenttype=shttpd_get_header(arg,"Content-Type");\r
                        }\r
-                       if(shttpd_get_env(arg,"QUERY_STRING"))\r
+                       \r
+                       if(contenttype.find("multipart/form-data")!=std::string::npos)\r
                        {\r
-                               StringFunctions::Split(shttpd_get_env(arg,"QUERY_STRING"),"&",argparts);\r
+                               HandleMultiPartData(contenttype,mystate->m_indata,mystate->m_indatalen,args);\r
                        }\r
-                       for(std::vector<std::string>::iterator argi=argparts.begin(); argi!=argparts.end(); argi++)\r
+                       else\r
                        {\r
-                               std::vector<std::string> parts;\r
-                               StringFunctions::Split((*argi),"=",parts);\r
-                               if(parts.size()>0)\r
+                               // split apart non-multipart POST\r
+                               if(mystate->m_indata)\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
+                                       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[1]=StringFunctions::Replace(parts[1],"+"," ");\r
-                                               args[StringFunctions::UriDecode(parts[0])]=StringFunctions::UriDecode(parts[1]);\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
@@ -153,3 +215,81 @@ const bool IPageHandler::Handle(shttpd_arg *arg)
                return false;\r
        }\r
 }\r
+\r
+void IPageHandler::HandleMultiPartData(const std::string &contenttypeheader, char *data, const long datalen, std::map<std::string,std::string> &args)\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
+\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
+\r
+               // split into parts separated by boundary\r
+               StringFunctions::Split(datastr,"--"+boundary+"\r\n",parts);\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
+\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
+\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
+{\r
+       // must do & first because all other elements have & in them!\r
+       std::string output=StringFunctions::Replace(input,"&","&amp;");\r
+       output=StringFunctions::Replace(output,"<","&lt;");\r
+       output=StringFunctions::Replace(output,">","&gt;");\r
+       output=StringFunctions::Replace(output,"\"","&quot;");\r
+       output=StringFunctions::Replace(output," ","&nbsp;");\r
+       return output;\r
+}\r