Changed some std::string to AString git-svn-id: http://mc-server.googlecode.com/svn/trunk@780 0a769ca7-a7f5-676a-18bf-c427514a06d6
		
			
				
	
	
		
			365 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			365 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
 | 
						|
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules
 | 
						|
 | 
						|
#include "cWebAdmin.h"
 | 
						|
#include "cStringMap.h"
 | 
						|
 | 
						|
#include "cWebPlugin.h"
 | 
						|
 | 
						|
#include "cPluginManager.h"
 | 
						|
#include "cPlugin.h"
 | 
						|
 | 
						|
#include "cWorld.h"
 | 
						|
#include "cPlayer.h"
 | 
						|
#include "cServer.h"
 | 
						|
#include "cRoot.h"
 | 
						|
 | 
						|
#include "../iniFile/iniFile.h"
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
	#include <psapi.h>
 | 
						|
#else
 | 
						|
	#include <sys/resource.h>
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/// Helper class - appends all player names together in a HTML list
 | 
						|
class cPlayerAccum :
 | 
						|
	public cPlayerListCallback
 | 
						|
{
 | 
						|
	virtual bool Item(cPlayer * a_Player) override
 | 
						|
	{
 | 
						|
		m_Contents.append("<li>");
 | 
						|
		m_Contents.append(a_Player->GetName());
 | 
						|
		m_Contents.append("</li>");
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	
 | 
						|
public:
 | 
						|
 | 
						|
	AString m_Contents;
 | 
						|
} ;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
cWebAdmin * WebAdmin = NULL;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
cWebAdmin::cWebAdmin( int a_Port /* = 8080 */ )
 | 
						|
	: m_Port( a_Port )
 | 
						|
	, m_bConnected( false )
 | 
						|
{
 | 
						|
	WebAdmin = this;
 | 
						|
	m_Event = new cEvent();
 | 
						|
	Init( m_Port );
 | 
						|
}
 | 
						|
 | 
						|
cWebAdmin::~cWebAdmin()
 | 
						|
{
 | 
						|
	WebAdmin = 0;
 | 
						|
	m_WebServer->Stop();
 | 
						|
 | 
						|
	while( m_Plugins.begin() != m_Plugins.end() )
 | 
						|
	{
 | 
						|
		delete *m_Plugins.begin();
 | 
						|
		//m_Plugins.remove( *m_Plugins.begin() );
 | 
						|
	}
 | 
						|
	delete m_WebServer;
 | 
						|
	delete m_IniFile;
 | 
						|
 | 
						|
	m_Event->Wait();
 | 
						|
	delete m_Event;
 | 
						|
}
 | 
						|
 | 
						|
void cWebAdmin::AddPlugin( cWebPlugin * a_Plugin )
 | 
						|
{
 | 
						|
	m_Plugins.remove( a_Plugin );
 | 
						|
	m_Plugins.push_back( a_Plugin );
 | 
						|
}
 | 
						|
 | 
						|
void cWebAdmin::RemovePlugin( cWebPlugin * a_Plugin )
 | 
						|
{
 | 
						|
	m_Plugins.remove( a_Plugin );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
void cWebAdmin::Request_Handler(webserver::http_request* r)
 | 
						|
{
 | 
						|
	if( WebAdmin == 0 ) return;
 | 
						|
	LOG("Path: %s", r->path_.c_str() );
 | 
						|
 | 
						|
	if (r->path_ == "/")
 | 
						|
	{
 | 
						|
		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;
 | 
						|
	}
 | 
						|
 | 
						|
	if (r->path_.empty() || r->path_[0] != '/')
 | 
						|
	{
 | 
						|
		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;
 | 
						|
	}
 | 
						|
	
 | 
						|
	std::string UserPassword = WebAdmin->m_IniFile->GetValue( "User:"+r->username_, "Password", "");
 | 
						|
	if ((UserPassword != "") && (r->password_ == UserPassword))
 | 
						|
	{
 | 
						|
		std::string BaseURL = "./";
 | 
						|
		if (Split.size() > 1)
 | 
						|
		{
 | 
						|
			for (unsigned int i = 0; i < Split.size(); i++)
 | 
						|
			{
 | 
						|
				BaseURL += "../";
 | 
						|
			}
 | 
						|
			BaseURL += "webadmin/";
 | 
						|
		}
 | 
						|
 | 
						|
		std::string Menu;
 | 
						|
		std::string Content;
 | 
						|
		std::string Template = bDontShowTemplate ? "{CONTENT}" : WebAdmin->GetTemplate();
 | 
						|
		std::string FoundPlugin;
 | 
						|
 | 
						|
		for (PluginList::iterator itr = WebAdmin->m_Plugins.begin(); itr != WebAdmin->m_Plugins.end(); ++itr)
 | 
						|
		{
 | 
						|
			cWebPlugin* WebPlugin = *itr;
 | 
						|
			std::list< std::pair<std::string, std::string> > NameList = WebPlugin->GetTabNames();
 | 
						|
			for( std::list< std::pair<std::string, std::string> >::iterator Names = NameList.begin(); Names != NameList.end(); ++Names )
 | 
						|
			{
 | 
						|
				Menu += "<li><a href='" + BaseURL + WebPlugin->GetName().c_str() + "/" + (*Names).second + "'>" + (*Names).first + "</a></li>";
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		HTTPRequest Request;
 | 
						|
		Request.Username = r->username_;
 | 
						|
		Request.Method = r->method_;
 | 
						|
		Request.Params = r->params_;
 | 
						|
		Request.PostParams = r->params_post_;
 | 
						|
		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() );
 | 
						|
			Request.FormData[ fd.name_ ] = HTTPfd;
 | 
						|
		}
 | 
						|
 | 
						|
		if( Split.size() > 1 )
 | 
						|
		{
 | 
						|
			for( PluginList::iterator itr = WebAdmin->m_Plugins.begin(); itr != WebAdmin->m_Plugins.end(); ++itr )
 | 
						|
			{
 | 
						|
				if( (*itr)->GetName() == Split[1] )
 | 
						|
				{
 | 
						|
					Content = (*itr)->HandleWebRequest( &Request );
 | 
						|
					cWebPlugin* WebPlugin = *itr;
 | 
						|
					FoundPlugin = WebPlugin->GetName();
 | 
						|
					AString TabName = WebPlugin->GetTabNameForRequest( &Request ).first;
 | 
						|
					if( TabName.empty() == false )
 | 
						|
					{
 | 
						|
						FoundPlugin += " - " + TabName;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if( FoundPlugin.empty() )	// Default page
 | 
						|
		{
 | 
						|
			Content.clear();
 | 
						|
			FoundPlugin = "Current Game";
 | 
						|
			Content += "<h4>Server Name:</h4>";
 | 
						|
			Content += "<p>" + std::string( cRoot::Get()->GetServer()->GetServerID() ) + "</p>";
 | 
						|
 | 
						|
			Content += "<h4>Plugins:</h4><ul>";
 | 
						|
			cPluginManager* PM = cRoot::Get()->GetPluginManager();
 | 
						|
			if( PM )
 | 
						|
			{
 | 
						|
				const cPluginManager::PluginList & List = PM->GetAllPlugins();
 | 
						|
				for( cPluginManager::PluginList::const_iterator itr = List.begin(); itr != List.end(); ++itr )
 | 
						|
				{
 | 
						|
					AString VersionNum;
 | 
						|
					AppendPrintf(Content, "<li>%s V.%i</li>", (*itr)->GetName().c_str(), (*itr)->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 == false && Split.size() > 1)
 | 
						|
		{
 | 
						|
			Content += "\n<p><a href='" + BaseURL + "'>Go back</a></p>";
 | 
						|
		}
 | 
						|
 | 
						|
		// mem usage
 | 
						|
#ifndef _WIN32
 | 
						|
		rusage resource_usage;
 | 
						|
		if (getrusage(RUSAGE_SELF, &resource_usage) != 0)
 | 
						|
		{
 | 
						|
			ReplaceString( Template, std::string("{MEM}"), "Error :(" );
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			AString MemUsage;
 | 
						|
			Printf(MemUsage, "%0.2f", ((double)resource_usage.ru_maxrss / 1024 / 1024) );
 | 
						|
			ReplaceString(Template, std::string("{MEM}"), MemUsage);
 | 
						|
		}
 | 
						|
#else
 | 
						|
		HANDLE hProcess = GetCurrentProcess();
 | 
						|
		PROCESS_MEMORY_COUNTERS pmc;
 | 
						|
		if( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc) ) )
 | 
						|
		{
 | 
						|
			AString MemUsage;
 | 
						|
			Printf(MemUsage, "%0.2f", (pmc.WorkingSetSize / 1024.f / 1024.f) );
 | 
						|
			ReplaceString( Template, "{MEM}", MemUsage );
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		// end mem usage
 | 
						|
 | 
						|
		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";
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
bool cWebAdmin::Init( int a_Port )
 | 
						|
{
 | 
						|
	m_Port = a_Port;
 | 
						|
 | 
						|
	m_IniFile = new cIniFile("webadmin.ini");
 | 
						|
	if( m_IniFile->ReadFile() )
 | 
						|
	{
 | 
						|
		m_Port = m_IniFile->GetValueI("WebAdmin", "Port", 8080 );
 | 
						|
	}
 | 
						|
 | 
						|
	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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
std::string cWebAdmin::GetTemplate()
 | 
						|
{
 | 
						|
	std::string retVal = "";
 | 
						|
 | 
						|
	char SourceFile[] = "webadmin/template.html";
 | 
						|
 | 
						|
	cFile f;
 | 
						|
	if (!f.Open(SourceFile, cFile::fmRead))
 | 
						|
	{
 | 
						|
		return "";
 | 
						|
	}
 | 
						|
 | 
						|
	// copy the file into the buffer:
 | 
						|
	f.ReadRestOfFile(retVal);
 | 
						|
 | 
						|
	return retVal;
 | 
						|
} |