HttpdForm Class ReferenceParse/store a http query_string/form-data body.
More...
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Public Member Functions | |
| HttpdForm (IFile *, const std::string &content_type, size_t content_length) | |
| Default constructor (used in POST operations). | |
| HttpdForm (const std::string &query_string, size_t length) | |
| Another constructor (used in GET operations). | |
| ~HttpdForm () | |
| void | EnableRaw (bool) |
| void | strcpyval (std::string &, const char *) const |
| Encode characters '<' '>' '&' as < > &. | |
| bool | getfirst (std::string &n) const |
| bool | getnext (std::string &n) const |
| bool | getfirst (std::string &n, std::string &v) const |
| bool | getnext (std::string &n, std::string &v) const |
| int | getvalue (const std::string &, std::string &) const |
| std::string | getvalue (const std::string &) const |
| size_t | getlength (const std::string &) const |
| cgi_v & | getbase () |
| const std::string & | GetBoundary () const |
Private Types | |
| typedef std::list< CGI * > | cgi_v |
| list of key/value pairs. | |
Private Member Functions | |
| HttpdForm (const HttpdForm &) | |
| HttpdForm & | operator= (const HttpdForm &) |
Private Attributes | |
| cgi_v | m_cgi |
| cgi_v::const_iterator | m_current |
| std::string | m_strBoundary |
| bool | raw |
Classes | |
| struct | CGI |
| Store the name/value pairs from a GET/POST operation. More... | |
Definition at line 48 of file HttpdForm.h.
typedef std::list<CGI *> HttpdForm::cgi_v [private] |
| HttpdForm::HttpdForm | ( | IFile * | infil, | |
| const std::string & | content_type, | |||
| size_t | content_length | |||
| ) |
Default constructor (used in POST operations).
Input is read from stdin. Number of characters to read can be found in the environment variable CONTENT_LENGTH.
Definition at line 52 of file HttpdForm.cpp.
References DEB, Parse::EnableQuote(), Parse::getrest(), Parse::getword(), m_cgi, m_current, m_strBoundary, and TMPSIZE.
00052 : 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 // Get headers until empty line 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 // get next header value 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 // Read content, save...? 00187 if (current_filename.empty()) // not a file 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 // remove trailing cr/linefeed 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 // current_filename.size() > 0 00206 { 00207 // read until m_strBoundary... 00208 FILE *fil; 00209 int out = 0; 00210 char c; 00211 char fn[2000]; // where post'd file will be saved 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); // %! ??? should we write value of 'c' here? 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); // next line 00265 } 00266 else 00267 { 00268 // couldn't open file 00269 break; 00270 } 00271 } 00272 } 00273 else 00274 { 00275 // Probably '<m_strBoundary>--' 00276 break; 00277 } 00278 } // while (!infil -> eof()) 00279 delete[] slask; 00280 } // if (m_strBoundary) 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; // tnx to FatherNitwit 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 '=': /* end of name */ 00303 name = slask; 00304 slask.resize(0); 00305 got_name = true; 00306 break; 00307 case '&': /* end of value */ 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 '+': /* space */ 00321 slask += " "; 00322 break; 00323 case '%': /* hex value */ 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: /* just another char */ 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 }
| HttpdForm::HttpdForm | ( | const std::string & | query_string, | |
| size_t | length | |||
| ) |
Another constructor (used in GET operations).
Input is read from the environment variable QUERY_STRING.
| query_string | The httpd server provided QUERY_STRING | |
| length | Query string length. |
Definition at line 358 of file HttpdForm.cpp.
References m_cgi, and m_current.
00358 : 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 '=': /* end of name */ 00376 name = slask; 00377 slask.resize(0); 00378 got_name = true; 00379 break; 00380 case '&': /* end of value */ 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 '+': /* space */ 00394 slask += " "; 00395 break; 00396 case '%': /* hex value */ 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: /* just another char */ 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 }
| HttpdForm::~HttpdForm | ( | ) |
Definition at line 420 of file HttpdForm.cpp.
References m_cgi.
00421 { 00422 CGI *cgi = NULL; //,*tmp; 00423 00424 for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); it++) 00425 { 00426 cgi = *it; 00427 delete cgi; 00428 } 00429 }
| HttpdForm::HttpdForm | ( | const HttpdForm & | ) | [inline, private] |
| void HttpdForm::EnableRaw | ( | bool | b | ) |
| void HttpdForm::strcpyval | ( | std::string & | v, | |
| const char * | value | |||
| ) | const |
Encode characters '<' '>' '&' as < > &.
Definition at line 438 of file HttpdForm.cpp.
Referenced by getnext(), and getvalue().
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 }
| bool HttpdForm::getfirst | ( | std::string & | n | ) | const |
| bool HttpdForm::getnext | ( | std::string & | n | ) | const |
Definition at line 472 of file HttpdForm.cpp.
References m_cgi, and m_current.
Referenced by getfirst().
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 }
| bool HttpdForm::getfirst | ( | std::string & | n, | |
| std::string & | v | |||
| ) | const |
| bool HttpdForm::getnext | ( | std::string & | n, | |
| std::string & | v | |||
| ) | const |
Definition at line 496 of file HttpdForm.cpp.
References m_cgi, m_current, raw, and strcpyval().
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 }
| int HttpdForm::getvalue | ( | const std::string & | n, | |
| std::string & | v | |||
| ) | const |
Definition at line 521 of file HttpdForm.cpp.
References m_cgi, raw, and strcpyval().
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 }
| std::string HttpdForm::getvalue | ( | const std::string & | n | ) | const |
Definition at line 554 of file HttpdForm.cpp.
References m_cgi.
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 }
| size_t HttpdForm::getlength | ( | const std::string & | n | ) | const |
Definition at line 568 of file HttpdForm.cpp.
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 }
| HttpdForm::cgi_v & HttpdForm::getbase | ( | ) |
| const std::string & HttpdForm::GetBoundary | ( | ) | const |
Definition at line 607 of file HttpdForm.cpp.
References m_strBoundary.
00608 { 00609 return m_strBoundary; 00610 }
cgi_v HttpdForm::m_cgi [private] |
Definition at line 106 of file HttpdForm.h.
Referenced by getbase(), getfirst(), getlength(), getnext(), getvalue(), HttpdForm(), and ~HttpdForm().
cgi_v::const_iterator HttpdForm::m_current [mutable, private] |
std::string HttpdForm::m_strBoundary [private] |
bool HttpdForm::raw [private] |
Definition at line 109 of file HttpdForm.h.
Referenced by EnableRaw(), getlength(), getnext(), and getvalue().
1.4.4