00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00098 const char *first = strstrlen(start, boundry, sizeleft);
00099 if (!first) return;
00100
00101
00102 first += boundrylen;
00103 sizeleft -= first - start;
00104 start = first;
00105
00106
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
00116 const char *data = strstrlen(start, "\r\n\r\n", sizeleft);
00117 if (!data) return;
00118 data += 4;
00119
00120
00121 const char *second = strstrlen(start, boundry, sizeleft);
00122 if (!second) return;
00123
00124
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
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
00321 if (sscanf(buffer, "#include %s",
00322 include) == 1)
00323 {
00324
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
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
00345 *start = '\0';
00346 *end = '\0';
00347 result += position;
00348 position = end + 2;
00349
00350 char *name = start + 2;
00351
00352
00353 if (fields.find(name) != fields.end())
00354 {
00355 result += fields[name];
00356 }
00357 else
00358 {
00359
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
00393 result += position;
00394 break;
00395 }
00396 }
00397 }
00398 }
00399 fclose(in);
00400
00401 while (true)
00402 {
00403
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
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 }