00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <time.h>
00024 #include <webserver/ServerWebServer.h>
00025 #include <webserver/ServerWebHandler.h>
00026 #include <webserver/ServerWebSettingsHandler.h>
00027 #include <webserver/ServerWebAppletHandler.h>
00028 #include <server/ServerChannelManager.h>
00029 #include <server/ServerCommon.h>
00030 #include <webserver/ServerWebServerUtil.h>
00031 #include <server/ScorchedServer.h>
00032 #include <net/NetMessagePool.h>
00033 #include <common/OptionsScorched.h>
00034 #include <common/Logger.h>
00035 #include <common/LoggerI.h>
00036 #include <common/Defines.h>
00037
00038 ServerWebServer *ServerWebServer::instance_ = 0;
00039
00040 ServerWebServer *ServerWebServer::instance()
00041 {
00042 if (!instance_)
00043 {
00044 instance_ = new ServerWebServer();
00045 }
00046 return instance_;
00047 }
00048
00049 ServerWebServer::ServerWebServer() :
00050 netServer_(new NetServerHTTPProtocolRecv),
00051 logger_(0), asyncTimer_(0)
00052 {
00053 sendThread_ = SDL_CreateThread(ServerWebServer::sendThreadFunc, 0);
00054 if (sendThread_ == 0)
00055 {
00056 Logger::log(S3D::formatStringBuffer("ServerWebServer: Failed to create thread"));
00057 }
00058
00059 addRequestHandler("/players", new ServerWebHandler::PlayerHandler());
00060 addThrededRequestHandler("/playersthreaded", new ServerWebHandler::PlayerHandlerThreaded());
00061 addRequestHandler("/logs", new ServerWebHandler::LogHandler());
00062 addRequestHandler("/logfile", new ServerWebHandler::LogFileHandler());
00063 addRequestHandler("/game", new ServerWebHandler::GameHandler());
00064 addRequestHandler("/server", new ServerWebHandler::ServerHandler());
00065 addRequestHandler("/talk", new ServerWebAppletHandler::AppletHtmlHandler());
00066 addRequestHandler("/banned", new ServerWebHandler::BannedHandler());
00067 addRequestHandler("/mods", new ServerWebHandler::ModsHandler());
00068 addRequestHandler("/sessions", new ServerWebHandler::SessionsHandler());
00069 addRequestHandler("/account", new ServerWebHandler::AccountHandler());
00070 addRequestHandler("/stats", new ServerWebHandler::StatsHandler());
00071 addRequestHandler("/settingsmain", new ServerWebSettingsHandler::SettingsMainHandler());
00072 addRequestHandler("/settingsall", new ServerWebSettingsHandler::SettingsAllHandler());
00073 addRequestHandler("/settingslandscape", new ServerWebSettingsHandler::SettingsLandscapeHandler());
00074 addRequestHandler("/settingsplayers", new ServerWebSettingsHandler::SettingsPlayersHandler());
00075 addRequestHandler("/settingsmod", new ServerWebSettingsHandler::SettingsModHandler());
00076 addRequestHandler("/Applet.jar", new ServerWebAppletHandler::AppletFileHandler());
00077 addAsyncRequestHandler("/appletstream", new ServerWebAppletHandler::AppletAsyncHandler());
00078 addRequestHandler("/action", new ServerWebAppletHandler::AppletActionHandler());
00079 }
00080
00081 ServerWebServer::~ServerWebServer()
00082 {
00083 }
00084
00085 int ServerWebServer::sendThreadFunc(void *)
00086 {
00087 while (true)
00088 {
00089 SDL_Delay(100);
00090
00091
00092 instance_->processQueue(instance_->threadedQueue_, false);
00093 }
00094 return 1;
00095 }
00096
00097 void ServerWebServer::start(int port)
00098 {
00099 Logger::log(S3D::formatStringBuffer("Starting management web server on port %i", port));
00100 netServer_.setMessageHandler(this);
00101 netServer_.start(port);
00102
00103 if (0 != strcmp(ScorchedServer::instance()->getOptionsGame().
00104 getServerFileLogger(), "none"))
00105 {
00106 logger_ = new FileLogger(
00107 S3D::formatStringBuffer("ServerWeb-%i-",
00108 ScorchedServer::instance()->getOptionsGame().getPortNo()));
00109 }
00110 }
00111
00112 void ServerWebServer::addRequestHandler(const char *url,
00113 ServerWebServerI *handler)
00114 {
00115 HandlerEntry entry = { handler, 0 };
00116 handlers_[url] = entry;
00117 }
00118
00119 void ServerWebServer::addThrededRequestHandler(const char *url,
00120 ServerWebServerI *handler)
00121 {
00122 HandlerEntry entry = { handler, HandlerEntry::eThreaded };
00123 handlers_[url] = entry;
00124 }
00125
00126 void ServerWebServer::addAsyncRequestHandler(const char *url,
00127 ServerWebServerI *handler)
00128 {
00129 HandlerEntry entry = { handler, HandlerEntry::eAsync };
00130 handlers_[url] = entry;
00131 }
00132
00133 void ServerWebServer::processMessages()
00134 {
00135
00136 while (!delayedMessages_.empty())
00137 {
00138 unsigned int theTime = (unsigned int) time(0);
00139 std::pair<unsigned int, NetMessage *> &delayedMessage =
00140 delayedMessages_.front();
00141 if (delayedMessage.first <= theTime)
00142 {
00143
00144 NetMessage *message = delayedMessage.second;
00145 delayedMessages_.pop_front();
00146
00147
00148 netServer_.sendMessageDest(message->getBuffer(), message->getDestinationId());
00149 NetMessagePool::instance()->addToPool(message);
00150 }
00151 else break;
00152 }
00153
00154
00155 netServer_.processMessages();
00156
00157
00158 unsigned int theTime = (unsigned int) time(0);
00159 if (theTime != asyncTimer_)
00160 {
00161 asyncTimer_ = theTime;
00162 processQueue(asyncQueue_, true);
00163 }
00164 }
00165
00166 void ServerWebServer::processMessage(NetMessage &message)
00167 {
00168 if (message.getMessageType() == NetMessage::BufferMessage)
00169 {
00170
00171
00172
00173
00174
00175 message.getBuffer().addToBuffer("");
00176 const char *buffer = message.getBuffer().getBuffer();
00177
00178
00179 bool ok = false;
00180 bool get = (strstr(buffer, "GET ") == buffer);
00181 bool post = (strstr(buffer, "POST ") == buffer);
00182 if (get || post)
00183 {
00184 std::map<std::string, std::string> fields;
00185 std::map<std::string, NetMessage *> parts;
00186
00187
00188 if (post)
00189 {
00190
00191 char *headerend = (char *) strstr(buffer, "\r\n\r\n");
00192 if (headerend)
00193 {
00194
00195
00196
00197 headerend[0] = '\0';
00198 const char *findStr = "Content-Type: multipart/form-data; boundary=";
00199 const char *multipart = strstr(buffer, findStr);
00200 headerend[0] = '\r';
00201 if (multipart)
00202 {
00203
00204
00205 const char *boundryStart = multipart + strlen(findStr);
00206 char *boundrysep = (char *) strstr(boundryStart, "\r\n");
00207 if (boundrysep)
00208 {
00209
00210 boundrysep[0] = '\0';
00211 std::string boundry = boundryStart;
00212 boundrysep[0] = '\r';
00213
00214
00215 headerend += 4;
00216 int headersize = headerend - buffer;
00217 int sizeleft = message.getBuffer().getBufferUsed() - headersize;
00218
00219 ServerWebServerUtil::extractMultiPartPost(headerend, boundry.c_str(), sizeleft, parts);
00220 }
00221 }
00222 else
00223 {
00224
00225 headerend += 4;
00226 ServerWebServerUtil::extractQueryFields(fields, headerend);
00227 }
00228 }
00229 }
00230
00231
00232 const char *url = buffer + (get?4:5);
00233 char *eol = (char *) strchr(url, ' ');
00234 if (eol)
00235 {
00236 *eol = '\0';
00237 if (*url)
00238 {
00239
00240 char *sep = (char *) strchr(url, '?');
00241 if (sep)
00242 {
00243 *sep = '\0'; sep++;
00244 ServerWebServerUtil::extractQueryFields(fields, sep);
00245 }
00246
00247
00248 fields["ipaddress"] =
00249 NetInterface::getIpName(message.getIpAddress());
00250
00251
00252 if (logger_)
00253 {
00254 time_t t = time(0);
00255 std::string f;
00256 std::map<std::string, std::string>::iterator itor;
00257 for (itor = fields.begin();
00258 itor != fields.end();
00259 itor++)
00260 {
00261 if (0 != strcmp((*itor).first.c_str(), "password"))
00262 {
00263 f += S3D::formatStringBuffer("%s=%s ",
00264 (*itor).first.c_str(),
00265 (*itor).second.c_str());
00266 }
00267 }
00268
00269 std::string username;
00270 if (fields.find("sid") != fields.end())
00271 {
00272 unsigned int sid = (unsigned int) atoi(fields["sid"].c_str());
00273 ServerAdminSessions::SessionParams *session =
00274 ServerAdminSessions::instance()->getSession(sid);
00275 if (session)
00276 {
00277 username = session->credentials.username;
00278 }
00279 }
00280
00281 LoggerInfo info(
00282 S3D::formatStringBuffer("%u %s http://%s [%s]",
00283 message.getDestinationId(),
00284 username.c_str(), url, f.c_str()),
00285 ctime(&t));
00286 logger_->logMessage(info);
00287 }
00288
00289
00290 const char *ipaddress = NetInterface::getIpName(message.getIpAddress());
00291 ok = processRequest(message.getDestinationId(), ipaddress, url, fields, parts);
00292 }
00293 }
00294
00295
00296 std::map<std::string, NetMessage *>::iterator partitor;
00297 for (partitor = parts.begin();
00298 partitor != parts.end();
00299 partitor++)
00300 {
00301 NetMessage *newMessage = (*partitor).second;
00302 NetMessagePool::instance()->addToPool(newMessage);
00303 }
00304 }
00305
00306 if (!ok)
00307 {
00308
00309 netServer_.disconnectClient(message.getDestinationId());
00310 }
00311 }
00312 else if (message.getMessageType() == NetMessage::SentMessage)
00313 {
00314
00315 if (asyncQueue_.hasEntry(message.getDestinationId()))
00316 {
00317
00318 }
00319 else
00320 {
00321
00322
00323 netServer_.disconnectClient(message.getDestinationId());
00324 }
00325 }
00326 else if (message.getMessageType() == NetMessage::DisconnectMessage)
00327 {
00328
00329
00330 asyncQueue_.removeEntry(message.getDestinationId());
00331 }
00332 }
00333
00334 bool ServerWebServer::processRequest(
00335 unsigned int destinationId,
00336 const char *ip,
00337 const char *url,
00338 std::map<std::string, std::string> &fields,
00339 std::map<std::string, NetMessage *> &parts)
00340 {
00341 bool delayed = false;
00342 std::string text;
00343 if (0 == strcmp(url, "/"))
00344 {
00345
00346
00347 if (validateUser(ip, url, fields))
00348 {
00349
00350
00351 ServerWebServerUtil::getHtmlRedirect(
00352 S3D::formatStringBuffer("/players?sid=%s", fields["sid"].c_str()), text);
00353 }
00354 else
00355 {
00356
00357
00358 if (!ServerWebServerUtil::getHtmlTemplate(
00359 0, "login.html", fields, text)) return false;
00360 delayed = true;
00361 }
00362 }
00363 else
00364 {
00365
00366
00367 unsigned int sid = validateSession(ip, url, fields);
00368 if (sid)
00369 {
00370
00371 std::map<std::string, HandlerEntry>::iterator itor =
00372 handlers_.find(url);
00373 if (itor == handlers_.end())
00374 {
00375 ServerWebServerUtil::getHtmlNotFound(text);
00376 }
00377 else
00378 {
00379 ServerWebServerI *handler = itor->second.handler->createCopy();
00380 ServerWebServerQueueEntry *entry = new ServerWebServerQueueEntry(
00381 destinationId, sid, url, handler, fields, parts);
00382
00383 if (itor->second.flags == HandlerEntry::eAsync)
00384 {
00385 asyncQueue_.addEntry(entry);
00386 }
00387 else if (itor->second.flags == HandlerEntry::eThreaded)
00388 {
00389 threadedQueue_.addEntry(entry);
00390 }
00391 else
00392 {
00393 normalQueue_.addEntry(entry);
00394 if (!processQueue(normalQueue_, false)) return false;
00395 }
00396 return true;
00397 }
00398 }
00399 else
00400 {
00401 if (handlers_.find(url) == handlers_.end())
00402 {
00403
00404
00405
00406
00407 ServerWebServerUtil::getHtmlNotFound(text);
00408 }
00409 else
00410 {
00411
00412 ServerWebServerUtil::getHtmlRedirect("/", text);
00413 delayed = true;
00414 }
00415 }
00416 }
00417
00418
00419 if (text.empty()) return false;
00420
00421
00422 NetMessage *message = NetMessagePool::instance()->getFromPool(
00423 NetMessage::BufferMessage, destinationId, 0, 0);
00424 message->getBuffer().addDataToBuffer(text.data(), text.size());
00425 if (delayed)
00426 {
00427
00428 unsigned int delayedTime = (unsigned int) time(0) + 5;
00429 std::pair<unsigned int, NetMessage *> delayedMessage(delayedTime, message);
00430 delayedMessages_.push_back(delayedMessage);
00431 }
00432 else
00433 {
00434
00435 netServer_.sendMessageDest(message->getBuffer(), message->getDestinationId());
00436 NetMessagePool::instance()->addToPool(message);
00437 }
00438
00439 return true;
00440 }
00441
00442 unsigned int ServerWebServer::validateSession(
00443 const char *ip,
00444 const char *url,
00445 std::map<std::string, std::string> &fields)
00446 {
00447
00448 if (strcmp(url, "/Applet.jar") == 0)
00449 {
00450 ServerAdminSessions::SessionParams *session =
00451 ServerAdminSessions::instance()->getFirstSession();
00452 if (session)
00453 {
00454 return session->sid;
00455 }
00456 }
00457
00458
00459 if (fields.find("sid") != fields.end())
00460 {
00461 unsigned int sid = (unsigned int) atoi(fields["sid"].c_str());
00462 ServerAdminSessions::SessionParams *params =
00463 ServerAdminSessions::instance()->getSession(sid);
00464 if (params) return sid;
00465 }
00466
00467 return 0;
00468 }
00469
00470 bool ServerWebServer::validateUser(
00471 const char *ip,
00472 const char *url,
00473 std::map<std::string, std::string> &fields)
00474 {
00475
00476 unsigned int sid = ServerAdminSessions::instance()->login(
00477 fields["name"].c_str(),
00478 fields["password"].c_str(),
00479 ip);
00480 if (sid != 0)
00481 {
00482
00483 fields["sid"] = S3D::formatStringBuffer("%u", sid);
00484
00485 ServerAdminSessions::SessionParams *adminSession =
00486 ServerAdminSessions::instance()->getSession(sid);
00487
00488 ServerChannelManager::instance()->sendText(
00489 ChannelText("info",
00490 "ADMIN_WEB_LOGIN",
00491 "server admin \"{0}\" logged in",
00492 adminSession->credentials.username.c_str()),
00493 true);
00494
00495 return true;
00496 }
00497 else
00498 {
00499 Logger::log(S3D::formatStringBuffer("Failed login for server admin \"%s\", via web, ip \"%s\"",
00500 fields["name"].c_str(), ip));
00501 }
00502
00503 return false;
00504 }
00505
00506 bool ServerWebServer::processQueue(ServerWebServerQueue &queue, bool keepEntries)
00507 {
00508 bool result = true;
00509 std::list<ServerWebServerQueueEntry *> keptEntries;
00510
00511
00512 ServerWebServerQueueEntry *entry = 0;
00513 while ((entry = queue.getEntry()) != 0)
00514 {
00515 bool keepEntry = keepEntries;
00516
00517
00518 ServerAdminSessions::SessionParams *session = ServerAdminSessions::instance()->getSession(
00519 entry->getSid());
00520 entry->getRequest().setSession(session);
00521
00522
00523 std::string resultText;
00524 if (session &&
00525 entry->getHandler()->processRequest(
00526 entry->getRequest(), resultText))
00527 {
00528 if (!resultText.empty())
00529 {
00530
00531
00532 NetMessage *message = NetMessagePool::instance()->getFromPool(
00533 NetMessage::BufferMessage, entry->getDestinationId(), 0, 0);
00534 message->getBuffer().addDataToBuffer(resultText.data(), resultText.size());
00535
00536
00537 netServer_.sendMessageDest(message->getBuffer(), message->getDestinationId());
00538 NetMessagePool::instance()->addToPool(message);
00539
00540
00541 ServerAdminSessions::instance()->getSession(entry->getSid());
00542 }
00543 else
00544 {
00545 result = false;
00546 }
00547 }
00548 else
00549 {
00550 keepEntry = false;
00551 result = false;
00552 }
00553
00554
00555 if (keepEntry) keptEntries.push_back(entry);
00556 else delete entry;
00557 }
00558
00559
00560 while (!keptEntries.empty())
00561 {
00562 entry = keptEntries.front();
00563 keptEntries.pop_front();
00564 queue.addEntry(entry);
00565 }
00566
00567 return result;
00568 }