00001 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 #ifdef _MSC_VER
00034 #pragma warning(disable:4786)
00035 #endif
00036 #include "socket_include.h"
00037 #include "Parse.h"
00038 #include "IFile.h"
00039 #include "HttpdForm.h"
00040 #include "IFileUpload.h"
00041 #include "IStream.h"
00042 #include "File.h"
00043 #include <memory>
00044 
00045 #ifdef SOCKETS_NAMESPACE
00046 namespace SOCKETS_NAMESPACE {
00047 #endif
00048 
00049 #define TMPSIZE 32000
00050 #ifdef _DEBUG
00051 #define DEB(x) x
00052 #else
00053 #define DEB(x)
00054 #endif
00055 
00056 
00057 HttpdForm::HttpdForm(FILE *fil)
00058 {
00059         const char *r_m = getenv("REQUEST_METHOD");
00060         const char *q_s = getenv("QUERY_STRING");
00061         if (r_m && !strcasecmp(r_m, "post"))
00062         {
00063                 const char *c_t = getenv("CONTENT_TYPE");
00064                 const char *c_l = getenv("CONTENT_LENGTH");
00065                 if (c_t && c_l)
00066                 {
00067                         std::auto_ptr<IFile> p = std::auto_ptr<IFile>(new File(fil));
00068                         ParseFormData( p.get(), c_t, atoi(c_l) );
00069                 }
00070         }
00071         if (q_s && strlen(q_s))
00072         {
00073                 ParseQueryString(q_s, strlen(q_s));
00074         }
00075 }
00076 
00077 HttpdForm::HttpdForm(IFile *infil, const std::string& content_type, size_t content_length) : raw(false)
00078 , m_file_upload(NULL)
00079 , m_upload_stream(NULL)
00080 {
00081         ParseFormData(infil, content_type, content_length);
00082 }
00083 
00084 
00085 
00086 HttpdForm::HttpdForm(const std::string& buffer,size_t l) : raw(false)
00087 , m_file_upload(NULL)
00088 , m_upload_stream(NULL)
00089 {
00090         ParseQueryString(buffer, l);
00091 }
00092 
00093 void HttpdForm::ParseFormData(IFile *infil, const std::string& content_type, size_t content_length)
00094 {
00095         CGI *cgi = NULL;
00096         size_t extra = 2;
00097         int cl = (int)content_length;
00098 
00099         m_current = m_cgi.end();
00100 
00101         if (content_type.size() >= 19 && content_type.substr(0, 19) == "multipart/form-data")
00102         {
00103                 Parse pa(content_type,";=");
00104                 char *tempcmp = NULL;
00105                 size_t tc = 0;
00106                 size_t l = 0;
00107                 std::string str = pa.getword();
00108                 m_strBoundary = "";
00109                 while (!str.empty())
00110                 {
00111                         if (!strcmp(str.c_str(),"boundary"))
00112                         {
00113                                 m_strBoundary = pa.getword();
00114                                 l = m_strBoundary.size();
00115                                 tempcmp = new char[l + extra];
00116                         }
00117                         
00118                         str = pa.getword();
00119                 }
00120                 if (!m_strBoundary.empty())
00121                 {
00122                         std::string content_type;
00123                         std::string current_name;
00124                         std::string current_filename;
00125                         char *slask = new char[TMPSIZE];
00126                         infil -> fgets(slask, TMPSIZE);
00127                         cl -= (int)strlen(slask);
00128                         while (cl >= 0 && !infil -> eof())
00129                         {
00130                                 while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
00131                                 {
00132                                         slask[strlen(slask) - 1] = 0;
00133                                 }
00134                                 content_type = "";
00135                                 current_name = "";
00136                                 current_filename = "";
00137                                 if ((strstr(slask,m_strBoundary.c_str()) || strstr(m_strBoundary.c_str(),slask)) && strcmp(slask, m_strBoundary.c_str()))
00138                                 {
00139                                         m_strBoundary = slask;
00140                                         l = m_strBoundary.size();
00141                                         delete[] tempcmp;
00142                                         tempcmp = new char[l + extra];
00143                                 }
00144                                 if (!strcmp(slask, m_strBoundary.c_str()))
00145                                 {
00146                                         
00147                                         infil -> fgets(slask, TMPSIZE);
00148                                         cl -= (int)strlen(slask);
00149                                         while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
00150                                         {
00151                                                 slask[strlen(slask) - 1] = 0;
00152                                         }
00153                                         while (cl >= 0 && !infil -> eof() && *slask)
00154                                         {
00155                                                 Parse pa(slask,":");
00156                                                 std::string h = pa.getword();
00157                                                 std::string h2 = pa.getrest();
00158                                                 if (!strcasecmp(h.c_str(),"Content-type"))
00159                                                 {
00160                                                         Parse pa(h2, ";");
00161                                                         content_type = pa.getword();
00162                                                 }
00163                                                 else
00164                                                 if (!strcasecmp(h.c_str(),"Content-Disposition"))
00165                                                 {
00166                                                         Parse pa(h2, ";");
00167                                                         h = pa.getword();
00168                                                         if (!strcmp(h.c_str(),"form-data"))
00169                                                         {
00170                                                                 pa.EnableQuote(true);
00171                                                                 h = pa.getword();
00172                                                                 while (!h.empty())
00173                                                                 {
00174                                                                         Parse pa2(h,"=");
00175                                                                         std::string name = pa2.getword();
00176                                                                         h = pa2.getrest();
00177                                                                         if (!strcmp(name.c_str(),"name"))
00178                                                                         {
00179                                                                                 if (!h.empty() && h[0] == '"')
00180                                                                                 {
00181                                                                                         current_name = h.substr(1, h.size() - 2);
00182                                                                                 }
00183                                                                                 else
00184                                                                                 {
00185                                                                                         current_name = h;
00186                                                                                 }
00187                                                                         }
00188                                                                         else
00189                                                                         if (!strcmp(name.c_str(),"filename"))
00190                                                                         {
00191                                                                                 if (!h.empty() && h[0] == '"')
00192                                                                                 {
00193                                                                                         current_filename = h.substr(1, h.size() - 2);
00194                                                                                 }
00195                                                                                 else
00196                                                                                 {
00197                                                                                         current_filename = h;
00198                                                                                 }
00199                                                                                 size_t x = 0;
00200                                                                                 for (size_t i = 0; i < current_filename.size(); i++)
00201                                                                                 {
00202                                                                                         if (current_filename[i] == '/' || current_filename[i] == '\\')
00203                                                                                                 x = i + 1;
00204                                                                                 }
00205                                                                                 if (x)
00206                                                                                 {
00207                                                                                         current_filename = current_filename.substr(x);
00208                                                                                 }
00209                                                                         }
00210                                                                         h = pa.getword();
00211                                                                 }
00212                                                         }
00213                                                 }
00214                                                 
00215                                                 infil -> fgets(slask, TMPSIZE);
00216                                                 cl -= (int)strlen(slask);
00217                                                 while (strlen(slask) && (slask[strlen(slask) - 1] == 13 || slask[strlen(slask) - 1] == 10))
00218                                                 {
00219                                                         slask[strlen(slask) - 1] = 0;
00220                                                 }
00221                                         }
00222                                         
00223                                         if (current_filename.empty()) 
00224                                         {
00225                                                 std::string val;
00226                                                 infil -> fgets(slask, TMPSIZE);
00227                                                 cl -= (int)strlen(slask);
00228                                                 while (cl >= 0 && !infil -> eof() && strncmp(slask,m_strBoundary.c_str(),m_strBoundary.size() ))
00229                                                 {
00230                                                         val += slask;
00231                                                         infil -> fgets(slask, TMPSIZE);
00232                                                         cl -= (int)strlen(slask);
00233                                                 }
00234                                                 
00235                                                 while (!val.empty() && (val[val.size() - 1] == 13 || val[val.size() - 1] == 10))
00236                                                 {
00237                                                         val = val.substr(0,val.size() - 1);
00238                                                 }
00239                                                 cgi = new CGI(current_name, val);
00240                                                 m_cgi.push_back(cgi);
00241                                                 if (!cl)
00242                                                 {
00243                                                         break;
00244                                                 }
00245                                         }
00246                                         else 
00247                                         {
00248                                                 
00249                                                 IFile *fil = NULL;
00250                                                 int out = 0;
00251                                                 char c;
00252                                                 char fn[2000]; 
00253 #ifdef _WIN32
00254                                                 {
00255                                                         char tmp_path[2000];
00256                                                         ::GetTempPathA(2000, tmp_path);
00257                                                         if (tmp_path[strlen(tmp_path) - 1] != '\\')
00258                                                         {
00259 #ifdef __CYGWIN__
00260                                                                 strcat(tmp_path, "\\");
00261 #else
00262                                                                 strcat_s(tmp_path, sizeof(tmp_path), "\\");
00263 #endif
00264                                                         }
00265                                                         snprintf(fn,sizeof(fn),"%s%s",tmp_path,current_filename.c_str());
00266                                                 }
00267 #else
00268                                                 snprintf(fn,sizeof(fn),"/tmp/%s",current_filename.c_str());
00269 #endif
00270                                                 if (m_file_upload && !m_upload_stream)
00271                                                         m_upload_stream = &m_file_upload -> IFileUploadBegin(current_name, current_filename, content_type);
00272                                                 else
00273                                                 {
00274                                                         fil = new File;
00275                                                         if (!fil -> fopen(fn, "wb"))
00276                                                         {
00277                                                                 delete fil;
00278                                                                 fil = NULL;
00279                                                         }
00280                                                 }
00281                                                 if (fil || m_upload_stream)
00282                                                 {
00283                                                         infil -> fread(&c,1,1);
00284                                                         cl -= 1;
00285                                                         while (cl >= 0 && !infil -> eof())
00286                                                         {
00287                                                                 if (out)
00288                                                                 {
00289                                                                         if (m_upload_stream)
00290                                                                                 m_upload_stream -> IStreamWrite(&tempcmp[tc], 1);
00291                                                                         else
00292                                                                                 fil -> fwrite(&tempcmp[tc],1,1);
00293                                                                 }
00294                                                                 tempcmp[tc] = c;
00295                                                                 tc++;
00296                                                                 if (tc >= l + extra)
00297                                                                 {
00298                                                                         tc = 0;
00299                                                                         out = 1;
00300                                                                 }
00301                                                                 if (tc)
00302                                                                 {
00303                                                                         if (!strncmp(tempcmp + tc + extra, m_strBoundary.c_str(), l - tc) &&
00304                                                                                         !strncmp(tempcmp, m_strBoundary.c_str() + l - tc, tc))
00305                                                                         {
00306                                                                                 break;
00307                                                                         }
00308                                                                 }
00309                                                                 else
00310                                                                 {
00311                                                                         if (!strncmp(tempcmp + extra, m_strBoundary.c_str(), l))
00312                                                                         {
00313                                                                                 break;
00314                                                                         }
00315                                                                 }
00316                                                                 infil -> fread(&c,1,1);
00317                                                                 cl -= 1;
00318                                                         }
00319                                                         if (m_file_upload && m_upload_stream)
00320                                                         {
00321                                                                 m_file_upload -> IFileUploadEnd();
00322                                                                 m_upload_stream = NULL;
00323                                                         }
00324                                                         else
00325                                                         if (fil)
00326                                                         {
00327                                                                 fil -> fclose();
00328                                                                 delete fil;
00329                                                         }
00330 
00331                                                         cgi = new CGI(current_name,fn,fn);
00332                                                         m_cgi.push_back(cgi);
00333                                                 
00334 #if defined( _WIN32) && !defined(__CYGWIN__)
00335                                                         strcpy_s(slask, TMPSIZE, m_strBoundary.c_str());
00336 #else
00337                                                         strcpy(slask, m_strBoundary.c_str());
00338 #endif
00339                                                         size_t l = strlen(slask);
00340                                                         infil -> fgets(slask + l, TMPSIZE - (int)l); 
00341                                                         cl -= (int)strlen(slask + l);
00342                                                 }
00343                                                 else
00344                                                 {
00345                                                         
00346                                                         break;
00347                                                 }
00348                                                 if (!cl)
00349                                                 {
00350                                                         break;
00351                                                 }
00352                                         }
00353                                 }
00354                                 else
00355                                 {
00356                                         
00357                                         break;
00358                                 }
00359                         } 
00360                         delete[] slask;
00361                 } 
00362                 if (tempcmp)
00363                 {
00364                         delete[] tempcmp;
00365                 }
00366         } 
00367         else
00368         if (strstr(content_type.c_str(), "x-www-form-urlencoded"))
00369         {
00370                 bool got_name = false; 
00371                 int cl = (int)content_length;
00372                 char c,chigh,clow;
00373                 std::string slask;
00374                 m_current = m_cgi.end();
00375                 std::string name;
00376 
00377                 infil -> fread(&c,1,1);
00378                 cl--;
00379                 while (cl >= 0 && !infil -> eof())
00380                 {
00381                         switch (c) 
00382                         {
00383                                 case '=': 
00384                                         name = slask;
00385                                         slask.resize(0);
00386                                         got_name = true;
00387                                         break;
00388                                 case '&': 
00389                                         if (got_name)
00390                                         {
00391                                                 cgi = new CGI(name,slask);
00392                                                 got_name = false;
00393                                         }
00394                                         else
00395                                         {
00396                                                 cgi = new CGI(slask, "");
00397                                         }
00398                                         slask.resize(0);
00399                                         m_cgi.push_back(cgi);
00400                                         break;
00401                                 case '+': 
00402                                         slask += " ";
00403                                         break;
00404                                 case '%': 
00405                                         infil -> fread(&chigh,1,1);
00406                                         cl--;
00407                                         chigh -= 48 + (chigh > '9' ? 7 : 0) + (chigh >= 'a' ? 32 : 0);
00408                                         infil -> fread(&clow,1,1);
00409                                         cl--;
00410                                         clow -= 48 + (clow > '9' ? 7 : 0) + (clow >= 'a' ? 32 : 0);
00411                                         slask += (char)(chigh * 16 + clow);
00412                                         break;
00413                                 default: 
00414                                         slask += c;
00415                                         break;
00416                         }
00417                         
00418                         if (cl > 0)
00419                         {
00420                                 infil -> fread(&c,1,1);
00421                         }
00422                         cl--;
00423                 }
00424                 if (got_name)
00425                 {
00426                         cgi = new CGI(name,slask);
00427                 }
00428                 else
00429                 {
00430                         cgi = new CGI(slask, "");
00431                 }
00432                 m_cgi.push_back(cgi);
00433         }
00434 }
00435 
00436 
00437 void HttpdForm::ParseQueryString(const std::string& buffer,size_t l)
00438 {
00439         CGI *cgi = NULL;
00440         std::string slask;
00441         std::string name;
00442         char c,chigh,clow;
00443         size_t ptr = 0;
00444         bool got_name = false;
00445 
00446         m_current = m_cgi.end();
00447 
00448         ptr = 0;
00449         while (ptr < l)
00450         {
00451                 c = buffer[ptr++];
00452                 switch (c)
00453                 {
00454                         case '=': 
00455                                 name = slask;
00456                                 slask.resize(0);
00457                                 got_name = true;
00458                                 break;
00459                         case '&': 
00460                                 if (got_name)
00461                                 {
00462                                         cgi = new CGI(name,slask);
00463                                         got_name = false;
00464                                 }
00465                                 else
00466                                 {
00467                                         cgi = new CGI(slask, "");
00468                                 }
00469                                 slask.resize(0);
00470                                 m_cgi.push_back(cgi);
00471                                 break;
00472                         case '+': 
00473                                 slask += " ";
00474                                 break;
00475                         case '%': 
00476                                 chigh = buffer[ptr++];
00477                                 chigh -= 48 + (chigh > '9' ? 7 : 0) + (chigh >= 'a' ? 32 : 0);
00478                                 clow = buffer[ptr++];
00479                                 clow -= 48 + (clow > '9' ? 7 : 0) + (clow >= 'a' ? 32 : 0);
00480                                 slask += (char)(chigh * 16 + clow);
00481                                 break;
00482                         default: 
00483                                 slask += c;
00484                                 break;
00485                 }
00486         }
00487         if (got_name)
00488         {
00489                 cgi = new CGI(name,slask);
00490         }
00491         else
00492         {
00493                 cgi = new CGI(slask, "");
00494         }
00495         m_cgi.push_back(cgi);
00496 }
00497 
00498 
00499 HttpdForm::~HttpdForm()
00500 {
00501         CGI *cgi = NULL; 
00502 
00503         for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); ++it)
00504         {
00505                 cgi = *it;
00506                 delete cgi;
00507         }
00508 }
00509 
00510 
00511 void HttpdForm::EnableRaw(bool b)
00512 {
00513         raw = b;
00514 }
00515 
00516 
00517 void HttpdForm::strcpyval(std::string& v,const char *value) const
00518 {
00519         v = "";
00520         for (size_t i = 0; i < strlen(value); i++)
00521         {
00522                 if (value[i] == '<')
00523                 {
00524                         v += "<";
00525                 }
00526                 else
00527                 if (value[i] == '>')
00528                 {
00529                         v += ">";
00530                 }
00531                 else
00532                 if (value[i] == '&')
00533                 {
00534                         v += "&";
00535                 }
00536                 else
00537                 {
00538                         v += value[i];
00539                 }
00540         }
00541 }
00542 
00543 
00544 bool HttpdForm::getfirst(std::string& n) const
00545 {
00546         m_current = m_cgi.begin();
00547         return getnext(n);
00548 }
00549 
00550 
00551 bool HttpdForm::getnext(std::string& n) const
00552 {
00553         if (m_current != m_cgi.end() )
00554         {
00555                 CGI *current = *m_current;
00556                 n = current -> name;
00557                 m_current++;
00558                 return true;
00559         }
00560         else
00561         {
00562                 n = "";
00563         }
00564         return false;
00565 }
00566 
00567 
00568 bool HttpdForm::getfirst(std::string& n,std::string& v) const
00569 {
00570         m_current = m_cgi.begin();
00571         return getnext(n,v);
00572 }
00573 
00574 
00575 bool HttpdForm::getnext(std::string& n,std::string& v) const
00576 {
00577         if (m_current != m_cgi.end() )
00578         {
00579                 CGI *current = *m_current;
00580                 n = current -> name;
00581                 if (raw)
00582                 {
00583                         v = current -> value;
00584                 }
00585                 else
00586                 {
00587                         strcpyval(v,current -> value.c_str());
00588                 }
00589                 m_current++;
00590                 return true;
00591         }
00592         else
00593         {
00594                 n = "";
00595         }
00596         return false;
00597 }
00598 
00599 
00600 int HttpdForm::getvalue(const std::string& n,std::string& v) const
00601 {
00602         CGI *cgi = NULL;
00603         int r = 0;
00604 
00605         for (cgi_v::const_iterator it = m_cgi.begin(); it != m_cgi.end(); ++it)
00606         {
00607                 cgi = *it;
00608                 if (cgi -> name == n)
00609                         break;
00610                 cgi = NULL;
00611         }
00612         if (cgi)
00613         {
00614                 if (raw)
00615                 {
00616                         v = cgi -> value;
00617                 }
00618                 else
00619                 {
00620                         strcpyval(v,cgi -> value.c_str());
00621                 }
00622                 r++;
00623         }
00624         else
00625         {
00626                 v = "";
00627         }
00628 
00629         return r;
00630 }
00631 
00632 
00633 std::string HttpdForm::getvalue(const std::string& n) const
00634 {
00635         for (cgi_v::const_iterator it = m_cgi.begin(); it != m_cgi.end(); ++it)
00636         {
00637                 CGI *cgi = *it;
00638                 if (cgi -> name == n)
00639                 {
00640                         return cgi -> value;
00641                 }
00642         }
00643         return "";
00644 }
00645 
00646 
00647 size_t HttpdForm::getlength(const std::string& n) const
00648 {
00649         CGI *cgi = NULL;
00650         size_t l;
00651 
00652         for (cgi_v::const_iterator it = m_cgi.begin(); it != m_cgi.end(); ++it)
00653         {
00654                 cgi = *it;
00655                 if (cgi -> name == n)
00656                         break;
00657                 cgi = NULL;
00658         }
00659         l = cgi ? cgi -> value.size() : 0;
00660         if (cgi && !raw)
00661         {
00662                 for (size_t i = 0; i < cgi -> value.size(); i++)
00663                 {
00664                         switch (cgi -> value[i])
00665                         {
00666                         case '<': 
00667                         case '>': 
00668                                 l += 4;
00669                                 break;
00670                         case '&': 
00671                                 l += 5;
00672                                 break;
00673                         }
00674                 }
00675         }
00676         return l;
00677 }
00678 
00679 
00680 HttpdForm::cgi_v& HttpdForm::getbase()
00681 {
00682         return m_cgi;
00683 }
00684 
00685 
00686 const std::string& HttpdForm::GetBoundary() const
00687 {
00688         return m_strBoundary;
00689 }
00690 
00691 
00692 void HttpdForm::SetFileUpload(IFileUpload& cb)
00693 {
00694         m_file_upload = &cb;
00695 }
00696 
00697 
00698 #ifdef SOCKETS_NAMESPACE
00699 }
00700 #endif
00701 
00702