![]() |
HttpdForm Class ReferenceParse/store a http query_string/form-data body.
More...
|
Public Member Functions | |
HttpdForm (FILE *) | |
Default constructor. | |
HttpdForm (IFile *, const std::string &content_type, size_t content_length) | |
Constructor (used in POST operations). | |
HttpdForm (const std::string &query_string, size_t length) | |
Another constructor (used in GET operations). | |
~HttpdForm () | |
void | ParseFormData (IFile *, const std::string &, size_t) |
Parses the following content-types "multipart/form-data" "x-www-form-urlencoded" Any other content-type is left alone and nothing is read from input stream. | |
void | ParseQueryString (const std::string &query_string, size_t length) |
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 |
void | SetFileUpload (IFileUpload &cb) |
Enable IFileUpload callback. | |
bool | ContentAvailable () const |
const std::vector< char > & | GetContent () 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 |
IFileUpload * | m_file_upload |
IStream * | m_upload_stream |
std::vector< char > | m_content |
Classes | |
struct | CGI |
Store the name/value pairs from a GET/POST operation. More... |
Definition at line 55 of file HttpdForm.h.
typedef std::list<CGI *> HttpdForm::cgi_v [private] |
HttpdForm::HttpdForm | ( | FILE * | fil | ) |
Default constructor.
Definition at line 57 of file HttpdForm.cpp.
References ParseFormData(), and ParseQueryString().
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 }
HttpdForm::HttpdForm | ( | IFile * | infil, | |
const std::string & | content_type, | |||
size_t | content_length | |||
) |
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 77 of file HttpdForm.cpp.
References ParseFormData().
00077 : raw(false) 00078 , m_file_upload(NULL) 00079 , m_upload_stream(NULL) 00080 { 00081 ParseFormData(infil, content_type, content_length); 00082 }
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 86 of file HttpdForm.cpp.
References ParseQueryString().
00086 : raw(false) 00087 , m_file_upload(NULL) 00088 , m_upload_stream(NULL) 00089 { 00090 ParseQueryString(buffer, l); 00091 }
HttpdForm::~HttpdForm | ( | ) |
Definition at line 499 of file HttpdForm.cpp.
References m_cgi.
00500 { 00501 CGI *cgi = NULL; //,*tmp; 00502 00503 for (cgi_v::iterator it = m_cgi.begin(); it != m_cgi.end(); ++it) 00504 { 00505 cgi = *it; 00506 delete cgi; 00507 } 00508 }
HttpdForm::HttpdForm | ( | const HttpdForm & | ) | [inline, private] |
void HttpdForm::ParseFormData | ( | IFile * | infil, | |
const std::string & | content_type, | |||
size_t | content_length | |||
) |
Parses the following content-types "multipart/form-data" "x-www-form-urlencoded" Any other content-type is left alone and nothing is read from input stream.
Definition at line 93 of file HttpdForm.cpp.
References Parse::EnableQuote(), Parse::getrest(), Parse::getword(), m_cgi, m_current, m_file_upload, m_strBoundary, m_upload_stream, and TMPSIZE.
Referenced by HttpdForm().
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 // Get headers until empty line 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 // get next header value 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 // Read content, save...? 00223 if (current_filename.empty()) // not a file 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 // remove trailing cr/linefeed 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 // current_filename.size() > 0 00247 { 00248 // read until m_strBoundary... 00249 IFile *fil = NULL; 00250 int out = 0; 00251 char c; 00252 char fn[2000]; // where post'd file will be saved 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); // next line 00341 cl -= (int)strlen(slask + l); 00342 } 00343 else 00344 { 00345 // couldn't open file 00346 break; 00347 } 00348 if (!cl) 00349 { 00350 break; 00351 } 00352 } 00353 } 00354 else 00355 { 00356 // Probably '<m_strBoundary>--' 00357 break; 00358 } 00359 } // while (!infil -> eof()) 00360 delete[] slask; 00361 } // if (m_strBoundary) 00362 if (tempcmp) 00363 { 00364 delete[] tempcmp; 00365 } 00366 } // end of multipart 00367 else 00368 if (strstr(content_type.c_str(), "x-www-form-urlencoded")) 00369 { 00370 bool got_name = false; // tnx to FatherNitwit 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) // built-in url decoder 00382 { 00383 case '=': /* end of name */ 00384 name = slask; 00385 slask.resize(0); 00386 got_name = true; 00387 break; 00388 case '&': /* end of value */ 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 '+': /* space */ 00402 slask += " "; 00403 break; 00404 case '%': /* hex value */ 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: /* just another char */ 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 }
void HttpdForm::ParseQueryString | ( | const std::string & | query_string, | |
size_t | length | |||
) |
Definition at line 437 of file HttpdForm.cpp.
References m_cgi, and m_current.
Referenced by HttpdForm().
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 '=': /* end of name */ 00455 name = slask; 00456 slask.resize(0); 00457 got_name = true; 00458 break; 00459 case '&': /* end of value */ 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 '+': /* space */ 00473 slask += " "; 00474 break; 00475 case '%': /* hex value */ 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: /* just another char */ 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 }
void HttpdForm::EnableRaw | ( | bool | b | ) |
void HttpdForm::strcpyval | ( | std::string & | v, | |
const char * | value | |||
) | const |
Encode characters '<' '>' '&' as < > &.
Definition at line 517 of file HttpdForm.cpp.
Referenced by getnext(), and getvalue().
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 }
bool HttpdForm::getfirst | ( | std::string & | n | ) | const |
bool HttpdForm::getnext | ( | std::string & | n | ) | const |
Definition at line 551 of file HttpdForm.cpp.
References m_cgi, and m_current.
Referenced by getfirst().
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 }
bool HttpdForm::getfirst | ( | std::string & | n, | |
std::string & | v | |||
) | const |
bool HttpdForm::getnext | ( | std::string & | n, | |
std::string & | v | |||
) | const |
Definition at line 575 of file HttpdForm.cpp.
References m_cgi, m_current, raw, and strcpyval().
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 }
int HttpdForm::getvalue | ( | const std::string & | n, | |
std::string & | v | |||
) | const |
Definition at line 600 of file HttpdForm.cpp.
References m_cgi, raw, and strcpyval().
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 }
std::string HttpdForm::getvalue | ( | const std::string & | n | ) | const |
Definition at line 633 of file HttpdForm.cpp.
References m_cgi.
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 }
size_t HttpdForm::getlength | ( | const std::string & | n | ) | const |
Definition at line 647 of file HttpdForm.cpp.
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 }
HttpdForm::cgi_v & HttpdForm::getbase | ( | ) |
const std::string & HttpdForm::GetBoundary | ( | ) | const |
Definition at line 686 of file HttpdForm.cpp.
References m_strBoundary.
00687 { 00688 return m_strBoundary; 00689 }
void HttpdForm::SetFileUpload | ( | IFileUpload & | cb | ) |
Enable IFileUpload callback.
Definition at line 692 of file HttpdForm.cpp.
References m_file_upload.
00693 { 00694 m_file_upload = &cb; 00695 }
bool HttpdForm::ContentAvailable | ( | ) | const [inline] |
const std::vector<char>& HttpdForm::GetContent | ( | ) | const [inline] |
cgi_v HttpdForm::m_cgi [private] |
Definition at line 132 of file HttpdForm.h.
Referenced by getbase(), getfirst(), getlength(), getnext(), getvalue(), ParseFormData(), ParseQueryString(), and ~HttpdForm().
cgi_v::const_iterator HttpdForm::m_current [mutable, private] |
Definition at line 133 of file HttpdForm.h.
Referenced by getfirst(), getnext(), ParseFormData(), and ParseQueryString().
std::string HttpdForm::m_strBoundary [private] |
bool HttpdForm::raw [private] |
Definition at line 135 of file HttpdForm.h.
Referenced by EnableRaw(), getlength(), getnext(), and getvalue().
IFileUpload* HttpdForm::m_file_upload [private] |
IStream* HttpdForm::m_upload_stream [private] |
std::vector<char> HttpdForm::m_content [private] |
Definition at line 138 of file HttpdForm.h.