00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef __GNUG__
00025 # pragma implementation
00026 #endif
00027
00028 #include <new>
00029 #include <algorithm>
00030 #include <functional>
00031 #include <iterator>
00032 #include <stdexcept>
00033
00034 #include "cgicc/CgiUtils.h"
00035 #include "cgicc/Cgicc.h"
00036
00037
00038 namespace cgicc {
00039
00040
00041
00042
00043 class FE_nameCompare : public std::unary_function<FormEntry, bool>
00044 {
00045 public:
00046
00047 inline explicit FE_nameCompare(const std::string& name)
00048 : fName(name) {}
00049
00050 inline bool operator() (const FormEntry& entry) const
00051 { return stringsAreEqual(fName, entry.getName()); }
00052
00053 private:
00054 std::string fName;
00055 };
00056
00057
00058
00059
00060 class FE_valueCompare : public std::unary_function<FormEntry, bool>
00061 {
00062 public:
00063
00064 inline explicit FE_valueCompare(const std::string& value)
00065 : fValue(value) {}
00066
00067 inline bool operator() (const FormEntry& entry) const
00068 { return stringsAreEqual(fValue, entry.getValue()); }
00069
00070 private:
00071 std::string fValue;
00072 };
00073
00074
00075
00076
00077
00078 class FF_compare : public std::unary_function<FormFile, bool>
00079 {
00080 public:
00081
00082 inline explicit FF_compare(const std::string& name)
00083 : fName(name) {}
00084
00085 inline bool operator() (const FormFile& entry) const
00086 { return stringsAreEqual(fName, entry.getName()); }
00087
00088 private:
00089 std::string fName;
00090 };
00091
00092
00093
00094
00095
00096
00097 template<class In, class Out, class Pred>
00098 Out
00099 copy_if(In first,
00100 In last,
00101 Out res,
00102 Pred p)
00103 {
00104 while(first != last) {
00105 if(p(*first))
00106 *res++ = *first;
00107 ++first;
00108 }
00109 return res;
00110 }
00111
00112 }
00113
00114
00115
00116
00117 class cgicc::MultipartHeader
00118 {
00119 public:
00120
00121 MultipartHeader(const std::string& disposition,
00122 const std::string& name,
00123 const std::string& filename,
00124 const std::string& cType);
00125
00126 inline
00127 MultipartHeader(const MultipartHeader& head)
00128 { operator=(head); }
00129 ~MultipartHeader();
00130
00131 MultipartHeader&
00132 operator= (const MultipartHeader& head);
00133
00134 inline std::string
00135 getContentDisposition() const
00136 { return fContentDisposition; }
00137
00138 inline std::string
00139 getName() const
00140 { return fName; }
00141
00142 inline std::string
00143 getFilename() const
00144 { return fFilename; }
00145
00146 inline std::string
00147 getContentType() const
00148 { return fContentType; }
00149
00150 private:
00151 std::string fContentDisposition;
00152 std::string fName;
00153 std::string fFilename;
00154 std::string fContentType;
00155 };
00156
00157 cgicc::MultipartHeader::MultipartHeader(const std::string& disposition,
00158 const std::string& name,
00159 const std::string& filename,
00160 const std::string& cType)
00161 : fContentDisposition(disposition),
00162 fName(name),
00163 fFilename(filename),
00164 fContentType(cType)
00165 {}
00166
00167 cgicc::MultipartHeader::~MultipartHeader()
00168 {}
00169
00170 cgicc::MultipartHeader&
00171 cgicc::MultipartHeader::operator= (const MultipartHeader& head)
00172 {
00173 fContentDisposition = head.fContentDisposition;
00174 fName = head.fName;
00175 fFilename = head.fFilename;
00176 fContentType = head.fContentType;
00177
00178 return *this;
00179 }
00180
00181
00182
00183
00184 cgicc::Cgicc::Cgicc(CgiInput *input)
00185 : fEnvironment(input)
00186 {
00187
00188 fFormData.reserve(20);
00189 fFormFiles.reserve(2);
00190
00191 parseFormInput(fEnvironment.getPostData());
00192 parseFormInput(fEnvironment.getQueryString());
00193 }
00194
00195 cgicc::Cgicc::~Cgicc()
00196 {}
00197
00198 cgicc::Cgicc&
00199 cgicc::Cgicc::operator= (const Cgicc& cgi)
00200 {
00201 this->fEnvironment = cgi.fEnvironment;
00202
00203 fFormData.clear();
00204 fFormFiles.clear();
00205
00206 parseFormInput(fEnvironment.getPostData());
00207 parseFormInput(fEnvironment.getQueryString());
00208
00209 return *this;
00210 }
00211
00212 const char*
00213 cgicc::Cgicc::getCompileDate() const
00214 { return __DATE__; }
00215
00216 const char*
00217 cgicc::Cgicc::getCompileTime() const
00218 { return __TIME__; }
00219
00220 const char*
00221 cgicc::Cgicc::getVersion() const
00222 { return VERSION; }
00223
00224 const char*
00225 cgicc::Cgicc::getHost() const
00226 { return HOST; }
00227
00228 void
00229 cgicc::Cgicc::save(const std::string& filename) const
00230 {
00231 fEnvironment.save(filename);
00232 }
00233
00234 void
00235 cgicc::Cgicc::restore(const std::string& filename)
00236 {
00237 fEnvironment.restore(filename);
00238
00239
00240 fFormData.clear();
00241 fFormFiles.clear();
00242
00243 parseFormInput(fEnvironment.getPostData());
00244 parseFormInput(fEnvironment.getQueryString());
00245 }
00246
00247 bool
00248 cgicc::Cgicc::queryCheckbox(const std::string& elementName) const
00249 {
00250 const_form_iterator iter = getElement(elementName);
00251 return (iter != fFormData.end() && stringsAreEqual(iter->getValue(), "on"));
00252 }
00253
00254 std::string
00255 cgicc::Cgicc::operator() (const std::string& name) const
00256 {
00257 std::string result;
00258 const_form_iterator iter = getElement(name);
00259 if(iter != fFormData.end() && false == iter->isEmpty())
00260 result = iter->getValue();
00261 return result;
00262 }
00263
00264 cgicc::form_iterator
00265 cgicc::Cgicc::getElement(const std::string& name)
00266 {
00267 return std::find_if(fFormData.begin(), fFormData.end(),FE_nameCompare(name));
00268 }
00269
00270 cgicc::const_form_iterator
00271 cgicc::Cgicc::getElement(const std::string& name) const
00272 {
00273 return std::find_if(fFormData.begin(), fFormData.end(),FE_nameCompare(name));
00274 }
00275
00276 bool
00277 cgicc::Cgicc::getElement(const std::string& name,
00278 std::vector<FormEntry>& result) const
00279 {
00280 return findEntries(name, true, result);
00281 }
00282
00283 cgicc::form_iterator
00284 cgicc::Cgicc::getElementByValue(const std::string& value)
00285 {
00286 return std::find_if(fFormData.begin(), fFormData.end(),
00287 FE_valueCompare(value));
00288 }
00289
00290 cgicc::const_form_iterator
00291 cgicc::Cgicc::getElementByValue(const std::string& value) const
00292 {
00293 return std::find_if(fFormData.begin(), fFormData.end(),
00294 FE_valueCompare(value));
00295 }
00296
00297 bool
00298 cgicc::Cgicc::getElementByValue(const std::string& value,
00299 std::vector<FormEntry>& result) const
00300 {
00301 return findEntries(value, false, result);
00302 }
00303
00304 cgicc::file_iterator
00305 cgicc::Cgicc::getFile(const std::string& name)
00306 {
00307 return std::find_if(fFormFiles.begin(), fFormFiles.end(), FF_compare(name));
00308 }
00309
00310 cgicc::const_file_iterator
00311 cgicc::Cgicc::getFile(const std::string& name) const
00312 {
00313 return std::find_if(fFormFiles.begin(), fFormFiles.end(), FF_compare(name));
00314 }
00315
00316
00317
00318 bool
00319 cgicc::Cgicc::findEntries(const std::string& param,
00320 bool byName,
00321 std::vector<FormEntry>& result) const
00322 {
00323
00324 result.clear();
00325
00326 if(byName) {
00327 copy_if(fFormData.begin(), fFormData.end(),
00328 std::back_inserter(result),FE_nameCompare(param));
00329 }
00330 else {
00331 copy_if(fFormData.begin(), fFormData.end(),
00332 std::back_inserter(result), FE_valueCompare(param));
00333 }
00334
00335 return false == result.empty();
00336 }
00337
00338 void
00339 cgicc::Cgicc::parseFormInput(const std::string& data)
00340 {
00341 std::string content_type = fEnvironment.getContentType();
00342 std::string standard_type = "application/x-www-form-urlencoded";
00343 std::string multipart_type = "multipart/form-data";
00344
00345
00346 if(true == data.empty())
00347 return;
00348
00349
00350
00351 if(true == content_type.empty()
00352 || stringsAreEqual(content_type, standard_type)) {
00353 std::string name, value;
00354 std::string::size_type pos;
00355 std::string::size_type oldPos = 0;
00356
00357
00358 while(true) {
00359
00360 pos = data.find_first_of('=', oldPos);
00361
00362
00363 if(std::string::npos == pos)
00364 break;
00365
00366
00367 name = form_urldecode(data.substr(oldPos, pos - oldPos));
00368 oldPos = ++pos;
00369
00370
00371 pos = data.find_first_of('&', oldPos);
00372
00373
00374 value = form_urldecode(data.substr(oldPos, pos - oldPos));
00375
00376
00377 fFormData.push_back(FormEntry(name, value));
00378
00379 if(std::string::npos == pos)
00380 break;
00381
00382
00383 oldPos = ++pos;
00384 }
00385 }
00386
00387 else if(stringsAreEqual(multipart_type, content_type,
00388 multipart_type.length())){
00389
00390
00391 std::string bType = "boundary=";
00392 std::string::size_type pos = content_type.find(bType);
00393
00394
00395 std::string sep1 = content_type.substr(pos + bType.length());
00396 sep1.append("\r\n");
00397 sep1.insert(0, "--");
00398
00399 std::string sep2 = content_type.substr(pos + bType.length());
00400 sep2.append("--\r\n");
00401 sep2.insert(0, "--");
00402
00403
00404 std::string::size_type start = data.find(sep1);
00405 std::string::size_type sepLen = sep1.length();
00406 std::string::size_type oldPos = start + sepLen;
00407
00408 while(true) {
00409 pos = data.find(sep1, oldPos);
00410
00411
00412 if(std::string::npos == pos)
00413 break;
00414
00415
00416 parseMIME(data.substr(oldPos, pos - oldPos));
00417
00418
00419 oldPos = pos + sepLen;
00420 }
00421
00422
00423 pos = data.find(sep2, oldPos);
00424
00425 if(std::string::npos != pos) {
00426 parseMIME(data.substr(oldPos, pos - oldPos));
00427 }
00428 }
00429 }
00430
00431 cgicc::MultipartHeader
00432 cgicc::Cgicc::parseHeader(const std::string& data)
00433 {
00434 std::string disposition;
00435 disposition = extractBetween(data, "Content-Disposition: ", ";");
00436
00437 std::string name;
00438 name = extractBetween(data, "name=\"", "\"");
00439
00440 std::string filename;
00441 filename = extractBetween(data, "filename=\"", "\"");
00442
00443 std::string cType;
00444 cType = extractBetween(data, "Content-Type: ", "\r\n\r\n");
00445
00446
00447
00448 filename = form_urldecode(filename);
00449
00450 return MultipartHeader(disposition, name, filename, cType);
00451 }
00452
00453 void
00454 cgicc::Cgicc::parseMIME(const std::string& data)
00455 {
00456
00457 std::string end = "\r\n\r\n";
00458 std::string::size_type headLimit = data.find(end, 0);
00459
00460
00461 if(std::string::npos == headLimit)
00462 throw std::runtime_error("Malformed input");
00463
00464
00465 std::string::size_type valueStart = headLimit + end.length();
00466 std::string value = data.substr(valueStart, data.length() - valueStart - 2);
00467
00468
00469 MultipartHeader head = parseHeader(data.substr(0, valueStart));
00470
00471 if(head.getFilename().empty())
00472 fFormData.push_back(FormEntry(head.getName(), value));
00473 else
00474 fFormFiles.push_back(FormFile(head.getName(),
00475 head.getFilename(),
00476 head.getContentType(),
00477 value));
00478 }