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