summaryrefslogtreecommitdiff
path: root/src/modules/m_httpd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/m_httpd.cpp')
-rw-r--r--src/modules/m_httpd.cpp189
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);
}