summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlinuxdaemon <linuxdaemon@users.noreply.github.com>2019-05-22 13:47:17 -0500
committerPeter Powell <petpow@saberuk.com>2019-05-22 19:47:17 +0100
commitde7011e54ad88656e01c92a88dd053a94b5acc6b (patch)
tree713d80e075dd880f0d635eee297bd313441b0337
parent05756b842f26c647e527ec186c192c8cf448113f (diff)
Add an overload of StreamSocket::Close which closes when all data has been written.
Fixes sending large pages in m_httpd (#1646).
-rw-r--r--include/inspsocket.h14
-rw-r--r--src/inspsocket.cpp20
-rw-r--r--src/modules/m_httpd.cpp27
3 files changed, 52 insertions, 9 deletions
diff --git a/include/inspsocket.h b/include/inspsocket.h
index a41c3ebc7..a07c2eb6f 100644
--- a/include/inspsocket.h
+++ b/include/inspsocket.h
@@ -227,6 +227,12 @@ class CoreExport StreamSocket : public EventHandler
};
private:
+ /** Whether this socket should close once its sendq is empty */
+ bool closeonempty;
+
+ /** Whether the socket is currently closing or not, used to avoid repeatedly closing a closed socket */
+ bool closing;
+
/** The IOHook that handles raw I/O for this socket, or NULL */
IOHook* iohook;
@@ -273,7 +279,9 @@ class CoreExport StreamSocket : public EventHandler
public:
const Type type;
StreamSocket(Type sstype = SS_UNKNOWN)
- : iohook(NULL)
+ : closeonempty(false)
+ , closing(false)
+ , iohook(NULL)
, type(sstype)
{
}
@@ -334,6 +342,10 @@ class CoreExport StreamSocket : public EventHandler
* Close the socket, remove from socket engine, etc
*/
virtual void Close();
+
+ /** If writeblock is true then only close the socket if all data has been sent. Otherwise, close immediately. */
+ void Close(bool writeblock);
+
/** This ensures that close is called prior to destructor */
CullResult cull() CXX11_OVERRIDE;
diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp
index 59d9558a4..684ee051d 100644
--- a/src/inspsocket.cpp
+++ b/src/inspsocket.cpp
@@ -95,6 +95,10 @@ BufferedSocketError BufferedSocket::BeginConnect(const irc::sockets::sockaddrs&
void StreamSocket::Close()
{
+ if (closing)
+ return;
+
+ closing = true;
if (this->fd > -1)
{
// final chance, dump as much of the sendq as we can
@@ -114,6 +118,14 @@ void StreamSocket::Close()
}
}
+void StreamSocket::Close(bool writeblock)
+{
+ if (getSendQSize() != 0 && writeblock)
+ closeonempty = true;
+ else
+ Close();
+}
+
CullResult StreamSocket::cull()
{
Close();
@@ -206,7 +218,12 @@ static const int MYIOV_MAX = IOV_MAX < 128 ? IOV_MAX : 128;
void StreamSocket::DoWrite()
{
if (getSendQSize() == 0)
+ {
+ if (closeonempty)
+ Close();
+
return;
+ }
if (!error.empty() || fd < 0)
{
ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "DoWrite on errored or closed socket");
@@ -242,6 +259,9 @@ void StreamSocket::DoWrite()
if (psendq)
FlushSendQ(*psendq);
+
+ if (getSendQSize() == 0 && closeonempty)
+ Close();
}
void StreamSocket::FlushSendQ(SendQueue& sq)
diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp
index 8c409cbcb..dadd2f257 100644
--- a/src/modules/m_httpd.cpp
+++ b/src/modules/m_httpd.cpp
@@ -72,11 +72,17 @@ 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)
+ {
+ AddToCull();
+ return false;
+ }
+
+ return true;
}
template<int (HttpServerSocket::*f)()>
@@ -186,6 +192,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru
int OnMessageComplete()
{
+ messagecomplete = true;
ServeData();
return 0;
}
@@ -197,6 +204,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()))
{
@@ -231,9 +239,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru
"<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));
- SendHeaders(data.length(), response, empty);
- WriteData(data);
- Close();
+ Page(data, response, &empty);
}
void SendHeaders(unsigned long size, unsigned int response, HTTPHeaders &rheaders)
@@ -286,11 +292,16 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru
}
}
+ void Page(const std::string& s, unsigned int response, HTTPHeaders* hheaders)
+ {
+ SendHeaders(s.length(), response, *hheaders);
+ WriteData(s);
+ Close(true);
+ }
+
void Page(std::stringstream* n, unsigned int response, HTTPHeaders* hheaders)
{
- SendHeaders(n->str().length(), response, *hheaders);
- WriteData(n->str());
- Close();
+ Page(n->str(), response, hheaders);
}
void AddToCull()