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