WebAdmin uses the new HTTP functionality.
This is a partial implementation of #183.
This commit is contained in:
parent
20d07a683f
commit
b5c90d7b20
@ -1,6 +1,6 @@
|
||||
/*
|
||||
** Lua binding: AllToLua
|
||||
** Generated automatically by tolua++-1.0.92 on 09/21/13 17:37:22.
|
||||
** Generated automatically by tolua++-1.0.92 on 10/05/13 18:34:12.
|
||||
*/
|
||||
|
||||
#ifndef __cplusplus
|
||||
@ -240,18 +240,19 @@ static void tolua_reg_types (lua_State* tolua_S)
|
||||
tolua_usertype(tolua_S,"cCraftingRecipe");
|
||||
tolua_usertype(tolua_S,"cPlugin");
|
||||
tolua_usertype(tolua_S,"cItemGrid");
|
||||
tolua_usertype(tolua_S,"cBlockArea");
|
||||
tolua_usertype(tolua_S,"cHTTPServer::cCallbacks");
|
||||
tolua_usertype(tolua_S,"cLuaWindow");
|
||||
tolua_usertype(tolua_S,"cInventory");
|
||||
tolua_usertype(tolua_S,"cBoundingBox");
|
||||
tolua_usertype(tolua_S,"cBlockEntityWithItems");
|
||||
tolua_usertype(tolua_S,"HTTPFormData");
|
||||
tolua_usertype(tolua_S,"cTracer");
|
||||
tolua_usertype(tolua_S,"HTTPFormData");
|
||||
tolua_usertype(tolua_S,"cWindow");
|
||||
tolua_usertype(tolua_S,"cArrowEntity");
|
||||
tolua_usertype(tolua_S,"cDropSpenserEntity");
|
||||
tolua_usertype(tolua_S,"cWindow");
|
||||
tolua_usertype(tolua_S,"Vector3i");
|
||||
tolua_usertype(tolua_S,"cBlockArea");
|
||||
tolua_usertype(tolua_S,"cCraftingGrid");
|
||||
tolua_usertype(tolua_S,"Vector3i");
|
||||
tolua_usertype(tolua_S,"cGroup");
|
||||
tolua_usertype(tolua_S,"cStringMap");
|
||||
tolua_usertype(tolua_S,"cBlockEntity");
|
||||
@ -18666,38 +18667,6 @@ static int tolua_AllToLua_cWebAdmin_GetMemoryUsage00(lua_State* tolua_S)
|
||||
}
|
||||
#endif //#ifndef TOLUA_DISABLE
|
||||
|
||||
/* method: GetPort of class cWebAdmin */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWebAdmin_GetPort00
|
||||
static int tolua_AllToLua_cWebAdmin_GetPort00(lua_State* tolua_S)
|
||||
{
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cWebAdmin",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cWebAdmin* self = (cWebAdmin*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPort'", NULL);
|
||||
#endif
|
||||
{
|
||||
int tolua_ret = (int) self->GetPort();
|
||||
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'GetPort'.",&tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif //#ifndef TOLUA_DISABLE
|
||||
|
||||
/* method: GetPage of class cWebAdmin */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWebAdmin_GetPage00
|
||||
static int tolua_AllToLua_cWebAdmin_GetPage00(lua_State* tolua_S)
|
||||
@ -30233,10 +30202,9 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||
tolua_variable(tolua_S,"PluginName",tolua_get_sWebAdminPage_PluginName,tolua_set_sWebAdminPage_PluginName);
|
||||
tolua_variable(tolua_S,"TabName",tolua_get_sWebAdminPage_TabName,tolua_set_sWebAdminPage_TabName);
|
||||
tolua_endmodule(tolua_S);
|
||||
tolua_cclass(tolua_S,"cWebAdmin","cWebAdmin","",NULL);
|
||||
tolua_cclass(tolua_S,"cWebAdmin","cWebAdmin","cHTTPServer::cCallbacks",NULL);
|
||||
tolua_beginmodule(tolua_S,"cWebAdmin");
|
||||
tolua_function(tolua_S,"GetMemoryUsage",tolua_AllToLua_cWebAdmin_GetMemoryUsage00);
|
||||
tolua_function(tolua_S,"GetPort",tolua_AllToLua_cWebAdmin_GetPort00);
|
||||
tolua_function(tolua_S,"GetPage",tolua_AllToLua_cWebAdmin_GetPage00);
|
||||
tolua_function(tolua_S,"GetBaseURL",tolua_AllToLua_cWebAdmin_GetBaseURL00);
|
||||
tolua_endmodule(tolua_S);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
** Lua binding: AllToLua
|
||||
** Generated automatically by tolua++-1.0.92 on 09/21/13 17:37:22.
|
||||
** Generated automatically by tolua++-1.0.92 on 10/05/13 18:34:12.
|
||||
*/
|
||||
|
||||
/* Exported function */
|
||||
|
@ -32,7 +32,7 @@ cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callba
|
||||
}
|
||||
if ((a_Request.GetMethod() == "POST") || (a_Request.GetMethod() == "PUT"))
|
||||
{
|
||||
if (a_Request.GetContentType() == "application/x-www-form-urlencoded")
|
||||
if (strncmp(a_Request.GetContentType().c_str(), "application/x-www-form-urlencoded", 33) == 0)
|
||||
{
|
||||
m_Kind = fpkFormUrlEncoded;
|
||||
return;
|
||||
@ -44,7 +44,8 @@ cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callba
|
||||
return;
|
||||
}
|
||||
}
|
||||
ASSERT(!"Unhandled request method");
|
||||
// Invalid method / content type combination, this is not a HTTP form
|
||||
m_IsValid = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -120,6 +120,23 @@ int cHTTPRequest::ParseHeaders(const char * a_Data, int a_Size)
|
||||
|
||||
|
||||
|
||||
AString cHTTPRequest::GetBareURL(void) const
|
||||
{
|
||||
size_t idxQM = m_URL.find('?');
|
||||
if (idxQM != AString::npos)
|
||||
{
|
||||
return m_URL.substr(0, idxQM);
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_URL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
|
||||
{
|
||||
m_IncomingHeaderData.append(a_Data, a_Size);
|
||||
|
@ -82,6 +82,9 @@ public:
|
||||
/// Returns the URL used in the request
|
||||
const AString & GetURL(void) const { return m_URL; }
|
||||
|
||||
/// Returns the URL used in the request, without any parameters
|
||||
AString GetBareURL(void) const;
|
||||
|
||||
/// Sets the UserData pointer that is stored within this request. The request doesn't touch this data (doesn't delete it)!
|
||||
void SetUserData(void * a_UserData) { m_UserData = a_UserData; }
|
||||
|
||||
|
@ -127,25 +127,16 @@ cHTTPServer::cHTTPServer(void) :
|
||||
|
||||
|
||||
|
||||
bool cHTTPServer::Initialize(cIniFile & a_IniFile)
|
||||
bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6)
|
||||
{
|
||||
if (!a_IniFile.GetValueSetB("WebAdmin", "Enabled", false))
|
||||
{
|
||||
// The WebAdmin is disabled
|
||||
return true;
|
||||
}
|
||||
bool HasAnyPort;
|
||||
HasAnyPort = m_ListenThreadIPv4.Initialize(a_IniFile.GetValueSet("WebAdmin", "Port", "8081"));
|
||||
HasAnyPort = m_ListenThreadIPv6.Initialize(a_IniFile.GetValueSet("WebAdmin", "PortsIPv6", "8082, 3300")) || HasAnyPort;
|
||||
HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4);
|
||||
HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort;
|
||||
if (!HasAnyPort)
|
||||
{
|
||||
LOG("WebAdmin is disabled");
|
||||
return false;
|
||||
}
|
||||
|
||||
// DEBUG:
|
||||
return Start(g_DebugCallbacks);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,8 @@ public:
|
||||
|
||||
cHTTPServer(void);
|
||||
|
||||
bool Initialize(cIniFile & a_IniFile);
|
||||
/// Initializes the server on the specified ports
|
||||
bool Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6);
|
||||
|
||||
/// Starts the server and assigns the callbacks to use for incoming requests
|
||||
bool Start(cCallbacks & a_Callbacks);
|
||||
|
@ -130,15 +130,9 @@ void cRoot::Start(void)
|
||||
}
|
||||
IniFile.WriteFile();
|
||||
|
||||
cIniFile WebIniFile("webadmin.ini");
|
||||
if (!WebIniFile.ReadFile())
|
||||
{
|
||||
LOGWARNING("webadmin.ini inaccessible, wabadmin is disabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HTTPServer.Initialize(WebIniFile);
|
||||
}
|
||||
LOG("Initialising WebAdmin...");
|
||||
m_WebAdmin = new cWebAdmin();
|
||||
m_WebAdmin->Init();
|
||||
|
||||
LOG("Loading settings...");
|
||||
m_GroupManager = new cGroupManager();
|
||||
@ -168,6 +162,9 @@ void cRoot::Start(void)
|
||||
LOG("Starting server...");
|
||||
m_Server->Start();
|
||||
|
||||
LOG("Starting WebAdmin...");
|
||||
m_WebAdmin->Start();
|
||||
|
||||
#if !defined(ANDROID_NDK)
|
||||
LOG("Starting InputThread...");
|
||||
m_InputThread = new cThread( InputThread, this, "cRoot::InputThread" );
|
||||
|
@ -14,7 +14,8 @@
|
||||
#include "Server.h"
|
||||
#include "Root.h"
|
||||
|
||||
#include "../iniFile/iniFile.h"
|
||||
#include "HTTPServer/HTTPMessage.h"
|
||||
#include "HTTPServer/HTTPConnection.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <psapi.h>
|
||||
@ -55,14 +56,13 @@ cWebAdmin * WebAdmin = NULL;
|
||||
|
||||
|
||||
|
||||
cWebAdmin::cWebAdmin( int a_Port /* = 8080 */ ) :
|
||||
m_Port(a_Port),
|
||||
m_bConnected(false),
|
||||
m_TemplateScript("<webadmin_template>")
|
||||
cWebAdmin::cWebAdmin(void) :
|
||||
m_IsInitialized(false),
|
||||
m_TemplateScript("<webadmin_template>"),
|
||||
m_IniFile("webadmin.ini")
|
||||
{
|
||||
WebAdmin = this;
|
||||
m_Event = new cEvent();
|
||||
Init( m_Port );
|
||||
}
|
||||
|
||||
|
||||
@ -73,10 +73,6 @@ cWebAdmin::~cWebAdmin()
|
||||
{
|
||||
|
||||
WebAdmin = 0;
|
||||
m_WebServer->Stop();
|
||||
|
||||
delete m_WebServer;
|
||||
delete m_IniFile;
|
||||
|
||||
m_Event->Wait();
|
||||
delete m_Event;
|
||||
@ -105,187 +101,34 @@ void cWebAdmin::RemovePlugin( cWebPlugin * a_Plugin )
|
||||
|
||||
|
||||
|
||||
void cWebAdmin::Request_Handler(webserver::http_request* r)
|
||||
bool cWebAdmin::Init(void)
|
||||
{
|
||||
if( WebAdmin == 0 ) return;
|
||||
LOG("Path: %s", r->path_.c_str() );
|
||||
|
||||
if (r->path_ == "/")
|
||||
if (!m_IniFile.ReadFile())
|
||||
{
|
||||
r->answer_ += "<h1>MCServer WebAdmin</h1>";
|
||||
r->answer_ += "<center>";
|
||||
r->answer_ += "<form method='get' action='webadmin/'>";
|
||||
r->answer_ += "<input type='submit' value='Log in'>";
|
||||
r->answer_ += "</form>";
|
||||
r->answer_ += "</center>";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (r->path_.empty() || r->path_[0] != '/')
|
||||
AString PortsIPv4 = m_IniFile.GetValue("WebAdmin", "Port", "8080");
|
||||
AString PortsIPv6 = m_IniFile.GetValue("WebAdmin", "PortsIPv6", "");
|
||||
|
||||
if (!m_HTTPServer.Initialize(PortsIPv4, PortsIPv6))
|
||||
{
|
||||
r->answer_ += "<h1>Bad request</h1>";
|
||||
r->answer_ += "<p>";
|
||||
r->answer_ = r->path_; // TODO: Shouldn't we sanitize this? Possible security issue.
|
||||
r->answer_ += "</p>";
|
||||
return;
|
||||
}
|
||||
|
||||
AStringVector Split = StringSplit(r->path_.substr(1), "/");
|
||||
|
||||
if (Split.empty() || (Split[0] != "webadmin" && Split[0] != "~webadmin"))
|
||||
{
|
||||
r->answer_ += "<h1>Bad request</h1>";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!r->authentication_given_)
|
||||
{
|
||||
r->answer_ += "no auth";
|
||||
r->auth_realm_ = "MCServer WebAdmin";
|
||||
}
|
||||
|
||||
bool bDontShowTemplate = false;
|
||||
if (Split[0] == "~webadmin")
|
||||
{
|
||||
bDontShowTemplate = true;
|
||||
}
|
||||
|
||||
AString UserPassword = WebAdmin->m_IniFile->GetValue( "User:"+r->username_, "Password", "");
|
||||
if ((UserPassword != "") && (r->password_ == UserPassword))
|
||||
{
|
||||
AString Template;
|
||||
|
||||
HTTPTemplateRequest TemplateRequest;
|
||||
TemplateRequest.Request.Username = r->username_;
|
||||
TemplateRequest.Request.Method = r->method_;
|
||||
TemplateRequest.Request.Params = r->params_;
|
||||
TemplateRequest.Request.PostParams = r->params_post_;
|
||||
TemplateRequest.Request.Path = r->path_.substr(1);
|
||||
|
||||
for( unsigned int i = 0; i < r->multipart_formdata_.size(); ++i )
|
||||
{
|
||||
webserver::formdata& fd = r->multipart_formdata_[i];
|
||||
|
||||
HTTPFormData HTTPfd;//( fd.value_ );
|
||||
HTTPfd.Value = fd.value_;
|
||||
HTTPfd.Type = fd.content_type_;
|
||||
HTTPfd.Name = fd.name_;
|
||||
LOGINFO("Form data name: %s", fd.name_.c_str() );
|
||||
TemplateRequest.Request.FormData[ fd.name_ ] = HTTPfd;
|
||||
}
|
||||
|
||||
// Try to get the template from the Lua template script
|
||||
bool bLuaTemplateSuccessful = false;
|
||||
if (!bDontShowTemplate)
|
||||
{
|
||||
bLuaTemplateSuccessful = WebAdmin->m_TemplateScript.Call("ShowPage", WebAdmin, &TemplateRequest, cLuaState::Return, Template);
|
||||
}
|
||||
|
||||
if (!bLuaTemplateSuccessful)
|
||||
{
|
||||
AString BaseURL = WebAdmin->GetBaseURL(Split);
|
||||
AString Menu;
|
||||
Template = bDontShowTemplate ? "{CONTENT}" : WebAdmin->GetTemplate();
|
||||
AString FoundPlugin;
|
||||
|
||||
for (PluginList::iterator itr = WebAdmin->m_Plugins.begin(); itr != WebAdmin->m_Plugins.end(); ++itr)
|
||||
{
|
||||
cWebPlugin* WebPlugin = *itr;
|
||||
std::list< std::pair<AString, AString> > NameList = WebPlugin->GetTabNames();
|
||||
for( std::list< std::pair<AString, AString> >::iterator Names = NameList.begin(); Names != NameList.end(); ++Names )
|
||||
{
|
||||
Menu += "<li><a href='" + BaseURL + WebPlugin->GetWebTitle().c_str() + "/" + (*Names).second + "'>" + (*Names).first + "</a></li>";
|
||||
}
|
||||
}
|
||||
|
||||
sWebAdminPage Page = WebAdmin->GetPage(TemplateRequest.Request);
|
||||
AString Content = Page.Content;
|
||||
FoundPlugin = Page.PluginName;
|
||||
if (!Page.TabName.empty())
|
||||
FoundPlugin += " - " + Page.TabName;
|
||||
|
||||
if( FoundPlugin.empty() ) // Default page
|
||||
{
|
||||
Content.clear();
|
||||
FoundPlugin = "Current Game";
|
||||
Content += "<h4>Server Name:</h4>";
|
||||
Content += "<p>" + AString( cRoot::Get()->GetServer()->GetServerID() ) + "</p>";
|
||||
|
||||
Content += "<h4>Plugins:</h4><ul>";
|
||||
cPluginManager* PM = cRoot::Get()->GetPluginManager();
|
||||
if( PM )
|
||||
{
|
||||
const cPluginManager::PluginMap & List = PM->GetAllPlugins();
|
||||
for( cPluginManager::PluginMap::const_iterator itr = List.begin(); itr != List.end(); ++itr )
|
||||
{
|
||||
if( itr->second == NULL ) continue;
|
||||
AString VersionNum;
|
||||
AppendPrintf(Content, "<li>%s V.%i</li>", itr->second->GetName().c_str(), itr->second->GetVersion());
|
||||
}
|
||||
}
|
||||
Content += "</ul>";
|
||||
Content += "<h4>Players:</h4><ul>";
|
||||
|
||||
cPlayerAccum PlayerAccum;
|
||||
cWorld * World = cRoot::Get()->GetDefaultWorld(); // TODO - Create a list of worlds and players
|
||||
if( World != NULL )
|
||||
{
|
||||
World->ForEachPlayer(PlayerAccum);
|
||||
Content.append(PlayerAccum.m_Contents);
|
||||
}
|
||||
Content += "</ul><br>";
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!bDontShowTemplate && (Split.size() > 1))
|
||||
{
|
||||
Content += "\n<p><a href='" + BaseURL + "'>Go back</a></p>";
|
||||
}
|
||||
|
||||
int MemUsageKiB = GetMemoryUsage();
|
||||
if (MemUsageKiB > 0)
|
||||
{
|
||||
ReplaceString(Template, "{MEM}", Printf("%.02f", (double)MemUsageKiB / 1024));
|
||||
ReplaceString(Template, "{MEMKIB}", Printf("%d", MemUsageKiB));
|
||||
}
|
||||
else
|
||||
{
|
||||
ReplaceString(Template, "{MEM}", "unknown");
|
||||
ReplaceString(Template, "{MEMKIB}", "unknown");
|
||||
}
|
||||
ReplaceString(Template, "{USERNAME}", r->username_);
|
||||
ReplaceString(Template, "{MENU}", Menu);
|
||||
ReplaceString(Template, "{PLUGIN_NAME}", FoundPlugin);
|
||||
ReplaceString(Template, "{CONTENT}", Content);
|
||||
ReplaceString(Template, "{TITLE}", "MCServer");
|
||||
|
||||
AString NumChunks;
|
||||
Printf(NumChunks, "%d", cRoot::Get()->GetTotalChunkCount());
|
||||
ReplaceString(Template, "{NUMCHUNKS}", NumChunks);
|
||||
}
|
||||
|
||||
r->answer_ = Template;
|
||||
}
|
||||
else
|
||||
{
|
||||
r->answer_ += "Wrong username/password";
|
||||
r->auth_realm_ = "MCServer WebAdmin";
|
||||
return false;
|
||||
}
|
||||
m_IsInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWebAdmin::Init(int a_Port)
|
||||
bool cWebAdmin::Start(void)
|
||||
{
|
||||
m_Port = a_Port;
|
||||
|
||||
m_IniFile = new cIniFile("webadmin.ini");
|
||||
if (m_IniFile->ReadFile())
|
||||
if (!m_IsInitialized)
|
||||
{
|
||||
m_Port = m_IniFile->GetValueI("WebAdmin", "Port", 8080);
|
||||
// Not initialized
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the WebAdmin template script and load the file
|
||||
@ -296,46 +139,7 @@ bool cWebAdmin::Init(int a_Port)
|
||||
m_TemplateScript.Close();
|
||||
}
|
||||
|
||||
|
||||
LOG("Starting WebAdmin on port %i", m_Port);
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE hThread = CreateThread(
|
||||
NULL, // default security
|
||||
0, // default stack size
|
||||
ListenThread, // name of the thread function
|
||||
this, // thread parameters
|
||||
0, // default startup flags
|
||||
NULL);
|
||||
CloseHandle( hThread ); // Just close the handle immediately
|
||||
#else
|
||||
pthread_t LstnThread;
|
||||
pthread_create( &LstnThread, 0, ListenThread, this);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD WINAPI cWebAdmin::ListenThread(LPVOID lpParam)
|
||||
#else
|
||||
void *cWebAdmin::ListenThread( void *lpParam )
|
||||
#endif
|
||||
{
|
||||
cWebAdmin* self = (cWebAdmin*)lpParam;
|
||||
|
||||
self->m_WebServer = new webserver(self->m_Port, Request_Handler );
|
||||
if (!self->m_WebServer->Begin())
|
||||
{
|
||||
LOGWARN("WebServer failed to start! WebAdmin is disabled");
|
||||
}
|
||||
|
||||
self->m_Event->Set();
|
||||
return 0;
|
||||
return m_HTTPServer.Start(*this);
|
||||
}
|
||||
|
||||
|
||||
@ -364,7 +168,156 @@ AString cWebAdmin::GetTemplate()
|
||||
|
||||
|
||||
|
||||
sWebAdminPage cWebAdmin::GetPage(const HTTPRequest& a_Request)
|
||||
void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request)
|
||||
{
|
||||
if (!a_Request.HasAuth())
|
||||
{
|
||||
a_Connection.SendNeedAuth("MCServer WebAdmin");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check auth:
|
||||
AString UserPassword = m_IniFile.GetValue("User:" + a_Request.GetAuthUsername(), "Password", "");
|
||||
if ((UserPassword == "") || (a_Request.GetAuthPassword() != UserPassword))
|
||||
{
|
||||
a_Connection.SendNeedAuth("MCServer WebAdmin - bad username or password");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the contents should be wrapped in the template:
|
||||
AString URL = a_Request.GetBareURL();
|
||||
ASSERT(URL.length() > 0);
|
||||
bool ShouldWrapInTemplate = ((URL.length() > 1) && (URL[1] != '~'));
|
||||
|
||||
// Retrieve the request data:
|
||||
cWebadminRequestData * Data = (cWebadminRequestData *)(a_Request.GetUserData());
|
||||
if (Data == NULL)
|
||||
{
|
||||
a_Connection.SendStatusAndReason(500, "Bad UserData");
|
||||
return;
|
||||
}
|
||||
|
||||
// Wrap it all up for the Lua call:
|
||||
AString Template;
|
||||
HTTPTemplateRequest TemplateRequest;
|
||||
TemplateRequest.Request.Username = a_Request.GetAuthUsername();
|
||||
TemplateRequest.Request.Method = a_Request.GetMethod();
|
||||
TemplateRequest.Request.Path = URL.substr(1);
|
||||
|
||||
if (Data->m_Form.Finish())
|
||||
{
|
||||
for (cHTTPFormParser::const_iterator itr = Data->m_Form.begin(), end = Data->m_Form.end(); itr != end; ++itr)
|
||||
{
|
||||
HTTPFormData HTTPfd;
|
||||
HTTPfd.Value = itr->second;
|
||||
HTTPfd.Type = "";
|
||||
HTTPfd.Name = itr->first;
|
||||
TemplateRequest.Request.FormData[itr->first] = HTTPfd;
|
||||
TemplateRequest.Request.PostParams[itr->first] = itr->second;
|
||||
TemplateRequest.Request.Params[itr->first] = itr->second;
|
||||
} // for itr - Data->m_Form[]
|
||||
}
|
||||
|
||||
// Try to get the template from the Lua template script
|
||||
if (ShouldWrapInTemplate)
|
||||
{
|
||||
if (WebAdmin->m_TemplateScript.Call("ShowPage", WebAdmin, &TemplateRequest, cLuaState::Return, Template))
|
||||
{
|
||||
cHTTPResponse Resp;
|
||||
Resp.SetContentType("text/html");
|
||||
a_Connection.Send(Resp);
|
||||
a_Connection.Send(Template.c_str(), Template.length());
|
||||
return;
|
||||
}
|
||||
a_Connection.SendStatusAndReason(500, "m_TemplateScript failed");
|
||||
return;
|
||||
}
|
||||
|
||||
AString BaseURL = GetBaseURL(URL);
|
||||
AString Menu;
|
||||
Template = "{CONTENT}";
|
||||
AString FoundPlugin;
|
||||
|
||||
for (PluginList::iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr)
|
||||
{
|
||||
cWebPlugin * WebPlugin = *itr;
|
||||
std::list< std::pair<AString, AString> > NameList = WebPlugin->GetTabNames();
|
||||
for (std::list< std::pair<AString, AString> >::iterator Names = NameList.begin(); Names != NameList.end(); ++Names)
|
||||
{
|
||||
Menu += "<li><a href='" + BaseURL + WebPlugin->GetWebTitle().c_str() + "/" + (*Names).second + "'>" + (*Names).first + "</a></li>";
|
||||
}
|
||||
}
|
||||
|
||||
sWebAdminPage Page = GetPage(TemplateRequest.Request);
|
||||
AString Content = Page.Content;
|
||||
FoundPlugin = Page.PluginName;
|
||||
if (!Page.TabName.empty())
|
||||
{
|
||||
FoundPlugin += " - " + Page.TabName;
|
||||
}
|
||||
|
||||
if (FoundPlugin.empty()) // Default page
|
||||
{
|
||||
Content = GetDefaultPage();
|
||||
}
|
||||
|
||||
if (ShouldWrapInTemplate && (URL.size() > 1))
|
||||
{
|
||||
Content += "\n<p><a href='" + BaseURL + "'>Go back</a></p>";
|
||||
}
|
||||
|
||||
int MemUsageKiB = GetMemoryUsage();
|
||||
if (MemUsageKiB > 0)
|
||||
{
|
||||
ReplaceString(Template, "{MEM}", Printf("%.02f", (double)MemUsageKiB / 1024));
|
||||
ReplaceString(Template, "{MEMKIB}", Printf("%d", MemUsageKiB));
|
||||
}
|
||||
else
|
||||
{
|
||||
ReplaceString(Template, "{MEM}", "unknown");
|
||||
ReplaceString(Template, "{MEMKIB}", "unknown");
|
||||
}
|
||||
ReplaceString(Template, "{USERNAME}", a_Request.GetAuthUsername());
|
||||
ReplaceString(Template, "{MENU}", Menu);
|
||||
ReplaceString(Template, "{PLUGIN_NAME}", FoundPlugin);
|
||||
ReplaceString(Template, "{CONTENT}", Content);
|
||||
ReplaceString(Template, "{TITLE}", "MCServer");
|
||||
|
||||
AString NumChunks;
|
||||
Printf(NumChunks, "%d", cRoot::Get()->GetTotalChunkCount());
|
||||
ReplaceString(Template, "{NUMCHUNKS}", NumChunks);
|
||||
|
||||
cHTTPResponse Resp;
|
||||
Resp.SetContentType("text/html");
|
||||
a_Connection.Send(Resp);
|
||||
a_Connection.Send(Template.c_str(), Template.length());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWebAdmin::HandleRootRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request)
|
||||
{
|
||||
static const char LoginForm[] = \
|
||||
"<h1>MCServer WebAdmin</h1>" \
|
||||
"<center>" \
|
||||
"<form method='get' action='webadmin/'>" \
|
||||
"<input type='submit' value='Log in'>" \
|
||||
"</form>" \
|
||||
"</center>";
|
||||
cHTTPResponse Resp;
|
||||
Resp.SetContentType("text/html");
|
||||
a_Connection.Send(Resp);
|
||||
a_Connection.Send(LoginForm, sizeof(LoginForm) - 1);
|
||||
a_Connection.FinishResponse();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sWebAdminPage cWebAdmin::GetPage(const HTTPRequest & a_Request)
|
||||
{
|
||||
sWebAdminPage Page;
|
||||
AStringVector Split = StringSplit(a_Request.Path, "/");
|
||||
@ -396,6 +349,41 @@ sWebAdminPage cWebAdmin::GetPage(const HTTPRequest& a_Request)
|
||||
|
||||
|
||||
|
||||
AString cWebAdmin::GetDefaultPage(void)
|
||||
{
|
||||
AString Content;
|
||||
Content += "<h4>Server Name:</h4>";
|
||||
Content += "<p>" + AString( cRoot::Get()->GetServer()->GetServerID() ) + "</p>";
|
||||
|
||||
Content += "<h4>Plugins:</h4><ul>";
|
||||
cPluginManager * PM = cPluginManager::Get();
|
||||
const cPluginManager::PluginMap & List = PM->GetAllPlugins();
|
||||
for (cPluginManager::PluginMap::const_iterator itr = List.begin(); itr != List.end(); ++itr)
|
||||
{
|
||||
if (itr->second == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
AString VersionNum;
|
||||
AppendPrintf(Content, "<li>%s V.%i</li>", itr->second->GetName().c_str(), itr->second->GetVersion());
|
||||
}
|
||||
Content += "</ul>";
|
||||
Content += "<h4>Players:</h4><ul>";
|
||||
|
||||
cPlayerAccum PlayerAccum;
|
||||
cWorld * World = cRoot::Get()->GetDefaultWorld(); // TODO - Create a list of worlds and players
|
||||
if( World != NULL )
|
||||
{
|
||||
World->ForEachPlayer(PlayerAccum);
|
||||
Content.append(PlayerAccum.m_Contents);
|
||||
}
|
||||
Content += "</ul><br>";
|
||||
return Content;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
AString cWebAdmin::GetBaseURL( const AString& a_URL )
|
||||
{
|
||||
return GetBaseURL(StringSplit(a_URL, "/"));
|
||||
@ -474,3 +462,76 @@ int cWebAdmin::GetMemoryUsage(void)
|
||||
|
||||
|
||||
|
||||
|
||||
void cWebAdmin::OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request)
|
||||
{
|
||||
const AString & URL = a_Request.GetURL();
|
||||
if (
|
||||
(strncmp(URL.c_str(), "/webadmin", 9) == 0) ||
|
||||
(strncmp(URL.c_str(), "/~webadmin", 10) == 0)
|
||||
)
|
||||
{
|
||||
a_Request.SetUserData(new cWebadminRequestData(a_Request));
|
||||
return;
|
||||
}
|
||||
if (URL == "/")
|
||||
{
|
||||
// The root needs no body handler and is fully handled in the OnRequestFinished() call
|
||||
return;
|
||||
}
|
||||
// TODO: Handle other requests
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWebAdmin::OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size)
|
||||
{
|
||||
cRequestData * Data = (cRequestData *)(a_Request.GetUserData());
|
||||
if (Data == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Data->OnBody(a_Data, a_Size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWebAdmin::OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request)
|
||||
{
|
||||
const AString & URL = a_Request.GetURL();
|
||||
if (
|
||||
(strncmp(URL.c_str(), "/webadmin", 9) == 0) ||
|
||||
(strncmp(URL.c_str(), "/~webadmin", 10) == 0)
|
||||
)
|
||||
{
|
||||
HandleWebadminRequest(a_Connection, a_Request);
|
||||
return;
|
||||
}
|
||||
if (URL == "/")
|
||||
{
|
||||
// The root needs no body handler and is fully handled in the OnRequestFinished() call
|
||||
HandleRootRequest(a_Connection, a_Request);
|
||||
return;
|
||||
}
|
||||
// TODO: Handle other requests
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cWebAdmin::cWebadminRequestData
|
||||
|
||||
void cWebAdmin::cWebadminRequestData::OnBody(const char * a_Data, int a_Size)
|
||||
{
|
||||
m_Form.Parse(a_Data, a_Size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,8 +1,26 @@
|
||||
|
||||
// WebAdmin.h
|
||||
|
||||
// Declares the cWebAdmin class representing the admin interface over http protocol, and related services (API)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../WebServer/WebServer.h"
|
||||
#include "OSSupport/Socket.h"
|
||||
#include "LuaState.h"
|
||||
#include "../iniFile/iniFile.h"
|
||||
#include "HTTPServer/HTTPServer.h"
|
||||
#include "HTTPServer/HTTPFormParser.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Disable MSVC warnings:
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4355) // 'this' : used in base member initializer list
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@ -10,7 +28,6 @@
|
||||
// fwd:
|
||||
class cStringMap;
|
||||
class cEvent;
|
||||
class cIniFile;
|
||||
class cWebPlugin;
|
||||
|
||||
|
||||
@ -73,7 +90,8 @@ struct sWebAdminPage
|
||||
|
||||
|
||||
// tolua_begin
|
||||
class cWebAdmin
|
||||
class cWebAdmin :
|
||||
public cHTTPServer::cCallbacks
|
||||
{
|
||||
public:
|
||||
// tolua_end
|
||||
@ -81,10 +99,14 @@ public:
|
||||
typedef std::list< cWebPlugin* > PluginList;
|
||||
|
||||
|
||||
cWebAdmin( int a_Port = 8080 );
|
||||
cWebAdmin(void);
|
||||
~cWebAdmin();
|
||||
|
||||
bool Init( int a_Port );
|
||||
/// Initializes the object. Returns true if successfully initialized and ready to start
|
||||
bool Init(void);
|
||||
|
||||
/// Starts the HTTP server taking care of the admin. Returns true if successful
|
||||
bool Start(void);
|
||||
|
||||
void AddPlugin( cWebPlugin* a_Plugin );
|
||||
void RemovePlugin( cWebPlugin* a_Plugin );
|
||||
@ -92,39 +114,71 @@ public:
|
||||
// TODO: Convert this to the auto-locking callback mechanism used for looping players in worlds and such
|
||||
PluginList GetPlugins() const { return m_Plugins; } // >> EXPORTED IN MANUALBINDINGS <<
|
||||
|
||||
static void Request_Handler(webserver::http_request* r);
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/// Returns the amount of currently used memory, in KiB, or -1 if it cannot be queried
|
||||
static int GetMemoryUsage(void);
|
||||
|
||||
int GetPort() { return m_Port; }
|
||||
|
||||
sWebAdminPage GetPage(const HTTPRequest& a_Request);
|
||||
|
||||
/// Returns the contents of the default page - the list of plugins and players
|
||||
AString GetDefaultPage(void);
|
||||
|
||||
AString GetBaseURL(const AString& a_URL);
|
||||
|
||||
// tolua_end
|
||||
|
||||
AString GetBaseURL(const AStringVector& a_URLSplit);
|
||||
|
||||
protected:
|
||||
/// Common base class for request body data handlers
|
||||
class cRequestData
|
||||
{
|
||||
public:
|
||||
/// Called when a new chunk of body data is received
|
||||
virtual void OnBody(const char * a_Data, int a_Size) = 0;
|
||||
} ;
|
||||
|
||||
private:
|
||||
int m_Port;
|
||||
/// The body handler for requests in the "/webadmin" and "/~webadmin" paths
|
||||
class cWebadminRequestData :
|
||||
public cRequestData,
|
||||
public cHTTPFormParser::cCallbacks
|
||||
{
|
||||
public:
|
||||
cHTTPFormParser m_Form;
|
||||
|
||||
bool m_bConnected;
|
||||
cSocket m_ListenSocket;
|
||||
|
||||
cIniFile * m_IniFile;
|
||||
cWebadminRequestData(cHTTPRequest & a_Request) :
|
||||
m_Form(a_Request, *this)
|
||||
{
|
||||
}
|
||||
|
||||
// cRequestData overrides:
|
||||
virtual void OnBody(const char * a_Data, int a_Size) override;
|
||||
|
||||
// cHTTPFormParser::cCallbacks overrides. Files are ignored:
|
||||
virtual void OnFileStart(cHTTPFormParser & a_Parser, const AString & a_FileName) override {}
|
||||
virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) override {}
|
||||
virtual void OnFileEnd(cHTTPFormParser & a_Parser) override {}
|
||||
} ;
|
||||
|
||||
|
||||
/// Set to true if Init() succeeds and the webadmin isn't to be disabled
|
||||
bool m_IsInitialized;
|
||||
|
||||
/// The webadmin.ini file, used for the settings and allowed logins
|
||||
cIniFile m_IniFile;
|
||||
|
||||
PluginList m_Plugins;
|
||||
|
||||
cEvent * m_Event;
|
||||
|
||||
webserver * m_WebServer;
|
||||
|
||||
/// The Lua template script to provide templates:
|
||||
cLuaState m_TemplateScript;
|
||||
|
||||
/// The HTTP server which provides the underlying HTTP parsing, serialization and events
|
||||
cHTTPServer m_HTTPServer;
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
static DWORD WINAPI ListenThread(LPVOID lpParam);
|
||||
@ -132,9 +186,29 @@ private:
|
||||
static void * ListenThread(void * lpParam);
|
||||
#endif
|
||||
|
||||
AString GetTemplate();
|
||||
AString GetTemplate(void);
|
||||
|
||||
/// Handles requests coming to the "/webadmin" or "/~webadmin" URLs
|
||||
void HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
|
||||
|
||||
/// Handles requests for the root page
|
||||
void HandleRootRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
|
||||
|
||||
// cHTTPServer::cCallbacks overrides:
|
||||
virtual void OnRequestBegun (cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override;
|
||||
virtual void OnRequestBody (cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override;
|
||||
virtual void OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override;
|
||||
} ; // tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Revert MSVC warnings back to orignal state:
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user