1
0

Can now receive POST data in WebPlugins!

Fixed Debug With optimized Noise in VS2010 by having it run the correct MCServer_debug.exe instead of MCServer.exe
Changed winsock.h to Winsock2.h in Globals.h so sockets can be graciously closed (See webserver Socket::Close() )

git-svn-id: http://mc-server.googlecode.com/svn/trunk@197 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
faketruth 2012-01-31 00:38:18 +00:00
parent f4583fda98
commit c142424571
14 changed files with 224 additions and 117 deletions

View File

@ -1,12 +1,12 @@
function HandleRequest_Reload( Request ) function HandleRequest_Reload( Request )
local Content = "" local Content = ""
if( Request.Params:get("reload") ~= "" ) then if( Request.PostParams:get("reload") ~= "" ) then
Content = Content .. "<head><meta http-equiv=\"refresh\" content=\"2;././\"></head>" Content = Content .. "<head><meta http-equiv=\"refresh\" content=\"2;././\"></head>"
Content = Content .. "<p>Reloading plugins... This can take a while depending on the plugins you're using.</p>" Content = Content .. "<p>Reloading plugins... This can take a while depending on the plugins you're using.</p>"
cRoot:Get():GetPluginManager():ReloadPlugins() cRoot:Get():GetPluginManager():ReloadPlugins()
else else
Content = Content .. "<form method=GET>" Content = Content .. "<form method=POST>"
Content = Content .. "<p>Click the reload button to reload all plugins!<br>" Content = Content .. "<p>Click the reload button to reload all plugins!<br>"
Content = Content .. "<input type=\"submit\" name=\"reload\" value=\"Reload!\"></p>" Content = Content .. "<input type=\"submit\" name=\"reload\" value=\"Reload!\"></p>"
Content = Content .. "</form>" Content = Content .. "</form>"

View File

@ -1,11 +1,11 @@
local function HTMLDeleteButton( name ) local function HTMLDeleteButton( name )
return "<form method=GET><input type=\"hidden\" name=\"whitelist-delete\" value=\"".. name .."\"><input type=\"submit\" value=\"Remove from whitelist\"></form>" return "<form method=\"POST\"><input type=\"hidden\" name=\"whitelist-delete\" value=\"".. name .."\"><input type=\"submit\" value=\"Remove from whitelist\"></form>"
end end
function HandleRequest_WhiteList( Request ) function HandleRequest_WhiteList( Request )
local UpdateMessage = "" local UpdateMessage = ""
if( Request.Params:get("whitelist-add") ~= "" ) then if( Request.PostParams:get("whitelist-add") ~= "" ) then
local PlayerName = Request.Params:get("whitelist-add") local PlayerName = Request.PostParams:get("whitelist-add")
if( WhiteListIni:GetValueB("WhiteList", PlayerName, false) == true ) then if( WhiteListIni:GetValueB("WhiteList", PlayerName, false) == true ) then
UpdateMessage = "<b>".. PlayerName.."</b> is already on the whitelist" UpdateMessage = "<b>".. PlayerName.."</b> is already on the whitelist"
@ -14,12 +14,12 @@ function HandleRequest_WhiteList( Request )
UpdateMessage = "Added <b>" .. PlayerName .. "</b> to whitelist." UpdateMessage = "Added <b>" .. PlayerName .. "</b> to whitelist."
WhiteListIni:WriteFile() WhiteListIni:WriteFile()
end end
elseif( Request.Params:get("whitelist-delete") ~= "" ) then elseif( Request.PostParams:get("whitelist-delete") ~= "" ) then
local PlayerName = Request.Params:get("whitelist-delete") local PlayerName = Request.PostParams:get("whitelist-delete")
WhiteListIni:DeleteValue( "WhiteList", PlayerName ) WhiteListIni:DeleteValue( "WhiteList", PlayerName )
UpdateMessage = "Removed <b>" .. PlayerName .. "</b> from whitelist." UpdateMessage = "Removed <b>" .. PlayerName .. "</b> from whitelist."
WhiteListIni:WriteFile() WhiteListIni:WriteFile()
elseif( Request.Params:get("whitelist-reload") ~= "" ) then elseif( Request.PostParams:get("whitelist-reload") ~= "" ) then
WhiteListIni:Erase() -- Empty entire loaded ini first, otherwise weird shit goes down WhiteListIni:Erase() -- Empty entire loaded ini first, otherwise weird shit goes down
WhiteListIni:ReadFile() WhiteListIni:ReadFile()
UpdateMessage = "Loaded from disk" UpdateMessage = "Loaded from disk"
@ -63,10 +63,10 @@ function HandleRequest_WhiteList( Request )
end end
Content = Content .. "</table>" Content = Content .. "</table>"
Content = Content .. "<br><h4>Add player to whitelist</h4>" Content = Content .. "<br><h4>Add player to whitelist</h4>"
Content = Content .. "<form method=\"GET\">" Content = Content .. "<form method=\"POST\">"
Content = Content .. "<input type=\"text\" name=\"whitelist-add\"><input type=\"submit\" value=\"Add player\">" Content = Content .. "<input type=\"text\" name=\"whitelist-add\"><input type=\"submit\" value=\"Add player\">"
Content = Content .. "</form>" Content = Content .. "</form>"
Content = Content .. "<form method=\"GET\">" Content = Content .. "<form method=\"POST\">"
Content = Content .. "<input type=\"submit\" name=\"whitelist-reload\" value=\"Reload from disk\">" Content = Content .. "<input type=\"submit\" name=\"whitelist-reload\" value=\"Reload from disk\">"
Content = Content .. "</form>" Content = Content .. "</form>"
Content = Content .. "<br>"..UpdateMessage Content = Content .. "<br>"..UpdateMessage

View File

@ -9,4 +9,11 @@
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory> <LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">
<LocalDebuggerCommand>$(TargetDir)\$(TargetName)_debug$(TargetExt)</LocalDebuggerCommand>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project> </Project>

View File

@ -12,7 +12,7 @@
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
#include <winsock.h> #include <Winsock2.h>
#else #else
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> // for mkdir #include <sys/stat.h> // for mkdir

View File

@ -118,9 +118,18 @@ Socket& Socket::operator=(Socket& o) {
return *this; return *this;
} }
void Socket::Close() { void Socket::Close( bool a_WaitSend /* = false */ )
{
if( s_ ) if( s_ )
{ {
if( a_WaitSend )
{
assert( shutdown(s_, SD_SEND ) == 0 );
char c;
while( recv(s_, &c, 1, 0 ) != 0 )
{}
}
closesocket(s_); closesocket(s_);
s_ = 0; s_ = 0;
} }
@ -135,12 +144,25 @@ std::string Socket::ReceiveLine() {
{ {
return ""; return "";
} }
ret += r; ret += r;
if (r == '\n') return ret; if (r == '\n') return ret;
} }
} }
std::string Socket::ReceiveBytes( unsigned int a_Length ) {
std::string ret;
while( ret.size() < a_Length ) {
char r;
if (recv(s_, &r, 1, 0) <= 0 )
{
return "";
}
ret += r;
}
return ret;
}
void Socket::SendLine(std::string s) { void Socket::SendLine(std::string s) {
s += '\n'; s += '\n';
if( send(s_,s.c_str(),s.length(),MSG_NOSIGNAL) <= 0 ) if( send(s_,s.c_str(),s.length(),MSG_NOSIGNAL) <= 0 )

View File

@ -35,8 +35,10 @@
#include "../source/MCSocket.h" #include "../source/MCSocket.h"
// #ifdef _WIN32 // #ifdef _WIN32
// #include <winsock2.h> // #include <winsock2.h>
// #endif // #endif
#include <string> #include <string>
enum TypeSocket {BlockingSocket, NonBlockingSocket}; enum TypeSocket {BlockingSocket, NonBlockingSocket};
@ -49,9 +51,9 @@ public:
Socket& operator=(Socket&); Socket& operator=(Socket&);
std::string ReceiveLine(); std::string ReceiveLine();
std::string ReceiveBytes(); std::string ReceiveBytes( unsigned int a_Length );
void Close(); void Close( bool a_WaitSend = false );
// The parameter of SendLine is not a const reference // The parameter of SendLine is not a const reference
// because SendLine modifes the std::string passed. // because SendLine modifes the std::string passed.

View File

@ -58,25 +58,28 @@ void* webserver::Request(void* ptr_s)
Socket* s = (reinterpret_cast<Socket*>(ptr_s)); Socket* s = (reinterpret_cast<Socket*>(ptr_s));
std::string line = s->ReceiveLine(); std::string line = s->ReceiveLine();
if (line.empty()) { if (line.empty())
{
s->Close(); s->Close();
delete s; delete s;
return 0; return 0;
} }
http_request req; http_request req;
if (line.find("GET") == 0) {
req.method_="GET";
}
else if (line.find("POST") == 0) {
req.method_="POST";
}
std::string path; std::string path;
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
size_t posStartPath = 0;
size_t posStartPath = line.find_first_not_of(" ",3); if (line.find("GET") == 0)
{
req.method_="GET";
posStartPath = line.find_first_not_of(" ",3);
}
else if (line.find("POST") == 0)
{
req.method_="POST";
posStartPath = line.find_first_not_of(" ",4);
}
SplitGetReq(line.substr(posStartPath), path, params); SplitGetReq(line.substr(posStartPath), path, params);
@ -90,10 +93,12 @@ void* webserver::Request(void* ptr_s)
static const std::string accept_language = "Accept-Language: " ; static const std::string accept_language = "Accept-Language: " ;
static const std::string accept_encoding = "Accept-Encoding: " ; static const std::string accept_encoding = "Accept-Encoding: " ;
static const std::string user_agent = "User-Agent: " ; static const std::string user_agent = "User-Agent: " ;
static const std::string content_length = "Content-Length: " ;
static const std::string content_type = "Content-Type: " ;
while(1) { while(1)
{
line=s->ReceiveLine(); line=s->ReceiveLine();
if (line.empty()) break; if (line.empty()) break;
unsigned int pos_cr_lf = line.find_first_of("\x0a\x0d"); unsigned int pos_cr_lf = line.find_first_of("\x0a\x0d");
@ -101,7 +106,8 @@ void* webserver::Request(void* ptr_s)
line = line.substr(0,pos_cr_lf); line = line.substr(0,pos_cr_lf);
if (line.substr(0, authorization.size()) == authorization) { if (line.substr(0, authorization.size()) == authorization)
{
req.authentication_given_ = true; req.authentication_given_ = true;
std::string encoded = line.substr(authorization.size()); std::string encoded = line.substr(authorization.size());
std::string decoded = base64_decode(encoded); std::string decoded = base64_decode(encoded);
@ -111,18 +117,49 @@ void* webserver::Request(void* ptr_s)
req.username_ = decoded.substr(0, pos_colon); req.username_ = decoded.substr(0, pos_colon);
req.password_ = decoded.substr(pos_colon+1 ); req.password_ = decoded.substr(pos_colon+1 );
} }
else if (line.substr(0, accept.size()) == accept) { else if (line.substr(0, accept.size()) == accept)
{
req.accept_ = line.substr(accept.size()); req.accept_ = line.substr(accept.size());
} }
else if (line.substr(0, accept_language.size()) == accept_language) { else if (line.substr(0, accept_language.size()) == accept_language)
{
req.accept_language_ = line.substr(accept_language.size()); req.accept_language_ = line.substr(accept_language.size());
} }
else if (line.substr(0, accept_encoding.size()) == accept_encoding) { else if (line.substr(0, accept_encoding.size()) == accept_encoding)
{
req.accept_encoding_ = line.substr(accept_encoding.size()); req.accept_encoding_ = line.substr(accept_encoding.size());
} }
else if (line.substr(0, user_agent.size()) == user_agent) { else if (line.substr(0, user_agent.size()) == user_agent)
{
req.user_agent_ = line.substr(user_agent.size()); req.user_agent_ = line.substr(user_agent.size());
} }
else if (line.substr(0, content_length.size()) == content_length)
{
req.content_length_ = atoi( line.substr(content_length.size()).c_str() );
}
else if (line.substr(0, content_type.size()) == content_type)
{
req.content_type_ = line.substr(content_type.size());
}
}
if( req.method_.compare("POST") == 0 )
{
if( req.content_length_ > 0 )
{
// The only content type we can parse at the moment, the default HTML post data
if( req.content_type_.compare( "application/x-www-form-urlencoded" ) == 0 )
{
std::string Content = s->ReceiveBytes( req.content_length_ );
Content.insert( 0, "/ ?" ); // Little hack, inserts dummy URL so that SplitGetReq() can work with this content
std::string dummy;
std::map<std::string, std::string> post_params;
SplitGetReq(Content, dummy, post_params);
req.params_post_ = post_params;
}
}
} }
request_func_(&req); request_func_(&req);
@ -148,13 +185,15 @@ void* webserver::Request(void* ptr_s)
s->SendBytes("HTTP/1.1 "); s->SendBytes("HTTP/1.1 ");
if (! req.auth_realm_.empty() ) { if (! req.auth_realm_.empty() )
{
s->SendLine("401 Unauthorized"); s->SendLine("401 Unauthorized");
s->SendBytes("WWW-Authenticate: Basic Realm=\""); s->SendBytes("WWW-Authenticate: Basic Realm=\"");
s->SendBytes(req.auth_realm_); s->SendBytes(req.auth_realm_);
s->SendLine("\""); s->SendLine("\"");
} }
else { else
{
s->SendLine(req.status_); s->SendLine(req.status_);
} }
s->SendLine(std::string("Date: ") + asctime_remove_nl + " GMT"); s->SendLine(std::string("Date: ") + asctime_remove_nl + " GMT");
@ -165,7 +204,7 @@ void* webserver::Request(void* ptr_s)
s->SendLine(""); s->SendLine("");
s->SendLine(req.answer_); s->SendLine(req.answer_);
s->Close(); s->Close( true ); // true = wait for all data to be sent before closing
delete s; delete s;

View File

@ -41,17 +41,21 @@ public:
http_request() http_request()
: s_( 0 ) : s_( 0 )
, authentication_given_(false) , authentication_given_(false)
, content_length_( 0 )
{} {}
Socket* s_; Socket* s_;
std::string method_; std::string method_;
std::string path_; std::string path_;
std::map<std::string, std::string> params_; std::map<std::string, std::string> params_;
std::map<std::string, std::string> params_post_;
std::string accept_; std::string accept_;
std::string accept_language_; std::string accept_language_;
std::string accept_encoding_; std::string accept_encoding_;
std::string user_agent_; std::string user_agent_;
int content_length_;
std::string content_type_;
/* status_: used to transmit server's error status, such as /* status_: used to transmit server's error status, such as
o 202 OK o 202 OK

View File

@ -1,6 +1,6 @@
/* /*
** Lua binding: AllToLua ** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 01/30/12 17:26:14. ** Generated automatically by tolua++-1.0.92 on 01/31/12 01:23:11.
*/ */
#ifndef __cplusplus #ifndef __cplusplus
@ -10453,6 +10453,36 @@ static int tolua_set_HTTPRequest_Params_ptr(lua_State* tolua_S)
} }
#endif //#ifndef TOLUA_DISABLE #endif //#ifndef TOLUA_DISABLE
/* get function: PostParams of class HTTPRequest */
#ifndef TOLUA_DISABLE_tolua_get_HTTPRequest_PostParams_ptr
static int tolua_get_HTTPRequest_PostParams_ptr(lua_State* tolua_S)
{
HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S,1,0);
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'PostParams'",NULL);
#endif
tolua_pushusertype(tolua_S,(void*)self->PostParams,"cStringMap");
return 1;
}
#endif //#ifndef TOLUA_DISABLE
/* set function: PostParams of class HTTPRequest */
#ifndef TOLUA_DISABLE_tolua_set_HTTPRequest_PostParams_ptr
static int tolua_set_HTTPRequest_PostParams_ptr(lua_State* tolua_S)
{
HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S,1,0);
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'PostParams'",NULL);
if (!tolua_isusertype(tolua_S,2,"cStringMap",0,&tolua_err))
tolua_error(tolua_S,"#vinvalid type in variable assignment.",&tolua_err);
#endif
self->PostParams = ((cStringMap*) tolua_tousertype(tolua_S,2,0))
;
return 0;
}
#endif //#ifndef TOLUA_DISABLE
/* get function: Username of class HTTPRequest */ /* get function: Username of class HTTPRequest */
#ifndef TOLUA_DISABLE_tolua_get_HTTPRequest_Username #ifndef TOLUA_DISABLE_tolua_get_HTTPRequest_Username
static int tolua_get_HTTPRequest_Username(lua_State* tolua_S) static int tolua_get_HTTPRequest_Username(lua_State* tolua_S)
@ -17001,6 +17031,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_variable(tolua_S,"Method",tolua_get_HTTPRequest_Method,tolua_set_HTTPRequest_Method); tolua_variable(tolua_S,"Method",tolua_get_HTTPRequest_Method,tolua_set_HTTPRequest_Method);
tolua_variable(tolua_S,"Path",tolua_get_HTTPRequest_Path,tolua_set_HTTPRequest_Path); tolua_variable(tolua_S,"Path",tolua_get_HTTPRequest_Path,tolua_set_HTTPRequest_Path);
tolua_variable(tolua_S,"Params",tolua_get_HTTPRequest_Params_ptr,tolua_set_HTTPRequest_Params_ptr); tolua_variable(tolua_S,"Params",tolua_get_HTTPRequest_Params_ptr,tolua_set_HTTPRequest_Params_ptr);
tolua_variable(tolua_S,"PostParams",tolua_get_HTTPRequest_PostParams_ptr,tolua_set_HTTPRequest_PostParams_ptr);
tolua_variable(tolua_S,"Username",tolua_get_HTTPRequest_Username,tolua_set_HTTPRequest_Username); tolua_variable(tolua_S,"Username",tolua_get_HTTPRequest_Username,tolua_set_HTTPRequest_Username);
tolua_endmodule(tolua_S); tolua_endmodule(tolua_S);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -1,6 +1,6 @@
/* /*
** Lua binding: AllToLua ** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 01/30/12 17:26:15. ** Generated automatically by tolua++-1.0.92 on 01/31/12 01:23:11.
*/ */
/* Exported function */ /* Exported function */

View File

@ -767,8 +767,7 @@ void cPlayer::LoadPermissionsFromDisk()
bool cPlayer::LoadFromDisk()
bool cPlayer::LoadFromDisk() // TODO - This should also get/set/whatever the correct world for this player
{ {
LoadPermissionsFromDisk(); LoadPermissionsFromDisk();

View File

@ -136,6 +136,7 @@ void cWebAdmin::Request_Handler(webserver::http_request* r)
Request.Username = r->username_; Request.Username = r->username_;
Request.Method = r->method_; Request.Method = r->method_;
Request.Params = new cStringMap(r->params_); Request.Params = new cStringMap(r->params_);
Request.PostParams = new cStringMap(r->params_post_);
Request.Path = r->path_; Request.Path = r->path_;
if( Split.size() > 1 ) if( Split.size() > 1 )
@ -158,6 +159,7 @@ void cWebAdmin::Request_Handler(webserver::http_request* r)
} }
delete Request.Params; delete Request.Params;
delete Request.PostParams;
if( FoundPlugin.empty() ) // Default page if( FoundPlugin.empty() ) // Default page
{ {

View File

@ -10,6 +10,7 @@ struct HTTPRequest
std::string Method; std::string Method;
std::string Path; std::string Path;
cStringMap* Params; cStringMap* Params;
cStringMap* PostParams;
std::string Username; std::string Username;
}; };
//tolua_end //tolua_end

View File

@ -76,13 +76,13 @@ std::string cWebPlugin_Lua::HandleRequest( HTTPRequest* a_Request )
if( Tab ) if( Tab )
{ {
LOGINFO("1. Stack size: %i", lua_gettop(LuaState) ); //LOGINFO("1. Stack size: %i", lua_gettop(LuaState) );
lua_rawgeti( LuaState, LUA_REGISTRYINDEX, Tab->Reference); // same as lua_getref() lua_rawgeti( LuaState, LUA_REGISTRYINDEX, Tab->Reference); // same as lua_getref()
LOGINFO("2. Stack size: %i", lua_gettop(LuaState) ); //LOGINFO("2. Stack size: %i", lua_gettop(LuaState) );
// Push HTTPRequest // Push HTTPRequest
tolua_pushusertype( LuaState, a_Request, "HTTPRequest" ); tolua_pushusertype( LuaState, a_Request, "HTTPRequest" );
LOGINFO("Calling bound function! :D"); //LOGINFO("Calling bound function! :D");
int s = lua_pcall( LuaState, 1, 1, 0); int s = lua_pcall( LuaState, 1, 1, 0);
if ( s != 0 ) if ( s != 0 )
@ -103,7 +103,7 @@ std::string cWebPlugin_Lua::HandleRequest( HTTPRequest* a_Request )
RetVal += tolua_tostring(LuaState, -1, 0); RetVal += tolua_tostring(LuaState, -1, 0);
lua_pop(LuaState, 1); // Pop return value lua_pop(LuaState, 1); // Pop return value
LOGINFO("ok. Stack size: %i", lua_gettop(LuaState) ); //LOGINFO("ok. Stack size: %i", lua_gettop(LuaState) );
} }
return RetVal; return RetVal;