X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_httpd.cpp;h=f3ec3298bd8823b154b4c9fb5017159ba7bea800;hb=b4a174ee9c32d62ea6bf010e837e8c5b1c3d36a3;hp=f9e5bc0fdca282acb328208c51deef4780847e02;hpb=87b1461e2a4710a38b32186c2582da9fe9bb3804;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp index f9e5bc0fd..f3ec3298b 100644 --- a/src/modules/m_httpd.cpp +++ b/src/modules/m_httpd.cpp @@ -1,12 +1,17 @@ /* * InspIRCd -- Internet Relay Chat Daemon * + * Copyright (C) 2019 linuxdaemon + * Copyright (C) 2018 edef + * Copyright (C) 2013-2014, 2017-2020 Sadie Powell + * Copyright (C) 2012-2016 Attila Molnar + * Copyright (C) 2012 Robby + * Copyright (C) 2009 Uli Schlachter * Copyright (C) 2009 Daniel De Graaf - * Copyright (C) 2007-2008 Robin Burchell - * Copyright (C) 2008 Pippijn van Steenhoven - * Copyright (C) 2006-2008 Craig Edwards - * Copyright (C) 2007 John Brooks + * Copyright (C) 2008 Robin Burchell + * 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 @@ -28,10 +33,17 @@ #include "iohook.h" #include "modules/httpd.h" -// Fix warnings about the use of commas at end of enumerator lists on C++03. +#ifdef __GNUC__ +# pragma GCC diagnostic push +#endif + +// Fix warnings about the use of commas at end of enumerator lists and long long +// on C++03. #if defined __clang__ # pragma clang diagnostic ignored "-Wc++11-extensions" +# pragma clang diagnostic ignored "-Wc++11-long-long" #elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) # pragma GCC diagnostic ignored "-Wpedantic" # else @@ -46,6 +58,10 @@ #include +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif + class ModuleHttpServer; static ModuleHttpServer* HttpModule; @@ -58,7 +74,8 @@ static http_parser_settings parser_settings; */ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intrusive_list_node { - friend ModuleHttpServer; + private: + friend class ModuleHttpServer; http_parser parser; http_parser_url url; @@ -72,11 +89,18 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru /** True if this object is in the cull list */ bool waitingcull; + bool messagecomplete; bool Tick(time_t currtime) CXX11_OVERRIDE { - AddToCull(); - return false; + if (!messagecomplete) + { + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP socket %d timed out", GetFd()); + Close(); + return false; + } + + return true; } template @@ -186,6 +210,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru int OnMessageComplete() { + messagecomplete = true; ServeData(); return 0; } @@ -197,6 +222,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru , ip(IP) , status_code(0) , waitingcull(false) + , messagecomplete(false) { if ((!via->iohookprovs.empty()) && (via->iohookprovs.back())) { @@ -204,7 +230,9 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru // IOHook may have errored if (!getError().empty()) { - AddToCull(); + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP socket %d encountered a hook error: %s", + GetFd(), getError().c_str()); + Close(); return; } } @@ -219,21 +247,37 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru sockets.erase(this); } - void OnError(BufferedSocketError) CXX11_OVERRIDE + void Close() CXX11_OVERRIDE { - AddToCull(); + if (waitingcull || !HasFd()) + return; + + waitingcull = true; + BufferedSocket::Close(); + ServerInstance->GlobalCulls.AddItem(this); } - void SendHTTPError(unsigned int response) + void OnError(BufferedSocketError err) CXX11_OVERRIDE { - HTTPHeaders empty; + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP socket %d encountered an error: %d - %s", + GetFd(), err, getError().c_str()); + Close(); + } + + void SendHTTPError(unsigned int response, const char* errstr = NULL) + { + if (!errstr) + errstr = http_status_str((http_status)response); + + ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Sending HTTP error %u: %s", response, errstr); + static HTTPHeaders empty; std::string data = InspIRCd::Format( - "Server error %u: %s
" - "Powered by InspIRCd", response, http_status_str((http_status)response)); + "" + "

Error %u

%s


" + "Powered by InspIRCd", + response, errstr); - SendHeaders(data.length(), response, empty); - WriteData(data); - Close(); + Page(data, response, &empty); } void SendHeaders(unsigned long size, unsigned int response, HTTPHeaders &rheaders) @@ -249,7 +293,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru else rheaders.RemoveHeader("Content-Type"); - /* Supporting Connection: keep-alive causes a whole world of hurt syncronizing timeouts, + /* Supporting Connection: keep-alive causes a whole world of hurt synchronizing timeouts, * so remove it, its not essential for what we need. */ rheaders.SetHeader("Connection", "Close"); @@ -263,8 +307,10 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru if (parser.upgrade || HTTP_PARSER_ERRNO(&parser)) return; http_parser_execute(&parser, &parser_settings, recvq.data(), recvq.size()); - if (parser.upgrade || HTTP_PARSER_ERRNO(&parser)) + if (parser.upgrade) SendHTTPError(status_code ? status_code : 400); + else if (HTTP_PARSER_ERRNO(&parser)) + SendHTTPError(status_code ? status_code : 400, http_errno_description((http_errno)parser.http_errno)); } void ServeData() @@ -277,8 +323,8 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru FIRST_MOD_RESULT_CUSTOM(*aclevprov, HTTPACLEventListener, OnHTTPACLCheck, MOD_RESULT, (acl)); if (MOD_RESULT != MOD_RES_DENY) { - HTTPRequest url(method, parsed, &headers, this, ip, body); - FIRST_MOD_RESULT_CUSTOM(*reqevprov, HTTPRequestEventListener, OnHTTPRequest, MOD_RESULT, (url)); + HTTPRequest request(method, parsed, &headers, this, ip, body); + FIRST_MOD_RESULT_CUSTOM(*reqevprov, HTTPRequestEventListener, OnHTTPRequest, MOD_RESULT, (request)); if (MOD_RESULT == MOD_RES_PASSTHRU) { SendHTTPError(404); @@ -286,31 +332,51 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru } } - void Page(std::stringstream* n, unsigned int response, HTTPHeaders* hheaders) + void Page(const std::string& s, unsigned int response, HTTPHeaders* hheaders) { - SendHeaders(n->str().length(), response, *hheaders); - WriteData(n->str()); - Close(); + SendHeaders(s.length(), response, *hheaders); + WriteData(s); + BufferedSocket::Close(true); } - void AddToCull() + void Page(std::stringstream* n, unsigned int response, HTTPHeaders* hheaders) { - if (waitingcull) - return; - - waitingcull = true; - Close(); - ServerInstance->GlobalCulls.AddItem(this); + Page(n->str(), response, hheaders); } - bool ParseURI(const std::string& uri, HTTPRequestURI& out) + bool ParseURI(const std::string& uristr, HTTPRequestURI& out) { http_parser_url_init(&url); - if (http_parser_parse_url(uri.c_str(), uri.size(), 0, &url) != 0) + if (http_parser_parse_url(uristr.c_str(), uristr.size(), 0, &url) != 0) return false; if (url.field_set & (1 << UF_PATH)) - out.path = uri.substr(url.field_data[UF_PATH].off, url.field_data[UF_PATH].len); + { + // Normalise the path. + std::vector pathsegments; + irc::sepstream pathstream(uri.substr(url.field_data[UF_PATH].off, url.field_data[UF_PATH].len), '/'); + for (std::string pathsegment; pathstream.GetToken(pathsegment); ) + { + if (pathsegment == ".") + { + // Stay at the current level. + continue; + } + + if (pathsegment == "..") + { + // Traverse up to the previous level. + if (!pathsegments.empty()) + pathsegments.pop_back(); + continue; + } + + pathsegments.push_back(pathsegment); + } + + out.path.reserve(url.field_data[UF_PATH].len); + out.path.append("/").append(stdalgo::string::join(pathsegments, '/')); + } if (url.field_set & (1 << UF_FRAGMENT)) out.fragment = uri.substr(url.field_data[UF_FRAGMENT].off, url.field_data[UF_FRAGMENT].len); @@ -409,14 +475,14 @@ class ModuleHttpServer : public Module for (insp::intrusive_list::const_iterator i = sockets.begin(); i != sockets.end(); ++i) { HttpServerSocket* sock = *i; - sock->AddToCull(); + sock->Close(); } return Module::cull(); } Version GetVersion() CXX11_OVERRIDE { - return Version("Provides HTTP serving facilities to modules", VF_VENDOR); + return Version("Allows the server administrator to serve various useful resources over HTTP.", VF_VENDOR); } };