diff options
Diffstat (limited to 'src/modules/m_httpd.cpp')
-rw-r--r-- | src/modules/m_httpd.cpp | 189 |
1 files changed, 101 insertions, 88 deletions
diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp index 2b079c6ff..a20b85f9d 100644 --- a/src/modules/m_httpd.cpp +++ b/src/modules/m_httpd.cpp @@ -23,16 +23,15 @@ #include "inspircd.h" -#include "httpd.h" - -/* $ModDesc: Provides HTTP serving facilities to modules */ -/* $ModDep: httpd.h */ +#include "iohook.h" +#include "modules/httpd.h" class ModuleHttpServer; static ModuleHttpServer* HttpModule; -static bool claimed; -static std::set<HttpServerSocket*> sockets; +static insp::intrusive_list<HttpServerSocket> sockets; +static Events::ModuleEventProvider* aclevprov; +static Events::ModuleEventProvider* reqevprov; /** HTTP socket states */ @@ -45,7 +44,7 @@ enum HttpState /** A socket used for HTTP transport */ -class HttpServerSocket : public BufferedSocket +class HttpServerSocket : public BufferedSocket, public Timer, public insp::intrusive_list_node<HttpServerSocket> { HttpState InternalState; std::string ip; @@ -58,18 +57,37 @@ class HttpServerSocket : public BufferedSocket std::string uri; std::string http_version; - public: - const time_t createtime; + /** True if this object is in the cull list + */ + bool waitingcull; - HttpServerSocket(int newfd, const std::string& IP, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) - : BufferedSocket(newfd), ip(IP), postsize(0) - , createtime(ServerInstance->Time()) + bool Tick(time_t currtime) CXX11_OVERRIDE { - InternalState = HTTP_SERVE_WAIT_REQUEST; + AddToCull(); + return false; + } - FOREACH_MOD(I_OnHookIO, OnHookIO(this, via)); - if (GetIOHook()) - GetIOHook()->OnStreamSocketAccept(this, client, server); + public: + HttpServerSocket(int newfd, const std::string& IP, ListenSocket* via, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server, unsigned int timeoutsec) + : BufferedSocket(newfd) + , Timer(timeoutsec) + , InternalState(HTTP_SERVE_WAIT_REQUEST) + , ip(IP) + , postsize(0) + , waitingcull(false) + { + if ((!via->iohookprovs.empty()) && (via->iohookprovs.back())) + { + via->iohookprovs.back()->OnAccept(this, client, server); + // IOHook may have errored + if (!getError().empty()) + { + AddToCull(); + return; + } + } + + ServerInstance->Timers.AddTimer(this); } ~HttpServerSocket() @@ -77,12 +95,12 @@ class HttpServerSocket : public BufferedSocket sockets.erase(this); } - virtual void OnError(BufferedSocketError) + void OnError(BufferedSocketError) CXX11_OVERRIDE { - ServerInstance->GlobalCulls.AddItem(this); + AddToCull(); } - std::string Response(int response) + std::string Response(unsigned int response) { switch (response) { @@ -173,7 +191,7 @@ class HttpServerSocket : public BufferedSocket } } - void SendHTTPError(int response) + void SendHTTPError(unsigned int response) { HTTPHeaders empty; std::string data = "<html><head></head><body>Server error "+ConvToStr(response)+": "+Response(response)+"<br>"+ @@ -183,18 +201,13 @@ class HttpServerSocket : public BufferedSocket WriteData(data); } - void SendHeaders(unsigned long size, int response, HTTPHeaders &rheaders) + void SendHeaders(unsigned long size, unsigned int response, HTTPHeaders &rheaders) { WriteData(http_version + " "+ConvToStr(response)+" "+Response(response)+"\r\n"); - time_t local = ServerInstance->Time(); - struct tm *timeinfo = gmtime(&local); - char *date = asctime(timeinfo); - date[strlen(date) - 1] = '\0'; - rheaders.CreateHeader("Date", date); - - rheaders.CreateHeader("Server", BRANCH); + rheaders.CreateHeader("Date", InspIRCd::TimeString(ServerInstance->Time(), "%a, %d %b %Y %H:%M:%S GMT", true)); + rheaders.CreateHeader("Server", INSPIRCD_BRANCH); rheaders.SetHeader("Content-Length", ConvToStr(size)); if (size) @@ -211,7 +224,7 @@ class HttpServerSocket : public BufferedSocket WriteData("\r\n"); } - void OnDataReady() + void OnDataReady() CXX11_OVERRIDE { if (InternalState == HTTP_SERVE_RECV_POSTDATA) { @@ -225,7 +238,7 @@ class HttpServerSocket : public BufferedSocket if (reqbuffer.length() >= 8192) { - ServerInstance->Logs->Log("m_httpd",DEBUG, "m_httpd dropped connection due to an oversized request buffer"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "m_httpd dropped connection due to an oversized request buffer"); reqbuffer.clear(); SetError("Buffer"); } @@ -265,7 +278,7 @@ class HttpServerSocket : public BufferedSocket continue; } - std::string cheader = reqbuffer.substr(hbegin, hend - hbegin); + std::string cheader(reqbuffer, hbegin, hend - hbegin); std::string::size_type fieldsep = cheader.find(':'); if ((fieldsep == std::string::npos) || (fieldsep == 0) || (fieldsep == cheader.length() - 1)) @@ -296,7 +309,7 @@ class HttpServerSocket : public BufferedSocket if (reqbuffer.length() >= postsize) { - postdata = reqbuffer.substr(0, postsize); + postdata.assign(reqbuffer, 0, postsize); reqbuffer.erase(0, postsize); } else if (!reqbuffer.empty()) @@ -318,92 +331,95 @@ class HttpServerSocket : public BufferedSocket { InternalState = HTTP_SERVE_SEND_DATA; - claimed = false; - HTTPRequest acl((Module*)HttpModule, "httpd_acl", request_type, uri, &headers, this, ip, postdata); - acl.Send(); - if (!claimed) + ModResult MOD_RESULT; + HTTPRequest acl(request_type, uri, &headers, this, ip, postdata); + FIRST_MOD_RESULT_CUSTOM(*aclevprov, HTTPACLEventListener, OnHTTPACLCheck, MOD_RESULT, (acl)); + if (MOD_RESULT != MOD_RES_DENY) { - HTTPRequest url((Module*)HttpModule, "httpd_url", request_type, uri, &headers, this, ip, postdata); - url.Send(); - if (!claimed) + HTTPRequest url(request_type, uri, &headers, this, ip, postdata); + FIRST_MOD_RESULT_CUSTOM(*reqevprov, HTTPRequestEventListener, OnHTTPRequest, MOD_RESULT, (url)); + if (MOD_RESULT == MOD_RES_PASSTHRU) { SendHTTPError(404); } } } - void Page(std::stringstream* n, int response, HTTPHeaders *hheaders) + void Page(std::stringstream* n, unsigned int response, HTTPHeaders *hheaders) { SendHeaders(n->str().length(), response, *hheaders); WriteData(n->str()); } + + void AddToCull() + { + if (waitingcull) + return; + + waitingcull = true; + Close(); + ServerInstance->GlobalCulls.AddItem(this); + } +}; + +class HTTPdAPIImpl : public HTTPdAPIBase +{ + public: + HTTPdAPIImpl(Module* parent) + : HTTPdAPIBase(parent) + { + } + + void SendResponse(HTTPDocumentResponse& resp) CXX11_OVERRIDE + { + resp.src.sock->Page(resp.document, resp.responsecode, &resp.headers); + } }; class ModuleHttpServer : public Module { + HTTPdAPIImpl APIImpl; unsigned int timeoutsec; + Events::ModuleEventProvider acleventprov; + Events::ModuleEventProvider reqeventprov; public: - - void init() + ModuleHttpServer() + : APIImpl(this) + , acleventprov(this, "event/http-acl") + , reqeventprov(this, "event/http-request") { - HttpModule = this; - Implementation eventlist[] = { I_OnAcceptConnection, I_OnBackgroundTimer, I_OnRehash, I_OnUnloadModule }; - ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation)); - OnRehash(NULL); + aclevprov = &acleventprov; + reqevprov = &reqeventprov; } - void OnRehash(User* user) + void init() CXX11_OVERRIDE { - ConfigTag* tag = ServerInstance->Config->ConfValue("httpd"); - timeoutsec = tag->getInt("timeout"); + HttpModule = this; } - void OnRequest(Request& request) + void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { - if (strcmp(request.id, "HTTP-DOC") != 0) - return; - HTTPDocumentResponse& resp = static_cast<HTTPDocumentResponse&>(request); - claimed = true; - resp.src.sock->Page(resp.document, resp.responsecode, &resp.headers); + ConfigTag* tag = ServerInstance->Config->ConfValue("httpd"); + timeoutsec = tag->getDuration("timeout", 10, 1); } - ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) + ModResult OnAcceptConnection(int nfd, ListenSocket* from, irc::sockets::sockaddrs* client, irc::sockets::sockaddrs* server) CXX11_OVERRIDE { if (from->bind_tag->getString("type") != "httpd") return MOD_RES_PASSTHRU; - int port; - std::string incomingip; - irc::sockets::satoap(*client, incomingip, port); - sockets.insert(new HttpServerSocket(nfd, incomingip, from, client, server)); - return MOD_RES_ALLOW; - } - void OnBackgroundTimer(time_t curtime) - { - if (!timeoutsec) - return; - - time_t oldest_allowed = curtime - timeoutsec; - for (std::set<HttpServerSocket*>::const_iterator i = sockets.begin(); i != sockets.end(); ) - { - HttpServerSocket* sock = *i; - ++i; - if (sock->createtime < oldest_allowed) - { - sock->cull(); - delete sock; - } - } + sockets.push_front(new HttpServerSocket(nfd, client->addr(), from, client, server, timeoutsec)); + return MOD_RES_ALLOW; } - void OnUnloadModule(Module* mod) + void OnUnloadModule(Module* mod) CXX11_OVERRIDE { - for (std::set<HttpServerSocket*>::const_iterator i = sockets.begin(); i != sockets.end(); ) + for (insp::intrusive_list<HttpServerSocket>::const_iterator i = sockets.begin(); i != sockets.end(); ) { HttpServerSocket* sock = *i; ++i; - if (sock->GetIOHook() == mod) + if (sock->GetModHook(mod)) { sock->cull(); delete sock; @@ -411,20 +427,17 @@ class ModuleHttpServer : public Module } } - CullResult cull() + CullResult cull() CXX11_OVERRIDE { - std::set<HttpServerSocket*> local; - local.swap(sockets); - for (std::set<HttpServerSocket*>::const_iterator i = local.begin(); i != local.end(); ++i) + for (insp::intrusive_list<HttpServerSocket>::const_iterator i = sockets.begin(); i != sockets.end(); ++i) { HttpServerSocket* sock = *i; - sock->cull(); - delete sock; + sock->AddToCull(); } return Module::cull(); } - virtual Version GetVersion() + Version GetVersion() CXX11_OVERRIDE { return Version("Provides HTTP serving facilities to modules", VF_VENDOR); } |