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 )
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 .. "<p>Reloading plugins... This can take a while depending on the plugins you're using.</p>"
cRoot:Get():GetPluginManager():ReloadPlugins()
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 .. "<input type=\"submit\" name=\"reload\" value=\"Reload!\"></p>"
Content = Content .. "</form>"

View File

@ -1,11 +1,11 @@
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
function HandleRequest_WhiteList( Request )
local UpdateMessage = ""
if( Request.Params:get("whitelist-add") ~= "" ) then
local PlayerName = Request.Params:get("whitelist-add")
if( Request.PostParams:get("whitelist-add") ~= "" ) then
local PlayerName = Request.PostParams:get("whitelist-add")
if( WhiteListIni:GetValueB("WhiteList", PlayerName, false) == true ) then
UpdateMessage = "<b>".. PlayerName.."</b> is already on the whitelist"
@ -14,12 +14,12 @@ function HandleRequest_WhiteList( Request )
UpdateMessage = "Added <b>" .. PlayerName .. "</b> to whitelist."
WhiteListIni:WriteFile()
end
elseif( Request.Params:get("whitelist-delete") ~= "" ) then
local PlayerName = Request.Params:get("whitelist-delete")
elseif( Request.PostParams:get("whitelist-delete") ~= "" ) then
local PlayerName = Request.PostParams:get("whitelist-delete")
WhiteListIni:DeleteValue( "WhiteList", PlayerName )
UpdateMessage = "Removed <b>" .. PlayerName .. "</b> from whitelist."
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:ReadFile()
UpdateMessage = "Loaded from disk"
@ -63,10 +63,10 @@ function HandleRequest_WhiteList( Request )
end
Content = Content .. "</table>"
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 .. "</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 .. "</form>"
Content = Content .. "<br>"..UpdateMessage

View File

@ -9,4 +9,11 @@
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</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>

View File

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

View File

@ -118,11 +118,20 @@ Socket& Socket::operator=(Socket& o) {
return *this;
}
void Socket::Close() {
void Socket::Close( bool a_WaitSend /* = false */ )
{
if( s_ )
{
closesocket(s_);
s_ = 0;
if( a_WaitSend )
{
assert( shutdown(s_, SD_SEND ) == 0 );
char c;
while( recv(s_, &c, 1, 0 ) != 0 )
{}
}
closesocket(s_);
s_ = 0;
}
}
@ -135,12 +144,25 @@ std::string Socket::ReceiveLine() {
{
return "";
}
ret += r;
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) {
s += '\n';
if( send(s_,s.c_str(),s.length(),MSG_NOSIGNAL) <= 0 )

View File

@ -31,11 +31,13 @@
#ifndef SOCKET_H
#define SOCKET_H
#include "../source/MCSocket.h"
// #ifdef _WIN32
// #include <winsock2.h>
// #endif
// #include <winsock2.h>
// #endif
#include <string>
@ -49,9 +51,9 @@ public:
Socket& operator=(Socket&);
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
// because SendLine modifes the std::string passed.

View File

@ -12,12 +12,12 @@
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
@ -55,121 +55,160 @@ unsigned webserver::Request(void* ptr_s)
void* webserver::Request(void* ptr_s)
#endif
{
Socket* s = (reinterpret_cast<Socket*>(ptr_s));
Socket* s = (reinterpret_cast<Socket*>(ptr_s));
std::string line = s->ReceiveLine();
if (line.empty()) {
s->Close();
delete s;
return 0;
}
std::string line = s->ReceiveLine();
if (line.empty())
{
s->Close();
delete s;
return 0;
}
http_request req;
http_request req;
std::string path;
std::map<std::string, std::string> params;
size_t posStartPath = 0;
if (line.find("GET") == 0) {
req.method_="GET";
}
else if (line.find("POST") == 0) {
req.method_="POST";
}
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);
}
std::string path;
std::map<std::string, std::string> params;
SplitGetReq(line.substr(posStartPath), path, params);
size_t posStartPath = line.find_first_not_of(" ",3);
req.status_ = "202 OK";
req.s_ = s;
req.path_ = path;
req.params_ = params;
SplitGetReq(line.substr(posStartPath), path, params);
static const std::string authorization = "Authorization: Basic ";
static const std::string accept = "Accept: " ;
static const std::string accept_language = "Accept-Language: " ;
static const std::string accept_encoding = "Accept-Encoding: " ;
static const std::string user_agent = "User-Agent: " ;
static const std::string content_length = "Content-Length: " ;
static const std::string content_type = "Content-Type: " ;
req.status_ = "202 OK";
req.s_ = s;
req.path_ = path;
req.params_ = params;
while(1)
{
line=s->ReceiveLine();
if (line.empty()) break;
static const std::string authorization = "Authorization: Basic ";
static const std::string accept = "Accept: " ;
static const std::string accept_language = "Accept-Language: " ;
static const std::string accept_encoding = "Accept-Encoding: " ;
static const std::string user_agent = "User-Agent: " ;
unsigned int pos_cr_lf = line.find_first_of("\x0a\x0d");
if (pos_cr_lf == 0) break;
while(1) {
line=s->ReceiveLine();
line = line.substr(0,pos_cr_lf);
if (line.empty()) break;
if (line.substr(0, authorization.size()) == authorization)
{
req.authentication_given_ = true;
std::string encoded = line.substr(authorization.size());
std::string decoded = base64_decode(encoded);
unsigned int pos_cr_lf = line.find_first_of("\x0a\x0d");
if (pos_cr_lf == 0) break;
unsigned int pos_colon = decoded.find(":");
line = line.substr(0,pos_cr_lf);
req.username_ = decoded.substr(0, pos_colon);
req.password_ = decoded.substr(pos_colon+1 );
}
else if (line.substr(0, accept.size()) == accept)
{
req.accept_ = line.substr(accept.size());
}
else if (line.substr(0, accept_language.size()) == accept_language)
{
req.accept_language_ = line.substr(accept_language.size());
}
else if (line.substr(0, accept_encoding.size()) == accept_encoding)
{
req.accept_encoding_ = line.substr(accept_encoding.size());
}
else if (line.substr(0, user_agent.size()) == user_agent)
{
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 (line.substr(0, authorization.size()) == authorization) {
req.authentication_given_ = true;
std::string encoded = line.substr(authorization.size());
std::string decoded = base64_decode(encoded);
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
unsigned int pos_colon = decoded.find(":");
std::string dummy;
std::map<std::string, std::string> post_params;
SplitGetReq(Content, dummy, post_params);
req.username_ = decoded.substr(0, pos_colon);
req.password_ = decoded.substr(pos_colon+1 );
}
else if (line.substr(0, accept.size()) == accept) {
req.accept_ = line.substr(accept.size());
}
else if (line.substr(0, accept_language.size()) == accept_language) {
req.accept_language_ = line.substr(accept_language.size());
}
else if (line.substr(0, accept_encoding.size()) == accept_encoding) {
req.accept_encoding_ = line.substr(accept_encoding.size());
}
else if (line.substr(0, user_agent.size()) == user_agent) {
req.user_agent_ = line.substr(user_agent.size());
}
}
req.params_post_ = post_params;
}
}
}
request_func_(&req);
request_func_(&req);
std::stringstream str_str;
str_str << req.answer_.size();
std::stringstream str_str;
str_str << req.answer_.size();
time_t ltime;
time(&ltime);
tm* gmt= gmtime(&ltime);
time_t ltime;
time(&ltime);
tm* gmt= gmtime(&ltime);
#ifdef _WIN32
static std::string const serverName = "MCServerWebAdmin (Windows)";
static std::string const serverName = "MCServerWebAdmin (Windows)";
#elif __APPLE__
static std::string const serverName = "MCServerWebAdmin (MacOSX)";
static std::string const serverName = "MCServerWebAdmin (MacOSX)";
#else
static std::string const serverName = "MCServerWebAdmin (Linux)";
static std::string const serverName = "MCServerWebAdmin (Linux)";
#endif
char* asctime_remove_nl = std::asctime(gmt);
asctime_remove_nl[24] = 0;
char* asctime_remove_nl = std::asctime(gmt);
asctime_remove_nl[24] = 0;
s->SendBytes("HTTP/1.1 ");
s->SendBytes("HTTP/1.1 ");
if (! req.auth_realm_.empty() ) {
s->SendLine("401 Unauthorized");
s->SendBytes("WWW-Authenticate: Basic Realm=\"");
s->SendBytes(req.auth_realm_);
s->SendLine("\"");
}
else {
s->SendLine(req.status_);
}
s->SendLine(std::string("Date: ") + asctime_remove_nl + " GMT");
s->SendLine(std::string("Server: ") +serverName);
s->SendLine("Connection: close");
s->SendLine("Content-Type: text/html; charset=ISO-8859-1");
s->SendLine("Content-Length: " + str_str.str());
s->SendLine("");
s->SendLine(req.answer_);
if (! req.auth_realm_.empty() )
{
s->SendLine("401 Unauthorized");
s->SendBytes("WWW-Authenticate: Basic Realm=\"");
s->SendBytes(req.auth_realm_);
s->SendLine("\"");
}
else
{
s->SendLine(req.status_);
}
s->SendLine(std::string("Date: ") + asctime_remove_nl + " GMT");
s->SendLine(std::string("Server: ") +serverName);
s->SendLine("Connection: close");
s->SendLine("Content-Type: text/html; charset=ISO-8859-1");
s->SendLine("Content-Length: " + str_str.str());
s->SendLine("");
s->SendLine(req.answer_);
s->Close();
delete s;
s->Close( true ); // true = wait for all data to be sent before closing
delete s;
return 0;
return 0;
}
void webserver::Stop()

View File

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

View File

@ -1,6 +1,6 @@
/*
** 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
@ -10453,6 +10453,36 @@ static int tolua_set_HTTPRequest_Params_ptr(lua_State* tolua_S)
}
#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 */
#ifndef TOLUA_DISABLE_tolua_get_HTTPRequest_Username
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,"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,"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_endmodule(tolua_S);
#ifdef __cplusplus

View File

@ -1,6 +1,6 @@
/*
** 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 */

View File

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

View File

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

View File

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

View File

@ -76,13 +76,13 @@ std::string cWebPlugin_Lua::HandleRequest( HTTPRequest* a_Request )
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()
LOGINFO("2. Stack size: %i", lua_gettop(LuaState) );
//LOGINFO("2. Stack size: %i", lua_gettop(LuaState) );
// Push 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);
if ( s != 0 )
@ -103,7 +103,7 @@ std::string cWebPlugin_Lua::HandleRequest( HTTPRequest* a_Request )
RetVal += tolua_tostring(LuaState, -1, 0);
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;