X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_httpd_stats.cpp;h=1e9f4ef4b92f6d8a33809b5b70d4778b6cfed8e1;hb=b0f16081ccaef527ed4b5434a7264508cf455f39;hp=4b18eadc44803ca07dbd02e53f02741e3d72546d;hpb=e84858dc7f1efdfb76efc1e115e6999fd222af74;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_httpd_stats.cpp b/src/modules/m_httpd_stats.cpp index 4b18eadc4..1e9f4ef4b 100644 --- a/src/modules/m_httpd_stats.cpp +++ b/src/modules/m_httpd_stats.cpp @@ -1,11 +1,19 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * Copyright (C) 2019 linuxdaemon + * Copyright (C) 2018 Matt Schatz + * Copyright (C) 2016 Johanna A + * Copyright (C) 2013-2016 Attila Molnar + * Copyright (C) 2013, 2017, 2019-2020 Sadie Powell + * Copyright (C) 2012 Robby + * Copyright (C) 2009 Uli Schlachter * Copyright (C) 2009 Daniel De Graaf - * Copyright (C) 2007-2008 Robin Burchell + * Copyright (C) 2008-2009 Robin Burchell * Copyright (C) 2008 Pippijn van Steenhoven - * Copyright (C) 2006-2008 Craig Edwards + * Copyright (C) 2007 John Brooks * Copyright (C) 2007 Dennis Friis + * Copyright (C) 2006-2008, 2010 Craig Edwards * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -86,7 +94,7 @@ namespace Stats for (Extensible::ExtensibleStore::const_iterator i = ext->GetExtList().begin(); i != ext->GetExtList().end(); i++) { ExtensionItem* item = i->first; - std::string value = item->serialize(FORMAT_USER, ext, i->second); + std::string value = item->ToHuman(ext, i->second); if (!value.empty()) data << "name << "\">" << Sanitize(value) << ""; else if (!item->name.empty()) @@ -99,7 +107,7 @@ namespace Stats { return data << "" << ServerInstance->Config->ServerName << "" << Sanitize(ServerInstance->Config->ServerDesc) << "" - << Sanitize(ServerInstance->GetVersionString()) << ""; + << Sanitize(ServerInstance->GetVersionString(true)) << ""; } std::ostream& ISupport(std::ostream& data) @@ -124,6 +132,7 @@ namespace Stats data << "" << ServerInstance->Users->all_opers.size() << ""; data << "" << (SocketEngine::GetUsedFds()) << "" << SocketEngine::GetMaxFds() << ""; data << "" << ServerInstance->startup_time << ""; + data << "" << ServerInstance->Time() << ""; data << ISupport; return data << ""; @@ -201,6 +210,37 @@ namespace Stats return data << ""; } + std::ostream& DumpUser(std::ostream& data, User* u) + { + data << ""; + data << "" << u->nick << "" << u->uuid << "" + << u->GetRealHost() << "" << u->GetDisplayedHost() << "" + << Sanitize(u->GetRealName()) << "" << u->server->GetName() << "" + << u->signon << "" << u->age << ""; + + if (u->IsAway()) + data << "" << Sanitize(u->awaymsg) << "" << u->awaytime << ""; + + if (u->IsOper()) + data << "" << Sanitize(u->oper->name) << ""; + + data << "" << u->GetModeLetters().substr(1) << "" << Sanitize(u->ident) << ""; + + LocalUser* lu = IS_LOCAL(u); + if (lu) + data << "" << lu->server_sa.port() << "" + << lu->server_sa.str() << "" + << lu->GetClass()->GetName() << "" + << lu->idle_lastmsg << ""; + + data << "" << u->GetIPString() << ""; + + DumpMeta(data, u); + + data << ""; + return data; + } + std::ostream& Users(std::ostream& data) { data << ""; @@ -209,24 +249,10 @@ namespace Stats { User* u = i->second; - data << ""; - data << "" << u->nick << "" << u->uuid << "" - << u->GetRealHost() << "" << u->GetDisplayedHost() << "" - << Sanitize(u->GetRealName()) << "" << u->server->GetName() << ""; - if (u->IsAway()) - data << "" << Sanitize(u->awaymsg) << "" << u->awaytime << ""; - if (u->IsOper()) - data << "" << Sanitize(u->oper->name) << ""; - data << "" << u->GetModeLetters().substr(1) << "" << Sanitize(u->ident) << ""; - LocalUser* lu = IS_LOCAL(u); - if (lu) - data << "" << lu->GetServerPort() << "" - << lu->server_sa.str() << ""; - data << "" << u->GetIPString() << ""; - - DumpMeta(data, u); + if (u->registered != REG_ALL) + continue; - data << ""; + DumpUser(data, u); } return data << ""; } @@ -265,49 +291,164 @@ namespace Stats } return data << ""; } + + enum OrderBy + { + OB_NICK, + OB_LASTMSG, + + OB_NONE + }; + + struct UserSorter + { + OrderBy order; + bool desc; + + UserSorter(OrderBy Order, bool Desc = false) : order(Order), desc(Desc) {} + + template + inline bool Compare(const T& a, const T& b) + { + return desc ? a > b : a < b; + } + + bool operator()(User* u1, User* u2) + { + switch (order) { + case OB_LASTMSG: + return Compare(IS_LOCAL(u1)->idle_lastmsg, IS_LOCAL(u2)->idle_lastmsg); + break; + case OB_NICK: + return Compare(u1->nick, u2->nick); + break; + default: + case OB_NONE: + return false; + break; + } + } + }; + + std::ostream& ListUsers(std::ostream& data, const HTTPQueryParameters& params) + { + if (params.empty()) + return Users(data); + + data << ""; + + // Filters + size_t limit = params.getNum("limit"); + bool showunreg = params.getBool("showunreg"); + bool localonly = params.getBool("localonly"); + + // Minimum time since a user's last message + unsigned long min_idle = params.getDuration("minidle"); + time_t maxlastmsg = ServerInstance->Time() - min_idle; + + if (min_idle) + // We can only check idle times on local users + localonly = true; + + // Sorting + const std::string& sortmethod = params.getString("sortby"); + bool desc = params.getBool("desc", false); + + OrderBy orderby; + if (stdalgo::string::equalsci(sortmethod, "nick")) + orderby = OB_NICK; + else if (stdalgo::string::equalsci(sortmethod, "lastmsg")) + { + orderby = OB_LASTMSG; + // We can only check idle times on local users + localonly = true; + } + else + orderby = OB_NONE; + + typedef std::list NewUserList; + NewUserList user_list; + user_hash users = ServerInstance->Users->GetUsers(); + for (user_hash::iterator i = users.begin(); i != users.end(); ++i) + { + User* u = i->second; + if (!showunreg && u->registered != REG_ALL) + continue; + + LocalUser* lu = IS_LOCAL(u); + if (localonly && !lu) + continue; + + if (min_idle && lu->idle_lastmsg > maxlastmsg) + continue; + + user_list.push_back(u); + } + + UserSorter sorter(orderby, desc); + if (sorter.order != OB_NONE && !(!localonly && sorter.order == OB_LASTMSG)) + user_list.sort(sorter); + + size_t count = 0; + for (NewUserList::const_iterator i = user_list.begin(); i != user_list.end() && (!limit || count < limit); ++i, ++count) + DumpUser(data, *i); + + data << ""; + return data; + } } class ModuleHttpStats : public Module, public HTTPRequestEventListener { HTTPdAPI API; + bool enableparams; public: ModuleHttpStats() : HTTPRequestEventListener(this) , API(this) + , enableparams(false) { } - ModResult HandleRequest(HTTPRequest* http) + void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { - std::string uri = http->GetURI(); + ConfigTag* conf = ServerInstance->Config->ConfValue("httpstats"); - if (uri != "/stats" && uri.substr(0, 7) != "/stats/") - return MOD_RES_PASSTHRU; + // Parameterized queries may cause a performance issue + // Due to the sheer volume of data + // So default them to disabled + enableparams = conf->getBool("enableparams"); + } - if (uri[uri.size() - 1] == '/') - uri.erase(uri.size() - 1, 1); + ModResult HandleRequest(HTTPRequest* http) + { + if (http->GetPath() != "/stats") + return MOD_RES_PASSTHRU; - ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling httpd event"); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Handling HTTP request for %s", http->GetPath().c_str()); bool found = true; std::stringstream data; data << ""; - if (uri == "/stats") + if (http->GetPath() == "/stats") { data << Stats::ServerInfo << Stats::General << Stats::XLines << Stats::Modules << Stats::Channels << Stats::Users << Stats::Servers << Stats::Commands; } - else if (uri == "/stats/general") + else if (http->GetPath() == "/stats/general") { data << Stats::General; } - else if (uri == "/stats/users") + else if (http->GetPath() == "/stats/users") { - data << Stats::Users; + if (enableparams) + Stats::ListUsers(data, http->GetParsedURI().query_params); + else + data << Stats::Users; } else { @@ -339,7 +480,7 @@ class ModuleHttpStats : public Module, public HTTPRequestEventListener Version GetVersion() CXX11_OVERRIDE { - return Version("Provides statistics over HTTP via m_httpd", VF_VENDOR); + return Version("Provides XML-serialised statistics about the server, channels, and users over HTTP via the /stats path.", VF_VENDOR); } };