*
* Copyright (C) 2019 linuxdaemon <linuxdaemon.irc@gmail.com>
* Copyright (C) 2018 edef <edef@edef.eu>
- * Copyright (C) 2013-2014, 2017-2019 Sadie Powell <sadie@witchery.services>
+ * Copyright (C) 2013-2014, 2017-2020 Sadie Powell <sadie@witchery.services>
* Copyright (C) 2012-2016 Attila Molnar <attilamolnar@hush.com>
- * Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
+ * Copyright (C) 2012 Robby <robby@chatbelgie.be>
* Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
* Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
* Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
{
if (!messagecomplete)
{
- AddToCull();
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "HTTP socket %d timed out", GetFd());
+ Close();
return false;
}
// 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;
}
}
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 OnError(BufferedSocketError err) CXX11_OVERRIDE
+ {
+ 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)
+ void SendHTTPError(unsigned int response, const char* errstr = NULL)
{
- HTTPHeaders empty;
+ 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(
- "<html><head></head><body>Server error %u: %s<br>"
- "<small>Powered by <a href='https://www.inspircd.org'>InspIRCd</a></small></body></html>", response, http_status_str((http_status)response));
+ "<html><head></head><body style='font-family: sans-serif; text-align: center'>"
+ "<h1 style='font-size: 48pt'>Error %u</h1><h2 style='font-size: 24pt'>%s</h2><hr>"
+ "<small>Powered by <a href='https://www.inspircd.org'>InspIRCd</a></small></body></html>",
+ response, errstr);
Page(data, response, &empty);
}
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");
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()
{
SendHeaders(s.length(), response, *hheaders);
WriteData(s);
- Close(true);
+ BufferedSocket::Close(true);
}
void Page(std::stringstream* n, unsigned int response, HTTPHeaders* hheaders)
Page(n->str(), response, hheaders);
}
- void AddToCull()
- {
- if (waitingcull)
- return;
-
- waitingcull = true;
- Close();
- ServerInstance->GlobalCulls.AddItem(this);
- }
-
bool ParseURI(const std::string& uristr, HTTPRequestURI& out)
{
http_parser_url_init(&url);
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<std::string> 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);
for (insp::intrusive_list<HttpServerSocket>::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);
}
};