]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Add an overload of StreamSocket::Close which closes when all data has been written.
authorlinuxdaemon <linuxdaemon@users.noreply.github.com>
Wed, 22 May 2019 18:47:17 +0000 (13:47 -0500)
committerPeter Powell <petpow@saberuk.com>
Wed, 22 May 2019 18:47:17 +0000 (19:47 +0100)
Fixes sending large pages in m_httpd (#1646).

include/inspsocket.h
src/inspsocket.cpp
src/modules/m_httpd.cpp

index a41c3ebc733e666c08ccdf0c4c873c88c99b5236..a07c2eb6f82c2aaf4519496fa7dadee80b69e560 100644 (file)
@@ -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;
 
index 59d9558a4ecd25a83930ff9a2935e853080d39b3..684ee051dd96cdc4ede09f68895a785912672ad8 100644 (file)
@@ -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)
index 8c409cbcb7a6f9501179ded1f03659cc22687524..dadd2f257e68ccee3c3f7cbccb7819ce3821c1de 100644 (file)
@@ -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()