BVB Source Codes

CRYENGINE Show SimpleHttpServerListener.cpp Source code

Return Download CRYENGINE: download SimpleHttpServerListener.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include <CryNetwork/ISimpleHttpServer.h>
  5. #include "SimpleHttpServerListener.h"
  6.  
  7. #include <md5/md5.h>
  8.  
  9. //#include <sstream>
  10.  
  11. CSimpleHttpServerListener CSimpleHttpServerListener::s_singleton;
  12.  
  13. ISimpleHttpServer* CSimpleHttpServerListener::s_http_server = NULL;
  14.  
  15. CSimpleHttpServerListener& CSimpleHttpServerListener::GetSingleton(ISimpleHttpServer* http_server)
  16. {
  17.         s_http_server = http_server;
  18.  
  19.         return s_singleton;
  20. }
  21.  
  22. CSimpleHttpServerListener& CSimpleHttpServerListener::GetSingleton()
  23. {
  24.         return s_singleton;
  25. }
  26.  
  27. CSimpleHttpServerListener::CSimpleHttpServerListener() : m_state(eAS_Disconnected), m_connectionID(ISimpleHttpServer::NoConnectionID)
  28. {
  29. }
  30.  
  31. CSimpleHttpServerListener::~CSimpleHttpServerListener()
  32. {
  33.  
  34. }
  35.  
  36. static ILINE void EscapeString(string& inout)
  37. {
  38.         static const char chars[] = { '&', '<', '>', '\"', '\'', '%' };
  39.         static const char* repls[] = { "&amp;", "&lt;", "&gt;", "&quot;", "&apos;", "&#37;" };
  40.  
  41.         for (size_t i = 0; i < sizeof(chars) / sizeof(char); ++i)
  42.         {
  43.                 size_t off = 0;
  44.                 while (true)
  45.                 {
  46.                         off = inout.find(chars[i], off);
  47.                         if (off == string::npos)
  48.                                 break;
  49.                         inout.replace(off, sizeof(char), repls[i]);
  50.                         off += strlen(repls[i]);
  51.                 }
  52.         }
  53. }
  54.  
  55. static const char* hexchars = "0123456789abcdef";
  56.  
  57. static ILINE string ToHexStr(const char* x, int len)
  58. {
  59.         string out;
  60.         for (int i = 0; i < len; i++)
  61.         {
  62.                 uint8 c = x[i];
  63.                 out += hexchars[c >> 4];
  64.                 out += hexchars[c & 0xf];
  65.         }
  66.         return out;
  67. }
  68.  
  69. void CSimpleHttpServerListener::Update()
  70. {
  71.         if (m_commands.empty())
  72.                 return;
  73.  
  74.         string reason;
  75.  
  76.         switch (m_state)
  77.         {
  78.         case eAS_Disconnected:
  79.                 m_commands.resize(0);
  80.                 return;
  81.  
  82.         case eAS_WaitChallengeRequest:
  83.                 {
  84.                         int start = 0;
  85.                         string command = m_commands.front().Tokenize(" ", start);
  86.                         if (command != "challenge") // challenge request must be a single method name
  87.                         {
  88.                                 reason = "Illegal Command";
  89.                                 goto L_fail;
  90.                         }
  91.  
  92.                         m_challenge.Format("%f", gEnv->pTimer->GetAsyncTime().GetSeconds());
  93.                         s_http_server->SendResponse(m_connectionID, ISimpleHttpServer::eSC_Okay, ISimpleHttpServer::eCT_XML,
  94.                                                     string().Format("<?xml version=\"1.0\"?><methodResponse><params><param><value><string>%s</string></value></param></params></methodResponse>", m_challenge.c_str()), false);
  95.                         m_state = eAS_WaitAuthenticationRequest;
  96.                         m_commands.pop_front();
  97.                         if (m_commands.empty())
  98.                                 return;
  99.                         // otherwise, fall through
  100.                 }
  101.  
  102.         case eAS_WaitAuthenticationRequest:
  103.                 {
  104.                         int start = 0;
  105.                         string command = m_commands.front().Tokenize(" ", start);
  106.                         if (command != "authenticate") // authenticate request must be with an MD5 hash
  107.                         {
  108.                                 reason = "Illegal Command";
  109.                                 goto L_fail;
  110.                         }
  111.  
  112.                         string digest = m_commands.front().Tokenize(" ", start);
  113.  
  114.                         ICVar* cvar = gEnv->pConsole->GetCVar("http_password"); // registered in CryAction::InitCVars()
  115.                         string password = cvar->GetString();
  116.                         string composed = m_challenge + ":" + password;
  117.  
  118.                         char md5[16];
  119.                         MD5Context context;
  120.                         MD5Init(&context);
  121.                         MD5Update(&context, (unsigned char*)composed.data(), composed.size());
  122.                         MD5Final((unsigned char*)md5, &context);
  123.  
  124.                         if (digest != ToHexStr(md5, 16))
  125.                         {
  126.                                 reason = "Authorization Failed";
  127.                                 goto L_fail;
  128.                         }
  129.  
  130.                         s_http_server->SendResponse(m_connectionID, ISimpleHttpServer::eSC_Okay, ISimpleHttpServer::eCT_XML,
  131.                                                     string().Format("<?xml version=\"1.0\"?><methodResponse><params><param><value><string>%s</string></value></param></params></methodResponse>", "authorized"), false);
  132.                         m_state = eAS_Authorized;
  133.                         m_commands.pop_front();
  134.                         if (m_commands.empty())
  135.                                 return;
  136.                         // otherwise, fall through
  137.                 }
  138.  
  139.         case eAS_Authorized:
  140.                 break;
  141.         }
  142.  
  143.         for (size_t i = 0; i < m_commands.size(); ++i)
  144.         {
  145.                 gEnv->pConsole->AddOutputPrintSink(this);
  146. #if defined(CVARS_WHITELIST)
  147.                 ICVarsWhitelist* pCVarsWhitelist = gEnv->pSystem->GetCVarsWhiteList();
  148.                 bool execute = (pCVarsWhitelist) ? pCVarsWhitelist->IsWhiteListed(m_commands[i].c_str(), false) : true;
  149.                 if (execute)
  150. #endif // defined(CVARS_WHITELIST)
  151.                 {
  152.                         gEnv->pConsole->ExecuteString(m_commands[i].c_str());
  153.                 }
  154.                 gEnv->pConsole->RemoveOutputPrintSink(this);
  155.  
  156.                 EscapeString(m_output);
  157.  
  158.                 s_http_server->SendResponse(m_connectionID, ISimpleHttpServer::eSC_Okay, ISimpleHttpServer::eCT_XML,
  159.                                             string().Format("<?xml version=\"1.0\"?><methodResponse><params><param><value><string>%s</string></value></param></params></methodResponse>", m_output.c_str()), false);
  160.                 m_output.resize(0);
  161.         }
  162.  
  163.         m_commands.resize(0);
  164.         return;
  165.  
  166. L_fail:
  167.         s_http_server->SendResponse(m_connectionID, ISimpleHttpServer::eSC_Okay, ISimpleHttpServer::eCT_XML,
  168.                                     string().Format("<?xml version=\"1.0\"?><methodResponse><params><param><value><string>%s</string></value></param></params></methodResponse>", reason.c_str()), true);
  169.         m_state = eAS_Disconnected;
  170.         m_commands.resize(0);
  171.         m_client.resize(0);
  172.         return;
  173. }
  174.  
  175. void CSimpleHttpServerListener::Print(const char* inszText)
  176. {
  177.         m_output += string().Format("%s\n", inszText);
  178. }
  179.  
  180. void CSimpleHttpServerListener::OnStartResult(bool started, EResultDesc desc)
  181. {
  182.         if (started)
  183.                 CryLogAlways("HTTP: server successfully started");
  184.         else
  185.         {
  186.                 string sdesc;
  187.                 switch (desc)
  188.                 {
  189.                 case eRD_Failed:
  190.                         sdesc = "failed starting server";
  191.                         break;
  192.  
  193.                 case eRD_AlreadyStarted:
  194.                         sdesc = "server already started";
  195.                         break;
  196.                 }
  197.                 CryLogAlways("HTTP: %s", sdesc.c_str());
  198.  
  199.                 gEnv->pConsole->ExecuteString("http_stopserver");
  200.         }
  201. }
  202.  
  203. void CSimpleHttpServerListener::OnClientConnected(int connectionID, string client)
  204. {
  205.         // only support one connected client
  206.         if (m_state != eAS_Disconnected)
  207.         {
  208.                 s_http_server->SendResponse(connectionID, ISimpleHttpServer::eSC_ServiceUnavailable, ISimpleHttpServer::eCT_HTML, "<HTML><HEAD><TITLE>Service Unavailable</TITLE></HEAD></HTML>", true);
  209.                 return;
  210.         }
  211.  
  212.         m_client = client;
  213.         m_challenge.resize(0);
  214.         m_state = eAS_WaitChallengeRequest;
  215.         m_connectionID = connectionID;
  216.         CryLogAlways("HTTP: accepted client connection from %s", client.c_str());
  217. }
  218.  
  219. void CSimpleHttpServerListener::OnClientDisconnected(int connectionID)
  220. {
  221.         CryLogAlways("HTTP: client from %s is gone", m_client.c_str());
  222.         m_client.resize(0);
  223.         m_state = eAS_Disconnected;
  224.         m_connectionID = ISimpleHttpServer::NoConnectionID;
  225. }
  226.  
  227. void CSimpleHttpServerListener::OnGetRequest(int connectionID, string url)
  228. {
  229.         CryLog("HTTP: client from %s is making a GET request: %s", m_client.c_str(), url.c_str());
  230.  
  231. #define HTTP_ROOT "/Libs/CryHttp"
  232. #define HTTP_FILE "/index.mhtml"
  233.  
  234.         if (url != HTTP_FILE)
  235.         {
  236.                 s_http_server->SendResponse(m_connectionID, ISimpleHttpServer::eSC_BadRequest, ISimpleHttpServer::eCT_HTML, "<HTML><HEAD><TITLE>Bad Request</TITLE></HEAD></HTML>", true);
  237.                 return;
  238.         }
  239.  
  240.         string page;
  241.         FILE* file = fopen(PathUtil::GetGameFolder() + HTTP_ROOT + HTTP_FILE, "rb");
  242.         if (file)
  243.         {
  244.                 if (0 == fseek(file, 0, SEEK_END))
  245.                 {
  246.                         long size = ftell(file);
  247.                         if (size > 0)
  248.                         {
  249.                                 page.resize(size, '0');
  250.                                 fseek(file, 0, SEEK_SET);
  251.                                 fread((char*)page.data(), 1, page.size(), file);
  252.                         }
  253.                 }
  254.                 fclose(file);
  255.         }
  256.  
  257.         if (page.empty())
  258.         {
  259.                 s_http_server->SendResponse(m_connectionID, ISimpleHttpServer::eSC_NotFound, ISimpleHttpServer::eCT_HTML, "<HTML><HEAD><TITLE>Not Found</TITLE></HEAD></HTML>", true);
  260.                 return;
  261.         }
  262.  
  263.         size_t index = page.find("$time$");
  264.         //std::stringstream ss; ss << gEnv->pTimer->GetAsyncCurTime();
  265.         char timestamp[33];
  266.         cry_sprintf(timestamp, "%f", gEnv->pTimer->GetAsyncCurTime());
  267.         page.replace(index, strlen("$time$"), timestamp);
  268.         s_http_server->SendWebpage(m_connectionID, page);
  269. }
  270.  
  271. void CSimpleHttpServerListener::OnRpcRequest(int connectionID, string xml)
  272. {
  273.         CryLog("HTTP: client from %s is making an RPC request: %s", m_client.c_str(), xml.c_str());
  274.  
  275.         string command;
  276.         XmlNodeRef root = GetISystem()->LoadXmlFromBuffer(xml.c_str(), xml.length());
  277.         if (root && root->isTag("methodCall"))
  278.         {
  279.                 if (root->getChildCount() < 1)
  280.                 {
  281.                         goto L_error;
  282.                 }
  283.                 XmlNodeRef methodName = root->getChild(0);
  284.                 if (methodName && methodName->isTag("methodName"))
  285.                 {
  286.                         command = methodName->getContent(); // command name must go first
  287.                         if (root->getChildCount() < 2)
  288.                         {
  289.                                 goto L_error;
  290.                         }
  291.                         XmlNodeRef params = root->getChild(1);
  292.                         if (params)
  293.                         {
  294.                                 if (params->isTag("params"))
  295.                                 {
  296.                                         int nparams = params->getChildCount();
  297.                                         for (int i = 0; i < nparams; ++i)
  298.                                         {
  299.                                                 XmlNodeRef param = params->getChild(i);
  300.                                                 XmlNodeRef value = param->getChild(0);
  301.                                                 if (value && value->isTag("value"))
  302.                                                 {
  303.                                                         // we treat all types as strings
  304.                                                         string svalue = " ";
  305.                                                         if (value->getChildCount() > 0)
  306.                                                         {
  307.                                                                 XmlNodeRef type = value->getChild(0);
  308.                                                                 if (type)
  309.                                                                         svalue += type->getContent();
  310.                                                         }
  311.                                                         else
  312.                                                                 svalue += value->getContent();
  313.                                                         command += svalue;
  314.                                                 }
  315.                                                 else
  316.                                                         goto L_error;
  317.                                         }
  318.                                 }
  319.                                 else
  320.                                         goto L_error;
  321.                         }
  322.                         // a command without params is allowed
  323.  
  324.                         // execute the command on the server
  325.                         CryLogAlways("HTTP: received xmlrpc command: %s", command.c_str());
  326.                         m_commands.push_back(command);
  327.  
  328.                         return;
  329.                 }
  330.         }
  331.  
  332. L_error:
  333.         s_http_server->SendResponse(m_connectionID, ISimpleHttpServer::eSC_BadRequest, ISimpleHttpServer::eCT_HTML, "<HTML><HEAD><TITLE>Bad Request</TITLE></HEAD></HTML>", true);
  334. }
  335.  
downloadSimpleHttpServerListener.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top