ulxr_htmlform_handler.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002         ulxr_htmlform_handler.cpp  -  work with html pages and forms
00003                              -------------------
00004     begin                : Fri Dec 05 2003
00005     copyright            : (C) 2002-2007 by Ewald Arnold
00006     email                : ulxmlrpcpp@ewald-arnold.de
00007 
00008     $Id: ulxr_htmlform_handler.cpp 940 2006-12-30 18:22:05Z ewald-arnold $
00009 
00010  ***************************************************************************/
00011 
00012 /**************************************************************************
00013  *
00014  * This program is free software; you can redistribute it and/or modify
00015  * it under the terms of the GNU Lesser General Public License as
00016  * published by the Free Software Foundation; either version 2 of the License,
00017  * or (at your option) any later version.
00018  *
00019  * This program is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Lesser General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00027  *
00028  ***************************************************************************/
00029 
00030 //#define ULXR_DEBUG_OUTPUT
00031 
00032 #define ULXR_NEED_EXPORTS
00033 #include <ulxmlrpcpp/ulxmlrpcpp.h>  // always first header
00034 
00035 #include <cstdio>
00036 #include <cctype>
00037 
00038 #include <ulxmlrpcpp/ulxr_htmlform_handler.h>
00039 #include <ulxmlrpcpp/ulxr_http_protocol.h>
00040 #include <ulxmlrpcpp/ulxr_except.h>
00041 
00042 
00043 namespace ulxr {
00044 
00045 
00046 namespace hidden {
00047 
00048 
00049 ULXR_API_IMPL0 SubResourceBase::SubResourceBase(const CppString &in_name, const CppString &in_descr)
00050  : name(in_name)
00051  , descr(in_descr)
00052 {
00053 }
00054 
00055 
00056 ULXR_API_IMPL0 SubResourceBase::~SubResourceBase()
00057 {
00058 }
00059 
00060 
00061 ULXR_API_IMPL(CppString) SubResourceBase::getName() const
00062 {
00063   return name;
00064 }
00065 
00066 
00067 ULXR_API_IMPL(CppString) SubResourceBase::getDescription() const
00068 {
00069   return descr;
00070 }
00071 
00072 
00073 }
00074 
00075 
00077 
00078 
00079 ULXR_API_IMPL0 HtmlFormHandler::HtmlFormHandler(const CppString &in_resource)
00080   : masterResource(in_resource)
00081 {
00082   addSubResource(getCssName(), this, &HtmlFormHandler::handle_css_file, ULXR_PCHAR("Common style sheet"));
00083 //  addSubResource(ULXR_PCHAR("subresources.html"), this, &HtmlFormHandler::handle_subresource_list, ULXR_PCHAR("Display subresources"));
00084 }
00085 
00086 
00087 ULXR_API_IMPL(CppString) HtmlFormHandler::getMasterResource() const
00088 {
00089   return masterResource;
00090 }
00091 
00092 
00093 ULXR_API_IMPL0 HtmlFormHandler::~HtmlFormHandler()
00094 {
00095   for (unsigned i = 0; i < subResources.size(); ++i)
00096     delete subResources[i];
00097 
00098   subResources.clear();
00099 }
00100 
00101 
00102 ULXR_API_IMPL(bool) HtmlFormHandler::handler(HttpProtocol *prot,
00103                                           const CppString &method,
00104                                           const CppString &resource,
00105                                           const Cpp8BitString &conn_data)
00106 {
00107   ULXR_TRACE(ULXR_PCHAR("HtmlFormHandler::handler ")
00108              << method << ULXR_PCHAR(" ")
00109              << resource << std::endl);
00110 
00111   CppString target;
00112   if (resourceSplit(method, resource, getMasterResource(), target))
00113   {
00114 
00115     HtmlFormData formdata;
00116     formdata = extractFormElements(prot, method, target, conn_data);
00117 
00118     for (unsigned i = 0; i < subResources.size(); ++i)
00119     {
00120       if (subResources[i]->getName() == target)
00121       {
00122         CppString mimetype = ULXR_PCHAR("text/html");
00123         std::string resp = encodeForHtml(subResources[i]->call(formdata, mimetype));
00124         prot->sendResponseHeader(200, ULXR_PCHAR("OK"), mimetype, resp.length());
00125         prot->writeRaw(resp.data(), resp.length());
00126         return true;
00127       }
00128     }
00129     return false;
00130   }
00131   else
00132     return false;
00133 }
00134 
00135 
00136 ULXR_API_IMPL(std::string) HtmlFormHandler::encodeForHtml(const CppString &data)
00137 {
00138 #ifdef ULXR_UNICODE
00139   return unicodeToUtf8(data);
00140 #else
00141   return data;
00142 #endif
00143 }
00144 
00145 
00146 ULXR_API_IMPL(CppString) HtmlFormHandler::encodeFromHtml(const std::string &data)
00147 {
00148 #ifdef ULXR_UNICODE
00149   return utf8ToUnicode(data);
00150 #else
00151   return data;
00152 #endif
00153 }
00154 
00155 
00156 ULXR_API_IMPL(bool) HtmlFormHandler::resourceSplit(const CppString &method,
00157                                                 const CppString &resource,
00158                                                 const CppString &rsc_start,
00159                                                 CppString &target)
00160 {
00161   if (resource.substr(0, rsc_start.length()) == rsc_start)
00162   {
00163     target = resource.substr(rsc_start.length());
00164     if (method == ULXR_PCHAR("GET"))
00165     {
00166       std::size_t pos = target.find('?');
00167       if (pos != CppString::npos)
00168         target.erase(0, pos);
00169     }
00170 
00171     return true;
00172   }
00173   else
00174   {
00175     target = ULXR_PCHAR("");
00176     return false;
00177   }
00178 }
00179 
00180 
00181 ULXR_API_IMPL(HtmlFormData) HtmlFormHandler::extractFormElements(HttpProtocol *prot,
00182                                                               const CppString &method,
00183                                                               const CppString &resource,
00184                                                               const Cpp8BitString &conn_data)
00185 {
00186   ULXR_TRACE(ULXR_PCHAR("HtmlFormHandler::extractFormElements")) ;
00187   HtmlFormData formdata;
00188   std::string post_data = conn_data;
00189 
00190   if (method == ULXR_PCHAR("POST"))
00191   {
00192     char conn_buffer [ULXR_RECV_BUFFER_SIZE];
00193     long conn_readed;
00194     bool done = false;
00195     while (!done && ((conn_readed = prot->readRaw(conn_buffer, sizeof(conn_buffer))) > 0) )
00196     {
00197       if (!prot->hasBytesToRead())
00198         done = true;
00199       post_data.append(conn_buffer, conn_readed);
00200     }
00201   }
00202   else
00203   {
00204     std::size_t pos = resource.find(ULXR_CHAR('?'));
00205     if (pos != CppString::npos)
00206       post_data = getLatin1(resource.substr(pos+1));
00207   }
00208 
00209   while (post_data.length() != 0)
00210   {
00211     ULXR_TRACE(ULXR_PCHAR("formdata ") << ULXR_GET_STRING(post_data));
00212     std::size_t pos = 0;
00213     std::string element;
00214     if ( (pos = post_data.find(ULXR_CHAR('&'))) != CppString::npos)
00215     {
00216       element = post_data.substr(0, pos);
00217       post_data.erase(0, pos+1);
00218     }
00219     else
00220     {
00221       element = post_data.substr(0, pos);
00222       post_data = "";
00223     }
00224 
00225     ULXR_TRACE(ULXR_PCHAR("element ") << ULXR_GET_STRING(element));
00226 
00227     if ( (pos = element.find(ULXR_CHAR('='))) != CppString::npos)
00228     {
00229       std::string name = element.substr(0, pos);
00230       std::string value = element.substr(pos+1);
00231       formdata.addElement(encodeFromHtml(formDecode(name)), encodeFromHtml(formDecode(value)));
00232     }
00233     else
00234     {
00235       // ignore bad pair??
00236     }
00237   }
00238 
00239   return formdata;
00240 }
00241 
00242 
00243 ULXR_API_IMPL(std::string) HtmlFormHandler::formDecode(std::string &value)
00244 {
00245   ULXR_TRACE(ULXR_PCHAR("formDecode 1 ") << ULXR_GET_STRING(value));
00246 
00247   std::size_t pos = 0;
00248   while ((pos = value.find('+')) != std::string::npos)
00249     value.replace(pos, 1, 1, ' ');
00250 
00251   ULXR_TRACE(ULXR_PCHAR("formDecode 2 ") << ULXR_GET_STRING(value));
00252 
00253   pos = 0;
00254   while ((pos = value.find('%', pos)) != std::string::npos)
00255   {
00256     if (value.length() >= pos+3)
00257     {
00258       int c1 = ulxr_toupper(value[pos+1]) - '0';
00259       if (c1 > 9)
00260         c1 += '0' - 'A' + 0x0A;
00261 
00262       int c2 = ulxr_toupper(value[pos+2]) - '0';
00263       if (c2 > 9)
00264         c2 += '0' - 'A' + 0x0A;
00265 
00266       ULXR_TRACE(ULXR_PCHAR("formDecode 3 ")
00267                  << (unsigned int) value[pos+1] << ULXR_PCHAR(" ")
00268                  << (unsigned int) c1 << ULXR_PCHAR(" ")
00269                  << (unsigned int) c2 );
00270 
00271       if (   c1 >= 0 && c1 <= 0x0F
00272           && c2 >= 0 && c2 <= 0x0F)
00273       {
00274         unsigned char x = c1 << 4 | c2;
00275         if (x !=0) // a remote bug or an attack?
00276           value.replace(pos, 3, 1, x);
00277       }
00278       pos++;
00279      }
00280      ULXR_TRACE(ULXR_PCHAR("formDecode 4 ") << ULXR_GET_STRING(value));
00281   }
00282   return value;
00283 }
00284 
00285 
00286 ULXR_API_IMPL(CppString) HtmlFormHandler::handle_subresource_list(const HtmlFormData &, CppString &mimetype)
00287 {
00288   mimetype = ULXR_PCHAR("text/html");
00289   CppString resp;
00290   resp += ULXR_PCHAR("<table border=\"3\">\n")
00291           ULXR_PCHAR("<tr><td>Resource</td>")
00292           ULXR_PCHAR("<td>Description</td></tr>");
00293 
00294   for (unsigned i = 0; i < subResources.size(); ++i)
00295   {
00296     CppString s = applyTags(makeAnchor(subResources[i]->getName(), subResources[i]->getName()),
00297                             ULXR_PCHAR("td"))
00298                 + applyTags(subResources[i]->getDescription(), ULXR_PCHAR("td"));
00299     resp += applyTags(s, ULXR_PCHAR("tr"));
00300   }
00301 
00302   return resp;
00303 }
00304 
00305 
00306 ULXR_API_IMPL(CppString) HtmlFormHandler::handle_css_file(const HtmlFormData &, CppString &mimetype)
00307 {
00308   mimetype = ULXR_PCHAR("text/css");
00309   return ULXR_PCHAR("// No css data set\n");
00310 }
00311 
00312 
00313 ULXR_API_IMPL(CppString) HtmlFormHandler::getCssName() const
00314 {
00315   return ULXR_PCHAR("ulxr.css");
00316 }
00317 
00318 
00319 ULXR_API_IMPL(CppString) HtmlFormHandler::getHeader(const CppString &title) const
00320 {
00321   return ULXR_PCHAR("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n")
00322          ULXR_PCHAR("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=")
00323          + getEncoding()
00324          + ULXR_PCHAR("\">\n<title>")
00325          + title
00326          + ULXR_PCHAR("</title>\n<link href=\"")
00327          + getCssName()
00328          + ULXR_PCHAR("\" rel=\"stylesheet\" type=\"text/css\"></head><body>\n");
00329 }
00330 
00331 
00332 ULXR_API_IMPL(CppString) HtmlFormHandler::getTail() const
00333 {
00334   return ULXR_PCHAR("\n</body></html>\n");
00335 }
00336 
00337 
00338 ULXR_API_IMPL(CppString) HtmlFormHandler::makeAnchor(const CppString &url, const CppString &descr)
00339 {
00340   return ULXR_PCHAR("<a href=\"") + url + ULXR_PCHAR("\">")
00341          + descr + ULXR_PCHAR("</a>");
00342 }
00343 
00344 
00345 ULXR_API_IMPL(CppString) HtmlFormHandler::makeIdent(const CppString &name, unsigned index)
00346 {
00347   return name + makeNumber(index);
00348 }
00349 
00350 
00351 ULXR_API_IMPL(CppString) HtmlFormHandler::openForm(const CppString &name, const CppString &method)
00352 {
00353   return ULXR_PCHAR("<form name=\"")
00354          + name
00355          + ULXR_PCHAR("\" accept-charset=\"")
00356          + getEncoding()
00357          + ULXR_PCHAR("\" method=\"")
00358          + method
00359          + ULXR_PCHAR("\">\n");
00360 }
00361 
00362 
00363 ULXR_API_IMPL(CppString) HtmlFormHandler::closeForm()
00364 {
00365   return ULXR_PCHAR("</form>\n");
00366 }
00367 
00368 
00369 ULXR_API_IMPL(CppString) HtmlFormHandler::applyTags(const CppString &data,
00370                                                  const CppString &tag,
00371                                                  bool newline)
00372 {
00373   std::size_t pos = 0;
00374   CppString end_tag = tag;
00375   if ( (pos = tag.find(ULXR_CHAR(' '))) != CppString::npos)  // start tag contains attributes
00376     end_tag = tag.substr(0, pos-1);
00377 
00378   CppString resp = ULXR_PCHAR("<") + tag + ULXR_PCHAR(">")
00379                    + data
00380                    + ULXR_PCHAR("</") + end_tag + ULXR_PCHAR(">\n");
00381 
00382   if (newline)
00383     resp += ULXR_PCHAR("\n");
00384 
00385   return resp;
00386 
00387 }
00388 
00389 
00390 ULXR_API_IMPL(CppString) HtmlFormHandler::makeLineBreak()
00391 {
00392   return ULXR_PCHAR("<br />");
00393 }
00394 
00395 
00396 ULXR_API_IMPL(CppString) HtmlFormHandler::makeCheckBox(const CppString &name,
00397                                                       const CppString &value,
00398                                                       bool checked)
00399 {
00400   CppString chkd;
00401   if (checked)
00402     chkd = ULXR_PCHAR(" checked=\"checked\"");
00403 
00404   return  ULXR_PCHAR("<input type=\"checkbox\" name=\"")
00405           + name
00406           + ULXR_PCHAR("\" value=\"")
00407           + value
00408           + ULXR_PCHAR("\"")
00409           + chkd
00410           + ULXR_PCHAR("></input>\n");
00411 }
00412 
00413 
00414 ULXR_API_IMPL(CppString) HtmlFormHandler::openSelect(const CppString &name,
00415                                                     int size,
00416                                                     bool multi)
00417 {
00418   CppString ret = ULXR_PCHAR("<select name=\"")
00419                   + name
00420                   + ULXR_PCHAR("\"");
00421   if (size >= 0)
00422     ret += ULXR_PCHAR(" size=\"")
00423            + makeNumber(size)
00424            + ULXR_PCHAR("\"");
00425 
00426   if (multi)
00427     ret += ULXR_PCHAR(" multiple=\"multiple\"");
00428 
00429   return ret + ULXR_PCHAR(">\n");
00430 }
00431 
00432 
00433 ULXR_API_IMPL(CppString) HtmlFormHandler::makeOption(const CppString &data,
00434                                                     const CppString &value,
00435                                                     bool selected)
00436 {
00437   CppString ret = ULXR_PCHAR("<option");
00438 
00439   if (value.length() != 0)
00440     ret += ULXR_PCHAR(" value=\"")
00441            + value
00442            + ULXR_PCHAR("\"");
00443 
00444   if (selected)
00445     ret += ULXR_PCHAR(" selected=\"selected\"");
00446 
00447   return ret + ULXR_PCHAR(">") + data + ULXR_PCHAR("</option>\n");
00448 }
00449 
00450 
00451 ULXR_API_IMPL(CppString) HtmlFormHandler::closeSelect()
00452 {
00453   return ULXR_PCHAR("</select>\n");
00454 }
00455 
00456 
00457 ULXR_API_IMPL(CppString) HtmlFormHandler::makeTextArea(const CppString &name,
00458                                                       const CppString &value,
00459                                                       int cols, int rows)
00460 {
00461   CppString ret = ULXR_PCHAR("<textarea name=\"")
00462                   + name
00463                   + ULXR_PCHAR("\"");
00464 
00465   if (cols >= 0)
00466     ret += ULXR_PCHAR(" cols=\"")
00467            + makeNumber(cols)
00468            + ULXR_PCHAR("\"");
00469 
00470   if (rows >= 0)
00471     ret += ULXR_PCHAR(" rows=\"")
00472            + makeNumber(rows)
00473            + ULXR_PCHAR("\"");
00474 
00475   return ret + ULXR_PCHAR(">") + value + ULXR_PCHAR("</textarea>");
00476 }
00477 
00478 
00479 ULXR_API_IMPL(CppString) HtmlFormHandler::makeTextField(const CppString &name,
00480                                                        const CppString &value)
00481 {
00482   return  ULXR_PCHAR("<input type=\"text\" name=\"")
00483           + name
00484           + ULXR_PCHAR("\" value=\"")
00485           + value
00486           + ULXR_PCHAR("\"></input>\n");
00487 }
00488 
00489 
00490 ULXR_API_IMPL(CppString) HtmlFormHandler::makeRadioButton(const CppString &name,
00491                                                          const CppString &value,
00492                                                          bool checked)
00493 {
00494   CppString chkd;
00495   if (checked)
00496     chkd = ULXR_PCHAR(" checked=\"checked\"");
00497 
00498   return  ULXR_PCHAR("<input type=\"radio\" name=\"")
00499           + name
00500           + ULXR_PCHAR("\" value=\"")
00501           + value
00502           + ULXR_PCHAR("\"")
00503           + chkd
00504           + ULXR_PCHAR("></input>\n");
00505 }
00506 
00507 
00508 ULXR_API_IMPL(CppString) HtmlFormHandler::makeSubmitButton(const CppString &name,
00509                                                           const CppString &value)
00510 {
00511   return ULXR_PCHAR("<input type=\"submit\" name=\"")
00512          + name
00513          + ULXR_PCHAR("\" value=\"")
00514          + value
00515          + ULXR_PCHAR("\"></input>\n");
00516 }
00517 
00518 
00519 ULXR_API_IMPL(CppString) HtmlFormHandler::makeResetButton(const CppString &name,
00520                                                          const CppString &value)
00521 {
00522   return ULXR_PCHAR("<input type=\"reset\" name=\"")
00523          + name
00524          + ULXR_PCHAR("\" value=\"")
00525          + value
00526          + ULXR_PCHAR("\"></input>\n");
00527 }
00528 
00529 
00530 ULXR_API_IMPL(CppString) HtmlFormHandler::makeText(const CppString &name)
00531 {
00532   return xmlEscape(name);
00533 }
00534 
00535 
00536 ULXR_API_IMPL(CppString) HtmlFormHandler::makeNumber(unsigned index)
00537 {
00538 #ifndef ULXR_UNICODE
00539   char cb[40];
00540   ulxr_sprintf(cb, "%d", index);
00541 #else
00542   wchar_t cb[40];
00543 # if defined(__BORLANDC__) || defined(_MSC_VER)
00544   ulxr_swprintf(cb, L"%d", index);
00545 # else
00546   ulxr_swprintf(cb, sizeof(cb), L"%d", index);
00547 # endif
00548 #endif
00549   return CppString(cb);
00550 }
00551 
00552 
00553 ULXR_API_IMPL(CppString) HtmlFormHandler::makeHexNumber(unsigned index)
00554 {
00555 #ifndef ULXR_UNICODE
00556   char cb[40];
00557   if (index <= 0x0F)
00558     ulxr_sprintf(cb, "0x0%x", index);
00559   else
00560     ulxr_sprintf(cb, "0x%x", index);
00561 #else
00562   wchar_t cb[40];
00563 # if defined(__BORLANDC__) || defined(_MSC_VER)
00564   if (index <= 0x0F)
00565     ulxr_swprintf(cb, L"0x0%x", index);
00566   else
00567     ulxr_swprintf(cb, L"0x%x", index);
00568 # else
00569   if (index <= 0x0F)
00570     ulxr_swprintf(cb, sizeof(cb), L"0x0%x", index);
00571   else
00572     ulxr_swprintf(cb, sizeof(cb), L"0x%x", index);
00573 # endif
00574 #endif
00575   return CppString(cb);
00576 }
00577 
00578 
00579 ULXR_API_IMPL(long) HtmlFormHandler::getLong(const CppString &num)
00580 {
00581 #ifndef ULXR_UNICODE
00582   return ulxr_atoi(num.c_str());
00583 #else
00584   std::string asc = getLatin1(num);
00585   return ulxr_atoi(asc.c_str());
00586 #endif
00587 }
00588 
00589 
00590 ULXR_API_IMPL(CppString) HtmlFormHandler::getEncoding() const
00591 {
00592 #ifdef ULXR_UNICODE
00593   return ULXR_PCHAR("UTF-8");
00594 #else
00595   return ULXR_PCHAR("ISO-8859-1");
00596 #endif
00597 }
00598 
00599 
00601 
00602 
00603 ULXR_API_IMPL(unsigned) HtmlFormData::size() const
00604 {
00605   return elements.size();
00606 }
00607 
00608 
00609 ULXR_API_IMPL(void) HtmlFormData::addElement( const CppString &name, const CppString &value)
00610 {
00611   elements[name].push_back(value);
00612 }
00613 
00614 
00615 ULXR_API_IMPL(std::vector<CppString>) HtmlFormData::getElement(const CppString &name) const
00616 {
00617   Elements::const_iterator it;
00618   if ((it = elements.find(name)) == elements.end())
00619     throw RuntimeException(ApplicationError, ulxr_i18n(ULXR_PCHAR("Index out out range for HtmlFormData::getElement() call")));
00620   else
00621     return (*it).second;
00622 }
00623 
00624 
00625 ULXR_API_IMPL(std::vector<CppString>) HtmlFormData::getElement(const CppString &base_name, unsigned index) const
00626 {
00627   return getElement(base_name + HtmlFormHandler::makeNumber(index));
00628 }
00629 
00630 
00631 ULXR_API_IMPL(bool) HtmlFormData::hasElement(const CppString &name) const
00632 {
00633   return elements.find(name) != elements.end();
00634 }
00635 
00636 
00637 ULXR_API_IMPL(bool) HtmlFormData::hasElement(const CppString &base_name, unsigned index) const
00638 {
00639   return hasElement(base_name + HtmlFormHandler::makeNumber(index));
00640 }
00641 
00642 
00643 } // namespace ulxr
00644 

Generated on Sun Aug 19 20:08:57 2007 for ulxmlrpcpp by  doxygen 1.5.1