ServerWebServerUtil.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2003
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <webserver/ServerWebServerUtil.h>
00022 #include <server/ScorchedServer.h>
00023 #include <net/NetMessagePool.h>
00024 #include <common/OptionsScorched.h>
00025 #include <common/Defines.h>
00026 #include <common/Logger.h>
00027 #include <common/OptionEntry.h>
00028 
00029 const char *ServerWebServerUtil::getField(
00030         std::map<std::string, std::string> &fields, const std::string &field)
00031 {
00032         std::map<std::string, std::string>::iterator itor = 
00033                 fields.find(field);
00034         if (itor != fields.end())
00035         {
00036                 return (*itor).second.c_str();
00037         }
00038         return 0;
00039 }
00040 
00041 std::string ServerWebServerUtil::getFile(const std::string &filename)
00042 {
00043         char buffer[100];
00044         std::string file;
00045         FILE *in = fopen(filename.c_str(), "r");
00046         if (in)
00047         {
00048                 while (fgets(buffer, 100, in))
00049                 {
00050                         file += buffer;
00051                 }
00052                 fclose(in);
00053         }
00054         return file;
00055 }
00056 
00057 std::string ServerWebServerUtil::concatLines(std::list<std::string> &lines)
00058 {
00059         std::string result;
00060         std::list<std::string>::iterator itor;
00061         for (itor = lines.begin();
00062                 itor != lines.end();
00063                 itor++)
00064         {
00065                 result.append(*itor).append("<br>");
00066 
00067         }
00068         return result;
00069 }
00070 
00071 const char *ServerWebServerUtil::strstrlen(const char *start, const char *find, int size)
00072 {
00073         int findsize = strlen(find);
00074         const char *current = start;
00075         for (int i=0; i<size - findsize; i++, current++)
00076         {
00077                 bool found = true;
00078                 for (int j=0; j<findsize; j++)
00079                 {
00080                         if (current[j] != find[j])
00081                         {
00082                                 found = false;
00083                                 break;
00084                         }
00085                 }
00086                 if (found) return current;
00087         }
00088         return 0;
00089 }
00090 
00091 void ServerWebServerUtil::extractMultiPartPost(const char *start, 
00092         const char *boundry, int sizeleft, std::map<std::string, NetMessage *> &parts)
00093 {
00094         int boundrylen = strlen(boundry);
00095         while (true)
00096         {
00097                 // Find the first boundry
00098                 const char *first = strstrlen(start, boundry, sizeleft);
00099                 if (!first) return;
00100 
00101                 // We've now got less to search
00102                 first += boundrylen;
00103                 sizeleft -= first - start; 
00104                 start = first;
00105 
00106                 // Find the name
00107                 const char *namestart = strstrlen(start, "name=\"", sizeleft); 
00108                 if (!namestart) return;
00109                 namestart += 6;
00110                 const char *nameend = strstrlen(namestart, "\"", sizeleft);
00111                 if (!nameend) return;
00112                 if (nameend-namestart < 1) return;
00113                 std::string name(namestart, nameend - namestart);
00114 
00115                 // Find the data start
00116                 const char *data = strstrlen(start, "\r\n\r\n", sizeleft);
00117                 if (!data) return;
00118                 data += 4;
00119 
00120                 // Find the second boundry
00121                 const char *second = strstrlen(start, boundry, sizeleft);
00122                 if (!second) return;
00123 
00124                 // The message is from data to second
00125                 int messagelen = second - data;
00126                 NetMessage *message = NetMessagePool::instance()->getFromPool(
00127                         NetMessage::BufferMessage, 0, 0, 0);
00128                 message->getBuffer().addDataToBuffer(data, messagelen);
00129                 parts[name] = message;
00130         }
00131 }
00132 
00133 void ServerWebServerUtil::extractQueryFields(std::map<std::string, std::string> &fields, char *sep)
00134 {
00135         char *token = strtok(sep, "&");
00136         while(token)
00137         {
00138                 char *eq = strchr(token, '=');
00139                 if (eq)
00140                 {
00141                         *eq = '\0';
00142                         std::string value;
00143                         for (const char *valueStr = (eq + 1); *valueStr; valueStr++)
00144                         {
00145                                 char c = *valueStr;
00146                                 if (c == '+') c = ' ';
00147                                 else if (c == '%')
00148                                 {
00149                                         char buf[3] = { 0, 0, 0 };
00150 
00151                                         buf[0] = *(valueStr + 1);
00152                                         if (!buf[0]) break;
00153                                         buf[1] = *(valueStr + 2);
00154                                         if (!buf[1]) break;
00155 
00156                                         c = (char) strtol(buf, 0, 16);
00157 
00158                                         valueStr += 2;
00159                                 }
00160 
00161                                 if (c != '\r') value += c;
00162                         }
00163 
00164                         if (fields.find(token) == fields.end())
00165                         {
00166                                 fields[token] = value;
00167                         }
00168                         *eq = '=';
00169                 }                               
00170                 token = strtok(0, "&");
00171         }
00172 }
00173 
00174 void ServerWebServerUtil::generateSettingValue(OptionEntry *entry, std::string &value)
00175 {
00176         if (entry->getEntryType() == OptionEntry::OptionEntryTextType)
00177         {
00178                 value = S3D::formatStringBuffer("<textarea name='%s' cols=20 rows=5>%s</textarea>",
00179                         entry->getName(),
00180                         entry->getValueAsString());
00181         }
00182         else if (entry->getEntryType() == OptionEntry::OptionEntryBoolType)
00183         {
00184                 OptionEntryBool *boolEntry = (OptionEntryBool *) entry;
00185                 
00186                 value = S3D::formatStringBuffer(
00187                         "<input type='radio' name='%s' %s value='on'>On</input>"
00188                         "<input type='radio' name='%s' %s value='off'>Off</input>",
00189                         entry->getName(), (boolEntry->getValue()?"checked":""),
00190                         entry->getName(), (!boolEntry->getValue()?"checked":""));
00191         }
00192         else if (entry->getEntryType() == OptionEntry::OptionEntryBoundedIntType)
00193         {
00194                 OptionEntryBoundedInt *intEntry = (OptionEntryBoundedInt *) entry;
00195                 
00196                 value = S3D::formatStringBuffer("<select name='%s'>", entry->getName());
00197                 bool found = false;
00198                 for (int i=intEntry->getMinValue(); 
00199                         i<=intEntry->getMaxValue();
00200                         i+=intEntry->getStepValue())
00201                 {
00202                         if (intEntry->getValue() < i && !found)
00203                         {
00204                                 found = true;
00205                                 value.append(S3D::formatStringBuffer("<option %s>%i</option>",
00206                                         "selected", 
00207                                         intEntry->getValue()));
00208                         }
00209                         else if (intEntry->getValue() == i)
00210                         {
00211                                 found = true;
00212                         }
00213 
00214                         value.append(S3D::formatStringBuffer("<option %s>%i</option>",
00215                                 (intEntry->getValue() == i?"selected":""), 
00216                                 i));
00217                 }
00218                 value.append("</select>");
00219         }
00220         else if (entry->getEntryType() == OptionEntry::OptionEntryEnumType)
00221         {
00222                 OptionEntryEnum *enumEntry = (OptionEntryEnum *) entry;
00223 
00224                 value = S3D::formatStringBuffer("<select name='%s'>", entry->getName());
00225                 OptionEntryEnum::EnumEntry *enums = enumEntry->getEnums();
00226                 for (OptionEntryEnum::EnumEntry *current = enums; current->description[0]; current++)
00227                 {
00228                         value.append(S3D::formatStringBuffer("<option %s>%s</option>",
00229                                 (enumEntry->getValue() == current->value?"selected":""), 
00230                                 current->description));         
00231                 }
00232                 value.append("</select>");
00233         }
00234         else if (entry->getEntryType() == OptionEntry::OptionEntryStringEnumType)
00235         {
00236                 OptionEntryStringEnum *enumEntry = (OptionEntryStringEnum *) entry;
00237                 
00238                 value = S3D::formatStringBuffer("<select name='%s'>", entry->getName());
00239                 OptionEntryStringEnum::EnumEntry *enums = enumEntry->getEnums();
00240                 for (OptionEntryStringEnum::EnumEntry *current = enums; current->value[0]; current++)
00241                 {
00242                         value.append(S3D::formatStringBuffer("<option %s>%s</option>",
00243                                 (0 == strcmp(enumEntry->getValue(), current->value)?"selected":""), 
00244                                 current->value));               
00245                 }
00246                 value.append("</select>");
00247         }
00248         else
00249         {
00250                 value = S3D::formatStringBuffer("<input type='text' name='%s' value='%s'>",
00251                         entry->getName(),
00252                         entry->getValueAsString());
00253         }
00254 }
00255 
00256 void ServerWebServerUtil::getHtmlRedirect(
00257         const std::string &url,
00258         std::string &result)
00259 {
00260         std::string header = 
00261                 S3D::formatStringBuffer(
00262                 "HTTP/1.1 302 OK\r\n"
00263                 "Server: Scorched3D\r\n"
00264                 "Content-Type: text/html\r\n"
00265                 "Connection: Close\r\n"
00266                 "Location: %s\r\n"
00267                 "\r\n", url.c_str());
00268         result.append(header);
00269 }
00270 
00271 void ServerWebServerUtil::getHtmlNotFound(
00272         std::string &result)
00273 {
00274         std::string header = 
00275                 S3D::formatStringBuffer(
00276                 "HTTP/1.1 404 OK\r\n"
00277                 "Server: Scorched3D\r\n"
00278                 "Content-Type: text/html\r\n"
00279                 "Connection: Close\r\n"
00280                 "\r\n");
00281         result.append(header);
00282 }
00283 
00284 bool ServerWebServerUtil::getHtmlTemplate(
00285         ServerAdminSessions::SessionParams *session,
00286         const std::string &name,
00287         std::map<std::string, std::string> &fields,
00288         std::string &result)
00289 {
00290         const char *header = 
00291                 "HTTP/1.1 200 OK\r\n"
00292                 "Server: Scorched3D\r\n"
00293                 "Content-Type: text/html\r\n"
00294                 "Connection: Close\r\n"
00295                 "\r\n";
00296         result.append(header);
00297 
00298         return getTemplate(session, name, fields, result);
00299 }
00300 
00301 bool ServerWebServerUtil::getTemplate(
00302         ServerAdminSessions::SessionParams *session,
00303         const std::string &name,
00304         std::map<std::string, std::string> &fields,
00305         std::string &result)
00306 {
00307         // Perhaps cache this
00308         std::string fileName = S3D::getDataFile(
00309                 S3D::formatStringBuffer("data/html/server/%s", name.c_str()));
00310         FILE *in = fopen(fileName.c_str(), "r");
00311         if (!in) 
00312         {
00313                 Logger::log(S3D::formatStringBuffer("ERROR: Failed to open web template \"%s\"", fileName.c_str()));
00314                 return false;
00315         }
00316 
00317         char buffer[1024], include[256];
00318         while (fgets(buffer, 1024, in))
00319         {
00320                 // Check for an include line
00321                 if (sscanf(buffer, "#include %s",
00322                         include) == 1)
00323                 {
00324                         // Add the included file
00325                         std::string tmp;
00326                         if (!getTemplate(session, include, fields, tmp))
00327                         {
00328                                 return false;
00329                         }
00330 
00331                         result += tmp;
00332                 }
00333                 else
00334                 {
00335                         // Check for any value replacements
00336                         char *position = buffer;
00337                         for (;;)
00338                         {
00339                                 char *start, *end;
00340                                 if ((start = strstr(position, "[[")) &&
00341                                         (end = strstr(position, "]]")) &&
00342                                         (end > start))
00343                                 {
00344                                         // Replace the text [[name]] with the value
00345                                         *start = '\0';
00346                                         *end = '\0';
00347                                         result += position;
00348                                         position = end + 2;
00349 
00350                                         char *name = start + 2;
00351 
00352                                         // First check to see if it is in the supplied fields
00353                                         if (fields.find(name) != fields.end())
00354                                         {
00355                                                 result += fields[name];
00356                                         }
00357                                         else
00358                                         {
00359                                                 // Then in the scorched3d settings
00360                                                 std::list<OptionEntry *>::iterator itor;
00361                                                 std::list<OptionEntry *> &options = 
00362                                                         ScorchedServer::instance()->getOptionsGame().
00363                                                                 getChangedOptions().getOptions();
00364                                                 for (itor = options.begin();
00365                                                         itor != options.end();
00366                                                         itor++)
00367                                                 {
00368                                                         OptionEntry *entry = (*itor);
00369                                                         if (!(entry->getData() & OptionEntry::DataProtected))
00370                                                         {
00371                                                                 if (strcmp(entry->getName(), name) == 0)
00372                                                                 {
00373                                                                         result += entry->getValueAsString();
00374                                                                 }
00375                                                                 else
00376                                                                 {
00377                                                                         std::string newName(entry->getName());
00378                                                                         newName.append("_set");
00379                                                                         if (strcmp(newName.c_str(), name) == 0)
00380                                                                         {
00381                                                                                 std::string value;
00382                                                                                 generateSettingValue(entry,value);
00383                                                                                 result += value;
00384                                                                         }
00385                                                                 }
00386                                                         }
00387                                                 }                                               
00388                                         }
00389                                 }
00390                                 else
00391                                 {
00392                                         // No replacements
00393                                         result += position;
00394                                         break;
00395                                 }
00396                         }
00397                 }
00398         }
00399         fclose(in);
00400 
00401         while (true)
00402         {
00403                 // Find start {{permission}}
00404                 int start1 = result.find("{{");
00405                 if (start1 == std::string::npos) break;
00406                 int end1 = result.find("}}", start1);
00407                 if (end1 == std::string::npos) break;
00408                 std::string perm(result, start1 + 2, end1 - start1 - 2);
00409                 result.replace(start1, end1 - start1 + 2, "");
00410 
00411                 // Find end {{permission}}
00412                 int start2 = result.find(S3D::formatStringBuffer("{{%s}}", perm.c_str()), start1);
00413                 if (start2 == std::string::npos) break;
00414                 result.replace(start2, 4 + perm.size(), "");
00415 
00416                 if (session->credentials.permissions.find(perm) == 
00417                         session->credentials.permissions.end())
00418                 {
00419                         result.replace(start1, start2 - start1, "");
00420                 }
00421         }
00422 
00423         return true;
00424 }
00425 
00426 bool ServerWebServerUtil::getHtmlMessage(
00427         ServerAdminSessions::SessionParams *session,
00428         const std::string &title,
00429         const std::string &text,
00430         std::map<std::string, std::string> &fields,
00431         std::string &result)
00432 {
00433         fields["MESSAGE"] = text;
00434         fields["TITLE"] = title;
00435         return getHtmlTemplate(session, "message.html", fields, result);
00436 }

Generated on Mon Feb 16 15:14:53 2009 for Scorched3D by  doxygen 1.5.3